X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c2a22141f8020a30bc71a426a15a5b83d05958c6..a51e79e87db3512823258d487849bb7e7947b700:/src/osx/cocoa/textctrl.mm diff --git a/src/osx/cocoa/textctrl.mm b/src/osx/cocoa/textctrl.mm index b5913b841b..b1364c509c 100644 --- a/src/osx/cocoa/textctrl.mm +++ b/src/osx/cocoa/textctrl.mm @@ -57,11 +57,18 @@ - (void)setSelectable:(BOOL)flag; @end +// An object of this class is created before the text is modified +// programmatically and destroyed as soon as this is done. It does several +// things, like ensuring that the control is editable to allow setting its text +// at all and eating any unwanted focus loss events from textDidEndEditing: +// which don't really correspond to focus change. class wxMacEditHelper { public : wxMacEditHelper( NSView* textView ) { + m_viewPreviouslyEdited = ms_viewCurrentlyEdited; + ms_viewCurrentlyEdited = m_textView = textView; m_formerEditable = YES; if ( textView ) @@ -79,14 +86,76 @@ public : [m_textView setEditable:m_formerEditable]; [m_textView setSelectable:m_formerSelectable]; } + + ms_viewCurrentlyEdited = m_viewPreviouslyEdited; } + // Returns the last view we were instantiated for or NULL. + static NSView *GetCurrentlyEditedView() { return ms_viewCurrentlyEdited; } + protected : BOOL m_formerEditable ; BOOL m_formerSelectable; NSView* m_textView; + + // The original value of ms_viewCurrentlyEdited when this object was + // created. + NSView* m_viewPreviouslyEdited; + + static NSView* ms_viewCurrentlyEdited; } ; +NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil; + +// a minimal NSFormatter that just avoids getting too long entries +@interface wxMaximumLengthFormatter : NSFormatter +{ + int maxLength; +} + +@end + +@implementation wxMaximumLengthFormatter + +- (id)init +{ + self = [super init]; + maxLength = 0; + return self; +} + +- (void) setMaxLength:(int) maxlen +{ + maxLength = maxlen; +} + +- (NSString *)stringForObjectValue:(id)anObject +{ + if(![anObject isKindOfClass:[NSString class]]) + return nil; + return [NSString stringWithString:anObject]; +} + +- (BOOL)getObjectValue:(id *)obj forString:(NSString *)string errorDescription:(NSString **)error +{ + *obj = [NSString stringWithString:string]; + return YES; +} + +- (BOOL)isPartialStringValid:(NSString **)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr + originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString **)error +{ + int len = [*partialStringPtr length]; + if ( maxLength > 0 && len > maxLength ) + { + // TODO wxEVT_COMMAND_TEXT_MAXLEN + return NO; + } + return YES; +} + +@end + @implementation wxNSSecureTextField + (void)initialize @@ -117,6 +186,39 @@ protected : } } +- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector +{ + wxUnusedVar(textView); + + BOOL handled = NO; + + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( control ); + if ( impl ) + { + wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer(); + if ( wxpeer ) + { + if (commandSelector == @selector(insertNewline:)) + { + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(wxpeer), wxTopLevelWindow); + if ( tlw && tlw->GetDefaultItem() ) + { + wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton); + if ( def && def->IsEnabled() ) + { + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() ); + event.SetEventObject(def); + def->Command(event); + handled = YES; + } + } + } + } + } + + return handled; +} + @end @interface wxNSTextScrollView : NSScrollView @@ -222,6 +324,15 @@ protected : - (void)textDidEndEditing:(NSNotification *)aNotification { wxUnusedVar(aNotification); + + if ( self == wxMacEditHelper::GetCurrentlyEditedView() ) + { + // This notification is generated as the result of calling our own + // wxTextCtrl method (e.g. WriteText()) and doesn't correspond to any + // real focus loss event so skip generating it. + return; + } + wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self ); if ( impl ) { @@ -296,7 +407,7 @@ protected : } - (NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words - forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(int*)index + forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger*)index { NSMutableArray* matches = NULL; @@ -659,6 +770,13 @@ void wxNSTextFieldControl::SetStringValue( const wxString &str) [m_textField setStringValue: wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()]; } +void wxNSTextFieldControl::SetMaxLength(unsigned long len) +{ + wxMaximumLengthFormatter* formatter = [[[wxMaximumLengthFormatter alloc] init] autorelease]; + [formatter setMaxLength:len]; + [m_textField setFormatter:formatter]; +} + void wxNSTextFieldControl::Copy() { NSText* editor = [m_textField currentEditor]; @@ -749,7 +867,12 @@ void wxNSTextFieldControl::WriteText(const wxString& str) if ( editor ) { wxMacEditHelper helper(m_textField); + BOOL hasUndo = [editor respondsToSelector:@selector(setAllowsUndo:)]; + if ( hasUndo ) + [editor setAllowsUndo:NO]; [editor insertText:wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()]; + if ( hasUndo ) + [editor setAllowsUndo:YES]; } else { @@ -805,6 +928,7 @@ wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer, wxNSTextScrollView* v = nil; v = [[wxNSTextScrollView alloc] initWithFrame:r]; c = new wxNSTextViewControl( wxpeer, v ); + c->SetNeedsFocusRect( true ); } else { @@ -814,24 +938,39 @@ wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer, else v = [[wxNSTextField alloc] initWithFrame:r]; - if ( style & wxNO_BORDER ) + if ( style & wxTE_RIGHT) { - // FIXME: How can we remove the native control's border? - // setBordered is separate from the text ctrl's border. + [v setAlignment:NSRightTextAlignment]; } - + else if ( style & wxTE_CENTRE) + { + [v setAlignment:NSCenterTextAlignment]; + } + NSTextFieldCell* cell = [v cell]; [cell setScrollable:YES]; // TODO: Remove if we definitely are sure, it's not needed // as setting scrolling to yes, should turn off any wrapping // [cell setLineBreakMode:NSLineBreakByClipping]; - [v setBezeled:NO]; - [v setBordered:NO]; - c = new wxNSTextFieldControl( wxpeer, wxpeer, v ); + + if ( (style & wxNO_BORDER) || (style & wxSIMPLE_BORDER) ) + { + // under 10.7 the textcontrol can draw its own focus + // even if no border is shown, on previous systems + // we have to emulate this + [v setBezeled:NO]; + [v setBordered:NO]; + if ( UMAGetSystemVersion() < 0x1070 ) + c->SetNeedsFocusRect( true ); + } + else + { + // use native border + c->SetNeedsFrame(false); + } } - c->SetNeedsFocusRect( true ); return c; }