From 7cb2a2418394a693447b9fe135458209d7ba81e8 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Thu, 11 Jun 2009 06:40:24 +0000 Subject: [PATCH] adding events to single line textcontrols (password is not fully supported) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@60993 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/osx/cocoa/private.h | 28 +++++++ src/osx/cocoa/nonownedwnd.mm | 20 +++++ src/osx/cocoa/textctrl.mm | 131 +++++++++++++++------------------ src/osx/cocoa/window.mm | 69 +++++++++++------ src/osx/textctrl_osx.cpp | 3 + 5 files changed, 156 insertions(+), 95 deletions(-) diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h index 38f82d00e9..fb8f330b3d 100644 --- a/include/wx/osx/cocoa/private.h +++ b/include/wx/osx/cocoa/private.h @@ -155,6 +155,9 @@ protected: WXWidget m_osxView; NSEvent* m_lastKeyDownEvent; bool m_isFlipped; + // if it the control has an editor, that editor will already send some + // events, don't resend them + bool m_hasEditor; DECLARE_DYNAMIC_CLASS_NO_COPY(wxWidgetCocoaImpl) }; @@ -244,9 +247,34 @@ protected : @end + @interface wxNSTextFieldEditor : NSTextView + { + NSEvent* lastKeyDownEvent; + } + + @end + @interface wxNSTextField : NSTextField + { + wxNSTextFieldEditor* fieldEditor; + } + + - (wxNSTextFieldEditor*) fieldEditor; + - (void) setFieldEditor:(wxNSTextFieldEditor*) fieldEditor; + + @end + + @interface wxNSSecureTextField : NSSecureTextField { } + + @end + + + @interface wxNSTextView : NSTextView + { + } + @end @interface wxNSMenu : NSMenu diff --git a/src/osx/cocoa/nonownedwnd.mm b/src/osx/cocoa/nonownedwnd.mm index 2823a386cc..c2bf25e06b 100644 --- a/src/osx/cocoa/nonownedwnd.mm +++ b/src/osx/cocoa/nonownedwnd.mm @@ -291,6 +291,26 @@ typedef void (*wxOSX_NoResponderHandlerPtr)(NSView* self, SEL _cmd, SEL selector } } +- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject +{ + wxUnusedVar(sender); + + if ([anObject isKindOfClass:[wxNSTextField class]]) + { + wxNSTextField* tf = (wxNSTextField*) anObject; + wxNSTextFieldEditor* editor = [tf fieldEditor]; + if ( editor == nil ) + { + editor = [[wxNSTextFieldEditor alloc] init]; + [editor setFieldEditor:YES]; + [tf setFieldEditor:editor]; + } + return editor; + } + + return nil; +} + @end IMPLEMENT_DYNAMIC_CLASS( wxNonOwnedWindowCocoaImpl , wxNonOwnedWindowImpl ) diff --git a/src/osx/cocoa/textctrl.mm b/src/osx/cocoa/textctrl.mm index 6814c6cdd5..03e04f2488 100644 --- a/src/osx/cocoa/textctrl.mm +++ b/src/osx/cocoa/textctrl.mm @@ -78,11 +78,6 @@ protected : NSView* m_textView; } ; -@interface wxNSSecureTextField : NSSecureTextField -{ -} -@end - @implementation wxNSSecureTextField + (void)initialize @@ -128,16 +123,6 @@ protected : } @end -@interface wxNSTextView : NSTextView -{ - wxNSTextScrollView* scrollView; -} - -- (void)setScrollView: (wxNSTextScrollView *) sv; -- (wxNSTextScrollView*) scrollView; - -@end - @implementation wxNSTextScrollView + (void)initialize @@ -150,79 +135,60 @@ protected : } } -- (void)textDidChange:(NSNotification *)aNotification +@end + +@implementation wxNSTextFieldEditor + +- (void) keyDown:(NSEvent*) event { - wxUnusedVar(aNotification); - wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); - if ( impl ) - { - wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer(); - if ( wxpeer ) { - wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, wxpeer->GetId()); - event.SetEventObject( wxpeer ); - event.SetString( static_cast(wxpeer)->GetValue() ); - wxpeer->HandleWindowEvent( event ); - } - } + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( [self delegate] ); + lastKeyDownEvent = event; + if ( impl == NULL || !impl->DoHandleKeyEvent(event) ) + [super keyDown:event]; + lastKeyDownEvent = nil; } -- (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)commandSelector +- (void) keyUp:(NSEvent*) event { - wxUnusedVar(aTextView); - wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); - if ( impl ) - { - wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer(); - if (commandSelector == @selector(insertNewline:)) - { - if ( wxpeer && wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER ) - { - wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId()); - event.SetEventObject( wxpeer ); - event.SetString( static_cast(wxpeer)->GetValue() ); - wxpeer->HandleWindowEvent( event ); - } - } - } - - return NO; + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( [self delegate] ); + if ( impl == NULL || !impl->DoHandleKeyEvent(event) ) + [super keyUp:event]; } -- (void)textDidEndEditing:(NSNotification *)aNotification +- (void) flagsChanged:(NSEvent*) event { - wxUnusedVar(aNotification); - wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); - if ( impl ) - { - impl->DoNotifyFocusEvent( false, NULL ); - } + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( [self delegate] ); + if ( impl == NULL || !impl->DoHandleKeyEvent(event) ) + [super flagsChanged:event]; } -@end -@implementation wxNSTextView +- (BOOL) performKeyEquivalent:(NSEvent*) event +{ + BOOL retval = [super performKeyEquivalent:event]; + return retval; +} -- (BOOL) becomeFirstResponder +- (void) insertText:(id) str { - BOOL val = [super becomeFirstResponder]; - - if ( val ) + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( [self delegate] ); + if ( impl == NULL || lastKeyDownEvent==nil || !impl->DoHandleCharEvent(lastKeyDownEvent, str) ) { - wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( scrollView ); - if (impl ) - impl->DoNotifyFocusEvent( true, NULL ); - + [super insertText:str]; } - return val; } -- (void)setScrollView: (wxNSTextScrollView *) sv -{ - scrollView = sv; -} +@end + +@implementation wxNSTextView -- (wxNSTextScrollView*) scrollView ++ (void)initialize { - return scrollView; + static BOOL initialized = NO; + if (!initialized) + { + initialized = YES; + wxOSXCocoaClassAddWXMethods( self ); + } } @end @@ -239,6 +205,24 @@ protected : } } +- (id) initWithFrame:(NSRect) frame +{ + self = [super initWithFrame:frame]; + fieldEditor = nil; + return self; +} + +- (void) setFieldEditor:(wxNSTextFieldEditor*) editor +{ + fieldEditor = editor; +} + +- (wxNSTextFieldEditor*) fieldEditor +{ + return fieldEditor; +} + + - (void) setEnabled:(BOOL) flag { [super setEnabled: flag]; @@ -329,7 +313,8 @@ wxNSTextViewControl::wxNSTextViewControl( wxTextCtrl *wxPeer, WXWidget w ) : wxW [m_scrollView setDocumentView: tv]; [tv setDelegate: w]; - [tv setScrollView:sv]; + + InstallEventHandler(tv); } wxNSTextViewControl::~wxNSTextViewControl() @@ -358,6 +343,7 @@ void wxNSTextViewControl::SetStringValue( const wxString &str) if (m_textView) [m_textView setString: wxCFStringRef( st , m_wxPeer->GetFont().GetEncoding() ).AsNSString()]; } + void wxNSTextViewControl::Copy() { if (m_textView) @@ -443,6 +429,7 @@ wxNSTextFieldControl::wxNSTextFieldControl( wxTextCtrl *wxPeer, WXWidget w ) : w m_textField = (NSTextField*) w; [m_textField setDelegate: w]; m_selStart = m_selEnd = 0; + m_hasEditor = [w isKindOfClass:[NSTextField class]]; } wxNSTextFieldControl::~wxNSTextFieldControl() diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 88d7166c49..e5e4b7e3b4 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -33,27 +33,39 @@ // Get the window with the focus -WXWidget wxWidgetImpl::FindFocus() +NSView* GetViewFromResponder( NSResponder* responder ) { - NSView* focusedView = nil; - NSWindow* keyWindow = [[NSApplication sharedApplication] keyWindow]; - if ( keyWindow != nil ) + NSView* view = nil; + if ( [responder isKindOfClass:[NSTextView class]] ) { - NSResponder* responder = [keyWindow firstResponder]; - if ( [responder isKindOfClass:[NSTextView class]] && - [keyWindow fieldEditor:NO forObject:nil] != nil ) - { - focusedView = [(NSTextView*)responder delegate]; - } + NSView* delegate = [(NSTextView*)responder delegate]; + if ( [delegate isKindOfClass:[NSTextField class] ] ) + view = delegate; else - { - if ( [responder isKindOfClass:[NSView class]] ) - focusedView = (NSView*) responder; - } + view = (NSView*) responder; } + else + { + if ( [responder isKindOfClass:[NSView class]] ) + view = (NSView*) responder; + } + return view; +} + +NSView* GetFocusedViewInWindow( NSWindow* keyWindow ) +{ + NSView* focusedView = nil; + if ( keyWindow != nil ) + focusedView = GetViewFromResponder([keyWindow firstResponder]); + return focusedView; } +WXWidget wxWidgetImpl::FindFocus() +{ + return GetFocusedViewInWindow( [[NSApplication sharedApplication] keyWindow] ); +} + NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin ) { int x, y, w, h ; @@ -583,6 +595,8 @@ BOOL wxOSX_performDragOperation( id self, SEL _cmd, id sender ) return impl->performDragOperation(sender, self, _cmd) ? YES:NO ; } +#endif + void wxOSX_mouseEvent(NSView* self, SEL _cmd, NSEvent *event) { wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); @@ -835,8 +849,6 @@ bool wxWidgetCocoaImpl::performDragOperation(void* s, WXWidget WXUNUSED(slf), vo return result != wxDragNone; } -#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); @@ -859,7 +871,7 @@ void wxWidgetCocoaImpl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd) void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd) { - if ( [[slf window] firstResponder] != slf || !DoHandleKeyEvent(event) ) + if ( GetFocusedViewInWindow([slf window]) != slf || m_hasEditor || !DoHandleKeyEvent(event) ) { wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd]; superimpl(slf, (SEL)_cmd, event); @@ -868,7 +880,7 @@ void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd) void wxWidgetCocoaImpl::insertText(NSString* text, WXWidget slf, void *_cmd) { - if (m_lastKeyDownEvent && !DoHandleCharEvent(m_lastKeyDownEvent, text) ) + if ( m_lastKeyDownEvent==NULL || m_hasEditor || !DoHandleCharEvent(m_lastKeyDownEvent, text) ) { wxOSX_TextEventHandlerPtr superimpl = (wxOSX_TextEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd]; superimpl(slf, (SEL)_cmd, text); @@ -899,12 +911,14 @@ bool wxWidgetCocoaImpl::becomeFirstResponder(WXWidget slf, void *_cmd) wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd]; // get the current focus before running becomeFirstResponder NSView* otherView = FindFocus(); + wxWidgetImpl* otherWindow = FindFromWXWidget(otherView); BOOL r = superimpl(slf, (SEL)_cmd); if ( r ) { DoNotifyFocusEvent( true, otherWindow ); } + return r; } @@ -913,11 +927,13 @@ bool wxWidgetCocoaImpl::resignFirstResponder(WXWidget slf, void *_cmd) wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd]; BOOL r = superimpl(slf, (SEL)_cmd); // get the current focus after running resignFirstResponder + // note that this value isn't reliable, it might return the same view that + // is resigning NSView* otherView = FindFocus(); wxWidgetImpl* otherWindow = FindFromWXWidget(otherView); // NSTextViews have an editor as true responder, therefore the might get the - // resign notification if their editor takes over, don't trigger any event hen - if ( r && otherWindow != this) + // resign notification if their editor takes over, don't trigger any event then + if ( r && !m_hasEditor) { DoNotifyFocusEvent( false, otherWindow ); } @@ -1067,7 +1083,7 @@ void wxOSXCocoaClassAddWXMethods(Class c) 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(performKeyEquivalent:), (IMP) wxOSX_performKeyEquivalent, "c@:@" ) wxOSX_CLASS_ADD_METHOD(c, @selector(acceptsFirstResponder), (IMP) wxOSX_acceptsFirstResponder, "c@:" ) wxOSX_CLASS_ADD_METHOD(c, @selector(becomeFirstResponder), (IMP) wxOSX_becomeFirstResponder, "c@:" ) @@ -1125,6 +1141,7 @@ void wxWidgetCocoaImpl::Init() m_osxView = NULL; m_isFlipped = true; m_lastKeyDownEvent = NULL; + m_hasEditor = false; } wxWidgetCocoaImpl::~wxWidgetCocoaImpl() @@ -1489,11 +1506,17 @@ bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event) // this will fire higher level events, like insertText, to help // us handle EVT_CHAR, etc. - if ([event type] == NSKeyDown) + if ( !m_hasEditor && [event type] == NSKeyDown) { m_lastKeyDownEvent = event; if ( !result ) - [m_osxView interpretKeyEvents:[NSArray arrayWithObject:event]]; + { + if ( [m_osxView isKindOfClass:[NSScrollView class] ] ) + [[(NSScrollView*)m_osxView documentView] interpretKeyEvents:[NSArray arrayWithObject:event]]; + else + [m_osxView interpretKeyEvents:[NSArray arrayWithObject:event]]; + result = true; + } } return result; } diff --git a/src/osx/textctrl_osx.cpp b/src/osx/textctrl_osx.cpp index 1059c4b6c6..86de81f539 100644 --- a/src/osx/textctrl_osx.cpp +++ b/src/osx/textctrl_osx.cpp @@ -580,6 +580,8 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) event.Skip(true) ; } + // osx_cocoa sends its event upon insertText +#if wxOSX_USE_CARBON if ( ( key >= 0x20 && key < WXK_START ) || ( key >= WXK_NUMPAD0 && key <= WXK_DIVIDE ) || key == WXK_RETURN || @@ -590,6 +592,7 @@ void wxTextCtrl::OnChar(wxKeyEvent& event) event1.SetEventObject( this ); wxPostEvent( GetEventHandler(), event1 ); } +#endif } // ---------------------------------------------------------------------------- -- 2.45.2