]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/cocoa/textctrl.mm
Add wxTimer::StartOnce().
[wxWidgets.git] / src / osx / cocoa / textctrl.mm
index 0eb4afc84edd3e0a89d77050726df4cc9d3d2e84..14f3a176e148796ef03b920d8f18cbe35c5c41e6 100644 (file)
@@ -111,6 +111,7 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
 @interface wxMaximumLengthFormatter : NSFormatter
 {
     int maxLength;
+    wxTextEntry* field;
 }
 
 @end
@@ -148,12 +149,17 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
     int len = [*partialStringPtr length];
     if ( maxLength > 0 && len > maxLength )
     {
-        // TODO wxEVT_COMMAND_TEXT_MAXLEN
+        field->SendMaxLenEvent();
         return NO;
     }
     return YES;
 }
 
+- (void) setTextEntry:(wxTextEntry*) tf
+{
+    field = tf;
+}
+
 @end
 
 @implementation wxNSSecureTextField
@@ -182,7 +188,11 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
     if ( impl )
     {
-        impl->DoNotifyFocusEvent( false, NULL );
+        NSResponder * responder = wxNonOwnedWindowCocoaImpl::GetNextFirstResponder();
+        NSView* otherView = wxOSXGetViewFromResponder(responder);
+        
+        wxWidgetImpl* otherWindow = impl->FindBestFromWXWidget(otherView);
+        impl->DoNotifyFocusEvent( false, otherWindow );
     }
 }
 
@@ -206,7 +216,7 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
                     wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
                     if ( def && def->IsEnabled() )
                     {
-                        wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
+                        wxCommandEvent event(wxEVT_BUTTON, def->GetId() );
                         event.SetEventObject(def);
                         def->Command(event);
                         handled = YES;
@@ -336,7 +346,11 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
     if ( impl )
     {
-        impl->DoNotifyFocusEvent( false, NULL );
+        NSResponder * responder = wxNonOwnedWindowCocoaImpl::GetNextFirstResponder();
+        NSView* otherView = wxOSXGetViewFromResponder(responder);
+        
+        wxWidgetImpl* otherWindow = impl->FindBestFromWXWidget(otherView);
+        impl->DoNotifyFocusEvent( false, otherWindow );
     }
 }
 
@@ -499,7 +513,18 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
     wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
     if ( impl )
     {
-        impl->DoNotifyFocusEvent( false, NULL );
+        wxNSTextFieldControl* timpl = dynamic_cast<wxNSTextFieldControl*>(impl);
+        if ( fieldEditor )
+        {
+            NSRange range = [fieldEditor selectedRange];
+            timpl->SetInternalSelection(range.location, range.location + range.length);
+        }
+
+        NSResponder * responder = wxNonOwnedWindowCocoaImpl::GetNextFirstResponder();
+        NSView* otherView = wxOSXGetViewFromResponder(responder);
+        
+        wxWidgetImpl* otherWindow = impl->FindBestFromWXWidget(otherView);
+        impl->DoNotifyFocusEvent( false, otherWindow );
     }
 }
 @end
@@ -515,7 +540,8 @@ wxNSTextViewControl::wxNSTextViewControl( wxTextCtrl *wxPeer, WXWidget w )
 
     [m_scrollView setHasVerticalScroller:YES];
     [m_scrollView setHasHorizontalScroller:NO];
