1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/iphone/textctrl.mm
4 // Author: Stefan Csomor
5 // Modified by: Ryan Norton (MLTE GetLineLength and GetLineText)
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 1
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 wxUITextFieldDelegate : NSObject<UITextFieldDelegate>
91 @interface wxUITextField : UITextField
97 @interface wxNSSecureTextField : UITextField<UITextFieldDelegate>
103 @implementation wxNSSecureTextField
107 static BOOL initialized = NO;
111 wxOSXIPhoneClassAddWXMethods( self );
115 - (void)controlTextDidChange:(NSNotification *)aNotification
117 wxUnusedVar(aNotification);
118 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
120 impl->controlTextDidChange();
123 - (void)controlTextDidEndEditing:(NSNotification *)aNotification
125 wxUnusedVar(aNotification);
126 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
129 impl->DoNotifyFocusEvent( false, NULL );
136 @implementation wxUITextFieldEditor
138 - (void) keyDown:(NSEvent*) event
140 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] );
141 lastKeyDownEvent = event;
142 if ( impl == NULL || !impl->DoHandleKeyEvent(event) )
143 [super keyDown:event];
144 lastKeyDownEvent = nil;
147 - (void) keyUp:(NSEvent*) event
149 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] );
150 if ( impl == NULL || !impl->DoHandleKeyEvent(event) )
154 - (void) flagsChanged:(NSEvent*) event
156 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] );
157 if ( impl == NULL || !impl->DoHandleKeyEvent(event) )
158 [super flagsChanged:event];
161 - (BOOL) performKeyEquivalent:(NSEvent*) event
163 BOOL retval = [super performKeyEquivalent:event];
167 - (void) insertText:(id) str
169 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( (WXWidget) [self delegate] );
170 if ( impl == NULL || lastKeyDownEvent==nil || !impl->DoHandleCharEvent(lastKeyDownEvent, str) )
172 [super insertText:str];
181 @implementation wxUITextFieldDelegate
183 - (BOOL)textFieldShouldReturn:(UITextField *)textField
185 // the user pressed the "Done" button, so dismiss the keyboard
186 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textField );
189 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
190 if ( wxpeer && wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER )
192 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
193 event.SetEventObject( wxpeer );
194 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
195 wxpeer->HandleWindowEvent( event );
199 [textField resignFirstResponder];
204 - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField; // return NO to disallow editing.
205 - (void)textFieldDidBeginEditing:(UITextField *)textField; // became first responder
206 - (BOOL)textFieldShouldEndEditing:(UITextField *)textField; // return YES to allow editing to stop and to resign first responder status. NO to disallow the editing session to end
207 - (void)textFieldDidEndEditing:(UITextField *)textField; // may be called if forced even if shouldEndEditing returns NO (e.g. view removed from window) or endEditing:YES called
209 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; // return NO to not change text
211 - (BOOL)textFieldShouldClear:(UITextField *)textField; // called when clear button pressed. return NO to ignore (no notifications)
217 @implementation wxUITextField
221 static BOOL initialized = NO;
225 wxOSXIPhoneClassAddWXMethods( self );
230 - (void)controlTextDidChange:(NSNotification *)aNotification
232 wxUnusedVar(aNotification);
233 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
235 impl->controlTextDidChange();
239 - (BOOL)textFieldShouldReturn:(UITextField *)textField
241 wxUnusedVar(textField);
247 - (void)controlTextDidEndEditing:(NSNotification *)aNotification
249 wxUnusedVar(aNotification);
250 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( self );
253 impl->DoNotifyFocusEvent( false, NULL );
260 @interface wxUITextViewDelegate : NSObject<UITextViewDelegate>
264 - (void)textViewDidChange:(UITextView *)textView;
265 - (void)textViewDidBeginEditing:(UITextView *)textView;
266 - (void)textViewDidEndEditing:(UITextView *)textView;
267 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
271 @implementation wxUITextViewDelegate
273 - (void)textViewDidChange:(UITextView *)textView
275 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView );
277 impl->controlTextDidChange();
280 - (void)textViewDidBeginEditing:(UITextView *)textView
282 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView );
284 impl->DoNotifyFocusEvent(true, NULL);
287 - (void)textViewDidEndEditing:(UITextView *)textView
289 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView );
291 impl->DoNotifyFocusEvent(false, NULL);
294 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
296 wxWidgetIPhoneImpl* impl = (wxWidgetIPhoneImpl* ) wxWidgetImpl::FindFromWXWidget( textView );
299 if ( !impl->GetWXPeer()->HasFlag(wxTE_MULTILINE) && [text isEqualToString:@"\n"])
301 [textView resignFirstResponder];
312 // wxUITextViewControl
315 wxUITextViewControl::wxUITextViewControl( wxTextCtrl *wxPeer, UITextView* v) :
316 wxWidgetIPhoneImpl(wxPeer, v),
317 wxTextWidgetImpl(wxPeer)
320 m_delegate= [[wxUITextViewDelegate alloc] init];
322 [m_textView setDelegate:m_delegate];
325 wxUITextViewControl::~wxUITextViewControl()
329 [m_textView setDelegate: nil];
331 [m_delegate release];
334 bool wxUITextViewControl::CanFocus() const
339 wxString wxUITextViewControl::GetStringValue() const
343 wxString result = wxCFStringRef::AsString([m_textView text], m_wxPeer->GetFont().GetEncoding());
344 wxMacConvertNewlines13To10( &result ) ;
347 return wxEmptyString;
350 void wxUITextViewControl::SetStringValue( const wxString &str)
353 wxMacConvertNewlines10To13( &st );
354 wxMacEditHelper helper(m_textView);
357 [m_textView setText: wxCFStringRef( st , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
360 void wxUITextViewControl::Copy()
363 [m_textView copy:nil];
367 void wxUITextViewControl::Cut()
370 [m_textView cut:nil];
373 void wxUITextViewControl::Paste()
376 [m_textView paste:nil];
379 bool wxUITextViewControl::CanPaste() const
384 void wxUITextViewControl::SetEditable(bool editable)
387 [m_textView setEditable: editable];
390 void wxUITextViewControl::GetSelection( long* from, long* to) const
394 NSRange range = [m_textView selectedRange];
395 *from = range.location;
396 *to = range.location + range.length;
400 void wxUITextViewControl::SetSelection( long from , long to )
402 long textLength = [[m_textView text] length];
403 if ((from == -1) && (to == -1))
410 from = wxMin(textLength,wxMax(from,0)) ;
414 to = wxMax(0,wxMin(textLength,to)) ;
417 NSRange selrange = NSMakeRange(from, to-from);
418 [m_textView setSelectedRange:selrange];
419 [m_textView scrollRangeToVisible:selrange];
422 void wxUITextViewControl::WriteText(const wxString& str)
425 wxMacConvertNewlines10To13( &st );
426 wxMacEditHelper helper(m_textView);
428 wxCFStringRef insert( st , m_wxPeer->GetFont().GetEncoding() );
429 NSMutableString* subst = [NSMutableString stringWithString:[m_textView text]];
430 [subst replaceCharactersInRange:[m_textView selectedRange] withString:insert.AsNSString()];
432 [m_textView setText:subst];
435 void wxUITextViewControl::SetFont( const wxFont & font , const wxColour& WXUNUSED(foreground) , long WXUNUSED(windowStyle), bool WXUNUSED(ignoreBlack) )
437 if ([m_textView respondsToSelector:@selector(setFont:)])
438 [m_textView setFont: font.OSXGetUIFont()];
441 bool wxUITextViewControl::GetStyle(long position, wxTextAttr& style)
443 if (m_textView && position >=0)
445 // UIFont* font = NULL;
446 // NSColor* bgcolor = NULL;
447 // NSColor* fgcolor = NULL;
448 // NOTE: It appears that other platforms accept GetStyle with the position == length
449 // but that UITextStorage does not accept length as a valid position.
450 // Therefore we return the default control style in that case.
452 if (position < [[m_textView string] length])
454 UITextStorage* storage = [m_textView textStorage];
455 font = [[storage attribute:NSFontAttributeName atIndex:position effectiveRange:NULL] autorelease];
456 bgcolor = [[storage attribute:NSBackgroundColorAttributeName atIndex:position effectiveRange:NULL] autorelease];
457 fgcolor = [[storage attribute:NSForegroundColorAttributeName atIndex:position effectiveRange:NULL] autorelease];
461 NSDictionary* attrs = [m_textView typingAttributes];
462 font = [[attrs objectForKey:NSFontAttributeName] autorelease];
463 bgcolor = [[attrs objectForKey:NSBackgroundColorAttributeName] autorelease];
464 fgcolor = [[attrs objectForKey:NSForegroundColorAttributeName] autorelease];
469 style.SetFont(wxFont(font));
472 style.SetBackgroundColour(wxColour(bgcolor));
475 style.SetTextColour(wxColour(fgcolor));
483 void wxUITextViewControl::SetStyle(long start,
485 const wxTextAttr& style)
488 NSRange range = NSMakeRange(start, end-start);
489 if (start == -1 && end == -1)
490 range = [m_textView selectedRange];
492 UITextStorage* storage = [m_textView textStorage];
494 wxFont font = style.GetFont();
495 if (style.HasFont() && font.IsOk())
496 [storage addAttribute:NSFontAttributeName value:font.OSXGetNSFont() range:range];
498 wxColour bgcolor = style.GetBackgroundColour();
499 if (style.HasBackgroundColour() && bgcolor.IsOk())
500 [storage addAttribute:NSBackgroundColorAttributeName value:bgcolor.OSXGetNSColor() range:range];
502 wxColour fgcolor = style.GetTextColour();
503 if (style.HasTextColour() && fgcolor.IsOk())
504 [storage addAttribute:NSForegroundColorAttributeName value:fgcolor.OSXGetNSColor() range:range];
509 void wxUITextViewControl::CheckSpelling(bool check)
513 wxSize wxUITextViewControl::GetBestSize() const
520 if (m_textView && [m_textView layoutManager])
522 NSRect rect = [[m_textView layoutManager] usedRectForTextContainer: [m_textView textContainer]];
523 wxSize size = wxSize(rect.size.width, rect.size.height);
524 size.x += [m_textView textContainerInset].width;
525 size.y += [m_textView textContainerInset].height;
531 wxSize sz = r.GetSize();
538 #if wxOSX_IPHONE_USE_TEXTFIELD
541 // wxUITextFieldControl
544 wxUITextFieldControl::wxUITextFieldControl( wxTextCtrl *wxPeer, UITextField* w ) :
545 wxWidgetIPhoneImpl(wxPeer, w),
546 wxTextWidgetImpl(wxPeer)
549 m_delegate = [[wxUITextFieldDelegate alloc] init];
550 [m_textField setDelegate: m_delegate];
551 m_selStart = m_selEnd = 0;
554 wxUITextFieldControl::~wxUITextFieldControl()
557 [m_textField setDelegate: nil];
558 [m_delegate release];
561 wxString wxUITextFieldControl::GetStringValue() const
563 return wxCFStringRef::AsString([m_textField text], m_wxPeer->GetFont().GetEncoding());
566 void wxUITextFieldControl::SetStringValue( const wxString &str)
568 // wxMacEditHelper helper(m_textField);
569 [m_textField setText: wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
572 wxSize wxUITextFieldControl::GetBestSize() const
577 wxSize sz = r.GetSize();
583 void wxUITextFieldControl::Copy()
585 [m_textField copy:nil];
588 void wxUITextFieldControl::Cut()
590 [m_textField cut:nil];
593 void wxUITextFieldControl::Paste()
595 [m_textField paste:nil];
598 bool wxUITextFieldControl::CanPaste() const
603 void wxUITextFieldControl::SetEditable(bool editable)
607 void wxUITextFieldControl::GetSelection( long* from, long* to) const
613 void wxUITextFieldControl::SetSelection( long from , long to )
615 long textLength = [[m_textField text] length];
616 if ((from == -1) && (to == -1))
623 from = wxMin(textLength,wxMax(from,0)) ;
627 to = wxMax(0,wxMin(textLength,to)) ;
634 void wxUITextFieldControl::WriteText(const wxString& str)
637 NSEvent* formerEvent = m_lastKeyDownEvent;
638 UIText* editor = [m_textField currentEditor];
641 wxMacEditHelper helper(m_textField);
642 [editor insertText:wxCFStringRef( str , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
647 wxString val = GetStringValue() ;
649 GetSelection( &start , &end ) ;
650 val.Remove( start , end - start ) ;
651 val.insert( start , str ) ;
652 SetStringValue( val ) ;
653 SetSelection( start + str.length() , start + str.length() ) ;
656 m_lastKeyDownEvent = formerEvent;
660 void wxUITextFieldControl::controlAction(WXWidget WXUNUSED(slf),
661 void* WXUNUSED(_cmd), void *WXUNUSED(sender))
663 wxWindow* wxpeer = (wxWindow*) GetWXPeer();
664 if ( wxpeer && (wxpeer->GetWindowStyle() & wxTE_PROCESS_ENTER) )
666 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, wxpeer->GetId());
667 event.SetEventObject( wxpeer );
668 event.SetString( static_cast<wxTextCtrl*>(wxpeer)->GetValue() );
669 wxpeer->HandleWindowEvent( event );
673 bool wxUITextFieldControl::SetHint(const wxString& hint)
675 wxCFStringRef hintstring(hint);
676 [m_textField setPlaceholder:hintstring.AsNSString()];
685 wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
686 wxWindowMac* WXUNUSED(parent),
687 wxWindowID WXUNUSED(id),
692 long WXUNUSED(extraStyle))
694 CGRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
695 wxWidgetIPhoneImpl* c = NULL;
696 wxTextWidgetImpl* t = NULL;
697 id<UITextInputTraits> tv = nil;
699 #if wxOSX_IPHONE_USE_TEXTFIELD
700 if ( style & wxTE_MULTILINE || style & wxTE_RICH || style & wxTE_RICH2 )
703 UITextView * v = nil;
704 v = [[UITextView alloc] initWithFrame:r];
707 wxUITextViewControl* tc = new wxUITextViewControl( wxpeer, v );
711 #if wxOSX_IPHONE_USE_TEXTFIELD
714 wxUITextField* v = [[wxUITextField alloc] initWithFrame:r];
717 v.textColor = [UIColor blackColor];
718 v.font = [UIFont systemFontOfSize:17.0];
719 v.backgroundColor = [UIColor whiteColor];
721 v.clearButtonMode = UITextFieldViewModeNever;
723 [v setBorderStyle:UITextBorderStyleBezel];
724 if ( style & wxNO_BORDER )
725 v.borderStyle = UITextBorderStyleNone;
727 wxUITextFieldControl* tc = new wxUITextFieldControl( wxpeer, v );
733 if ( style & wxTE_PASSWORD )
734 [tv setSecureTextEntry:YES];
736 if ( !(style & wxTE_MULTILINE) )
738 [tv setAutocorrectionType:UITextAutocorrectionTypeNo];
739 [tv setReturnKeyType:UIReturnKeyDone];
741 [tv setKeyboardType:UIKeyboardTypeDefault];
743 t->SetStringValue(str);
749 #endif // wxUSE_TEXTCTRL