X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f487501a2c84aa5053b5c3ea57fa2627bac25041..55410bb4f67febe1ca20654f078ea4fb9a6223ae:/src/osx/cocoa/window.mm diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 3f9f4e7154..9b2cfd9b55 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -44,10 +44,13 @@ NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const @interface wxNSView : NSView { + NSTrackingRectTag rectTag; } - (BOOL) canBecomeKeyView; - +// the tracking tag is needed to track mouse enter / exit events +- (void) setTrackingTag: (NSTrackingRectTag)tag; +- (NSTrackingRectTag) trackingTag; @end // wxNSView @interface NSView(PossibleMethods) @@ -77,57 +80,113 @@ NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const - (void)setDoubleAction:(SEL)aSelector; @end -long wxOSXTranslateCocoaKey( int unichar ) +long wxOSXTranslateCocoaKey( NSEvent* event ) { - long retval = unichar; - switch( unichar ) + long retval = 0; + + if ([event type] != NSFlagsChanged) + { + NSString* s = [event charactersIgnoringModifiers]; + // backspace char reports as delete w/modifiers for some reason + if ([s length] == 1) + { + switch ( [s characterAtIndex:0] ) + { + // backspace key + case 0x7F : + case 8 : + retval = WXK_BACK; + break; + case NSUpArrowFunctionKey : + retval = WXK_UP; + break; + case NSDownArrowFunctionKey : + retval = WXK_DOWN; + break; + case NSLeftArrowFunctionKey : + retval = WXK_LEFT; + break; + case NSRightArrowFunctionKey : + retval = WXK_RIGHT; + break; + case NSInsertFunctionKey : + retval = WXK_INSERT; + break; + case NSDeleteFunctionKey : + retval = WXK_DELETE; + break; + case NSHomeFunctionKey : + retval = WXK_HOME; + break; + // case NSBeginFunctionKey : + // retval = WXK_BEGIN; + // break; + case NSEndFunctionKey : + retval = WXK_END; + break; + case NSPageUpFunctionKey : + retval = WXK_PAGEUP; + break; + case NSPageDownFunctionKey : + retval = WXK_PAGEDOWN; + break; + case NSHelpFunctionKey : + retval = WXK_HELP; + break; + default: + int intchar = [[event characters] characterAtIndex: 0]; + if ( intchar >= NSF1FunctionKey && intchar >= NSF24FunctionKey ) + retval = WXK_F1 + (intchar - NSF1FunctionKey ); + break; + } + } + } + + // Some keys don't seem to have constants. The code mimics the approach + // taken by WebKit. See: + // http://trac.webkit.org/browser/trunk/WebCore/platform/mac/KeyEventMac.mm + switch( [event keyCode] ) { - case NSUpArrowFunctionKey : - retval = WXK_UP; + // command key + case 54: + case 55: + retval = WXK_COMMAND; break; - case NSDownArrowFunctionKey : - retval = WXK_DOWN; + // caps locks key + case 57: // Capslock + retval = WXK_CAPITAL; break; - case NSLeftArrowFunctionKey : - retval = WXK_LEFT; + // shift key + case 56: // Left Shift + case 60: // Right Shift + retval = WXK_SHIFT; break; - case NSRightArrowFunctionKey : - retval = WXK_RIGHT; + // alt key + case 58: // Left Alt + case 61: // Right Alt + retval = WXK_ALT; break; - case NSInsertFunctionKey : - retval = WXK_INSERT; + // ctrl key + case 59: // Left Ctrl + case 62: // Right Ctrl + retval = WXK_CONTROL; break; - case NSDeleteFunctionKey : - retval = WXK_DELETE; + // clear key + case 71: + retval = WXK_CLEAR; break; - case NSHomeFunctionKey : - retval = WXK_HOME; - break; -// case NSBeginFunctionKey : -// retval = WXK_BEGIN; -// break; - case NSEndFunctionKey : - retval = WXK_END; - break; - case NSPageUpFunctionKey : - retval = WXK_PAGEUP; - break; - case NSPageDownFunctionKey : - retval = WXK_PAGEDOWN; - break; - case NSHelpFunctionKey : - retval = WXK_HELP; + // tab key + case 48: + retval = WXK_TAB; break; default : - if ( unichar >= NSF1FunctionKey && unichar >= NSF24FunctionKey ) - retval = WXK_F1 + (unichar - NSF1FunctionKey ); break; } return retval; } -void SetupKeyEvent( wxKeyEvent &wxevent , NSEvent * nsEvent ) +void SetupKeyEvent( wxKeyEvent &wxevent , NSEvent * nsEvent, NSString* charString = NULL ) { UInt32 modifiers = [nsEvent modifierFlags] ; int eventType = [nsEvent type]; @@ -160,20 +219,36 @@ void SetupKeyEvent( wxKeyEvent &wxevent , NSEvent * nsEvent ) if ( eventType != NSFlagsChanged ) { NSString* nschars = [nsEvent characters]; - if ( nschars ) + if ( charString ) + { + // if charString is set, it did not come from key up / key down + wxevent.SetEventType( wxEVT_CHAR ); + wxCFStringRef cfchars((CFStringRef)[charString retain]); + chars = cfchars.AsString(); + } + else if ( nschars ) { wxCFStringRef cfchars((CFStringRef)[nschars retain]); chars = cfchars.AsString(); } } - int unichar = chars.Length() > 0 ? chars[0] : 0; - long keyval = wxOSXTranslateCocoaKey(unichar) ; - if ( keyval == unichar && ( wxevent.GetEventType() == wxEVT_KEY_UP || wxevent.GetEventType() == wxEVT_KEY_DOWN ) ) - keyval = wxToupper( keyval ) ; + int aunichar = chars.Length() > 0 ? chars[0] : 0; + long keyval = 0; + + if (wxevent.GetEventType() != wxEVT_CHAR) + keyval = wxOSXTranslateCocoaKey(nsEvent) ; + if ( !keyval ) + { + if ( wxevent.GetEventType() == wxEVT_KEY_UP || wxevent.GetEventType() == wxEVT_KEY_DOWN ) + keyval = wxToupper( aunichar ) ; + else + keyval = aunichar; + } + #if wxUSE_UNICODE - wxevent.m_uniChar = unichar; + wxevent.m_uniChar = aunichar; #endif wxevent.m_keyCode = keyval; } @@ -190,7 +265,7 @@ void SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent ) // these parameters are not given for all events UInt32 button = [nsEvent buttonNumber]; UInt32 clickCount = 0; - if ( eventType != NSScrollWheel ) + if ( [nsEvent respondsToSelector:@selector(clickCount:)] ) [nsEvent clickCount]; wxevent.m_x = screenMouseLocation.x; @@ -316,22 +391,27 @@ void SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent ) case NSScrollWheel : { wxevent.SetEventType( wxEVT_MOUSEWHEEL ) ; - wxevent.m_wheelDelta = 1; + wxevent.m_wheelDelta = 10; wxevent.m_linesPerAction = 1; + NSLog(@"deltaX %f, deltaY %f",[nsEvent deltaX], [nsEvent deltaY]); if ( abs([nsEvent deltaX]) > abs([nsEvent deltaY]) ) { wxevent.m_wheelAxis = 1; - wxevent.m_wheelRotation = [nsEvent deltaX] > 0.0 ? 1 : -1; + wxevent.m_wheelRotation = [nsEvent deltaX] * 10.0; } else { - wxevent.m_wheelRotation = [nsEvent deltaY] > 0.0 ? 1 : -1; + wxevent.m_wheelRotation = [nsEvent deltaY] * 10.0; } } break ; case NSMouseEntered : + wxevent.SetEventType( wxEVT_ENTER_WINDOW ) ; + break; case NSMouseExited : + wxevent.SetEventType( wxEVT_LEAVE_WINDOW ) ; + break; case NSLeftMouseDragged : case NSRightMouseDragged : case NSOtherMouseDragged : @@ -360,6 +440,16 @@ void SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent ) return YES; } +- (void) setTrackingTag: (NSTrackingRectTag)tag +{ + rectTag = tag; +} + +- (NSTrackingRectTag) trackingTag +{ + return rectTag; +} + @end // wxNSView // @@ -425,6 +515,15 @@ void wxOSX_keyEvent(NSView* self, SEL _cmd, NSEvent *event) impl->keyEvent(event, self, _cmd); } +void wxOSX_insertText(NSView* self, SEL _cmd, NSString* text) +{ + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); + if (impl == NULL) + return; + + impl->insertText(text, self, _cmd); +} + BOOL wxOSX_performKeyEquivalent(NSView* self, SEL _cmd, NSEvent *event) { wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); @@ -479,22 +578,22 @@ void wxOSX_drawRect(NSView* self, SEL _cmd, NSRect rect) return impl->drawRect(&rect, self, _cmd); } -void wxOSX_clickedAction(NSView* self, SEL _cmd, id sender) +void wxOSX_controlAction(NSView* self, SEL _cmd, id sender) { wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); if (impl == NULL) return; - impl->clickedAction(self, _cmd, sender); + impl->controlAction(self, _cmd, sender); } -void wxOSX_doubleClickedAction(NSView* self, SEL _cmd, id sender) +void wxOSX_controlDoubleAction(NSView* self, SEL _cmd, id sender) { wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); if (impl == NULL) return; - impl->doubleClickedAction(self, _cmd, sender); + impl->controlDoubleAction(self, _cmd, sender); } unsigned int wxWidgetCocoaImpl::draggingEntered(void* s, WXWidget slf, void *_cmd) @@ -637,6 +736,7 @@ bool wxWidgetCocoaImpl::performDragOperation(void* s, WXWidget slf, void *_cmd) #endif +typedef void (*wxOSX_TextEventHandlerPtr)(NSView* self, SEL _cmd, NSString *event); typedef void (*wxOSX_EventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event); typedef BOOL (*wxOSX_PerformKeyEventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event); typedef BOOL (*wxOSX_FocusHandlerPtr)(NSView* self, SEL _cmd); @@ -654,22 +754,28 @@ void wxWidgetCocoaImpl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd) void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd) { - if ( !DoHandleKeyEvent(event) ) + if ( [[slf window] firstResponder] != slf || !DoHandleKeyEvent(event) ) { wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd]; superimpl(slf, (SEL)_cmd, event); } } -bool wxWidgetCocoaImpl::performKeyEquivalent(WX_NSEvent event, WXWidget slf, void *_cmd) +void wxWidgetCocoaImpl::insertText(NSString* text, WXWidget slf, void *_cmd) { - if ( !DoHandleKeyEvent(event) ) + if (m_lastKeyDownEvent && !DoHandleCharEvent(m_lastKeyDownEvent, text) ) { - wxOSX_PerformKeyEventHandlerPtr superimpl = (wxOSX_PerformKeyEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd]; - return superimpl(slf, (SEL)_cmd, event); + wxOSX_TextEventHandlerPtr superimpl = (wxOSX_TextEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd]; + superimpl(slf, (SEL)_cmd, text); } + m_lastKeyDownEvent = NULL; +} - return YES; + +bool wxWidgetCocoaImpl::performKeyEquivalent(WX_NSEvent event, WXWidget slf, void *_cmd) +{ + wxOSX_PerformKeyEventHandlerPtr superimpl = (wxOSX_PerformKeyEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd]; + return superimpl(slf, (SEL)_cmd, event); } bool wxWidgetCocoaImpl::becomeFirstResponder(WXWidget slf, void *_cmd) @@ -702,8 +808,10 @@ void wxWidgetCocoaImpl::resetCursorRects(WXWidget slf, void *_cmd) superimpl(slf, (SEL)_cmd); } else + { [slf addCursorRect: [slf bounds] cursor: cursor]; + } } } @@ -755,44 +863,33 @@ void wxWidgetCocoaImpl::drawRect(void* rect, WXWidget slf, void *_cmd) wxpeer->GetUpdateRegion() = updateRgn; wxpeer->MacSetCGContextRef( context ); - // first send an erase event to the entire update area - // for the toplevel window this really is the entire area - // for all the others only their client area, otherwise they - // might be drawing with full alpha and eg put blue into - // the grow-box area of a scrolled window (scroll sample) - - wxDC* dc = new wxWindowDC(wxpeer); - dc->SetDeviceClippingRegion(updateRgn); - - wxEraseEvent eevent( wxpeer->GetId(), dc ); - eevent.SetEventObject( wxpeer ); - wxpeer->HandleWindowEvent( eevent ); - delete dc ; - - wxPaintEvent event; - event.SetTimestamp(0); // todo - event.SetEventObject(wxpeer); - bool handled = wxpeer->HandleWindowEvent(event); + bool handled = wxpeer->MacDoRedraw( 0 ); CGContextRestoreGState( context ); - + + CGContextSaveGState( context ); if ( !handled ) { // call super SEL _cmd = @selector(drawRect:); wxOSX_DrawRectHandlerPtr superimpl = (wxOSX_DrawRectHandlerPtr) [[slf superclass] instanceMethodForSelector:_cmd]; superimpl(slf, _cmd, *(NSRect*)rect); + CGContextRestoreGState( context ); + CGContextSaveGState( context ); } + wxpeer->MacPaintChildrenBorders(); + wxpeer->MacSetCGContextRef( NULL ); + CGContextRestoreGState( context ); } -void wxWidgetCocoaImpl::clickedAction( WXWidget slf, void *_cmd, void *sender) +void wxWidgetCocoaImpl::controlAction( WXWidget slf, void *_cmd, void *sender) { wxWindow* wxpeer = (wxWindow*) GetWXPeer(); if ( wxpeer ) wxpeer->OSXHandleClicked(0); } -void wxWidgetCocoaImpl::doubleClickedAction( WXWidget slf, void *_cmd, void *sender) +void wxWidgetCocoaImpl::controlDoubleAction( WXWidget slf, void *_cmd, void *sender) { } @@ -839,10 +936,11 @@ void wxOSXCocoaClassAddWXMethods(Class c) wxOSX_CLASS_ADD_METHOD(c, @selector(keyDown:), (IMP) wxOSX_keyEvent, "v@:@" ) wxOSX_CLASS_ADD_METHOD(c, @selector(keyUp:), (IMP) wxOSX_keyEvent, "v@:@" ) wxOSX_CLASS_ADD_METHOD(c, @selector(flagsChanged:), (IMP) wxOSX_keyEvent, "v@:@" ) + + wxOSX_CLASS_ADD_METHOD(c, @selector(insertText:), (IMP) wxOSX_insertText, "v@:@" ) wxOSX_CLASS_ADD_METHOD(c, @selector(performKeyEquivalent:), (IMP) wxOSX_performKeyEquivalent, "v@:@" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(becomeFirstResponder), (IMP) wxOSX_becomeFirstResponder, "c@:" ) wxOSX_CLASS_ADD_METHOD(c, @selector(resignFirstResponder), (IMP) wxOSX_resignFirstResponder, "c@:" ) wxOSX_CLASS_ADD_METHOD(c, @selector(resetCursorRects), (IMP) wxOSX_resetCursorRects, "v@:" ) @@ -850,8 +948,8 @@ void wxOSXCocoaClassAddWXMethods(Class c) wxOSX_CLASS_ADD_METHOD(c, @selector(isFlipped), (IMP) wxOSX_isFlipped, "c@:" ) wxOSX_CLASS_ADD_METHOD(c, @selector(drawRect:), (IMP) wxOSX_drawRect, "v@:{_NSRect={_NSPoint=ff}{_NSSize=ff}}" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(clickedAction:), (IMP) wxOSX_clickedAction, "v@:@" ) - wxOSX_CLASS_ADD_METHOD(c, @selector(doubleClickedAction:), (IMP) wxOSX_doubleClickedAction, "v@:@" ) + wxOSX_CLASS_ADD_METHOD(c, @selector(controlAction:), (IMP) wxOSX_controlAction, "v@:@" ) + wxOSX_CLASS_ADD_METHOD(c, @selector(controlDoubleAction:), (IMP) wxOSX_controlDoubleAction, "v@:@" ) #if wxUSE_DRAG_AND_DROP wxOSX_CLASS_ADD_METHOD(c, @selector(draggingEntered:), (IMP) wxOSX_draggingEntered, "I@:@" ) @@ -897,6 +995,7 @@ void wxWidgetCocoaImpl::Init() { m_osxView = NULL; m_isFlipped = true; + m_lastKeyDownEvent = NULL; } wxWidgetCocoaImpl::~wxWidgetCocoaImpl() @@ -953,12 +1052,24 @@ void wxWidgetCocoaImpl::Move(int x, int y, int width, int height) // adjust the coordinates if (parent) { - wxPoint pt(parent->GetClientAreaOrigin()); - x -= pt.x; - y -= pt.y; + int cx = 0,cy = 0,cw = 0,ch = 0; + if ( parent->GetPeer() ) + { + parent->GetPeer()->GetContentArea(cx, cy, cw, ch); + x -= cx; + y -= cy; + } } NSRect r = wxToNSRect( [m_osxView superview], wxRect(x,y,width, height) ); [m_osxView setFrame:r]; + + if ([m_osxView respondsToSelector:@selector(trackingTag)] ) + { + if ( [(wxNSView*)m_osxView trackingTag] ) + [m_osxView removeTrackingRect: [(wxNSView*)m_osxView trackingTag]]; + + [(wxNSView*)m_osxView setTrackingTag: [m_osxView addTrackingRect: [m_osxView bounds] owner: m_osxView userData: nil assumeInside: NO]]; + } } void wxWidgetCocoaImpl::GetPosition( int &x, int &y ) const @@ -1057,6 +1168,11 @@ void wxWidgetCocoaImpl::SetLabel( const wxString& title, wxFontEncoding encoding wxCFStringRef cf( title , m_wxPeer->GetFont().GetEncoding() ); [m_osxView setTitle:cf.AsNSString()]; } + else if ( [m_osxView respondsToSelector:@selector(setStringValue:) ] ) + { + wxCFStringRef cf( title , m_wxPeer->GetFont().GetEncoding() ); + [m_osxView setStringValue:cf.AsNSString()]; + } } @@ -1213,21 +1329,38 @@ void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control ) if ([c respondsToSelector:@selector(setAction:)]) { [c setTarget: c]; - [c setAction: @selector(clickedAction:)]; + [c setAction: @selector(controlAction:)]; if ([c respondsToSelector:@selector(setDoubleAction:)]) { - [c setDoubleAction: @selector(doubleClickedAction:)]; + [c setDoubleAction: @selector(controlDoubleAction:)]; } } } +bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text) +{ + wxKeyEvent wxevent(wxEVT_KEY_DOWN); + SetupKeyEvent( wxevent, event, text ); + + return GetWXPeer()->OSXHandleKeyEvent(wxevent); +} + bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event) { wxKeyEvent wxevent(wxEVT_KEY_DOWN); SetupKeyEvent( wxevent, event ); + + bool result = GetWXPeer()->OSXHandleKeyEvent(wxevent); - return GetWXPeer()->OSXHandleKeyEvent(wxevent); + // this will fire higher level events, like insertText, to help + // us handle EVT_CHAR, etc. + if ([event type] == NSKeyDown) + { + m_lastKeyDownEvent = event; + [m_osxView interpretKeyEvents:[NSArray arrayWithObject:event]]; + } + return result; } bool wxWidgetCocoaImpl::DoHandleMouseEvent(NSEvent *event) @@ -1336,6 +1469,7 @@ wxWidgetImpl* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now ) NSWindow* tlw = now->GetWXWindow(); wxNSView* v = [[wxNSView alloc] initWithFrame:[[tlw contentView] frame]]; wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( now, v, true ); + c->InstallEventHandler(); [tlw setContentView:v]; return c; }