Add OpenCV source code
[platform/upstream/opencv.git] / modules / highgui / src / window_cocoa.mm
1 /* The file is the modified version of window_cocoa.mm from opencv-cocoa project by Andre Cohen */
2
3 /*M///////////////////////////////////////////////////////////////////////////////////////
4 //
5 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
6 //
7 //  By downloading, copying, installing or using the software you agree to this license.
8 //  If you do not agree to this license, do not download, install,
9 //  copy or use the software.
10 //
11 //
12 //                         License Agreement
13 //                For Open Source Computer Vision Library
14 //
15 // Copyright (C) 2010, Willow Garage Inc., all rights reserved.
16 // Third party copyrights are property of their respective owners.
17 //
18 // Redistribution and use in source and binary forms, with or without modification,
19 // are permitted provided that the following conditions are met:
20 //
21 //   * Redistribution's of source code must retain the above copyright notice,
22 //     this list of conditions and the following disclaimer.
23 //
24 //   * Redistribution's in binary form must reproduce the above copyright notice,
25 //     this list of conditions and the following disclaimer in the documentation
26 //     and/or other materials provided with the distribution.
27 //
28 //   * The name of Intel Corporation may not be used to endorse or promote products
29 //     derived from this software without specific prior written permission.
30 //
31 // This software is provided by the copyright holders and contributors "as is" and
32 // any express or implied warranties, including, but not limited to, the implied
33 // warranties of merchantability and fitness for a particular purpose are disclaimed.
34 // In no event shall the Intel Corporation or contributors be liable for any direct,
35 // indirect, incidental, special, exemplary, or consequential damages
36 // (including, but not limited to, procurement of substitute goods or services;
37 // loss of use, data, or profits; or business interruption) however caused
38 // and on any theory of liability, whether in contract, strict liability,
39 // or tort (including negligence or otherwise) arising in any way out of
40 // the use of this software, even if advised of the possibility of such damage.
41 //
42 //M*/
43 #include "precomp.hpp"
44
45 #import <TargetConditionals.h>
46
47 #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
48 /*** begin IPhone OS Stubs ***/
49 // When highgui functions are referred to on iPhone OS, they will fail silently.
50 CV_IMPL int cvInitSystem( int argc, char** argv) { return 0;}
51 CV_IMPL int cvStartWindowThread(){ return 0; }
52 CV_IMPL void cvDestroyWindow( const char* name) {}
53 CV_IMPL void cvDestroyAllWindows( void ) {}
54 CV_IMPL void cvShowImage( const char* name, const CvArr* arr) {}
55 CV_IMPL void cvResizeWindow( const char* name, int width, int height) {}
56 CV_IMPL void cvMoveWindow( const char* name, int x, int y){}
57 CV_IMPL int cvCreateTrackbar (const char* trackbar_name,const char* window_name,
58                               int* val, int count, CvTrackbarCallback on_notify) {return  0;}
59 CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,const char* window_name,
60                               int* val, int count, CvTrackbarCallback2 on_notify2, void* userdata) {return 0;}
61 CV_IMPL void cvSetMouseCallback( const char* name, CvMouseCallback function, void* info) {}
62 CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) {return 0;}
63 CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos) {}
64 CV_IMPL void* cvGetWindowHandle( const char* name ) {return NULL;}
65 CV_IMPL const char* cvGetWindowName( void* window_handle ) {return NULL;}
66 CV_IMPL int cvNamedWindow( const char* name, int flags ) {return 0; }
67 CV_IMPL int cvWaitKey (int maxWait) {return 0;}
68 //*** end IphoneOS Stubs ***/
69 #else
70
71 #import <Cocoa/Cocoa.h>
72
73 #include <iostream>
74 using namespace std;
75
76 const int TOP_BORDER  = 7;
77 const int MIN_SLIDER_WIDTH=200;
78
79 static NSApplication *application = nil;
80 static NSAutoreleasePool *pool = nil;
81 static NSMutableDictionary *windows = nil;
82 static bool wasInitialized = false;
83
84 @interface CVView : NSView {
85     NSImage *image;
86 }
87 @property(retain) NSImage *image;
88 - (void)setImageData:(CvArr *)arr;
89 @end
90
91 @interface CVSlider : NSView {
92     NSSlider *slider;
93     NSTextField *name;
94     int *value;
95     void *userData;
96     CvTrackbarCallback callback;
97     CvTrackbarCallback2 callback2;
98 }
99 @property(retain) NSSlider *slider;
100 @property(retain) NSTextField *name;
101 @property(assign) int *value;
102 @property(assign) void *userData;
103 @property(assign) CvTrackbarCallback callback;
104 @property(assign) CvTrackbarCallback2 callback2;
105 @end
106
107 @interface CVWindow : NSWindow {
108     NSMutableDictionary *sliders;
109     CvMouseCallback mouseCallback;
110     void *mouseParam;
111     BOOL autosize;
112     BOOL firstContent;
113     int status;
114 }
115 @property(assign) CvMouseCallback mouseCallback;
116 @property(assign) void *mouseParam;
117 @property(assign) BOOL autosize;
118 @property(assign) BOOL firstContent;
119 @property(retain) NSMutableDictionary *sliders;
120 @property(readwrite) int status;
121 - (CVView *)contentView;
122 - (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags;
123 - (void)cvMouseEvent:(NSEvent *)event;
124 - (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback;
125 @end
126
127 /*static void icvCocoaCleanup(void)
128 {
129     //cout << "icvCocoaCleanup" << endl;
130     if( application )
131     {
132         cvDestroyAllWindows();
133         //[application terminate:nil];
134         application = 0;
135         [pool release];
136     }
137 }*/
138
139 CV_IMPL int cvInitSystem( int , char** )
140 {
141     //cout << "cvInitSystem" << endl;
142     wasInitialized = true;
143
144     pool = [[NSAutoreleasePool alloc] init];
145     application = [NSApplication sharedApplication];
146     windows = [[NSMutableDictionary alloc] init];
147
148 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
149
150 #ifndef NSAppKitVersionNumber10_5
151 #define NSAppKitVersionNumber10_5 949
152 #endif
153     if( floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5 )
154         [application setActivationPolicy:0/*NSApplicationActivationPolicyRegular*/];
155 #endif
156     //[application finishLaunching];
157     //atexit(icvCocoaCleanup);
158
159     return 0;
160 }
161
162 static CVWindow *cvGetWindow(const char *name) {
163     //cout << "cvGetWindow" << endl;
164     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
165     NSString *cvname = [NSString stringWithFormat:@"%s", name];
166     CVWindow* retval = (CVWindow*) [windows valueForKey:cvname] ;
167     //cout << "retain count: " << [retval retainCount] << endl;
168     //retval = [retval retain];
169     //cout << "retain count: " << [retval retainCount] << endl;
170     [localpool drain];
171     //cout << "retain count: " << [retval retainCount] << endl;
172     return retval;
173 }
174
175 CV_IMPL int cvStartWindowThread()
176 {
177     //cout << "cvStartWindowThread" << endl;
178     return 0;
179 }
180
181 CV_IMPL void cvDestroyWindow( const char* name)
182 {
183
184     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
185     //cout << "cvDestroyWindow" << endl;
186     CVWindow *window = cvGetWindow(name);
187     if(window) {
188         [window close];
189         [windows removeObjectForKey:[NSString stringWithFormat:@"%s", name]];
190     }
191     [localpool drain];
192 }
193
194
195 CV_IMPL void cvDestroyAllWindows( void )
196 {
197     //cout << "cvDestroyAllWindows" << endl;
198     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
199     NSDictionary* list = [NSDictionary dictionaryWithDictionary:windows];
200     for(NSString *key in list) {
201         cvDestroyWindow([key cStringUsingEncoding:NSASCIIStringEncoding]);
202     }
203     [localpool drain];
204 }
205
206
207 CV_IMPL void cvShowImage( const char* name, const CvArr* arr)
208 {
209     //cout << "cvShowImage" << endl;
210     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
211     CVWindow *window = cvGetWindow(name);
212     if(!window)
213     {
214         cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
215         window = cvGetWindow(name);
216     }
217
218     if(window)
219     {
220         bool empty = [[window contentView] image] == nil;
221         NSRect rect = [window frame];
222         NSRect vrectOld = [[window contentView] frame];
223
224         [[window contentView] setImageData:(CvArr *)arr];
225         if([window autosize] || [window firstContent] || empty)
226         {
227             //Set new view size considering sliders (reserve height and min width)
228             NSRect vrectNew = vrectOld;
229             int slider_height = 0;
230             for(NSString *key in [window sliders]) {
231                 slider_height += [[[window sliders] valueForKey:key] frame].size.height;
232             }
233             vrectNew.size.height = [[[window contentView] image] size].height + slider_height;
234             vrectNew.size.width = std::max<int>([[[window contentView] image] size].width, MIN_SLIDER_WIDTH);
235             [[window contentView]  setFrameSize:vrectNew.size]; //adjust sliders to fit new window size
236
237             rect.size.width += vrectNew.size.width - vrectOld.size.width;
238             rect.size.height += vrectNew.size.height - vrectOld.size.height;
239             rect.origin.y -= vrectNew.size.height - vrectOld.size.height;
240
241             [window setFrame:rect display:YES];
242         }
243         else
244             [window display];
245         [window setFirstContent:NO];
246     }
247     [localpool drain];
248 }
249
250 CV_IMPL void cvResizeWindow( const char* name, int width, int height)
251 {
252
253     //cout << "cvResizeWindow" << endl;
254     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
255     CVWindow *window = cvGetWindow(name);
256     if(window) {
257         NSRect frame = [window frame];
258         frame.size.width = width;
259         frame.size.height = height;
260         [window setFrame:frame display:YES];
261     }
262     [localpool drain];
263 }
264
265 CV_IMPL void cvMoveWindow( const char* name, int x, int y)
266 {
267
268     CV_FUNCNAME("cvMoveWindow");
269     __BEGIN__;
270
271     NSAutoreleasePool* localpool1 = [[NSAutoreleasePool alloc] init];
272     CVWindow *window = nil;
273
274     if(name == NULL)
275         CV_ERROR( CV_StsNullPtr, "NULL window name" );
276     //cout << "cvMoveWindow"<< endl;
277     window = cvGetWindow(name);
278     if(window) {
279         y = [[window screen] frame].size.height - y;
280         [window setFrameTopLeftPoint:NSMakePoint(x, y)];
281     }
282     [localpool1 drain];
283
284     __END__;
285 }
286
287 CV_IMPL int cvCreateTrackbar (const char* trackbar_name,
288                               const char* window_name,
289                               int* val, int count,
290                               CvTrackbarCallback on_notify)
291 {
292     CV_FUNCNAME("cvCreateTrackbar");
293
294
295     int result = 0;
296     CVWindow *window = nil;
297     NSAutoreleasePool* localpool2 = nil;
298
299     __BEGIN__;
300     if (localpool2 != nil) [localpool2 drain];
301     localpool2 = [[NSAutoreleasePool alloc] init];
302
303     if(window_name == NULL)
304         CV_ERROR( CV_StsNullPtr, "NULL window name" );
305
306     //cout << "cvCreateTrackbar" << endl ;
307     window = cvGetWindow(window_name);
308     if(window) {
309         [window createSliderWithName:trackbar_name
310                             maxValue:count
311                                value:val
312                             callback:on_notify];
313         result = 1;
314     }
315     [localpool2 drain];
316     __END__;
317     return result;
318 }
319
320
321 CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,
322                               const char* window_name,
323                               int* val, int count,
324                               CvTrackbarCallback2 on_notify2,
325                               void* userdata)
326 {
327     //cout <<"cvCreateTrackbar2" << endl;
328     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
329     int res = cvCreateTrackbar(trackbar_name, window_name, val, count, NULL);
330     if(res) {
331         CVSlider *slider = [[cvGetWindow(window_name) sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
332         [slider setCallback2:on_notify2];
333         [slider setUserData:userdata];
334     }
335     [localpool drain];
336     return res;
337 }
338
339
340 CV_IMPL void
341 cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
342 {
343     CV_FUNCNAME("cvSetMouseCallback");
344
345     CVWindow *window = nil;
346     NSAutoreleasePool* localpool3 = nil;
347     __BEGIN__;
348     //cout << "cvSetMouseCallback" << endl;
349
350     if (localpool3 != nil) [localpool3 drain];
351     localpool3 = [[NSAutoreleasePool alloc] init];
352
353     if(name == NULL)
354         CV_ERROR( CV_StsNullPtr, "NULL window name" );
355
356     window = cvGetWindow(name);
357     if(window) {
358         [window setMouseCallback:function];
359         [window setMouseParam:info];
360     }
361     [localpool3 drain];
362
363     __END__;
364 }
365
366  CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
367 {
368     CV_FUNCNAME("cvGetTrackbarPos");
369
370     CVWindow *window = nil;
371     int pos = -1;
372     NSAutoreleasePool* localpool4 = nil;
373     __BEGIN__;
374
375     //cout << "cvGetTrackbarPos" << endl;
376     if(trackbar_name == NULL || window_name == NULL)
377         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
378
379     if (localpool4 != nil) [localpool4 drain];
380     localpool4 = [[NSAutoreleasePool alloc] init];
381
382     window = cvGetWindow(window_name);
383     if(window) {
384         CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
385         if(slider) {
386             pos = [[slider slider] intValue];
387         }
388     }
389     [localpool4 drain];
390     __END__;
391     return pos;
392 }
393
394 CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos)
395 {
396     CV_FUNCNAME("cvSetTrackbarPos");
397
398     CVWindow *window = nil;
399     CVSlider *slider = nil;
400     NSAutoreleasePool* localpool5 = nil;
401
402     __BEGIN__;
403     //cout << "cvSetTrackbarPos" << endl;
404     if(trackbar_name == NULL || window_name == NULL)
405         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
406
407     if(pos < 0)
408         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
409
410     if (localpool5 != nil) [localpool5 drain];
411     localpool5 = [[NSAutoreleasePool alloc] init];
412
413     window = cvGetWindow(window_name);
414     if(window) {
415         slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
416         if(slider) {
417             [[slider slider] setIntValue:pos];
418         }
419     }
420     [localpool5 drain];
421
422     __END__;
423 }
424
425 CV_IMPL void* cvGetWindowHandle( const char* name )
426 {
427     //cout << "cvGetWindowHandle" << endl;
428     return cvGetWindow(name);
429 }
430
431
432 CV_IMPL const char* cvGetWindowName( void* window_handle )
433 {
434     //cout << "cvGetWindowName" << endl;
435     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
436     for(NSString *key in windows) {
437         if([windows valueForKey:key] == window_handle) {
438             [localpool drain];
439             return [key UTF8String];
440         }
441     }
442     [localpool drain];
443     return 0;
444 }
445
446 CV_IMPL int cvNamedWindow( const char* name, int flags )
447 {
448     if( !wasInitialized )
449         cvInitSystem(0, 0);
450
451     //cout << "cvNamedWindow" << endl;
452     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
453     CVWindow *window = cvGetWindow(name);
454     if( window )
455     {
456         [window setAutosize:(flags == CV_WINDOW_AUTOSIZE)];
457         [localpool drain];
458         return 0;
459     }
460
461     NSScreen* mainDisplay = [NSScreen mainScreen];
462
463     NSString *windowName = [NSString stringWithFormat:@"%s", name];
464     NSUInteger showResize = (flags == CV_WINDOW_AUTOSIZE) ? 0: NSResizableWindowMask ;
465     NSUInteger styleMask = NSTitledWindowMask|NSMiniaturizableWindowMask|showResize;
466     CGFloat windowWidth = [NSWindow minFrameWidthWithTitle:windowName styleMask:styleMask];
467     NSRect initContentRect = NSMakeRect(0, 0, windowWidth, 0);
468     if (mainDisplay) {
469         NSRect dispFrame = [mainDisplay visibleFrame];
470         initContentRect.origin.y = dispFrame.size.height-20;
471     }
472
473
474     window = [[CVWindow alloc] initWithContentRect:initContentRect
475                                          styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|showResize
476                                            backing:NSBackingStoreBuffered
477                                              defer:YES
478                                             screen:mainDisplay];
479
480     [window setFrameTopLeftPoint:initContentRect.origin];
481
482     [window setFirstContent:YES];
483
484     [window setContentView:[[CVView alloc] init]];
485
486     [window setHasShadow:YES];
487     [window setAcceptsMouseMovedEvents:YES];
488     [window useOptimizedDrawing:YES];
489     [window setTitle:windowName];
490     [window makeKeyAndOrderFront:nil];
491
492     [window setAutosize:(flags == CV_WINDOW_AUTOSIZE)];
493
494     [windows setValue:window forKey:windowName];
495
496     [localpool drain];
497     return [windows count]-1;
498 }
499
500 CV_IMPL int cvWaitKey (int maxWait)
501 {
502     //cout << "cvWaitKey" << endl;
503     int returnCode = -1;
504     NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
505     double start = [[NSDate date] timeIntervalSince1970];
506
507     while(true) {
508         if(([[NSDate date] timeIntervalSince1970] - start) * 1000 >= maxWait && maxWait>0)
509             break;
510
511         //event = [application currentEvent];
512         [localpool drain];
513         localpool = [[NSAutoreleasePool alloc] init];
514
515         NSEvent *event =
516         [application
517          nextEventMatchingMask:NSAnyEventMask
518          untilDate://[NSDate dateWithTimeIntervalSinceNow: 1./100]
519          [NSDate distantPast]
520          inMode:NSDefaultRunLoopMode
521          dequeue:YES];
522
523         if([event type] == NSKeyDown) {
524             returnCode = [[event characters] characterAtIndex:0];
525             break;
526         }
527
528         [application sendEvent:event];
529         [application updateWindows];
530
531         [NSThread sleepForTimeInterval:1/100.];
532     }
533     [localpool drain];
534
535     return returnCode;
536 }
537
538 double cvGetModeWindow_COCOA( const char* name )
539 {
540     double result = -1;
541     CVWindow *window = nil;
542
543     CV_FUNCNAME( "cvGetModeWindow_COCOA" );
544
545     __BEGIN__;
546     if( name == NULL )
547     {
548         CV_ERROR( CV_StsNullPtr, "NULL name string" );
549     }
550
551     window = cvGetWindow( name );
552     if ( window == NULL )
553     {
554         CV_ERROR( CV_StsNullPtr, "NULL window" );
555     }
556
557     result = window.status;
558
559     __END__;
560     return result;
561 }
562
563 void cvSetModeWindow_COCOA( const char* name, double prop_value )
564 {
565     CVWindow *window = nil;
566     NSDictionary *fullscreenOptions = nil;
567     NSAutoreleasePool* localpool = nil;
568
569     CV_FUNCNAME( "cvSetModeWindow_COCOA" );
570
571     __BEGIN__;
572     if( name == NULL )
573     {
574         CV_ERROR( CV_StsNullPtr, "NULL name string" );
575     }
576
577     window = cvGetWindow(name);
578     if ( window == NULL )
579     {
580         CV_ERROR( CV_StsNullPtr, "NULL window" );
581     }
582
583     if ( [window autosize] )
584     {
585         return;
586     }
587
588     localpool = [[NSAutoreleasePool alloc] init];
589
590     fullscreenOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSFullScreenModeSetting];
591     if ( [[window contentView] isInFullScreenMode] && prop_value==CV_WINDOW_NORMAL )
592     {
593         [[window contentView] exitFullScreenModeWithOptions:fullscreenOptions];
594         window.status=CV_WINDOW_NORMAL;
595     }
596     else if( ![[window contentView] isInFullScreenMode] && prop_value==CV_WINDOW_FULLSCREEN )
597     {
598         [[window contentView] enterFullScreenMode:[NSScreen mainScreen] withOptions:fullscreenOptions];
599         window.status=CV_WINDOW_FULLSCREEN;
600     }
601
602     [localpool drain];
603
604     __END__;
605 }
606
607 @implementation CVWindow
608
609 @synthesize mouseCallback;
610 @synthesize mouseParam;
611 @synthesize autosize;
612 @synthesize firstContent;
613 @synthesize sliders;
614 @synthesize status;
615
616 - (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags {
617     (void)event;
618     //cout << "cvSendMouseEvent" << endl;
619     NSPoint mp = [NSEvent mouseLocation];
620     //NSRect visible = [[self contentView] frame];
621     mp = [self convertScreenToBase: mp];
622     double viewHeight = [self contentView].frame.size.height;
623     double viewWidth = [self contentView].frame.size.width;
624     CVWindow *window = (CVWindow *)[[self contentView] window];
625     for(NSString *key in [window sliders]) {
626         NSSlider *slider = [[window sliders] valueForKey:key];
627         viewHeight = std::min(viewHeight, (double)([slider frame].origin.y));
628     }
629     viewHeight -= TOP_BORDER;
630     mp.y = viewHeight - mp.y;
631
632     NSImage* image = ((CVView*)[self contentView]).image;
633     NSSize imageSize = [image size];
634     mp.x = mp.x * imageSize.width / std::max(viewWidth, 1.);
635     mp.y = mp.y * imageSize.height / std::max(viewHeight, 1.);
636
637     if( mp.x >= 0 && mp.y >= 0 && mp.x < imageSize.width && mp.y < imageSize.height )
638         mouseCallback(type, mp.x, mp.y, flags, mouseParam);
639 }
640
641 - (void)cvMouseEvent:(NSEvent *)event {
642     //cout << "cvMouseEvent" << endl;
643     if(!mouseCallback)
644         return;
645
646     int flags = 0;
647     if([event modifierFlags] & NSShiftKeyMask)          flags |= CV_EVENT_FLAG_SHIFTKEY;
648     if([event modifierFlags] & NSControlKeyMask)        flags |= CV_EVENT_FLAG_CTRLKEY;
649     if([event modifierFlags] & NSAlternateKeyMask)      flags |= CV_EVENT_FLAG_ALTKEY;
650
651     if([event type] == NSLeftMouseDown) {[self cvSendMouseEvent:event type:CV_EVENT_LBUTTONDOWN flags:flags | CV_EVENT_FLAG_LBUTTON];}
652     if([event type] == NSLeftMouseUp)   {[self cvSendMouseEvent:event type:CV_EVENT_LBUTTONUP   flags:flags | CV_EVENT_FLAG_LBUTTON];}
653     if([event type] == NSRightMouseDown){[self cvSendMouseEvent:event type:CV_EVENT_RBUTTONDOWN flags:flags | CV_EVENT_FLAG_RBUTTON];}
654     if([event type] == NSRightMouseUp)  {[self cvSendMouseEvent:event type:CV_EVENT_RBUTTONUP   flags:flags | CV_EVENT_FLAG_RBUTTON];}
655     if([event type] == NSOtherMouseDown){[self cvSendMouseEvent:event type:CV_EVENT_MBUTTONDOWN flags:flags];}
656     if([event type] == NSOtherMouseUp)  {[self cvSendMouseEvent:event type:CV_EVENT_MBUTTONUP   flags:flags];}
657     if([event type] == NSMouseMoved)    {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags];}
658     if([event type] == NSLeftMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags | CV_EVENT_FLAG_LBUTTON];}
659     if([event type] == NSRightMouseDragged)     {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags | CV_EVENT_FLAG_RBUTTON];}
660     if([event type] == NSOtherMouseDragged)     {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags | CV_EVENT_FLAG_MBUTTON];}
661 }
662 - (void)keyDown:(NSEvent *)theEvent {
663     //cout << "keyDown" << endl;
664     [super keyDown:theEvent];
665 }
666 - (void)rightMouseDragged:(NSEvent *)theEvent {
667     //cout << "rightMouseDragged" << endl ;
668     [self cvMouseEvent:theEvent];
669 }
670 - (void)rightMouseUp:(NSEvent *)theEvent {
671     //cout << "rightMouseUp" << endl;
672     [self cvMouseEvent:theEvent];
673 }
674 - (void)rightMouseDown:(NSEvent *)theEvent {
675     // Does not seem to work?
676     //cout << "rightMouseDown" << endl;
677     [self cvMouseEvent:theEvent];
678 }
679 - (void)mouseMoved:(NSEvent *)theEvent {
680     [self cvMouseEvent:theEvent];
681 }
682 - (void)otherMouseDragged:(NSEvent *)theEvent {
683     [self cvMouseEvent:theEvent];
684 }
685 - (void)otherMouseUp:(NSEvent *)theEvent {
686     [self cvMouseEvent:theEvent];
687 }
688 - (void)otherMouseDown:(NSEvent *)theEvent {
689     [self cvMouseEvent:theEvent];
690 }
691 - (void)mouseDragged:(NSEvent *)theEvent {
692     [self cvMouseEvent:theEvent];
693 }
694 - (void)mouseUp:(NSEvent *)theEvent {
695     [self cvMouseEvent:theEvent];
696 }
697 - (void)mouseDown:(NSEvent *)theEvent {
698     [self cvMouseEvent:theEvent];
699 }
700
701 - (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback {
702     //cout << "createSliderWithName" << endl;
703     if(sliders == nil)
704         sliders = [[NSMutableDictionary alloc] init];
705
706     NSString *cvname = [NSString stringWithFormat:@"%s", name];
707
708     // Avoid overwriting slider
709     if([sliders valueForKey:cvname]!=nil)
710         return;
711
712     // Create slider
713     CVSlider *slider = [[CVSlider alloc] init];
714     [[slider name] setStringValue:cvname];
715     [[slider slider] setMaxValue:max];
716     [[slider slider] setMinValue:0];
717     [[slider slider] setNumberOfTickMarks:(max+1)];
718     [[slider slider] setAllowsTickMarkValuesOnly:YES];
719     if(value)
720     {
721         [[slider slider] setIntValue:*value];
722         [slider setValue:value];
723     }
724     if(callback)
725         [slider setCallback:callback];
726
727     // Save slider
728     [sliders setValue:slider forKey:cvname];
729     [[self contentView] addSubview:slider];
730
731
732     //update contentView size to contain sliders
733     NSSize viewSize=[[self contentView] frame].size,
734            sliderSize=[slider frame].size;
735     viewSize.height += sliderSize.height;
736     viewSize.width = std::max<int>(viewSize.width, MIN_SLIDER_WIDTH);
737
738     // Update slider sizes
739     [[self contentView] setFrameSize:viewSize];
740     [[self contentView] setNeedsDisplay:YES];
741
742     //update window size to contain sliders
743     NSRect rect = [self frame];
744     rect.size.height += [slider frame].size.height;
745     rect.size.width = std::max<int>(rect.size.width, MIN_SLIDER_WIDTH);
746     [self setFrame:rect display:YES];
747
748
749
750 }
751
752 - (CVView *)contentView {
753     return (CVView*)[super contentView];
754 }
755
756 @end
757
758 @implementation CVView
759
760 @synthesize image;
761
762 - (id)init {
763     //cout << "CVView init" << endl;
764     [super init];
765     image = [[NSImage alloc] init];
766     return self;
767 }
768
769 - (void)setImageData:(CvArr *)arr {
770     //cout << "setImageData" << endl;
771     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
772     CvMat *arrMat, *cvimage, stub;
773
774     arrMat = cvGetMat(arr, &stub);
775
776     cvimage = cvCreateMat(arrMat->rows, arrMat->cols, CV_8UC3);
777     cvConvertImage(arrMat, cvimage, CV_CVTIMG_SWAP_RB);
778
779     /*CGColorSpaceRef colorspace = NULL;
780     CGDataProviderRef provider = NULL;
781     int width = cvimage->width;
782     int height = cvimage->height;
783
784     colorspace = CGColorSpaceCreateDeviceRGB();
785
786     int size = 8;
787     int nbChannels = 3;
788
789     provider = CGDataProviderCreateWithData(NULL, cvimage->data.ptr, width * height , NULL );
790
791     CGImageRef imageRef = CGImageCreate(width, height, size , size*nbChannels , cvimage->step, colorspace,  kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault);
792
793     NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:imageRef];
794     if(image) {
795         [image release];
796     }*/
797
798     NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
799                 pixelsWide:cvimage->width
800                 pixelsHigh:cvimage->height
801                 bitsPerSample:8
802                 samplesPerPixel:3
803                 hasAlpha:NO
804                 isPlanar:NO
805                 colorSpaceName:NSDeviceRGBColorSpace
806                 bytesPerRow:(cvimage->width * 4)
807                 bitsPerPixel:32];
808
809     int pixelCount = cvimage->width * cvimage->height;
810     unsigned char *src = cvimage->data.ptr;
811     unsigned char *dst = [bitmap bitmapData];
812
813     for( int i = 0; i < pixelCount; i++ )
814     {
815         dst[i * 4 + 0] = src[i * 3 + 0];
816         dst[i * 4 + 1] = src[i * 3 + 1];
817         dst[i * 4 + 2] = src[i * 3 + 2];
818     }
819
820     if( image )
821         [image release];
822
823     image = [[NSImage alloc] init];
824     [image addRepresentation:bitmap];
825     [bitmap release];
826
827     /*CGColorSpaceRelease(colorspace);
828     CGDataProviderRelease(provider);
829     CGImageRelease(imageRef);*/
830     cvReleaseMat(&cvimage);
831     [localpool drain];
832
833     [self setNeedsDisplay:YES];
834
835 }
836
837 - (void)setFrameSize:(NSSize)size {
838     //cout << "setFrameSize" << endl;
839     [super setFrameSize:size];
840
841     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
842     int height = size.height;
843
844     CVWindow *cvwindow = (CVWindow *)[self window];
845     for(NSString *key in [cvwindow sliders]) {
846         NSSlider *slider = [[cvwindow sliders] valueForKey:key];
847         NSRect r = [slider frame];
848         r.origin.y = height - r.size.height;
849         r.size.width = [[cvwindow contentView] frame].size.width;
850         [slider setFrame:r];
851         height -= r.size.height;
852     }
853     [localpool drain];
854 }
855
856 - (void)drawRect:(NSRect)rect {
857     //cout << "drawRect" << endl;
858     [super drawRect:rect];
859
860     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
861     CVWindow *cvwindow = (CVWindow *)[self window];
862     int height = 0;
863     if ([cvwindow respondsToSelector:@selector(sliders)]) {
864         for(NSString *key in [cvwindow sliders]) {
865             height += [[[cvwindow sliders] valueForKey:key] frame].size.height;
866         }
867     }
868
869
870     NSRect imageRect = {{0,0}, {[image size].width, [image size].height}};
871
872     if(image != nil) {
873         [image drawInRect: imageRect
874                               fromRect: NSZeroRect
875                              operation: NSCompositeSourceOver
876                               fraction: 1.0];
877     }
878     [localpool release];
879
880 }
881
882 @end
883
884 @implementation CVSlider
885
886 @synthesize slider;
887 @synthesize name;
888 @synthesize value;
889 @synthesize userData;
890 @synthesize callback;
891 @synthesize callback2;
892
893 - (id)init {
894     [super init];
895
896     callback = NULL;
897     value = NULL;
898     userData = NULL;
899
900     [self setFrame:NSMakeRect(0,0,200,30)];
901
902     name = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 0,110, 25)];
903     [name setEditable:NO];
904     [name setSelectable:NO];
905     [name setBezeled:NO];
906     [name setBordered:NO];
907     [name setDrawsBackground:NO];
908     [[name cell] setLineBreakMode:NSLineBreakByTruncatingTail];
909     [self addSubview:name];
910
911     slider = [[NSSlider alloc] initWithFrame:NSMakeRect(120, 0, 70, 25)];
912     [slider setAutoresizingMask:NSViewWidthSizable];
913     [slider setMinValue:0];
914     [slider setMaxValue:100];
915     [slider setContinuous:YES];
916     [slider setTarget:self];
917     [slider setAction:@selector(sliderChanged:)];
918     [self addSubview:slider];
919
920     [self setAutoresizingMask:NSViewWidthSizable];
921
922     //[self setFrame:NSMakeRect(12, 0, 100, 30)];
923
924     return self;
925 }
926
927 - (void)sliderChanged:(NSNotification *)notification {
928     (void)notification;
929     int pos = [slider intValue];
930     if(value)
931         *value = pos;
932     if(callback)
933         callback(pos);
934     if(callback2)
935         callback2(pos, userData);
936 }
937
938 @end
939
940 #endif
941
942 /* End of file. */