1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/textctrl.mm
4 // Author: Stefan Csomor
5 // Modified by: Ryan Norton (MLTE GetLineLength and GetLineText)
7 // RCS-ID: $Id: textctrl.cpp 54820 2008-07-29 20:04:11Z SC $
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
16 #include "wx/textctrl.h"
23 #include "wx/button.h"
25 #include "wx/settings.h"
26 #include "wx/msgdlg.h"
27 #include "wx/toplevel.h"
31 #include <sys/types.h>
37 #if wxUSE_STD_IOSTREAM
45 #include "wx/filefn.h"
46 #include "wx/sysopt.h"
47 #include "wx/thread.h"
49 #include "wx/osx/private.h"
50 #include "wx/osx/iphone/private/textimpl.h"
52 // currently for some reasong the UITextField leads to a recursion when the keyboard should be shown, so let's leave the code
53 // in case this gets resolved...
55 #define wxOSX_IPHONE_USE_TEXTFIELD 0
60 wxMacEditHelper( UITextView* textView )
62 m_textView = textView;
66 m_formerState = [textView isEditable];
67 [textView setEditable:YES];
74 [m_textView setEditable:m_formerState];
79 UITextView* m_textView;
82 #if wxOSX_IPHONE_USE_TEXTFIELD
84 @interface wxUITextField : UITextField<UITextFieldDelegate>
90 @implementation wxNSSecureTextField
94 static BOOL initialized = NO;
98 wxOSXIPhoneClassAddWXMethods( self );
102 - (void)controlTextDidChange:(NSNotification *)aNotification
104 wxUnusedVar(aNotification);
105 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
107 impl->controlTextDidChange();
110 - (void)controlTextDidEndEditing:(NSNotification *)aNotification
112 wxUnusedVar(aNotification);
113 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
116 impl->DoNotifyFocusEvent( false, NULL );
122 @implementation wxUITextFieldEditor
124 - (void) keyDown:(NSEvent*) event
126 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] );
127 lastKeyDownEvent = event;
128 if ( impl == NULL || !impl->DoHandleKeyEvent(event) )
129 [super keyDown:event];
130 lastKeyDownEvent = nil;
133 - (void) keyUp:(NSEvent*) event
135 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] );
136 if ( impl == NULL || !impl->DoHandleKeyEvent(event) )
140 - (void) flagsChanged:(NSEvent*) event
142 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] );
143 if ( impl == NULL || !impl->DoHandleKeyEvent(event) )
144 [super flagsChanged:event];
147 - (BOOL) performKeyEquivalent:(NSEvent*) event
149 BOOL retval = [super performKeyEquivalent:event];
153 - (void) insertText:(id) str
155 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] );
156 if ( impl == NULL || lastKeyDownEvent==nil || !impl->DoHandleCharEvent(lastKeyDownEvent, str) )
158 [super insertText:str];
164 @implementation wxUITextField
168 static BOOL initialized = NO;
172 wxOSXIPhoneClassAddWXMethods( self );
177 - (void)controlTextDidChange:(NSNotification *)aNotification
179 wxUnusedVar(aNotification);
180 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
182 impl->controlTextDidChange();
186 - (BOOL)textFieldShouldReturn:(UITextField *)textField
188 wxUnusedVar(textField);
190 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
193 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
194 if ( wxpeer && wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER )
196 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
197 event.SetEventObject( wxpeer );
198 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
199 wxpeer->HandleWindowEvent( event );
206 - (void)controlTextDidEndEditing:(NSNotification *)aNotification
208 wxUnusedVar(aNotification);
209 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
212 impl->DoNotifyFocusEvent( false, NULL );
219 @interface wxUITextViewDelegate : NSObject<UITextViewDelegate>
223 - (void)textViewDidChange:(UITextView *)textView;
224 - (void)textViewDidBeginEditing:(UITextView *)textView;
225 - (void)textViewDidEndEditing:(UITextView *)textView;
226 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
230 @implementation wxUITextViewDelegate
232 - (void)textViewDidChange:(UITextView *)textView
234 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView );
236 impl->controlTextDidChange();
239 - (void)textViewDidBeginEditing:(UITextView *)textView
241 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView );
243 impl->DoNotifyFocusEvent(true, NULL);
246 - (void)textViewDidEndEditing:(UITextView *)textView
248 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView );
250 impl->DoNotifyFocusEvent(false, NULL);
253 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
255 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView );
258 if ( !impl->GetWXPeer()->HasFlag(wxTE_MULTILINE) && [text isEqualToString:@"\n"])
260 [textView resignFirstResponder];
271 // wxUITextViewControl
274 wxUITextViewControl::wxUITextViewControl( wxTextCtrl *wxPeer, UITextView* v) :
275 wxWidgetIPhoneImpl(wxPeer, v),
276 wxTextWidgetImpl(wxPeer)
279 wxUITextViewDelegate* d = [[wxUITextViewDelegate alloc] init];
281 [m_textView setDelegate:d];
284 wxUITextViewControl::~wxUITextViewControl()
288 wxUITextViewDelegate* d = [m_textView delegate];
289 [m_textView setDelegate: nil];
294 bool wxUITextViewControl::CanFocus() const
299 wxString wxUITextViewControl::GetStringValue() const
303 wxString result = wxCFStringRef::AsString([m_textView text], m_wxPeer->GetFont().GetEncoding());
304 wxMacConvertNewlines13To10( &result ) ;
307 return wxEmptyString;
310 void wxUITextViewControl::SetStringValue( const wxString &str)
313 wxMacConvertNewlines10To13( &st );
314 wxMacEditHelper helper(m_textView);
317 [m_textView setText: wxCFStringRef( st , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
320 void wxUITextViewControl::Copy()
323 [m_textView copy:nil];
327 void wxUITextViewControl::Cut()
330 [m_textView cut:nil];
333 void wxUITextViewControl::Paste()
336 [m_textView paste:nil];
339 bool wxUITextViewControl::CanPaste() const
344 void wxUITextViewControl::SetEditable(bool editable)
347 [m_textView setEditable: editable];
350 void wxUITextViewControl::GetSelection( long* from, long* to) const
354 NSRange range = [m_textView selectedRange];
355 *from = range.location;
356 *to = range.location + range.length;
360 void wxUITextViewControl::SetSelection( long from , long to )
362 long textLength = [[m_textView text] length];
363 if ((from == -1) && (to == -1))
370 from = wxMin(textLength,wxMax(from,0)) ;
374 to = wxMax(0,wxMin(textLength,to)) ;
377 NSRange selrange = NSMakeRange(from, to-from);
378 [m_textView setSelectedRange:selrange];
379 [m_textView scrollRangeToVisible:selrange];
382 void wxUITextViewControl::WriteText(const wxString& str)
385 wxMacConvertNewlines10To13( &st );
386 wxMacEditHelper helper(m_textView);
388 wxCFStringRef insert( st , m_wxPeer->GetFont().GetEncoding() );
389 NSMutableString* subst = [NSMutableString stringWithString:[m_textView text]];
390 [subst replaceCharactersInRange:[m_textView selectedRange] withString:insert.AsNSString()];
392 [m_textView setText:subst];
395 void wxUITextViewControl::SetFont( const wxFont & font , const wxColour& WXUNUSED(foreground) , long WXUNUSED(windowStyle), bool WXUNUSED(ignoreBlack) )
397 if ([m_textView respondsToSelector:@selector(setFont:)])
398 [m_textView setFont: font.OSXGetUIFont()];
401 bool wxUITextViewControl::GetStyle(long position, wxTextAttr& style)
403 if (m_textView && position >=0)
406 NSColor* bgcolor = NULL;
407 NSColor* fgcolor = NULL;
408 // NOTE: It appears that other platforms accept GetStyle with the position == length
409 // but that UITextStorage does not accept length as a valid position.
410 // Therefore we return the default control style in that case.
412 if (position < [[m_textView string] length])
414 UITextStorage* storage = [m_textView textStorage];
415 font = [[storage attribute:NSFontAttributeName atIndex:position effectiveRange:NULL] autorelease];
416 bgcolor = [[storage attribute:NSBackgroundColorAttributeName atIndex:position effectiveRange:NULL] autorelease];
417 fgcolor = [[storage attribute:NSForegroundColorAttributeName atIndex:position effectiveRange:NULL] autorelease];
421 NSDictionary* attrs = [m_textView typingAttributes];
422 font = [[attrs objectForKey:NSFontAttributeName] autorelease];
423 bgcolor = [[attrs objectForKey:NSBackgroundColorAttributeName] autorelease];
424 fgcolor = [[attrs objectForKey:NSForegroundColorAttributeName] autorelease];
429 style.SetFont(wxFont(font));
432 style.SetBackgroundColour(wxColour(bgcolor));
435 style.SetTextColour(wxColour(fgcolor));
443 void wxUITextViewControl::SetStyle(long start,
445 const wxTextAttr& style)
448 NSRange range = NSMakeRange(start, end-start);
449 if (start == -1 && end == -1)
450 range = [m_textView selectedRange];
452 UITextStorage* storage = [m_textView textStorage];
454 wxFont font = style.GetFont();
455 if (style.HasFont() && font.IsOk())
456 [storage addAttribute:NSFontAttributeName value:font.OSXGetNSFont() range:range];
458 wxColour bgcolor = style.GetBackgroundColour();
459 if (style.HasBackgroundColour() && bgcolor.IsOk())
460 [storage addAttribute:NSBackgroundColorAttributeName value:bgcolor.OSXGetNSColor() range:range];
462 wxColour fgcolor = style.GetTextColour();
463 if (style.HasTextColour() && fgcolor.IsOk())
464 [storage addAttribute:NSForegroundColorAttributeName value:fgcolor.OSXGetNSColor() range:range];
469 void wxUITextViewControl::CheckSpelling(bool check)
473 wxSize wxUITextViewControl::GetBestSize() const
480 if (m_textView && [m_textView layoutManager])
482 NSRect rect = [[m_textView layoutManager] usedRectForTextContainer: [m_textView textContainer]];
483 wxSize size = wxSize(rect.size.width, rect.size.height);
484 size.x += [m_textView textContainerInset].width;
485 size.y += [m_textView textContainerInset].height;
493 #if wxOSX_IPHONE_USE_TEXTFIELD
496 // wxUITextFieldControl
499 wxUITextFieldControl::wxUITextFieldControl( wxWindow *wxPeer, UITextField* w ) : wxWidgetIPhoneImpl(wxPeer, w)
501 UITextField wxOSX_10_6_AND_LATER(<UITextFieldDelegate>) *tf = (UITextField*) w;
503 [m_textField setDelegate: tf];
504 m_selStart = m_selEnd = 0;
507 wxUITextFieldControl::~wxUITextFieldControl()
510 [m_textField setDelegate: nil];
513 wxString wxUITextFieldControl::GetStringValue() const
515 return wxCFStringRef::AsString([m_textField text], m_wxPeer->GetFont().GetEncoding());
518 void wxUITextFieldControl::SetStringValue( const wxString &str)
520 // wxMacEditHelper helper(m_textField);
521 [m_textField setText: wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
524 void wxUITextFieldControl::Copy()
526 [m_textField copy:nil];
529 void wxUITextFieldControl::Cut()
531 [m_textField cut:nil];
534 void wxUITextFieldControl::Paste()
536 [m_textField paste:nil];
539 bool wxUITextFieldControl::CanPaste() const
544 void wxUITextFieldControl::SetEditable(bool editable)
548 void wxUITextFieldControl::GetSelection( long* from, long* to) const
554 void wxUITextFieldControl::SetSelection( long from , long to )
556 long textLength = [[m_textField text] length];
557 if ((from == -1) && (to == -1))
564 from = wxMin(textLength,wxMax(from,0)) ;
568 to = wxMax(0,wxMin(textLength,to)) ;
575 void wxUITextFieldControl::WriteText(const wxString& str)
578 NSEvent* formerEvent = m_lastKeyDownEvent;
579 UIText* editor = [m_textField currentEditor];
582 wxMacEditHelper helper(m_textField);
583 [editor insertText:wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
588 wxString val = GetStringValue() ;
590 GetSelection( &start , &end ) ;
591 val.Remove( start , end - start ) ;
592 val.insert( start , str ) ;
593 SetStringValue( val ) ;
594 SetSelection( start + str.length() , start + str.length() ) ;
597 m_lastKeyDownEvent = formerEvent;
601 void wxUITextFieldControl::controlAction(WXWidget WXUNUSED(slf),
602 void* WXUNUSED(_cmd), void *WXUNUSED(sender))
604 wxWindow* wxpeer = (wxWindow*) GetWXPeer();
605 if ( wxpeer && (wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER) )
607 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
608 event.SetEventObject( wxpeer );
609 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
610 wxpeer->HandleWindowEvent( event );
620 wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
621 wxWindowMac* WXUNUSED(parent),
622 wxWindowID WXUNUSED(id),
627 long WXUNUSED(extraStyle))
629 CGRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
630 wxWidgetIPhoneImpl* c = NULL;
631 wxTextWidgetImpl* t = NULL;
632 id<UITextInputTraits> tv = nil;
634 #if wxOSX_IPHONE_USE_TEXTFIELD
635 if ( style & wxTE_MULTILINE || style & wxTE_RICH || style & wxTE_RICH2 )
638 UITextView * v = nil;
639 v = [[UITextView alloc] initWithFrame:r];
642 wxUITextViewControl* tc = new wxUITextViewControl( wxpeer, v );
646 #if wxOSX_IPHONE_USE_TEXTFIELD
649 UITextField* v = [[UITextField alloc] initWithFrame:r];
652 v.textColor = [UIColor blackColor];
653 v.font = [UIFont systemFontOfSize:17.0];
654 v.placeholder = @"<enter text>";
655 v.backgroundColor = [UIColor whiteColor];
657 v.clearButtonMode = UITextFieldViewModeWhileEditing; // has a clear 'x' button to the right
659 v.delegate = v; // let us be the delegate so we know when the keyboard's "Done" button is pressed
661 [v setBorderStyle:UITextBorderStyleBezel];
662 if ( style & wxNO_BORDER )
663 v.borderStyle = UITextBorderStyleNone;
665 wxUITextFieldControl* tc = new wxUITextFieldControl( wxpeer, v );
671 if ( style & wxTE_PASSWORD )
672 [tv setSecureTextEntry:YES];
674 if ( !(style & wxTE_MULTILINE) )
676 [tv setAutocorrectionType:UITextAutocorrectionTypeNo];
677 [tv setReturnKeyType:UIReturnKeyDone];
679 [tv setKeyboardType:UIKeyboardTypeDefault];
681 t->SetStringValue(str);
687 #endif // wxUSE_TEXTCTRL