fixing locale settings - making it universal
[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 cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval) {}
65 CV_IMPL void* cvGetWindowHandle( const char* name ) {return NULL;}
66 CV_IMPL const char* cvGetWindowName( void* window_handle ) {return NULL;}
67 CV_IMPL int cvNamedWindow( const char* name, int flags ) {return 0; }
68 CV_IMPL int cvWaitKey (int maxWait) {return 0;}
69 //*** end IphoneOS Stubs ***/
70 #else
71
72 #import <Cocoa/Cocoa.h>
73
74 #include <iostream>
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:NSApplicationActivationPolicyRegular];
155 #endif
156     //[application finishLaunching];
157     //atexit(icvCocoaCleanup);
158
159     setlocale(LC_NUMERIC,"C");
160
161     return 0;
162 }
163
164 static CVWindow *cvGetWindow(const char *name) {
165     //cout << "cvGetWindow" << endl;
166     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
167     NSString *cvname = [NSString stringWithFormat:@"%s", name];
168     CVWindow* retval = (CVWindow*) [windows valueForKey:cvname] ;
169     //cout << "retain count: " << [retval retainCount] << endl;
170     //retval = [retval retain];
171     //cout << "retain count: " << [retval retainCount] << endl;
172     [localpool drain];
173     //cout << "retain count: " << [retval retainCount] << endl;
174     return retval;
175 }
176
177 CV_IMPL int cvStartWindowThread()
178 {
179     //cout << "cvStartWindowThread" << endl;
180     return 0;
181 }
182
183 CV_IMPL void cvDestroyWindow( const char* name)
184 {
185
186     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
187     //cout << "cvDestroyWindow" << endl;
188     CVWindow *window = cvGetWindow(name);
189     if(window) {
190         [window close];
191         [windows removeObjectForKey:[NSString stringWithFormat:@"%s", name]];
192     }
193     [localpool drain];
194 }
195
196
197 CV_IMPL void cvDestroyAllWindows( void )
198 {
199     //cout << "cvDestroyAllWindows" << endl;
200     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
201     NSDictionary* list = [NSDictionary dictionaryWithDictionary:windows];
202     for(NSString *key in list) {
203         cvDestroyWindow([key cStringUsingEncoding:NSASCIIStringEncoding]);
204     }
205     [localpool drain];
206 }
207
208
209 CV_IMPL void cvShowImage( const char* name, const CvArr* arr)
210 {
211     //cout << "cvShowImage" << endl;
212     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
213     CVWindow *window = cvGetWindow(name);
214     if(!window)
215     {
216         cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
217         window = cvGetWindow(name);
218     }
219
220     if(window)
221     {
222         bool empty = [[window contentView] image] == nil;
223         NSRect rect = [window frame];
224         NSRect vrectOld = [[window contentView] frame];
225
226         [[window contentView] setImageData:(CvArr *)arr];
227         if([window autosize] || [window firstContent] || empty)
228         {
229             //Set new view size considering sliders (reserve height and min width)
230             NSRect vrectNew = vrectOld;
231             int slider_height = 0;
232             for(NSString *key in [window sliders]) {
233                 slider_height += [[[window sliders] valueForKey:key] frame].size.height;
234             }
235             vrectNew.size.height = [[[window contentView] image] size].height + slider_height;
236             vrectNew.size.width = std::max<int>([[[window contentView] image] size].width, MIN_SLIDER_WIDTH);
237             [[window contentView]  setFrameSize:vrectNew.size]; //adjust sliders to fit new window size
238
239             rect.size.width += vrectNew.size.width - vrectOld.size.width;
240             rect.size.height += vrectNew.size.height - vrectOld.size.height;
241             rect.origin.y -= vrectNew.size.height - vrectOld.size.height;
242
243             [window setFrame:rect display:YES];
244         }
245         else
246             [window display];
247         [window setFirstContent:NO];
248     }
249     [localpool drain];
250 }
251
252 CV_IMPL void cvResizeWindow( const char* name, int width, int height)
253 {
254
255     //cout << "cvResizeWindow" << endl;
256     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
257     CVWindow *window = cvGetWindow(name);
258     if(window) {
259         NSRect frame = [window frame];
260         frame.size.width = width;
261         frame.size.height = height;
262         [window setFrame:frame display:YES];
263     }
264     [localpool drain];
265 }
266
267 CV_IMPL void cvMoveWindow( const char* name, int x, int y)
268 {
269
270     CV_FUNCNAME("cvMoveWindow");
271     __BEGIN__;
272
273     NSAutoreleasePool* localpool1 = [[NSAutoreleasePool alloc] init];
274     CVWindow *window = nil;
275
276     if(name == NULL)
277         CV_ERROR( CV_StsNullPtr, "NULL window name" );
278     //cout << "cvMoveWindow"<< endl;
279     window = cvGetWindow(name);
280     if(window) {
281         y = [[window screen] frame].size.height - y;
282         [window setFrameTopLeftPoint:NSMakePoint(x, y)];
283     }
284     [localpool1 drain];
285
286     __END__;
287 }
288
289 CV_IMPL int cvCreateTrackbar (const char* trackbar_name,
290                               const char* window_name,
291                               int* val, int count,
292                               CvTrackbarCallback on_notify)
293 {
294     CV_FUNCNAME("cvCreateTrackbar");
295
296
297     int result = 0;
298     CVWindow *window = nil;
299     NSAutoreleasePool* localpool2 = nil;
300
301     __BEGIN__;
302     if (localpool2 != nil) [localpool2 drain];
303     localpool2 = [[NSAutoreleasePool alloc] init];
304
305     if(window_name == NULL)
306         CV_ERROR( CV_StsNullPtr, "NULL window name" );
307
308     //cout << "cvCreateTrackbar" << endl ;
309     window = cvGetWindow(window_name);
310     if(window) {
311         [window createSliderWithName:trackbar_name
312                             maxValue:count
313                                value:val
314                             callback:on_notify];
315         result = 1;
316     }
317     [localpool2 drain];
318     __END__;
319     return result;
320 }
321
322
323 CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,
324                               const char* window_name,
325                               int* val, int count,
326                               CvTrackbarCallback2 on_notify2,
327                               void* userdata)
328 {
329     //cout <<"cvCreateTrackbar2" << endl;
330     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
331     int res = cvCreateTrackbar(trackbar_name, window_name, val, count, NULL);
332     if(res) {
333         CVSlider *slider = [[cvGetWindow(window_name) sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
334         [slider setCallback2:on_notify2];
335         [slider setUserData:userdata];
336     }
337     [localpool drain];
338     return res;
339 }
340
341
342 CV_IMPL void
343 cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
344 {
345     CV_FUNCNAME("cvSetMouseCallback");
346
347     CVWindow *window = nil;
348     NSAutoreleasePool* localpool3 = nil;
349     __BEGIN__;
350     //cout << "cvSetMouseCallback" << endl;
351
352     if (localpool3 != nil) [localpool3 drain];
353     localpool3 = [[NSAutoreleasePool alloc] init];
354
355     if(name == NULL)
356         CV_ERROR( CV_StsNullPtr, "NULL window name" );
357
358     window = cvGetWindow(name);
359     if(window) {
360         [window setMouseCallback:function];
361         [window setMouseParam:info];
362     }
363     [localpool3 drain];
364
365     __END__;
366 }
367
368  CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
369 {
370     CV_FUNCNAME("cvGetTrackbarPos");
371
372     CVWindow *window = nil;
373     int pos = -1;
374     NSAutoreleasePool* localpool4 = nil;
375     __BEGIN__;
376
377     //cout << "cvGetTrackbarPos" << endl;
378     if(trackbar_name == NULL || window_name == NULL)
379         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
380
381     if (localpool4 != nil) [localpool4 drain];
382     localpool4 = [[NSAutoreleasePool alloc] init];
383
384     window = cvGetWindow(window_name);
385     if(window) {
386         CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
387         if(slider) {
388             pos = [[slider slider] intValue];
389         }
390     }
391     [localpool4 drain];
392     __END__;
393     return pos;
394 }
395
396 CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos)
397 {
398     CV_FUNCNAME("cvSetTrackbarPos");
399
400     CVWindow *window = nil;
401     CVSlider *slider = nil;
402     NSAutoreleasePool* localpool5 = nil;
403
404     __BEGIN__;
405     //cout << "cvSetTrackbarPos" << endl;
406     if(trackbar_name == NULL || window_name == NULL)
407         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
408
409     if(pos < 0)
410         CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
411
412     if (localpool5 != nil) [localpool5 drain];
413     localpool5 = [[NSAutoreleasePool alloc] init];
414
415     window = cvGetWindow(window_name);
416     if(window) {
417         slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
418         if(slider) {
419             [[slider slider] setIntValue:pos];
420         }
421     }
422     [localpool5 drain];
423
424     __END__;
425 }
426
427 CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
428 {
429     CV_FUNCNAME("cvSetTrackbarPos");
430
431     CVWindow *window = nil;
432     CVSlider *slider = nil;
433     NSAutoreleasePool* localpool5 = nil;
434
435     __BEGIN__;
436     //cout << "cvSetTrackbarPos" << endl;
437     if(trackbar_name == NULL || window_name == NULL)
438         CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
439
440     if (localpool5 != nil) [localpool5 drain];
441     localpool5 = [[NSAutoreleasePool alloc] init];
442
443     window = cvGetWindow(window_name);
444     if(window) {
445         slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
446         if(slider) {
447             if(maxval >= 0) {
448                 [[slider slider] setMaxValue:maxval];
449             }
450         }
451     }
452     [localpool5 drain];
453
454     __END__;
455 }
456
457 CV_IMPL void* cvGetWindowHandle( const char* name )
458 {
459     //cout << "cvGetWindowHandle" << endl;
460     return cvGetWindow(name);
461 }
462
463
464 CV_IMPL const char* cvGetWindowName( void* window_handle )
465 {
466     //cout << "cvGetWindowName" << endl;
467     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
468     for(NSString *key in windows) {
469         if([windows valueForKey:key] == window_handle) {
470             [localpool drain];
471             return [key UTF8String];
472         }
473     }
474     [localpool drain];
475     return 0;
476 }
477
478 CV_IMPL int cvNamedWindow( const char* name, int flags )
479 {
480     if( !wasInitialized )
481         cvInitSystem(0, 0);
482
483     //cout << "cvNamedWindow" << endl;
484     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
485     CVWindow *window = cvGetWindow(name);
486     if( window )
487     {
488         [window setAutosize:(flags == CV_WINDOW_AUTOSIZE)];
489         [localpool drain];
490         return 0;
491     }
492
493     NSScreen* mainDisplay = [NSScreen mainScreen];
494
495     NSString *windowName = [NSString stringWithFormat:@"%s", name];
496     NSUInteger showResize = (flags == CV_WINDOW_AUTOSIZE) ? 0: NSResizableWindowMask ;
497     NSUInteger styleMask = NSTitledWindowMask|NSMiniaturizableWindowMask|showResize;
498     CGFloat windowWidth = [NSWindow minFrameWidthWithTitle:windowName styleMask:styleMask];
499     NSRect initContentRect = NSMakeRect(0, 0, windowWidth, 0);
500     if (mainDisplay) {
501         NSRect dispFrame = [mainDisplay visibleFrame];
502         initContentRect.origin.y = dispFrame.size.height-20;
503     }
504
505
506     window = [[CVWindow alloc] initWithContentRect:initContentRect
507                                          styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|showResize
508                                            backing:NSBackingStoreBuffered
509                                              defer:YES
510                                             screen:mainDisplay];
511
512     [window setFrameTopLeftPoint:initContentRect.origin];
513
514     [window setFirstContent:YES];
515
516     [window setContentView:[[CVView alloc] init]];
517
518     [window setHasShadow:YES];
519     [window setAcceptsMouseMovedEvents:YES];
520     [window useOptimizedDrawing:YES];
521     [window setTitle:windowName];
522     [window makeKeyAndOrderFront:nil];
523
524     [window setAutosize:(flags == CV_WINDOW_AUTOSIZE)];
525
526     [windows setValue:window forKey:windowName];
527
528     [localpool drain];
529     return [windows count]-1;
530 }
531
532 CV_IMPL int cvWaitKey (int maxWait)
533 {
534     //cout << "cvWaitKey" << endl;
535     int returnCode = -1;
536     NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
537     double start = [[NSDate date] timeIntervalSince1970];
538
539     while(true) {
540         if(([[NSDate date] timeIntervalSince1970] - start) * 1000 >= maxWait && maxWait>0)
541             break;
542
543         //event = [application currentEvent];
544         [localpool drain];
545         localpool = [[NSAutoreleasePool alloc] init];
546
547         NSEvent *event =
548         [application
549          nextEventMatchingMask:NSAnyEventMask
550          untilDate://[NSDate dateWithTimeIntervalSinceNow: 1./100]
551          [NSDate distantPast]
552          inMode:NSDefaultRunLoopMode
553          dequeue:YES];
554
555         if([event type] == NSKeyDown) {
556             returnCode = [[event characters] characterAtIndex:0];
557             break;
558         }
559
560         [application sendEvent:event];
561         [application updateWindows];
562
563         [NSThread sleepForTimeInterval:1/100.];
564     }
565     [localpool drain];
566
567     return returnCode;
568 }
569
570 double cvGetModeWindow_COCOA( const char* name )
571 {
572     double result = -1;
573     CVWindow *window = nil;
574
575     CV_FUNCNAME( "cvGetModeWindow_COCOA" );
576
577     __BEGIN__;
578     if( name == NULL )
579     {
580         CV_ERROR( CV_StsNullPtr, "NULL name string" );
581     }
582
583     window = cvGetWindow( name );
584     if ( window == NULL )
585     {
586         CV_ERROR( CV_StsNullPtr, "NULL window" );
587     }
588
589     result = window.status;
590
591     __END__;
592     return result;
593 }
594
595 void cvSetModeWindow_COCOA( const char* name, double prop_value )
596 {
597     CVWindow *window = nil;
598     NSDictionary *fullscreenOptions = nil;
599     NSAutoreleasePool* localpool = nil;
600
601     CV_FUNCNAME( "cvSetModeWindow_COCOA" );
602
603     __BEGIN__;
604     if( name == NULL )
605     {
606         CV_ERROR( CV_StsNullPtr, "NULL name string" );
607     }
608
609     window = cvGetWindow(name);
610     if ( window == NULL )
611     {
612         CV_ERROR( CV_StsNullPtr, "NULL window" );
613     }
614
615     if ( [window autosize] )
616     {
617         return;
618     }
619
620     localpool = [[NSAutoreleasePool alloc] init];
621
622     fullscreenOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSFullScreenModeSetting];
623     if ( [[window contentView] isInFullScreenMode] && prop_value==CV_WINDOW_NORMAL )
624     {
625         [[window contentView] exitFullScreenModeWithOptions:fullscreenOptions];
626         window.status=CV_WINDOW_NORMAL;
627     }
628     else if( ![[window contentView] isInFullScreenMode] && prop_value==CV_WINDOW_FULLSCREEN )
629     {
630         [[window contentView] enterFullScreenMode:[NSScreen mainScreen] withOptions:fullscreenOptions];
631         window.status=CV_WINDOW_FULLSCREEN;
632     }
633
634     [localpool drain];
635
636     __END__;
637 }
638
639 void cv::setWindowTitle(const String& winname, const String& title)
640 {
641     CVWindow *window = cvGetWindow(winname.c_str());
642
643     if (window == NULL)
644     {
645         namedWindow(winname);
646         window = cvGetWindow(winname.c_str());
647     }
648
649     if (window == NULL)
650         CV_Error(Error::StsNullPtr, "NULL window");
651
652     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
653
654     NSString *windowTitle = [NSString stringWithFormat:@"%s", title.c_str()];
655     [window setTitle:windowTitle];
656
657     [localpool drain];
658 }
659
660 @implementation CVWindow
661
662 @synthesize mouseCallback;
663 @synthesize mouseParam;
664 @synthesize autosize;
665 @synthesize firstContent;
666 @synthesize sliders;
667 @synthesize status;
668
669 - (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags {
670     (void)event;
671     //cout << "cvSendMouseEvent" << endl;
672     NSPoint mp = [NSEvent mouseLocation];
673     //NSRect visible = [[self contentView] frame];
674     mp = [self convertScreenToBase: mp];
675     double viewHeight = [self contentView].frame.size.height;
676     double viewWidth = [self contentView].frame.size.width;
677     CVWindow *window = (CVWindow *)[[self contentView] window];
678     for(NSString *key in [window sliders]) {
679         NSSlider *slider = [[window sliders] valueForKey:key];
680         viewHeight = std::min(viewHeight, (double)([slider frame].origin.y));
681     }
682     viewHeight -= TOP_BORDER;
683     mp.y = viewHeight - mp.y;
684
685     NSImage* image = ((CVView*)[self contentView]).image;
686     NSSize imageSize = [image size];
687     mp.x = mp.x * imageSize.width / std::max(viewWidth, 1.);
688     mp.y = mp.y * imageSize.height / std::max(viewHeight, 1.);
689
690     if( mp.x >= 0 && mp.y >= 0 && mp.x < imageSize.width && mp.y < imageSize.height )
691         mouseCallback(type, mp.x, mp.y, flags, mouseParam);
692 }
693
694 - (void)cvMouseEvent:(NSEvent *)event {
695     //cout << "cvMouseEvent" << endl;
696     if(!mouseCallback)
697         return;
698
699     int flags = 0;
700     if([event modifierFlags] & NSShiftKeyMask)          flags |= CV_EVENT_FLAG_SHIFTKEY;
701     if([event modifierFlags] & NSControlKeyMask)        flags |= CV_EVENT_FLAG_CTRLKEY;
702     if([event modifierFlags] & NSAlternateKeyMask)      flags |= CV_EVENT_FLAG_ALTKEY;
703
704     if([event type] == NSLeftMouseDown) {[self cvSendMouseEvent:event type:CV_EVENT_LBUTTONDOWN flags:flags | CV_EVENT_FLAG_LBUTTON];}
705     if([event type] == NSLeftMouseUp)   {[self cvSendMouseEvent:event type:CV_EVENT_LBUTTONUP   flags:flags | CV_EVENT_FLAG_LBUTTON];}
706     if([event type] == NSRightMouseDown){[self cvSendMouseEvent:event type:CV_EVENT_RBUTTONDOWN flags:flags | CV_EVENT_FLAG_RBUTTON];}
707     if([event type] == NSRightMouseUp)  {[self cvSendMouseEvent:event type:CV_EVENT_RBUTTONUP   flags:flags | CV_EVENT_FLAG_RBUTTON];}
708     if([event type] == NSOtherMouseDown){[self cvSendMouseEvent:event type:CV_EVENT_MBUTTONDOWN flags:flags];}
709     if([event type] == NSOtherMouseUp)  {[self cvSendMouseEvent:event type:CV_EVENT_MBUTTONUP   flags:flags];}
710     if([event type] == NSMouseMoved)    {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags];}
711     if([event type] == NSLeftMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags | CV_EVENT_FLAG_LBUTTON];}
712     if([event type] == NSRightMouseDragged)     {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags | CV_EVENT_FLAG_RBUTTON];}
713     if([event type] == NSOtherMouseDragged)     {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE   flags:flags | CV_EVENT_FLAG_MBUTTON];}
714 }
715 - (void)keyDown:(NSEvent *)theEvent {
716     //cout << "keyDown" << endl;
717     [super keyDown:theEvent];
718 }
719 - (void)rightMouseDragged:(NSEvent *)theEvent {
720     //cout << "rightMouseDragged" << endl ;
721     [self cvMouseEvent:theEvent];
722 }
723 - (void)rightMouseUp:(NSEvent *)theEvent {
724     //cout << "rightMouseUp" << endl;
725     [self cvMouseEvent:theEvent];
726 }
727 - (void)rightMouseDown:(NSEvent *)theEvent {
728     // Does not seem to work?
729     //cout << "rightMouseDown" << endl;
730     [self cvMouseEvent:theEvent];
731 }
732 - (void)mouseMoved:(NSEvent *)theEvent {
733     [self cvMouseEvent:theEvent];
734 }
735 - (void)otherMouseDragged:(NSEvent *)theEvent {
736     [self cvMouseEvent:theEvent];
737 }
738 - (void)otherMouseUp:(NSEvent *)theEvent {
739     [self cvMouseEvent:theEvent];
740 }
741 - (void)otherMouseDown:(NSEvent *)theEvent {
742     [self cvMouseEvent:theEvent];
743 }
744 - (void)mouseDragged:(NSEvent *)theEvent {
745     [self cvMouseEvent:theEvent];
746 }
747 - (void)mouseUp:(NSEvent *)theEvent {
748     [self cvMouseEvent:theEvent];
749 }
750 - (void)mouseDown:(NSEvent *)theEvent {
751     [self cvMouseEvent:theEvent];
752 }
753
754 - (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback {
755     //cout << "createSliderWithName" << endl;
756     if(sliders == nil)
757         sliders = [[NSMutableDictionary alloc] init];
758
759     NSString *cvname = [NSString stringWithFormat:@"%s", name];
760
761     // Avoid overwriting slider
762     if([sliders valueForKey:cvname]!=nil)
763         return;
764
765     // Create slider
766     CVSlider *slider = [[CVSlider alloc] init];
767     [[slider name] setStringValue:cvname];
768     [[slider slider] setMaxValue:max];
769     [[slider slider] setMinValue:0];
770     [[slider slider] setNumberOfTickMarks:(max+1)];
771     [[slider slider] setAllowsTickMarkValuesOnly:YES];
772     if(value)
773     {
774         [[slider slider] setIntValue:*value];
775         [slider setValue:value];
776     }
777     if(callback)
778         [slider setCallback:callback];
779
780     // Save slider
781     [sliders setValue:slider forKey:cvname];
782     [[self contentView] addSubview:slider];
783
784
785     //update contentView size to contain sliders
786     NSSize viewSize=[[self contentView] frame].size,
787            sliderSize=[slider frame].size;
788     viewSize.height += sliderSize.height;
789     viewSize.width = std::max<int>(viewSize.width, MIN_SLIDER_WIDTH);
790
791     // Update slider sizes
792     [[self contentView] setFrameSize:viewSize];
793     [[self contentView] setNeedsDisplay:YES];
794
795     //update window size to contain sliders
796     NSRect rect = [self frame];
797     rect.size.height += [slider frame].size.height;
798     rect.size.width = std::max<int>(rect.size.width, MIN_SLIDER_WIDTH);
799     [self setFrame:rect display:YES];
800
801
802
803 }
804
805 - (CVView *)contentView {
806     return (CVView*)[super contentView];
807 }
808
809 @end
810
811 @implementation CVView
812
813 @synthesize image;
814
815 - (id)init {
816     //cout << "CVView init" << endl;
817     [super init];
818     image = [[NSImage alloc] init];
819     return self;
820 }
821
822 - (void)setImageData:(CvArr *)arr {
823     //cout << "setImageData" << endl;
824     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
825     CvMat *arrMat, *cvimage, stub;
826
827     arrMat = cvGetMat(arr, &stub);
828
829     cvimage = cvCreateMat(arrMat->rows, arrMat->cols, CV_8UC3);
830     cvConvertImage(arrMat, cvimage, CV_CVTIMG_SWAP_RB);
831
832     /*CGColorSpaceRef colorspace = NULL;
833     CGDataProviderRef provider = NULL;
834     int width = cvimage->width;
835     int height = cvimage->height;
836
837     colorspace = CGColorSpaceCreateDeviceRGB();
838
839     int size = 8;
840     int nbChannels = 3;
841
842     provider = CGDataProviderCreateWithData(NULL, cvimage->data.ptr, width * height , NULL );
843
844     CGImageRef imageRef = CGImageCreate(width, height, size , size*nbChannels , cvimage->step, colorspace,  kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault);
845
846     NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:imageRef];
847     if(image) {
848         [image release];
849     }*/
850
851     NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
852                 pixelsWide:cvimage->width
853                 pixelsHigh:cvimage->height
854                 bitsPerSample:8
855                 samplesPerPixel:3
856                 hasAlpha:NO
857                 isPlanar:NO
858                 colorSpaceName:NSDeviceRGBColorSpace
859                 bytesPerRow:(cvimage->width * 4)
860                 bitsPerPixel:32];
861
862     int pixelCount = cvimage->width * cvimage->height;
863     unsigned char *src = cvimage->data.ptr;
864     unsigned char *dst = [bitmap bitmapData];
865
866     for( int i = 0; i < pixelCount; i++ )
867     {
868         dst[i * 4 + 0] = src[i * 3 + 0];
869         dst[i * 4 + 1] = src[i * 3 + 1];
870         dst[i * 4 + 2] = src[i * 3 + 2];
871     }
872
873     if( image )
874         [image release];
875
876     image = [[NSImage alloc] init];
877     [image addRepresentation:bitmap];
878     [bitmap release];
879
880     /*CGColorSpaceRelease(colorspace);
881     CGDataProviderRelease(provider);
882     CGImageRelease(imageRef);*/
883     cvReleaseMat(&cvimage);
884     [localpool drain];
885
886     [self setNeedsDisplay:YES];
887
888 }
889
890 - (void)setFrameSize:(NSSize)size {
891     //cout << "setFrameSize" << endl;
892     [super setFrameSize:size];
893
894     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
895     int height = size.height;
896
897     CVWindow *cvwindow = (CVWindow *)[self window];
898     for(NSString *key in [cvwindow sliders]) {
899         NSSlider *slider = [[cvwindow sliders] valueForKey:key];
900         NSRect r = [slider frame];
901         r.origin.y = height - r.size.height;
902         r.size.width = [[cvwindow contentView] frame].size.width;
903         [slider setFrame:r];
904         height -= r.size.height;
905     }
906     [localpool drain];
907 }
908
909 - (void)drawRect:(NSRect)rect {
910     //cout << "drawRect" << endl;
911     [super drawRect:rect];
912
913     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
914     CVWindow *cvwindow = (CVWindow *)[self window];
915     int height = 0;
916     if ([cvwindow respondsToSelector:@selector(sliders)]) {
917         for(NSString *key in [cvwindow sliders]) {
918             height += [[[cvwindow sliders] valueForKey:key] frame].size.height;
919         }
920     }
921
922
923     NSRect imageRect = {{0,0}, {[image size].width, [image size].height}};
924
925     if(image != nil) {
926         [image drawInRect: imageRect
927                               fromRect: NSZeroRect
928                              operation: NSCompositeSourceOver
929                               fraction: 1.0];
930     }
931     [localpool release];
932
933 }
934
935 @end
936
937 @implementation CVSlider
938
939 @synthesize slider;
940 @synthesize name;
941 @synthesize value;
942 @synthesize userData;
943 @synthesize callback;
944 @synthesize callback2;
945
946 - (id)init {
947     [super init];
948
949     callback = NULL;
950     value = NULL;
951     userData = NULL;
952
953     [self setFrame:NSMakeRect(0,0,200,30)];
954
955     name = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 0,110, 25)];
956     [name setEditable:NO];
957     [name setSelectable:NO];
958     [name setBezeled:NO];
959     [name setBordered:NO];
960     [name setDrawsBackground:NO];
961     [[name cell] setLineBreakMode:NSLineBreakByTruncatingTail];
962     [self addSubview:name];
963
964     slider = [[NSSlider alloc] initWithFrame:NSMakeRect(120, 0, 70, 25)];
965     [slider setAutoresizingMask:NSViewWidthSizable];
966     [slider setMinValue:0];
967     [slider setMaxValue:100];
968     [slider setContinuous:YES];
969     [slider setTarget:self];
970     [slider setAction:@selector(sliderChanged:)];
971     [self addSubview:slider];
972
973     [self setAutoresizingMask:NSViewWidthSizable];
974
975     //[self setFrame:NSMakeRect(12, 0, 100, 30)];
976
977     return self;
978 }
979
980 - (void)sliderChanged:(NSNotification *)notification {
981     (void)notification;
982     int pos = [slider intValue];
983     if(value)
984         *value = pos;
985     if(callback)
986         callback(pos);
987     if(callback2)
988         callback2(pos, userData);
989 }
990
991 @end
992
993 #endif
994
995 /* End of file. */