Open Source Computer Vision Library https://opencv.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1304 lines
41 KiB

/* The file is the modified version of window_cocoa.mm from opencv-cocoa project by Andre Cohen */
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
#include "opencv2/imgproc.hpp"
#import <TargetConditionals.h>
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
/*** begin IPhone OS Stubs ***/
// When highgui functions are referred to on iPhone OS, they will fail silently.
CV_IMPL int cvInitSystem( int argc, char** argv) { return 0;}
CV_IMPL int cvStartWindowThread(){ return 0; }
CV_IMPL void cvDestroyWindow( const char* name) {}
CV_IMPL void cvDestroyAllWindows( void ) {}
CV_IMPL void cvShowImage( const char* name, const CvArr* arr) {}
CV_IMPL void cvResizeWindow( const char* name, int width, int height) {}
CV_IMPL void cvMoveWindow( const char* name, int x, int y){}
CV_IMPL int cvCreateTrackbar (const char* trackbar_name,const char* window_name,
int* val, int count, CvTrackbarCallback on_notify) {return 0;}
CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,const char* window_name,
int* val, int count, CvTrackbarCallback2 on_notify2, void* userdata) {return 0;}
CV_IMPL void cvSetMouseCallback( const char* name, CvMouseCallback function, void* info) {}
CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name ) {return 0;}
CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos) {}
CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval) {}
CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval) {}
CV_IMPL void* cvGetWindowHandle( const char* name ) {return NULL;}
CV_IMPL const char* cvGetWindowName( void* window_handle ) {return NULL;}
CV_IMPL int cvNamedWindow( const char* name, int flags ) {return 0; }
CV_IMPL int cvWaitKey (int maxWait) {return 0;}
//*** end IphoneOS Stubs ***/
#else
#import <Cocoa/Cocoa.h>
#include <iostream>
const int MIN_SLIDER_WIDTH=200;
static NSApplication *application = nil;
static NSAutoreleasePool *pool = nil;
static NSMutableDictionary *windows = nil;
static bool wasInitialized = false;
@interface CVView : NSView
@property(retain) NSView *imageView;
@property(retain) NSImage *image;
@property int sliderHeight;
- (void)setImageData:(CvArr *)arr;
@end
@interface CVSlider : NSView {
NSSlider *slider;
NSTextField *name;
NSString *initialName;
int *value;
void *userData;
CvTrackbarCallback callback;
CvTrackbarCallback2 callback2;
}
@property(retain) NSSlider *slider;
@property(retain) NSTextField *name;
@property(retain) NSString *initialName;
@property(assign) int *value;
@property(assign) void *userData;
@property(assign) CvTrackbarCallback callback;
@property(assign) CvTrackbarCallback2 callback2;
@end
@interface CVWindow : NSWindow {
NSMutableDictionary *sliders;
NSMutableArray *slidersKeys;
CvMouseCallback mouseCallback;
void *mouseParam;
BOOL autosize;
BOOL firstContent;
int status;
int x0, y0;
}
@property(assign) CvMouseCallback mouseCallback;
@property(assign) void *mouseParam;
@property(assign) BOOL autosize;
@property(assign) BOOL firstContent;
@property(assign) int x0;
@property(assign) int y0;
@property(retain) NSMutableDictionary *sliders;
@property(retain) NSMutableArray *slidersKeys;
@property(readwrite) int status;
- (CVView *)contentView;
- (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags;
- (void)cvMouseEvent:(NSEvent *)event;
- (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback;
@end
/*static void icvCocoaCleanup(void)
{
//cout << "icvCocoaCleanup" << endl;
if( application )
{
cvDestroyAllWindows();
//[application terminate:nil];
application = 0;
[pool release];
}
}*/
CV_IMPL int cvInitSystem( int , char** )
{
//cout << "cvInitSystem" << endl;
wasInitialized = true;
pool = [[NSAutoreleasePool alloc] init];
application = [NSApplication sharedApplication];
windows = [[NSMutableDictionary alloc] init];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
#ifndef NSAppKitVersionNumber10_5
#define NSAppKitVersionNumber10_5 949
#endif
if( floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5 )
[application setActivationPolicy:NSApplicationActivationPolicyRegular];
#endif
//[application finishLaunching];
//atexit(icvCocoaCleanup);
setlocale(LC_NUMERIC,"C");
return 0;
}
static CVWindow *cvGetWindow(const char *name) {
//cout << "cvGetWindow" << endl;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
NSString *cvname = [NSString stringWithFormat:@"%s", name];
CVWindow* retval = (CVWindow*) [windows valueForKey:cvname] ;
//cout << "retain count: " << [retval retainCount] << endl;
//retval = [retval retain];
//cout << "retain count: " << [retval retainCount] << endl;
[localpool drain];
//cout << "retain count: " << [retval retainCount] << endl;
return retval;
}
CV_IMPL int cvStartWindowThread()
{
//cout << "cvStartWindowThread" << endl;
return 0;
}
CV_IMPL void cvDestroyWindow( const char* name)
{
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
//cout << "cvDestroyWindow" << endl;
CVWindow *window = cvGetWindow(name);
if(window) {
if ([window styleMask] & NSFullScreenWindowMask) {
[window toggleFullScreen:nil];
}
[window close];
[windows removeObjectForKey:[NSString stringWithFormat:@"%s", name]];
}
[localpool drain];
}
CV_IMPL void cvDestroyAllWindows( void )
{
//cout << "cvDestroyAllWindows" << endl;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
NSDictionary* list = [NSDictionary dictionaryWithDictionary:windows];
for(NSString *key in list) {
cvDestroyWindow([key cStringUsingEncoding:NSASCIIStringEncoding]);
}
[localpool drain];
}
CV_IMPL void cvShowImage( const char* name, const CvArr* arr)
{
//cout << "cvShowImage" << endl;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
CVWindow *window = cvGetWindow(name);
if(!window)
{
cvNamedWindow(name, CV_WINDOW_AUTOSIZE);
window = cvGetWindow(name);
}
if(window)
{
bool empty = [[window contentView] image] == nil;
NSRect vrectOld = [[window contentView] frame];
NSSize oldImageSize = [[[window contentView] image] size];
[[window contentView] setImageData:(CvArr *)arr];
if([window autosize] || [window firstContent] || empty)
{
NSSize imageSize = [[[window contentView] image] size];
// Only adjust the image size if the new image is a different size from the previous
if (oldImageSize.height != imageSize.height || oldImageSize.width != imageSize.width)
{
//Set new view size considering sliders (reserve height and min width)
NSSize scaledImageSize = imageSize;
if ([[window contentView] respondsToSelector:@selector(convertSizeFromBacking:)])
{
// Only resize for retina displays if the image is bigger than the screen
NSSize screenSize = NSScreen.mainScreen.visibleFrame.size;
CGFloat titleBarHeight = window.frame.size.height - [window contentRectForFrameRect:window.frame].size.height;
screenSize.height -= titleBarHeight;
if (imageSize.width > screenSize.width || imageSize.height > screenSize.height)
{
CGFloat fx = screenSize.width/std::max(imageSize.width, (CGFloat)1.f);
CGFloat fy = screenSize.height/std::max(imageSize.height, (CGFloat)1.f);
CGFloat min_f = std::min(fx, fy);
scaledImageSize = [[window contentView] convertSizeFromBacking:imageSize];
scaledImageSize.width = std::min(scaledImageSize.width, min_f*imageSize.width);
scaledImageSize.height = std::min(scaledImageSize.height, min_f*imageSize.height);
}
}
NSSize contentSize = vrectOld.size;
contentSize.height = scaledImageSize.height + [window contentView].sliderHeight;
contentSize.width = std::max<int>(scaledImageSize.width, MIN_SLIDER_WIDTH);
[window setContentSize:contentSize]; //adjust sliders to fit new window size
if([window firstContent])
{
int x = [window x0];
int y = [window y0];
if(x >= 0 && y >= 0)
{
y = [[window screen] visibleFrame].size.height - y;
[window setFrameTopLeftPoint:NSMakePoint(x, y)];
}
}
}
}
[window setFirstContent:NO];
}
[localpool drain];
}
CV_IMPL void cvResizeWindow( const char* name, int width, int height)
{
//cout << "cvResizeWindow" << endl;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
CVWindow *window = cvGetWindow(name);
if(window && ![window autosize]) {
height += [window contentView].sliderHeight;
NSSize size = { (CGFloat)width, (CGFloat)height };
[window setContentSize:size];
}
[localpool drain];
}
CV_IMPL void cvMoveWindow( const char* name, int x, int y)
{
CV_FUNCNAME("cvMoveWindow");
__BEGIN__;
NSAutoreleasePool* localpool1 = [[NSAutoreleasePool alloc] init];
CVWindow *window = nil;
if(name == NULL)
CV_ERROR( CV_StsNullPtr, "NULL window name" );
//cout << "cvMoveWindow"<< endl;
window = cvGetWindow(name);
if(window) {
if([window firstContent]) {
[window setX0:x];
[window setY0:y];
}
else {
y = [[window screen] visibleFrame].size.height - y;
[window setFrameTopLeftPoint:NSMakePoint(x, y)];
}
}
[localpool1 drain];
__END__;
}
CV_IMPL int cvCreateTrackbar (const char* trackbar_name,
const char* window_name,
int* val, int count,
CvTrackbarCallback on_notify)
{
CV_FUNCNAME("cvCreateTrackbar");
int result = 0;
CVWindow *window = nil;
NSAutoreleasePool* localpool2 = nil;
__BEGIN__;
if (localpool2 != nil) [localpool2 drain];
localpool2 = [[NSAutoreleasePool alloc] init];
if(window_name == NULL)
CV_ERROR( CV_StsNullPtr, "NULL window name" );
//cout << "cvCreateTrackbar" << endl ;
window = cvGetWindow(window_name);
if(window) {
[window createSliderWithName:trackbar_name
maxValue:count
value:val
callback:on_notify];
result = 1;
}
[localpool2 drain];
__END__;
return result;
}
CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,
const char* window_name,
int* val, int count,
CvTrackbarCallback2 on_notify2,
void* userdata)
{
//cout <<"cvCreateTrackbar2" << endl;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
int res = cvCreateTrackbar(trackbar_name, window_name, val, count, NULL);
if(res) {
CVWindow *window = cvGetWindow(window_name);
if (window && [window respondsToSelector:@selector(sliders)]) {
CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
[slider setCallback2:on_notify2];
[slider setUserData:userdata];
}
}
[localpool drain];
return res;
}
CV_IMPL void
cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
{
CV_FUNCNAME("cvSetMouseCallback");
CVWindow *window = nil;
NSAutoreleasePool* localpool3 = nil;
__BEGIN__;
//cout << "cvSetMouseCallback" << endl;
if (localpool3 != nil) [localpool3 drain];
localpool3 = [[NSAutoreleasePool alloc] init];
if(name == NULL)
CV_ERROR( CV_StsNullPtr, "NULL window name" );
window = cvGetWindow(name);
if(window) {
[window setMouseCallback:function];
[window setMouseParam:info];
}
[localpool3 drain];
__END__;
}
CV_IMPL int cvGetTrackbarPos( const char* trackbar_name, const char* window_name )
{
CV_FUNCNAME("cvGetTrackbarPos");
CVWindow *window = nil;
int pos = -1;
NSAutoreleasePool* localpool4 = nil;
__BEGIN__;
//cout << "cvGetTrackbarPos" << endl;
if(trackbar_name == NULL || window_name == NULL)
CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
if (localpool4 != nil) [localpool4 drain];
localpool4 = [[NSAutoreleasePool alloc] init];
window = cvGetWindow(window_name);
if(window && [window respondsToSelector:@selector(sliders)]) {
CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
if(slider) {
pos = [[slider slider] intValue];
}
}
[localpool4 drain];
__END__;
return pos;
}
CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name, int pos)
{
CV_FUNCNAME("cvSetTrackbarPos");
CVWindow *window = nil;
CVSlider *slider = nil;
NSAutoreleasePool* localpool5 = nil;
__BEGIN__;
//cout << "cvSetTrackbarPos" << endl;
if(trackbar_name == NULL || window_name == NULL)
CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
if(pos < 0)
CV_ERROR( CV_StsOutOfRange, "Bad trackbar maximal value" );
if (localpool5 != nil) [localpool5 drain];
localpool5 = [[NSAutoreleasePool alloc] init];
window = cvGetWindow(window_name);
if(window && [window respondsToSelector:@selector(sliders)]) {
slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
if(slider) {
[[slider slider] setIntValue:pos];
if([slider respondsToSelector:@selector(handleSlider)]) {
[slider performSelector:@selector(handleSlider)];
}
}
}
[localpool5 drain];
__END__;
}
CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name, int maxval)
{
CV_FUNCNAME("cvSetTrackbarMax");
CVWindow *window = nil;
CVSlider *slider = nil;
NSAutoreleasePool* localpool5 = nil;
__BEGIN__;
//cout << "cvSetTrackbarPos" << endl;
if(trackbar_name == NULL || window_name == NULL)
CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
if (localpool5 != nil) [localpool5 drain];
localpool5 = [[NSAutoreleasePool alloc] init];
window = cvGetWindow(window_name);
if(window && [window respondsToSelector:@selector(sliders)]) {
slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
if(slider) {
if(maxval >= 0) {
int minval = [[slider slider] minValue];
maxval = (minval>maxval)?minval:maxval;
[[slider slider] setMaxValue:maxval];
}
}
}
[localpool5 drain];
__END__;
}
CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name, int minval)
{
CV_FUNCNAME("cvSetTrackbarMin");
CVWindow *window = nil;
CVSlider *slider = nil;
NSAutoreleasePool* localpool5 = nil;
__BEGIN__;
if(trackbar_name == NULL || window_name == NULL)
CV_ERROR( CV_StsNullPtr, "NULL trackbar or window name" );
if (localpool5 != nil) [localpool5 drain];
localpool5 = [[NSAutoreleasePool alloc] init];
window = cvGetWindow(window_name);
if(window && [window respondsToSelector:@selector(sliders)]) {
slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
if(slider) {
if(minval >= 0) {
int maxval = [[slider slider] maxValue];
minval = (minval<maxval)?minval:maxval;
[[slider slider] setMinValue:minval];
}
}
}
[localpool5 drain];
__END__;
}
CV_IMPL void* cvGetWindowHandle( const char* name )
{
//cout << "cvGetWindowHandle" << endl;
return cvGetWindow(name);
}
CV_IMPL const char* cvGetWindowName( void* window_handle )
{
//cout << "cvGetWindowName" << endl;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
for(NSString *key in windows) {
if([windows valueForKey:key] == window_handle) {
[localpool drain];
return [key UTF8String];
}
}
[localpool drain];
return 0;
}
CV_IMPL int cvNamedWindow( const char* name, int flags )
{
if( !wasInitialized )
cvInitSystem(0, 0);
//cout << "cvNamedWindow" << endl;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
CVWindow *window = cvGetWindow(name);
if( window )
{
[window setAutosize:(flags == CV_WINDOW_AUTOSIZE)];
[localpool drain];
return 0;
}
NSScreen* mainDisplay = [NSScreen mainScreen];
NSString *windowName = [NSString stringWithFormat:@"%s", name];
NSUInteger showResize = NSResizableWindowMask;
NSUInteger styleMask = NSTitledWindowMask|NSMiniaturizableWindowMask|showResize;
CGFloat windowWidth = [NSWindow minFrameWidthWithTitle:windowName styleMask:styleMask];
NSRect initContentRect = NSMakeRect(0, 0, windowWidth, 0);
if (mainDisplay) {
NSRect dispFrame = [mainDisplay visibleFrame];
initContentRect.origin.y = dispFrame.size.height-20;
}
window = [[CVWindow alloc] initWithContentRect:initContentRect
styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|showResize
backing:NSBackingStoreBuffered
defer:YES
screen:mainDisplay];
[window setFrameTopLeftPoint:initContentRect.origin];
[window setFirstContent:YES];
[window setX0:-1];
[window setY0:-1];
[window setContentView:[[CVView alloc] init]];
[NSApp activateIgnoringOtherApps:YES];
[window setHasShadow:YES];
[window setAcceptsMouseMovedEvents:YES];
[window useOptimizedDrawing:YES];
[window setTitle:windowName];
[window makeKeyAndOrderFront:nil];
[window setAutosize:(flags == CV_WINDOW_AUTOSIZE)];
[windows setValue:window forKey:windowName];
[localpool drain];
return [windows count]-1;
}
CV_IMPL int cvWaitKey (int maxWait)
{
//cout << "cvWaitKey" << endl;
int returnCode = -1;
NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
double start = [[NSDate date] timeIntervalSince1970];
while(true) {
if(([[NSDate date] timeIntervalSince1970] - start) * 1000 >= maxWait && maxWait>0)
break;
//event = [application currentEvent];
[localpool drain];
localpool = [[NSAutoreleasePool alloc] init];
NSEvent *event =
[application
nextEventMatchingMask:NSAnyEventMask
untilDate://[NSDate dateWithTimeIntervalSinceNow: 1./100]
[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if([event type] == NSKeyDown && [[event characters] length]) {
returnCode = [[event characters] characterAtIndex:0];
break;
}
[application sendEvent:event];
[application updateWindows];
[NSThread sleepForTimeInterval:1/100.];
}
[localpool drain];
return returnCode;
}
CvRect cvGetWindowRect_COCOA( const char* name )
{
CvRect result = cvRect(-1, -1, -1, -1);
CVWindow *window = nil;
CV_FUNCNAME( "cvGetWindowRect_COCOA" );
__BEGIN__;
if( name == NULL )
{
CV_ERROR( CV_StsNullPtr, "NULL name string" );
}
window = cvGetWindow( name );
if ( window == NULL )
{
CV_ERROR( CV_StsNullPtr, "NULL window" );
} else {
NSRect rect = [window frame];
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_6
NSPoint pt = [window convertRectToScreen:rect].origin;
#else
NSPoint pt = [window convertBaseToScreen:rect.origin];
#endif
NSSize sz = [[[window contentView] image] size];
result = cvRect(pt.x, pt.y, sz.width, sz.height);
}
__END__;
return result;
}
double cvGetModeWindow_COCOA( const char* name )
{
double result = -1;
CVWindow *window = nil;
CV_FUNCNAME( "cvGetModeWindow_COCOA" );
__BEGIN__;
if( name == NULL )
{
CV_ERROR( CV_StsNullPtr, "NULL name string" );
}
window = cvGetWindow( name );
if ( window == NULL )
{
CV_ERROR( CV_StsNullPtr, "NULL window" );
}
result = window.status;
__END__;
return result;
}
void cvSetModeWindow_COCOA( const char* name, double prop_value )
{
CVWindow *window = nil;
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
NSDictionary *fullscreenOptions = nil;
#endif
NSAutoreleasePool* localpool = nil;
CV_FUNCNAME( "cvSetModeWindow_COCOA" );
__BEGIN__;
if( name == NULL )
{
CV_ERROR( CV_StsNullPtr, "NULL name string" );
}
window = cvGetWindow(name);
if ( window == NULL )
{
CV_ERROR( CV_StsNullPtr, "NULL window" );
}
if ( [window autosize] )
{
return;
}
localpool = [[NSAutoreleasePool alloc] init];
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_6
if ( ([window styleMask] & NSFullScreenWindowMask) && prop_value==CV_WINDOW_NORMAL )
{
[window toggleFullScreen:nil];
window.status=CV_WINDOW_NORMAL;
}
else if( !([window styleMask] & NSFullScreenWindowMask) && prop_value==CV_WINDOW_FULLSCREEN )
{
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
NSScreen* screen = [window screen];
NSRect frame = [screen frame];
[window setFrame:frame display:YES];
[window setContentSize:frame.size];
[window toggleFullScreen:nil];
[window setFrameTopLeftPoint: frame.origin];
window.status=CV_WINDOW_FULLSCREEN;
}
#else
fullscreenOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSFullScreenModeSetting];
if ( [[window contentView] isInFullScreenMode] && prop_value==CV_WINDOW_NORMAL )
{
[[window contentView] exitFullScreenModeWithOptions:fullscreenOptions];
window.status=CV_WINDOW_NORMAL;
}
else if( ![[window contentView] isInFullScreenMode] && prop_value==CV_WINDOW_FULLSCREEN )
{
[[window contentView] enterFullScreenMode:[NSScreen mainScreen] withOptions:fullscreenOptions];
window.status=CV_WINDOW_FULLSCREEN;
}
#endif
[localpool drain];
__END__;
}
double cvGetPropVisible_COCOA(const char* name)
{
double result = -1;
CVWindow* window = nil;
CV_FUNCNAME("cvGetPropVisible_COCOA");
__BEGIN__;
if (name == NULL)
{
CV_ERROR(CV_StsNullPtr, "NULL name string");
}
window = cvGetWindow(name);
if (window == NULL)
{
CV_ERROR(CV_StsNullPtr, "NULL window");
}
result = window.isVisible ? 1 : 0;
__END__;
return result;
}
double cvGetPropTopmost_COCOA(const char* name)
{
double result = -1;
CVWindow* window = nil;
CV_FUNCNAME("cvGetPropTopmost_COCOA");
__BEGIN__;
if (name == NULL)
{
CV_ERROR(CV_StsNullPtr, "NULL name string");
}
window = cvGetWindow(name);
if (window == NULL)
{
CV_ERROR(CV_StsNullPtr, "NULL window");
}
result = (window.level == NSStatusWindowLevel) ? 1 : 0;
__END__;
return result;
}
void cvSetPropTopmost_COCOA( const char* name, const bool topmost )
{
CVWindow *window = nil;
NSAutoreleasePool* localpool = nil;
CV_FUNCNAME( "cvSetPropTopmost_COCOA" );
__BEGIN__;
if( name == NULL )
{
CV_ERROR( CV_StsNullPtr, "NULL name string" );
}
window = cvGetWindow(name);
if ( window == NULL )
{
CV_ERROR( CV_StsNullPtr, "NULL window" );
}
if (([window styleMask] & NSFullScreenWindowMask))
{
EXIT;
}
localpool = [[NSAutoreleasePool alloc] init];
if (topmost)
{
[window makeKeyAndOrderFront:window.self];
[window setLevel:CGWindowLevelForKey(kCGMaximumWindowLevelKey)];
}
else
{
[window makeKeyAndOrderFront:nil];
}
[localpool drain];
__END__;
}
void setWindowTitle_COCOA(const cv::String& winname, const cv::String& title)
{
CVWindow *window = cvGetWindow(winname.c_str());
if (window == NULL)
{
cv::namedWindow(winname);
window = cvGetWindow(winname.c_str());
}
if (window == NULL)
CV_Error(cv::Error::StsNullPtr, "NULL window");
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
NSString *windowTitle = [NSString stringWithFormat:@"%s", title.c_str()];
[window setTitle:windowTitle];
[localpool drain];
}
static NSSize constrainAspectRatio(NSSize base, NSSize constraint) {
CGFloat heightDiff = (base.height / constraint.height);
CGFloat widthDiff = (base.width / constraint.width);
if (heightDiff == 0) heightDiff = widthDiff;
if (widthDiff == heightDiff) {
return base;
}
else if (widthDiff > heightDiff) {
NSSize out = { constraint.width / constraint.height * base.height, base.height };
return out;
}
else {
NSSize out = { base.width, constraint.height / constraint.width * base.width };
return out;
}
}
@implementation CVWindow
@synthesize mouseCallback;
@synthesize mouseParam;
@synthesize autosize;
@synthesize firstContent;
@synthesize x0;
@synthesize y0;
@synthesize sliders;
@synthesize slidersKeys;
@synthesize status;
- (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags {
(void)event;
//cout << "cvSendMouseEvent" << endl;
NSPoint mp = [NSEvent mouseLocation];
//NSRect visible = [[self contentView] frame];
mp = [self convertScreenToBase: mp];
CVView *contentView = [self contentView];
NSSize viewSize = contentView.frame.size;
if (contentView.imageView) {
viewSize = contentView.imageView.frame.size;
}
else {
viewSize.height -= contentView.sliderHeight;
}
mp.y = viewSize.height - mp.y;
NSSize imageSize = contentView.image.size;
mp.y *= (imageSize.height / std::max(viewSize.height, 1.));
mp.x *= (imageSize.width / std::max(viewSize.width, 1.));
if( [event type] == NSEventTypeScrollWheel ) {
if( event.hasPreciseScrollingDeltas ) {
mp.x = int(event.scrollingDeltaX);
mp.y = int(event.scrollingDeltaY);
} else {
mp.x = int(event.scrollingDeltaX / 0.100006);
mp.y = int(event.scrollingDeltaY / 0.100006);
}
if( mp.x && !mp.y && CV_EVENT_MOUSEWHEEL == type ) {
type = CV_EVENT_MOUSEHWHEEL;
}
mouseCallback(type, mp.x, mp.y, flags, mouseParam);
} else if( mp.x >= 0 && mp.y >= 0 && mp.x < imageSize.width && mp.y < imageSize.height ) {
mouseCallback(type, mp.x, mp.y, flags, mouseParam);
}
}
- (void)cvMouseEvent:(NSEvent *)event {
//cout << "cvMouseEvent" << endl;
if(!mouseCallback)
return;
int flags = 0;
if([event modifierFlags] & NSShiftKeyMask) flags |= CV_EVENT_FLAG_SHIFTKEY;
if([event modifierFlags] & NSControlKeyMask) flags |= CV_EVENT_FLAG_CTRLKEY;
if([event modifierFlags] & NSAlternateKeyMask) flags |= CV_EVENT_FLAG_ALTKEY;
if([event type] == NSLeftMouseDown) {[self cvSendMouseEvent:event type:CV_EVENT_LBUTTONDOWN flags:flags | CV_EVENT_FLAG_LBUTTON];}
if([event type] == NSLeftMouseUp) {[self cvSendMouseEvent:event type:CV_EVENT_LBUTTONUP flags:flags | CV_EVENT_FLAG_LBUTTON];}
if([event type] == NSRightMouseDown){[self cvSendMouseEvent:event type:CV_EVENT_RBUTTONDOWN flags:flags | CV_EVENT_FLAG_RBUTTON];}
if([event type] == NSRightMouseUp) {[self cvSendMouseEvent:event type:CV_EVENT_RBUTTONUP flags:flags | CV_EVENT_FLAG_RBUTTON];}
if([event type] == NSOtherMouseDown){[self cvSendMouseEvent:event type:CV_EVENT_MBUTTONDOWN flags:flags];}
if([event type] == NSOtherMouseUp) {[self cvSendMouseEvent:event type:CV_EVENT_MBUTTONUP flags:flags];}
if([event type] == NSMouseMoved) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE flags:flags];}
if([event type] == NSLeftMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE flags:flags | CV_EVENT_FLAG_LBUTTON];}
if([event type] == NSRightMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE flags:flags | CV_EVENT_FLAG_RBUTTON];}
if([event type] == NSOtherMouseDragged) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEMOVE flags:flags | CV_EVENT_FLAG_MBUTTON];}
if([event type] == NSEventTypeScrollWheel) {[self cvSendMouseEvent:event type:CV_EVENT_MOUSEWHEEL flags:flags ];}
}
-(void)scrollWheel:(NSEvent *)theEvent {
[self cvMouseEvent:theEvent];
}
- (void)keyDown:(NSEvent *)theEvent {
//cout << "keyDown" << endl;
[super keyDown:theEvent];
}
- (void)rightMouseDragged:(NSEvent *)theEvent {
//cout << "rightMouseDragged" << endl ;
[self cvMouseEvent:theEvent];
}
- (void)rightMouseUp:(NSEvent *)theEvent {
//cout << "rightMouseUp" << endl;
[self cvMouseEvent:theEvent];
}
- (void)rightMouseDown:(NSEvent *)theEvent {
// Does not seem to work?
//cout << "rightMouseDown" << endl;
[self cvMouseEvent:theEvent];
}
- (void)mouseMoved:(NSEvent *)theEvent {
[self cvMouseEvent:theEvent];
}
- (void)otherMouseDragged:(NSEvent *)theEvent {
[self cvMouseEvent:theEvent];
}
- (void)otherMouseUp:(NSEvent *)theEvent {
[self cvMouseEvent:theEvent];
}
- (void)otherMouseDown:(NSEvent *)theEvent {
[self cvMouseEvent:theEvent];
}
- (void)mouseDragged:(NSEvent *)theEvent {
[self cvMouseEvent:theEvent];
}
- (void)mouseUp:(NSEvent *)theEvent {
[self cvMouseEvent:theEvent];
}
- (void)mouseDown:(NSEvent *)theEvent {
[self cvMouseEvent:theEvent];
}
- (void)createSliderWithName:(const char *)name maxValue:(int)max value:(int *)value callback:(CvTrackbarCallback)callback {
//cout << "createSliderWithName" << endl;
if(sliders == nil)
sliders = [[NSMutableDictionary alloc] init];
if(slidersKeys == nil)
slidersKeys = [[NSMutableArray alloc] init];
NSString *cvname = [NSString stringWithFormat:@"%s", name];
// Avoid overwriting slider
if([sliders valueForKey:cvname]!=nil)
return;
// Create slider
CVSlider *slider = [[CVSlider alloc] init];
[[slider name] setStringValue:cvname];
slider.initialName = [NSString stringWithFormat:@"%s", name];
[[slider slider] setMaxValue:max];
[[slider slider] setMinValue:0];
if(value)
{
[[slider slider] setIntValue:*value];
[slider setValue:value];
NSString *temp = [slider initialName];
NSString *text = [NSString stringWithFormat:@"%@ %d", temp, *value];
[[slider name] setStringValue: text];
}
if(callback)
[slider setCallback:callback];
// Save slider
[sliders setValue:slider forKey:cvname];
[slidersKeys addObject:cvname];
[[self contentView] addSubview:slider];
//update contentView size to contain sliders
NSSize viewSize=[[self contentView] frame].size,
sliderSize=[slider frame].size;
viewSize.height += sliderSize.height;
viewSize.width = std::max<int>(viewSize.width, MIN_SLIDER_WIDTH);
// Update slider sizes
[self contentView].sliderHeight += sliderSize.height;
if ([[self contentView] image] && ![[self contentView] imageView]) {
[[self contentView] setNeedsDisplay:YES];
}
//update window size to contain sliders
[self setContentSize: viewSize];
}
- (CVView *)contentView {
return (CVView*)[super contentView];
}
@end
@implementation CVView
@synthesize image;
- (id)init {
//cout << "CVView init" << endl;
[super init];
return self;
}
- (void)setImageData:(CvArr *)arr {
//cout << "setImageData" << endl;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
cv::Mat arrMat = cv::cvarrToMat(arr);
/*CGColorSpaceRef colorspace = NULL;
CGDataProviderRef provider = NULL;
int width = cvimage->width;
int height = cvimage->height;
colorspace = CGColorSpaceCreateDeviceRGB();
int size = 8;
int nbChannels = 3;
provider = CGDataProviderCreateWithData(NULL, cvimage->data.ptr, width * height , NULL );
CGImageRef imageRef = CGImageCreate(width, height, size , size*nbChannels , cvimage->step, colorspace, kCGImageAlphaNone , provider, NULL, true, kCGRenderingIntentDefault);
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:imageRef];
if(image) {
[image release];
}*/
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:arrMat.cols
pixelsHigh:arrMat.rows
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bitmapFormat: kCGImageAlphaNone
bytesPerRow:((arrMat.cols * 3 + 3) & -4)
bitsPerPixel:24];
if (bitmap) {
cv::Mat dst(arrMat.rows, arrMat.cols, CV_8UC3, [bitmap bitmapData], [bitmap bytesPerRow]);
convertToShow(arrMat, dst);
}
else {
// It's not guaranteed to like the bitsPerPixel:24, but this is a lot slower so we'd rather not do it
bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:arrMat.cols
pixelsHigh:arrMat.rows
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:(arrMat.cols * 4)
bitsPerPixel:32];
cv::Mat dst(arrMat.rows, arrMat.cols, CV_8UC4, [bitmap bitmapData], [bitmap bytesPerRow]);
convertToShow(arrMat, dst);
}
if( image ) {
[image release];
}
image = [[NSImage alloc] init];
[image addRepresentation:bitmap];
[bitmap release];
// This isn't supported on older versions of macOS
// The performance issues this solves are mainly on newer versions of macOS, so that's fine
if( floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5 ) {
if (![self imageView]) {
[self setImageView:[[NSView alloc] init]];
[[self imageView] setWantsLayer:true];
[self addSubview:[self imageView]];
}
[[[self imageView] layer] setContents:image];
NSRect imageViewFrame = [self frame];
imageViewFrame.size.height -= [self sliderHeight];
NSRect constrainedFrame = { imageViewFrame.origin, constrainAspectRatio(imageViewFrame.size, [image size]) };
[[self imageView] setFrame:constrainedFrame];
}
else {
NSRect redisplayRect = [self frame];
redisplayRect.size.height -= [self sliderHeight];
[self setNeedsDisplayInRect:redisplayRect];
}
/*CGColorSpaceRelease(colorspace);
CGDataProviderRelease(provider);
CGImageRelease(imageRef);*/
[localpool drain];
}
- (void)setFrameSize:(NSSize)size {
//cout << "setFrameSize" << endl;
[super setFrameSize:size];
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
int height = size.height;
CVWindow *cvwindow = (CVWindow *)[self window];
if ([cvwindow respondsToSelector:@selector(sliders)]) {
for(NSString *key in [cvwindow slidersKeys]) {
CVSlider *slider = [[cvwindow sliders] valueForKey:key];
NSRect r = [slider frame];
r.origin.y = height - r.size.height;
r.size.width = [[cvwindow contentView] frame].size.width;
CGRect sliderRect = slider.slider.frame;
CGFloat targetWidth = r.size.width - (sliderRect.origin.x + 10);
sliderRect.size.width = targetWidth < 0 ? 0 : targetWidth;
slider.slider.frame = sliderRect;
[slider setFrame:r];
height -= r.size.height;
}
}
NSRect frame = self.frame;
if (frame.size.height < self.sliderHeight) {
frame.size.height = self.sliderHeight;
self.frame = frame;
}
if ([self imageView]) {
NSRect imageViewFrame = frame;
imageViewFrame.size.height -= [self sliderHeight];
NSRect constrainedFrame = { imageViewFrame.origin, constrainAspectRatio(imageViewFrame.size, [image size]) };
[[self imageView] setFrame:constrainedFrame];
}
[localpool drain];
}
- (void)drawRect:(NSRect)rect {
//cout << "drawRect" << endl;
[super drawRect:rect];
// If imageView exists, all drawing will be done by it and nothing needs to happen here
if ([self image] && ![self imageView]) {
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
if(image != nil) {
[image drawInRect: [self frame]
fromRect: NSZeroRect
operation: NSCompositeSourceOver
fraction: 1.0];
}
[localpool release];
}
}
@end
@implementation CVSlider
@synthesize slider;
@synthesize name;
@synthesize initialName;
@synthesize value;
@synthesize userData;
@synthesize callback;
@synthesize callback2;
- (id)init {
[super init];
callback = NULL;
value = NULL;
userData = NULL;
[self setFrame:NSMakeRect(0,0,200,30)];
name = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 0,110, 25)];
[name setEditable:NO];
[name setSelectable:NO];
[name setBezeled:NO];
[name setBordered:NO];
[name setDrawsBackground:NO];
[[name cell] setLineBreakMode:NSLineBreakByTruncatingTail];
[self addSubview:name];
slider = [[NSSlider alloc] initWithFrame:NSMakeRect(120, 0, 70, 25)];
[slider setAutoresizingMask:NSViewWidthSizable];
[slider setMinValue:0];
[slider setMaxValue:100];
[slider setContinuous:YES];
[slider setTarget:self];
[slider setAction:@selector(handleSliderNotification:)];
[self addSubview:slider];
[self setAutoresizingMask:NSViewWidthSizable];
//[self setFrame:NSMakeRect(12, 0, 100, 30)];
return self;
}
- (void)handleSliderNotification:(NSNotification *)notification {
(void)notification;
[self handleSlider];
}
- (void)handleSlider {
int pos = [slider intValue];
NSString *temp = [self initialName];
NSString *text = [NSString stringWithFormat:@"%@ %d", temp, pos];
[name setStringValue: text];
if(value)
*value = pos;
if(callback)
callback(pos);
if(callback2)
callback2(pos, userData);
}
@end
#endif
/* End of file. */