-    [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+    // TODO Remove if no regression, this was causing automatic resizes of multi-line textfields when the tlw changed
+    // [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
     NSSize contentSize = [m_scrollView contentSize];
 
     wxNSTextView* tv = [[wxNSTextView alloc] initWithFrame: NSMakeRect(0, 0,
@@ -688,24 +714,35 @@ void wxNSTextViewControl::SetStyle(long start,
                                 long end,
                                 const wxTextAttr& style)
 {
-    if (m_textView) {
+    if ( !m_textView )
+        return;
+
+    if ( start == -1 && end == -1 )
+    {
+        NSMutableDictionary* const
+            attrs = [NSMutableDictionary dictionaryWithCapacity:3];
+        if ( style.HasFont() )
+            [attrs setValue:style.GetFont().OSXGetNSFont() forKey:NSFontAttributeName];
+        if ( style.HasBackgroundColour() )
+            [attrs setValue:style.GetBackgroundColour().OSXGetNSColor() forKey:NSBackgroundColorAttributeName];
+        if ( style.HasTextColour() )
+            [attrs setValue:style.GetTextColour().OSXGetNSColor() forKey:NSForegroundColorAttributeName];
+
+        [m_textView setTypingAttributes:attrs];
+    }
+    else // Set the attributes just for this range.
+    {
         NSRange range = NSMakeRange(start, end-start);
-        if (start == -1 && end == -1)
-            range = [m_textView selectedRange];
 
         NSTextStorage* storage = [m_textView textStorage];
-        
-        wxFont font = style.GetFont();
-        if (style.HasFont() && font.IsOk())
-            [storage addAttribute:NSFontAttributeName value:font.OSXGetNSFont() range:range];
-        
-        wxColour bgcolor = style.GetBackgroundColour();
-        if (style.HasBackgroundColour() && bgcolor.IsOk())
-            [storage addAttribute:NSBackgroundColorAttributeName value:bgcolor.OSXGetNSColor() range:range];
-        
-        wxColour fgcolor = style.GetTextColour();
-        if (style.HasTextColour() && fgcolor.IsOk())
-            [storage addAttribute:NSForegroundColorAttributeName value:fgcolor.OSXGetNSColor() range:range];
+        if ( style.HasFont() )
+            [storage addAttribute:NSFontAttributeName value:style.GetFont().OSXGetNSFont() range:range];
+
+        if ( style.HasBackgroundColour() )
+            [storage addAttribute:NSBackgroundColorAttributeName value:style.GetBackgroundColour().OSXGetNSColor() range:range];
+
+        if ( style.HasTextColour() )
+            [storage addAttribute:NSForegroundColorAttributeName value:style.GetTextColour().OSXGetNSColor() range:range];
     }
 }
 
@@ -774,6 +811,7 @@ void wxNSTextFieldControl::SetMaxLength(unsigned long len)
 {
     wxMaximumLengthFormatter* formatter = [[[wxMaximumLengthFormatter alloc] init] autorelease];
     [formatter setMaxLength:len];
+    [formatter setTextEntry:GetTextEntry()];
     [m_textField setFormatter:formatter];
 }
 
@@ -852,11 +890,11 @@ void wxNSTextFieldControl::SetSelection( long from , long to )
     {
         [editor setSelectedRange:NSMakeRange(from, to-from)];
     }
-    else
-    {
-        m_selStart = from;
-        m_selEnd = to;
-    }
+
+    // the editor might still be in existence, but we might be already passed our 'focus lost' storage
+    // of the selection, so make sure we copy this
+    m_selStart = from;
+    m_selEnd = to;
 }
 
 void wxNSTextFieldControl::WriteText(const wxString& str)
@@ -867,7 +905,12 @@ void wxNSTextFieldControl::WriteText(const wxString& str)
     if ( editor )
     {
         wxMacEditHelper helper(m_textField);
+        BOOL hasUndo = [editor respondsToSelector:@selector(setAllowsUndo:)];
+        if ( hasUndo )
+            [(NSTextView*)editor setAllowsUndo:NO];
         [editor insertText:wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
+        if ( hasUndo )
+            [(NSTextView*)editor setAllowsUndo:YES];
     }
     else
     {
@@ -888,13 +931,59 @@ void wxNSTextFieldControl::controlAction(WXWidget WXUNUSED(slf),
     wxWindow* wxpeer = (wxWindow*) GetWXPeer();
     if ( wxpeer && (wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER) )
     {
-        wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
+        wxCommandEvent event(wxEVT_TEXT_ENTER, wxpeer->GetId());
         event.SetEventObject( wxpeer );
         event.SetString( GetTextEntry()->GetValue() );
         wxpeer->HandleWindowEvent( event );
     }
 }
 
+void wxNSTextFieldControl::SetInternalSelection( long from , long to )
+{
+    m_selStart = from;
+    m_selEnd = to;
+}
+
+// as becoming first responder on a window - triggers a resign on the same control, we have to avoid
+// the resign notification writing back native selection values before we can set our own
+
+static WXWidget s_widgetBecomingFirstResponder = nil;
+
+bool wxNSTextFieldControl::becomeFirstResponder(WXWidget slf, void *_cmd)
+{
+    s_widgetBecomingFirstResponder = slf;
+    bool retval = wxWidgetCocoaImpl::becomeFirstResponder(slf, _cmd);
+    s_widgetBecomingFirstResponder = nil;
+    if ( retval )
+    {
+        NSText* editor = [m_textField currentEditor];
+        if ( editor )
+        {
+            long textLength = [[m_textField stringValue] length];
+            m_selStart = wxMin(textLength,wxMax(m_selStart,0)) ;
+            m_selEnd = wxMax(0,wxMin(textLength,m_selEnd)) ;
+            
+            [editor setSelectedRange:NSMakeRange(m_selStart, m_selEnd-m_selStart)];
+        }
+    }
+    return retval;
+}
+
+bool wxNSTextFieldControl::resignFirstResponder(WXWidget slf, void *_cmd)
+{
+    if ( slf != s_widgetBecomingFirstResponder )
+    {
+        NSText* editor = [m_textField currentEditor];
+        if ( editor )
+        {
+            NSRange range = [editor selectedRange];
+            m_selStart = range.location;
+            m_selEnd = range.location + range.length;
+        }
+    }
+    return wxWidgetCocoaImpl::resignFirstResponder(slf, _cmd);
+}
+
 bool wxNSTextFieldControl::SetHint(const wxString& hint)
 {
     wxCFStringRef hintstring(hint);
@@ -918,11 +1007,12 @@ wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
     NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
     wxWidgetCocoaImpl* c = NULL;
 
-    if ( style & wxTE_MULTILINE || style & wxTE_RICH || style & wxTE_RICH2 )
+    if ( style & wxTE_MULTILINE )
     {
         wxNSTextScrollView* v = nil;
         v = [[wxNSTextScrollView alloc] initWithFrame:r];
         c = new wxNSTextViewControl( wxpeer, v );
+        c->SetNeedsFocusRect( true );
     }
     else
     {
@@ -940,25 +1030,31 @@ wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
         {
             [v setAlignment:NSCenterTextAlignment];
         }
-        
-        if ( style & wxNO_BORDER )
-        {
-            // FIXME: How can we remove the native control's border?
-            // setBordered is separate from the text ctrl's border.
-        }
-        
+                
         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;
 }