1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: Stefan Csomor
5 // Modified by: Ryan Norton (MLTE GetLineLength and GetLineText)
6 // Created: 1998-01-01
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #if wxUSE_TEXTCTRL
14
15 #include "wx/textctrl.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/intl.h"
19 #include "wx/app.h"
20 #include "wx/utils.h"
21 #include "wx/dc.h"
22 #include "wx/button.h"
23 #include "wx/menu.h"
24 #include "wx/settings.h"
25 #include "wx/msgdlg.h"
26 #include "wx/toplevel.h"
27 #endif
28
29 #ifdef __DARWIN__
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #else
33 #include <stat.h>
34 #endif
35
36 #if wxUSE_STD_IOSTREAM
37 #if wxUSE_IOSTREAMH
38 #include <fstream.h>
39 #else
40 #include <fstream>
41 #endif
42 #endif
43
44 #include "wx/filefn.h"
45 #include "wx/sysopt.h"
46 #include "wx/thread.h"
47
48 #include "wx/osx/private.h"
49 #include "wx/osx/carbon/private/mactext.h"
50
51 class wxMacFunctor
52 {
53 public :
wxMacFunctor()54 wxMacFunctor() {}
~wxMacFunctor()55 virtual ~wxMacFunctor() {}
56
57 virtual void* operator()() = 0 ;
58
CallBackProc(void * param)59 static void* CallBackProc( void *param )
60 {
61 wxMacFunctor* f = (wxMacFunctor*) param ;
62 void *result = (*f)() ;
63 return result ;
64 }
65 } ;
66
67 template<typename classtype, typename param1type>
68
69 class wxMacObjectFunctor1 : public wxMacFunctor
70 {
71 typedef void (classtype::*function)( param1type p1 ) ;
72 typedef void (classtype::*ref_function)( const param1type& p1 ) ;
73 public :
wxMacObjectFunctor1(classtype * obj,function f,param1type p1)74 wxMacObjectFunctor1( classtype *obj , function f , param1type p1 ) :
75 wxMacFunctor()
76 {
77 m_object = obj ;
78 m_function = f ;
79 m_param1 = p1 ;
80 }
81
wxMacObjectFunctor1(classtype * obj,ref_function f,param1type p1)82 wxMacObjectFunctor1( classtype *obj , ref_function f , param1type p1 ) :
83 wxMacFunctor()
84 {
85 m_object = obj ;
86 m_refFunction = f ;
87 m_param1 = p1 ;
88 }
89
~wxMacObjectFunctor1()90 virtual ~wxMacObjectFunctor1() {}
91
operator ()()92 virtual void* operator()()
93 {
94 (m_object->*m_function)( m_param1 ) ;
95 return NULL ;
96 }
97
98 private :
99 classtype* m_object ;
100 param1type m_param1 ;
101 union
102 {
103 function m_function ;
104 ref_function m_refFunction ;
105 } ;
106 } ;
107
108 template<typename classtype, typename param1type>
wxMacMPRemoteCall(classtype * object,void (classtype::* function)(param1type p1),param1type p1)109 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
110 {
111 wxMacObjectFunctor1<classtype, param1type> params(object, function, p1) ;
112 void *result =
113 MPRemoteCall( wxMacFunctor::CallBackProc , ¶ms , kMPOwningProcessRemoteContext ) ;
114 return result ;
115 }
116
117 template<typename classtype, typename param1type>
wxMacMPRemoteCall(classtype * object,void (classtype::* function)(const param1type & p1),param1type p1)118 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
119 {
120 wxMacObjectFunctor1<classtype,param1type> params(object, function, p1) ;
121 void *result =
122 MPRemoteCall( wxMacFunctor::CallBackProc , ¶ms , kMPOwningProcessRemoteContext ) ;
123 return result ;
124 }
125
126 template<typename classtype, typename param1type>
wxMacMPRemoteGUICall(classtype * object,void (classtype::* function)(param1type p1),param1type p1)127 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
128 {
129 wxMutexGuiLeave() ;
130 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
131 wxMutexGuiEnter() ;
132 return result ;
133 }
134
135 template<typename classtype, typename param1type>
wxMacMPRemoteGUICall(classtype * object,void (classtype::* function)(const param1type & p1),param1type p1)136 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
137 {
138 wxMutexGuiLeave() ;
139 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
140 wxMutexGuiEnter() ;
141 return result ;
142 }
143
144 class WXDLLEXPORT wxMacPortSaver
145 {
146 wxDECLARE_NO_COPY_CLASS(wxMacPortSaver);
147
148 public:
149 wxMacPortSaver( GrafPtr port );
150 ~wxMacPortSaver();
151 private :
152 GrafPtr m_port;
153 };
154
155
156 /*
157 Clips to the visible region of a control within the current port
158 */
159
160 class WXDLLEXPORT wxMacWindowClipper : public wxMacPortSaver
161 {
162 wxDECLARE_NO_COPY_CLASS(wxMacWindowClipper);
163
164 public:
165 wxMacWindowClipper( const wxWindow* win );
166 ~wxMacWindowClipper();
167 private:
168 GrafPtr m_newPort;
169 RgnHandle m_formerClip;
170 RgnHandle m_newClip;
171 };
172
wxMacPortSaver(GrafPtr port)173 wxMacPortSaver::wxMacPortSaver( GrafPtr port )
174 {
175 ::GetPort( &m_port );
176 ::SetPort( port );
177 }
178
~wxMacPortSaver()179 wxMacPortSaver::~wxMacPortSaver()
180 {
181 ::SetPort( m_port );
182 }
183
wxMacWindowClipper(const wxWindow * win)184 wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) :
185 wxMacPortSaver( (GrafPtr) GetWindowPort( (WindowRef) win->MacGetTopLevelWindowRef() ) )
186 {
187 m_newPort = (GrafPtr) GetWindowPort( (WindowRef) win->MacGetTopLevelWindowRef() ) ;
188 m_formerClip = NewRgn() ;
189 m_newClip = NewRgn() ;
190 GetClip( m_formerClip ) ;
191
192 if ( win )
193 {
194 // guard against half constructed objects, this just leads to a empty clip
195 if ( win->GetPeer() )
196 {
197 int x = 0 , y = 0;
198 win->MacWindowToRootWindow( &x, &y ) ;
199
200 // get area including focus rect
201 HIShapeGetAsQDRgn( ((wxWindow*)win)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip );
202 if ( !EmptyRgn( m_newClip ) )
203 OffsetRgn( m_newClip , x , y ) ;
204 }
205
206 SetClip( m_newClip ) ;
207 }
208 }
209
~wxMacWindowClipper()210 wxMacWindowClipper::~wxMacWindowClipper()
211 {
212 SetPort( m_newPort ) ;
213 SetClip( m_formerClip ) ;
214 DisposeRgn( m_newClip ) ;
215 DisposeRgn( m_formerClip ) ;
216 }
217
218 // common parts for implementations based on MLTE
219
220 class wxMacMLTEControl : public wxMacControl, public wxTextWidgetImpl
221 {
222 public :
223 wxMacMLTEControl( wxTextCtrl *peer ) ;
~wxMacMLTEControl()224 ~wxMacMLTEControl() {}
225
CanFocus() const226 virtual bool CanFocus() const
227 { return true; }
228
229 virtual wxString GetStringValue() const ;
230 virtual void SetStringValue( const wxString &str ) ;
231
232 static TXNFrameOptions FrameOptionsFromWXStyle( long wxStyle ) ;
233
234 void AdjustCreationAttributes( const wxColour& background, bool visible ) ;
235
236 virtual void SetFont( const wxFont & font, const wxColour& foreground, long windowStyle, bool ignoreBlack ) ;
237 virtual void SetBackgroundColour(const wxColour& col );
238 virtual void SetStyle( long start, long end, const wxTextAttr& style ) ;
239 virtual void Copy() ;
240 virtual void Cut() ;
241 virtual void Paste() ;
242 virtual bool CanPaste() const ;
243 virtual void SetEditable( bool editable ) ;
244 virtual long GetLastPosition() const ;
245 virtual void Replace( long from, long to, const wxString &str ) ;
246 virtual void Remove( long from, long to ) ;
247 virtual void GetSelection( long* from, long* to ) const ;
248 virtual void SetSelection( long from, long to ) ;
249
250 virtual void WriteText( const wxString& str ) ;
251
HasOwnContextMenu() const252 virtual bool HasOwnContextMenu() const
253 {
254 TXNCommandEventSupportOptions options ;
255 TXNGetCommandEventSupport( m_txn , & options ) ;
256 return options & kTXNSupportEditCommandProcessing ;
257 }
258
CheckSpelling(bool check)259 virtual void CheckSpelling(bool check)
260 {
261 TXNSetSpellCheckAsYouType( m_txn, (Boolean) check );
262 }
263 virtual void Clear() ;
264
265 virtual bool CanUndo() const ;
266 virtual void Undo() ;
267 virtual bool CanRedo() const;
268 virtual void Redo() ;
269 virtual int GetNumberOfLines() const ;
270 virtual long XYToPosition(long x, long y) const ;
271 virtual bool PositionToXY(long pos, long *x, long *y) const ;
272 virtual void ShowPosition( long pos ) ;
273 virtual int GetLineLength(long lineNo) const ;
274 virtual wxString GetLineText(long lineNo) const ;
275
276 void SetTXNData( const wxString& st , TXNOffset start , TXNOffset end ) ;
GetTXNObject()277 TXNObject GetTXNObject() { return m_txn ; }
278
279 protected :
280 void TXNSetAttribute( const wxTextAttr& style , long from , long to ) ;
281
282 TXNObject m_txn ;
283 } ;
284
285 // implementation available under OSX
286
287 class wxMacMLTEHIViewControl : public wxMacMLTEControl
288 {
289 public :
290 wxMacMLTEHIViewControl( wxTextCtrl *wxPeer,
291 const wxString& str,
292 const wxPoint& pos,
293 const wxSize& size, long style ) ;
294 virtual ~wxMacMLTEHIViewControl() ;
295
296 virtual bool SetFocus() ;
297 virtual bool HasFocus() const ;
298 virtual void SetBackgroundColour(const wxColour& col ) ;
299
300 protected :
301 HIViewRef m_scrollView ;
302 HIViewRef m_textView ;
303 };
304
305 // 'classic' MLTE implementation
306
307 class wxMacMLTEClassicControl : public wxMacMLTEControl
308 {
309 public :
310 wxMacMLTEClassicControl( wxTextCtrl *wxPeer,
311 const wxString& str,
312 const wxPoint& pos,
313 const wxSize& size, long style ) ;
314 virtual ~wxMacMLTEClassicControl() ;
315
316 virtual void VisibilityChanged(bool shown) ;
317 virtual void SuperChangedPosition() ;
318
319 virtual void MacControlUserPaneDrawProc(wxInt16 part) ;
320 virtual wxInt16 MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y) ;
321 virtual wxInt16 MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc) ;
322 virtual void MacControlUserPaneIdleProc() ;
323 virtual wxInt16 MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers) ;
324 virtual void MacControlUserPaneActivateProc(bool activating) ;
325 virtual wxInt16 MacControlUserPaneFocusProc(wxInt16 action) ;
326 virtual void MacControlUserPaneBackgroundProc(void* info) ;
327
SetupCursor(const wxPoint & WXUNUSED (pt))328 virtual bool SetupCursor( const wxPoint& WXUNUSED(pt) )
329 {
330 MacControlUserPaneIdleProc();
331 return true;
332 }
333
334 virtual void Move(int x, int y, int width, int height);
335
336 protected :
337 OSStatus DoCreate();
338
339 void MacUpdatePosition() ;
340 void MacActivatePaneText(bool setActive) ;
341 void MacFocusPaneText(bool setFocus) ;
342 void MacSetObjectVisibility(bool vis) ;
343
344 private :
345 TXNFrameID m_txnFrameID ;
346 GrafPtr m_txnPort ;
347 WindowRef m_txnWindow ;
348 // bounds of the control as we last did set the txn frames
349 Rect m_txnControlBounds ;
350 Rect m_txnVisBounds ;
351
352 static pascal void TXNScrollActionProc( ControlRef controlRef , ControlPartCode partCode ) ;
353 static pascal void TXNScrollInfoProc(
354 SInt32 iValue, SInt32 iMaximumValue,
355 TXNScrollBarOrientation iScrollBarOrientation, SInt32 iRefCon ) ;
356
357 ControlRef m_sbHorizontal ;
358 SInt32 m_lastHorizontalValue ;
359 ControlRef m_sbVertical ;
360 SInt32 m_lastVerticalValue ;
361 };
362
CreateTextControl(wxTextCtrl * wxpeer,wxWindowMac * WXUNUSED (parent),wxWindowID WXUNUSED (id),const wxString & str,const wxPoint & pos,const wxSize & size,long style,long WXUNUSED (extraStyle))363 wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
364 wxWindowMac* WXUNUSED(parent),
365 wxWindowID WXUNUSED(id),
366 const wxString& str,
367 const wxPoint& pos,
368 const wxSize& size,
369 long style,
370 long WXUNUSED(extraStyle))
371 {
372 return new wxMacMLTEHIViewControl( wxpeer , str , pos , size , style ) ;
373 }
374
375 // ----------------------------------------------------------------------------
376 // standard unicode control implementation
377 // ----------------------------------------------------------------------------
378
379 // the current unicode textcontrol implementation has a bug : only if the control
380 // is currently having the focus, the selection can be retrieved by the corresponding
381 // data tag. So we have a mirroring using a member variable
382 // TODO : build event table using virtual member functions for wxMacControl
383
384 static const EventTypeSpec unicodeTextControlEventList[] =
385 {
386 { kEventClassControl , kEventControlSetFocusPart } ,
387 } ;
388
wxMacUnicodeTextControlControlEventHandler(EventHandlerCallRef handler,EventRef event,void * data)389 static pascal OSStatus wxMacUnicodeTextControlControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
390 {
391 OSStatus result = eventNotHandledErr ;
392 wxMacUnicodeTextControl* focus = (wxMacUnicodeTextControl*) data ;
393 wxMacCarbonEvent cEvent( event ) ;
394
395 switch ( GetEventKind( event ) )
396 {
397 case kEventControlSetFocusPart :
398 {
399 ControlPartCode controlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
400 if ( controlPart == kControlFocusNoPart )
401 {
402 // about to lose focus -> store selection to field
403 focus->GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &focus->m_selection );
404 }
405 result = CallNextEventHandler(handler,event) ;
406 if ( controlPart != kControlFocusNoPart )
407 {
408 // about to gain focus -> set selection from field
409 focus->SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &focus->m_selection );
410 }
411 break;
412 }
413 default:
414 break ;
415 }
416
417 return result ;
418 }
419
wxMacUnicodeTextControlEventHandler(EventHandlerCallRef handler,EventRef event,void * data)420 static pascal OSStatus wxMacUnicodeTextControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
421 {
422 OSStatus result = eventNotHandledErr ;
423
424 switch ( GetEventClass( event ) )
425 {
426 case kEventClassControl :
427 result = wxMacUnicodeTextControlControlEventHandler( handler , event , data ) ;
428 break ;
429
430 default :
431 break ;
432 }
433 return result ;
434 }
435
DEFINE_ONE_SHOT_HANDLER_GETTER(wxMacUnicodeTextControlEventHandler)436 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacUnicodeTextControlEventHandler )
437
438 wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxTextCtrl *wxPeer )
439 : wxMacControl( wxPeer ),
440 wxTextWidgetImpl( wxPeer )
441 {
442 }
443
wxMacUnicodeTextControl(wxTextCtrl * wxPeer,const wxString & str,const wxPoint & pos,const wxSize & size,long style)444 wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxTextCtrl *wxPeer,
445 const wxString& str,
446 const wxPoint& pos,
447 const wxSize& size, long style )
448 : wxMacControl( wxPeer ),
449 wxTextWidgetImpl( wxPeer )
450 {
451 m_font = wxPeer->GetFont() ;
452 m_windowStyle = style ;
453 m_selection.selStart = m_selection.selEnd = 0;
454 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
455 wxString st = str ;
456 wxMacConvertNewlines10To13( &st ) ;
457 wxCFStringRef cf(st , m_font.GetEncoding()) ;
458
459 m_valueTag = kControlEditTextCFStringTag ;
460 Boolean isPassword = ( m_windowStyle & wxTE_PASSWORD ) != 0 ;
461 if ( isPassword )
462 {
463 m_valueTag = kControlEditTextPasswordCFStringTag ;
464 }
465 OSStatus err = CreateEditUnicodeTextControl(
466 MAC_WXHWND(wxPeer->MacGetTopLevelWindowRef()), &bounds , cf ,
467 isPassword , NULL , &m_controlRef ) ;
468 verify_noerr( err );
469
470 if ( !(m_windowStyle & wxTE_MULTILINE) )
471 SetData<Boolean>( kControlEditTextPart , kControlEditTextSingleLineTag , true ) ;
472
473 InstallEventHandlers();
474 }
475
InstallEventHandlers()476 void wxMacUnicodeTextControl::InstallEventHandlers()
477 {
478 ::InstallControlEventHandler( m_controlRef , GetwxMacUnicodeTextControlEventHandlerUPP(),
479 GetEventTypeCount(unicodeTextControlEventList), unicodeTextControlEventList, this,
480 (EventHandlerRef*) &m_macTextCtrlEventHandler);
481 }
482
~wxMacUnicodeTextControl()483 wxMacUnicodeTextControl::~wxMacUnicodeTextControl()
484 {
485 ::RemoveEventHandler((EventHandlerRef) m_macTextCtrlEventHandler);
486 }
487
VisibilityChanged(bool shown)488 void wxMacUnicodeTextControl::VisibilityChanged(bool shown)
489 {
490 if ( !(m_windowStyle & wxTE_MULTILINE) && shown )
491 {
492 // work around a refresh issue insofar as not always the entire content is shown,
493 // even if this would be possible
494 ControlEditTextSelectionRec sel ;
495 CFStringRef value = NULL ;
496
497 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
498 verify_noerr( GetData<CFStringRef>( 0, m_valueTag, &value ) );
499 verify_noerr( SetData<CFStringRef>( 0, m_valueTag, &value ) );
500 verify_noerr( SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
501
502 CFRelease( value ) ;
503 }
504 }
505
GetStringValue() const506 wxString wxMacUnicodeTextControl::GetStringValue() const
507 {
508 wxString result ;
509 CFStringRef value = GetData<CFStringRef>(0, m_valueTag) ;
510 if ( value )
511 {
512 wxCFStringRef cf(value) ;
513 result = cf.AsString() ;
514 }
515
516 #if '\n' == 10
517 wxMacConvertNewlines13To10( &result ) ;
518 #else
519 wxMacConvertNewlines10To13( &result ) ;
520 #endif
521
522 return result ;
523 }
524
SetStringValue(const wxString & str)525 void wxMacUnicodeTextControl::SetStringValue( const wxString &str )
526 {
527 wxString st = str ;
528 wxMacConvertNewlines10To13( &st ) ;
529 wxCFStringRef cf( st , m_font.GetEncoding() ) ;
530 verify_noerr( SetData<CFStringRef>( 0, m_valueTag , cf ) ) ;
531 }
532
Copy()533 void wxMacUnicodeTextControl::Copy()
534 {
535 SendHICommand( kHICommandCopy ) ;
536 }
537
Cut()538 void wxMacUnicodeTextControl::Cut()
539 {
540 SendHICommand( kHICommandCut ) ;
541 }
542
Paste()543 void wxMacUnicodeTextControl::Paste()
544 {
545 SendHICommand( kHICommandPaste ) ;
546 }
547
CanPaste() const548 bool wxMacUnicodeTextControl::CanPaste() const
549 {
550 return true ;
551 }
552
SetEditable(bool WXUNUSED (editable))553 void wxMacUnicodeTextControl::SetEditable(bool WXUNUSED(editable))
554 {
555 #if 0 // leads to problem because text cannot be selected anymore
556 SetData<Boolean>( kControlEditTextPart , kControlEditTextLockedTag , (Boolean) !editable ) ;
557 #endif
558 }
559
GetSelection(long * from,long * to) const560 void wxMacUnicodeTextControl::GetSelection( long* from, long* to ) const
561 {
562 ControlEditTextSelectionRec sel ;
563 if (HasFocus())
564 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ) ;
565 else
566 sel = m_selection ;
567
568 if ( from )
569 *from = sel.selStart ;
570 if ( to )
571 *to = sel.selEnd ;
572 }
573
SetSelection(long from,long to)574 void wxMacUnicodeTextControl::SetSelection( long from , long to )
575 {
576 ControlEditTextSelectionRec sel ;
577 wxString result ;
578 int textLength = 0 ;
579 CFStringRef value = GetData<CFStringRef>(0, m_valueTag) ;
580 if ( value )
581 {
582 wxCFStringRef cf(value) ;
583 textLength = cf.AsString().length() ;
584 }
585
586 if ((from == -1) && (to == -1))
587 {
588 from = 0 ;
589 to = textLength ;
590 }
591 else
592 {
593 from = wxMin(textLength,wxMax(from,0)) ;
594 if ( to == -1 )
595 to = textLength;
596 else
597 to = wxMax(0,wxMin(textLength,to)) ;
598 }
599
600 sel.selStart = from ;
601 sel.selEnd = to ;
602 if ( HasFocus() )
603 SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ;
604 else
605 m_selection = sel;
606 }
607
WriteText(const wxString & str)608 void wxMacUnicodeTextControl::WriteText( const wxString& str )
609 {
610 // TODO: this MPRemoting will be moved into a remoting peer proxy for any command
611 if ( !wxIsMainThread() )
612 {
613 #if wxOSX_USE_CARBON
614 // unfortunately CW 8 is not able to correctly deduce the template types,
615 // so we have to instantiate explicitly
616 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( (wxTextCtrl*) GetWXPeer() , &wxTextCtrl::WriteText , str ) ;
617 #endif
618 return ;
619 }
620
621 wxString st = str ;
622 wxMacConvertNewlines10To13( &st ) ;
623
624 if ( HasFocus() )
625 {
626 wxCFStringRef cf(st , m_font.GetEncoding() ) ;
627 CFStringRef value = cf ;
628 SetData<CFStringRef>( 0, kControlEditTextInsertCFStringRefTag, &value );
629 }
630 else
631 {
632 wxString val = GetStringValue() ;
633 long start , end ;
634 GetSelection( &start , &end ) ;
635 val.Remove( start , end - start ) ;
636 val.insert( start , str ) ;
637 SetStringValue( val ) ;
638 SetSelection( start + str.length() , start + str.length() ) ;
639 }
640 }
641
642 // ----------------------------------------------------------------------------
643 // MLTE control implementation (common part)
644 // ----------------------------------------------------------------------------
645
646 // if MTLE is read only, no changes at all are allowed, not even from
647 // procedural API, in order to allow changes via API all the same we must undo
648 // the readonly status while we are executing, this class helps to do so
649
650 class wxMacEditHelper
651 {
652 public :
wxMacEditHelper(TXNObject txn)653 wxMacEditHelper( TXNObject txn )
654 {
655 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
656 m_txn = txn ;
657 TXNGetTXNObjectControls( m_txn , 1 , tag , m_data ) ;
658 if ( m_data[0].uValue == kTXNReadOnly )
659 {
660 TXNControlData data[] = { { kTXNReadWrite } } ;
661 TXNSetTXNObjectControls( m_txn , false , 1 , tag , data ) ;
662 }
663 }
664
~wxMacEditHelper()665 ~wxMacEditHelper()
666 {
667 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
668 if ( m_data[0].uValue == kTXNReadOnly )
669 TXNSetTXNObjectControls( m_txn , false , 1 , tag , m_data ) ;
670 }
671
672 protected :
673 TXNObject m_txn ;
674 TXNControlData m_data[1] ;
675 } ;
676
wxMacMLTEControl(wxTextCtrl * peer)677 wxMacMLTEControl::wxMacMLTEControl( wxTextCtrl *peer )
678 : wxMacControl( peer ),
679 wxTextWidgetImpl( peer )
680 {
681 SetNeedsFocusRect( true ) ;
682 }
683
GetStringValue() const684 wxString wxMacMLTEControl::GetStringValue() const
685 {
686 wxString result ;
687 OSStatus err ;
688 Size actualSize = 0;
689
690 {
691 #if wxUSE_UNICODE
692 Handle theText ;
693 err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNUnicodeTextData );
694
695 // all done
696 if ( err != noErr )
697 {
698 actualSize = 0 ;
699 }
700 else
701 {
702 actualSize = GetHandleSize( theText ) / sizeof(UniChar) ;
703 if ( actualSize > 0 )
704 {
705 wxChar *ptr = NULL ;
706
707 SetHandleSize( theText, (actualSize + 1) * sizeof(UniChar) ) ;
708 HLock( theText ) ;
709 (((UniChar*)*theText)[actualSize]) = 0 ;
710 wxMBConvUTF16 converter ;
711 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
712 wxASSERT_MSG( noChars != wxCONV_FAILED, wxT("Unable to count the number of characters in this string!") );
713 ptr = new wxChar[noChars + 1] ;
714
715 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars + 1 ) ;
716 wxASSERT_MSG( noChars != wxCONV_FAILED, wxT("Conversion of string failed!") );
717 ptr[noChars] = 0 ;
718 HUnlock( theText ) ;
719
720 ptr[actualSize] = 0 ;
721 result = wxString( ptr ) ;
722 delete [] ptr ;
723 }
724
725 DisposeHandle( theText ) ;
726 }
727 #else // !wxUSE_UNICODE
728 Handle theText ;
729 err = TXNGetDataEncoded( m_txn , kTXNStartOffset, kTXNEndOffset, &theText, kTXNTextData );
730
731 // all done
732 if ( err != noErr )
733 {
734 actualSize = 0 ;
735 }
736 else
737 {
738 actualSize = GetHandleSize( theText ) ;
739 if ( actualSize > 0 )
740 {
741 HLock( theText ) ;
742 result = wxString( *theText , wxConvLocal , actualSize ) ;
743 HUnlock( theText ) ;
744 }
745
746 DisposeHandle( theText ) ;
747 }
748 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
749 }
750
751 #if '\n' == 10
752 wxMacConvertNewlines13To10( &result ) ;
753 #else
754 wxMacConvertNewlines10To13( &result ) ;
755 #endif
756
757 return result ;
758 }
759
SetStringValue(const wxString & str)760 void wxMacMLTEControl::SetStringValue( const wxString &str )
761 {
762 wxString st = str;
763 wxMacConvertNewlines10To13( &st );
764
765 {
766 #ifndef __LP64__
767 wxMacWindowClipper c( GetWXPeer() ) ;
768 #endif
769
770 {
771 wxMacEditHelper help( m_txn );
772 SetTXNData( st, kTXNStartOffset, kTXNEndOffset );
773 }
774
775 TXNSetSelection( m_txn, 0, 0 );
776 TXNShowSelection( m_txn, kTXNShowStart );
777 }
778 }
779
FrameOptionsFromWXStyle(long wxStyle)780 TXNFrameOptions wxMacMLTEControl::FrameOptionsFromWXStyle( long wxStyle )
781 {
782 TXNFrameOptions frameOptions = kTXNDontDrawCaretWhenInactiveMask;
783
784 frameOptions |= kTXNDoFontSubstitutionMask;
785
786 if ( ! (wxStyle & wxTE_NOHIDESEL) )
787 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
788
789 if ( wxStyle & (wxHSCROLL | wxTE_DONTWRAP) )
790 frameOptions |= kTXNWantHScrollBarMask ;
791
792 if ( wxStyle & wxTE_MULTILINE )
793 {
794 if ( ! (wxStyle & wxTE_DONTWRAP ) )
795 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
796
797 if ( !(wxStyle & wxTE_NO_VSCROLL) )
798 {
799 frameOptions |= kTXNWantVScrollBarMask ;
800
801 // The following code causes drawing problems on 10.4. Perhaps it can be restored for
802 // older versions of the OS, but I'm not sure it's appropriate to put a grow icon here
803 // anyways, as AFAIK users can't actually use it to resize the text ctrl.
804 // if ( frameOptions & kTXNWantHScrollBarMask )
805 // frameOptions |= kTXNDrawGrowIconMask ;
806 }
807 }
808 else
809 {
810 frameOptions |= kTXNSingleLineOnlyMask ;
811 }
812
813 return frameOptions ;
814 }
815
AdjustCreationAttributes(const wxColour & background,bool WXUNUSED (visible))816 void wxMacMLTEControl::AdjustCreationAttributes(const wxColour &background,
817 bool WXUNUSED(visible))
818 {
819 TXNControlTag iControlTags[] =
820 {
821 kTXNDoFontSubstitution,
822 kTXNWordWrapStateTag ,
823 };
824 TXNControlData iControlData[] =
825 {
826 { true },
827 { kTXNNoAutoWrap },
828 };
829
830 int toptag = WXSIZEOF( iControlTags ) ;
831
832 if ( m_windowStyle & wxTE_MULTILINE )
833 {
834 iControlData[1].uValue =
835 (m_windowStyle & wxTE_DONTWRAP)
836 ? kTXNNoAutoWrap
837 : kTXNAutoWrap;
838 }
839
840 OSStatus err = TXNSetTXNObjectControls( m_txn, false, toptag, iControlTags, iControlData ) ;
841 verify_noerr( err );
842
843 // setting the default font:
844 // under 10.2 this causes a visible caret, therefore we avoid it
845
846 Str255 fontName ;
847 SInt16 fontSize ;
848 Style fontStyle ;
849
850 GetThemeFont( kThemeSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
851
852 TXNTypeAttributes typeAttr[] =
853 {
854 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
855 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
856 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
857 } ;
858
859 err = TXNSetTypeAttributes(
860 m_txn, WXSIZEOF(typeAttr),
861 typeAttr, kTXNStartOffset, kTXNEndOffset );
862 verify_noerr( err );
863
864 if ( m_windowStyle & wxTE_PASSWORD )
865 {
866 UniChar c = 0x00A5 ;
867 err = TXNEchoMode( m_txn , c , 0 , true );
868 verify_noerr( err );
869 }
870
871 TXNBackground tback;
872 tback.bgType = kTXNBackgroundTypeRGB;
873 background.GetRGBColor( &tback.bg.color );
874 TXNSetBackground( m_txn , &tback );
875
876
877 TXNCommandEventSupportOptions options ;
878 if ( TXNGetCommandEventSupport( m_txn, &options ) == noErr )
879 {
880 options |=
881 kTXNSupportEditCommandProcessing
882 | kTXNSupportEditCommandUpdating
883 | kTXNSupportFontCommandProcessing
884 | kTXNSupportFontCommandUpdating;
885
886 // only spell check when not read-only
887 // use system options for the default
888 bool checkSpelling = false ;
889 if ( !(m_windowStyle & wxTE_READONLY) )
890 {
891 #if wxUSE_SYSTEM_OPTIONS
892 if ( wxSystemOptions::HasOption( wxMAC_TEXTCONTROL_USE_SPELL_CHECKER ) && (wxSystemOptions::GetOptionInt( wxMAC_TEXTCONTROL_USE_SPELL_CHECKER ) == 1) )
893 {
894 checkSpelling = true ;
895 }
896 #endif
897 }
898
899 if ( checkSpelling )
900 options |=
901 kTXNSupportSpellCheckCommandProcessing
902 | kTXNSupportSpellCheckCommandUpdating;
903
904 TXNSetCommandEventSupport( m_txn , options ) ;
905 }
906 }
907
SetBackgroundColour(const wxColour & col)908 void wxMacMLTEControl::SetBackgroundColour(const wxColour& col )
909 {
910 TXNBackground tback;
911 tback.bgType = kTXNBackgroundTypeRGB;
912 col.GetRGBColor(&tback.bg.color);
913 TXNSetBackground( m_txn , &tback );
914 }
915
wxConvertToTXN(int x)916 static inline int wxConvertToTXN(int x)
917 {
918 return static_cast<int>(x / 254.0 * 72 + 0.5);
919 }
920
TXNSetAttribute(const wxTextAttr & style,long from,long to)921 void wxMacMLTEControl::TXNSetAttribute( const wxTextAttr& style , long from , long to )
922 {
923 TXNTypeAttributes typeAttr[4] ;
924 RGBColor color ;
925 size_t typeAttrCount = 0 ;
926
927 TXNMargins margins;
928 TXNControlTag controlTags[4];
929 TXNControlData controlData[4];
930 size_t controlAttrCount = 0;
931
932 TXNTab* tabs = NULL;
933
934 bool relayout = false;
935 wxFont font ;
936
937 if ( style.HasFont() )
938 {
939 wxASSERT( typeAttrCount < WXSIZEOF(typeAttr) );
940 font = style.GetFont() ;
941 typeAttr[typeAttrCount].tag = kTXNATSUIStyle ;
942 typeAttr[typeAttrCount].size = kTXNATSUIStyleSize ;
943 typeAttr[typeAttrCount].data.dataPtr = font.MacGetATSUStyle() ;
944 typeAttrCount++ ;
945 }
946
947 if ( style.HasTextColour() )
948 {
949 wxASSERT( typeAttrCount < WXSIZEOF(typeAttr) );
950 style.GetTextColour().GetRGBColor( &color );
951 typeAttr[typeAttrCount].tag = kTXNQDFontColorAttribute ;
952 typeAttr[typeAttrCount].size = kTXNQDFontColorAttributeSize ;
953 typeAttr[typeAttrCount].data.dataPtr = (void*) &color ;
954 typeAttrCount++ ;
955 }
956
957 if ( style.HasAlignment() )
958 {
959 wxASSERT( controlAttrCount < WXSIZEOF(controlTags) );
960 SInt32 align;
961
962 switch ( style.GetAlignment() )
963 {
964 case wxTEXT_ALIGNMENT_LEFT:
965 align = kTXNFlushLeft;
966 break;
967 case wxTEXT_ALIGNMENT_CENTRE:
968 align = kTXNCenter;
969 break;
970 case wxTEXT_ALIGNMENT_RIGHT:
971 align = kTXNFlushRight;
972 break;
973 case wxTEXT_ALIGNMENT_JUSTIFIED:
974 align = kTXNFullJust;
975 break;
976 default :
977 case wxTEXT_ALIGNMENT_DEFAULT:
978 align = kTXNFlushDefault;
979 break;
980 }
981
982 controlTags[controlAttrCount] = kTXNJustificationTag ;
983 controlData[controlAttrCount].sValue = align ;
984 controlAttrCount++ ;
985 }
986
987 if ( style.HasLeftIndent() || style.HasRightIndent() )
988 {
989 wxASSERT( controlAttrCount < WXSIZEOF(controlTags) );
990 controlTags[controlAttrCount] = kTXNMarginsTag;
991 controlData[controlAttrCount].marginsPtr = &margins;
992 verify_noerr( TXNGetTXNObjectControls (m_txn, 1 ,
993 &controlTags[controlAttrCount], &controlData[controlAttrCount]) );
994 if ( style.HasLeftIndent() )
995 {
996 margins.leftMargin = wxConvertToTXN(style.GetLeftIndent());
997 }
998 if ( style.HasRightIndent() )
999 {
1000 margins.rightMargin = wxConvertToTXN(style.GetRightIndent());
1001 }
1002 controlAttrCount++ ;
1003 }
1004
1005 if ( style.HasTabs() )
1006 {
1007 const wxArrayInt& tabarray = style.GetTabs();
1008 // unfortunately Mac only applies a tab distance, not individually different tabs
1009 controlTags[controlAttrCount] = kTXNTabSettingsTag;
1010 if ( tabarray.size() > 0 )
1011 controlData[controlAttrCount].tabValue.value = wxConvertToTXN(tabarray[0]);
1012 else
1013 controlData[controlAttrCount].tabValue.value = 72 ;
1014
1015 controlData[controlAttrCount].tabValue.tabType = kTXNLeftTab;
1016 controlAttrCount++ ;
1017 }
1018
1019 // unfortunately the relayout is not automatic
1020 if ( controlAttrCount > 0 )
1021 {
1022 verify_noerr( TXNSetTXNObjectControls (m_txn, false /* don't clear all */, controlAttrCount,
1023 controlTags, controlData) );
1024 relayout = true;
1025 }
1026
1027 if ( typeAttrCount > 0 )
1028 {
1029 verify_noerr( TXNSetTypeAttributes( m_txn , typeAttrCount, typeAttr, from , to ) );
1030 if (from != to)
1031 relayout = true;
1032 }
1033
1034 if ( tabs != NULL )
1035 {
1036 delete[] tabs;
1037 }
1038
1039 if ( relayout )
1040 {
1041 TXNRecalcTextLayout( m_txn );
1042 }
1043 }
1044
SetFont(const wxFont & font,const wxColour & foreground,long WXUNUSED (windowStyle),bool WXUNUSED (ignoreBlack))1045 void wxMacMLTEControl::SetFont(const wxFont & font,
1046 const wxColour& foreground,
1047 long WXUNUSED(windowStyle),
1048 bool WXUNUSED(ignoreBlack))
1049 {
1050 wxMacEditHelper help( m_txn ) ;
1051 TXNSetAttribute( wxTextAttr( foreground, wxNullColour, font ), kTXNStartOffset, kTXNEndOffset ) ;
1052 }
1053
SetStyle(long start,long end,const wxTextAttr & style)1054 void wxMacMLTEControl::SetStyle( long start, long end, const wxTextAttr& style )
1055 {
1056 wxMacEditHelper help( m_txn ) ;
1057 TXNSetAttribute( style, start, end ) ;
1058 }
1059
Copy()1060 void wxMacMLTEControl::Copy()
1061 {
1062 TXNCopy( m_txn );
1063 }
1064
Cut()1065 void wxMacMLTEControl::Cut()
1066 {
1067 TXNCut( m_txn );
1068 }
1069
Paste()1070 void wxMacMLTEControl::Paste()
1071 {
1072 TXNPaste( m_txn );
1073 }
1074
CanPaste() const1075 bool wxMacMLTEControl::CanPaste() const
1076 {
1077 return TXNIsScrapPastable() ;
1078 }
1079
SetEditable(bool editable)1080 void wxMacMLTEControl::SetEditable(bool editable)
1081 {
1082 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1083 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1084 TXNSetTXNObjectControls( m_txn, false, WXSIZEOF(tag), tag, data ) ;
1085 }
1086
GetLastPosition() const1087 long wxMacMLTEControl::GetLastPosition() const
1088 {
1089 wxTextPos actualsize = 0 ;
1090
1091 Handle theText ;
1092 #if wxUSE_UNICODE
1093 OSErr err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNUnicodeTextData );
1094 // all done
1095 if ( err == noErr )
1096 {
1097 actualsize = GetHandleSize( theText )/sizeof(UniChar);
1098 DisposeHandle( theText ) ;
1099 }
1100 #else
1101 OSErr err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNTextData );
1102
1103 // all done
1104 if ( err == noErr )
1105 {
1106 actualsize = GetHandleSize( theText ) ;
1107 DisposeHandle( theText ) ;
1108 }
1109 #endif
1110 else
1111 {
1112 actualsize = 0 ;
1113 }
1114
1115 return actualsize ;
1116 }
1117
Replace(long from,long to,const wxString & str)1118 void wxMacMLTEControl::Replace( long from , long to , const wxString &str )
1119 {
1120 wxString value = str ;
1121 wxMacConvertNewlines10To13( &value ) ;
1122
1123 wxMacEditHelper help( m_txn ) ;
1124 #ifndef __LP64__
1125 wxMacWindowClipper c( GetWXPeer() ) ;
1126 #endif
1127
1128 TXNSetSelection( m_txn, from, to == -1 ? kTXNEndOffset : to ) ;
1129 TXNClear( m_txn ) ;
1130 SetTXNData( value, kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1131 }
1132
Remove(long from,long to)1133 void wxMacMLTEControl::Remove( long from , long to )
1134 {
1135 #ifndef __LP64__
1136 wxMacWindowClipper c( GetWXPeer() ) ;
1137 #endif
1138 wxMacEditHelper help( m_txn ) ;
1139 TXNSetSelection( m_txn , from , to ) ;
1140 TXNClear( m_txn ) ;
1141 }
1142
GetSelection(long * from,long * to) const1143 void wxMacMLTEControl::GetSelection( long* from, long* to) const
1144 {
1145 TXNOffset f,t ;
1146 TXNGetSelection( m_txn , &f , &t ) ;
1147 *from = f;
1148 *to = t;
1149 }
1150
SetSelection(long from,long to)1151 void wxMacMLTEControl::SetSelection( long from , long to )
1152 {
1153 #ifndef __LP64__
1154 wxMacWindowClipper c( GetWXPeer() ) ;
1155 #endif
1156
1157 // change the selection
1158 if ((from == -1) && (to == -1))
1159 TXNSelectAll( m_txn );
1160 else
1161 TXNSetSelection( m_txn, from, to == -1 ? kTXNEndOffset : to );
1162
1163 TXNShowSelection( m_txn, kTXNShowStart );
1164 }
1165
WriteText(const wxString & str)1166 void wxMacMLTEControl::WriteText( const wxString& str )
1167 {
1168 // TODO: this MPRemoting will be moved into a remoting peer proxy for any command
1169 if ( !wxIsMainThread() )
1170 {
1171 #if wxOSX_USE_CARBON
1172 // unfortunately CW 8 is not able to correctly deduce the template types,
1173 // so we have to instantiate explicitly
1174 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( (wxTextCtrl*) GetWXPeer() , &wxTextCtrl::WriteText , str ) ;
1175 #endif
1176 return ;
1177 }
1178
1179 wxString st = str ;
1180 wxMacConvertNewlines10To13( &st ) ;
1181
1182 long start , end , dummy ;
1183
1184 GetSelection( &start , &dummy ) ;
1185 #ifndef __LP64__
1186 wxMacWindowClipper c( GetWXPeer() ) ;
1187 #endif
1188
1189 {
1190 wxMacEditHelper helper( m_txn ) ;
1191 SetTXNData( st, kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1192 }
1193
1194 GetSelection( &dummy, &end ) ;
1195
1196 // TODO: SetStyle( start , end , GetDefaultStyle() ) ;
1197 }
1198
Clear()1199 void wxMacMLTEControl::Clear()
1200 {
1201 #ifndef __LP64__
1202 wxMacWindowClipper c( GetWXPeer() ) ;
1203 #endif
1204 wxMacEditHelper st( m_txn ) ;
1205 TXNSetSelection( m_txn , kTXNStartOffset , kTXNEndOffset ) ;
1206 TXNClear( m_txn ) ;
1207 }
1208
CanUndo() const1209 bool wxMacMLTEControl::CanUndo() const
1210 {
1211 return TXNCanUndo( m_txn , NULL ) ;
1212 }
1213
Undo()1214 void wxMacMLTEControl::Undo()
1215 {
1216 TXNUndo( m_txn ) ;
1217 }
1218
CanRedo() const1219 bool wxMacMLTEControl::CanRedo() const
1220 {
1221 return TXNCanRedo( m_txn , NULL ) ;
1222 }
1223
Redo()1224 void wxMacMLTEControl::Redo()
1225 {
1226 TXNRedo( m_txn ) ;
1227 }
1228
GetNumberOfLines() const1229 int wxMacMLTEControl::GetNumberOfLines() const
1230 {
1231 ItemCount lines = 0 ;
1232 TXNGetLineCount( m_txn, &lines ) ;
1233
1234 return lines ;
1235 }
1236
XYToPosition(long x,long y) const1237 long wxMacMLTEControl::XYToPosition(long x, long y) const
1238 {
1239 Point curpt ;
1240 wxTextPos lastpos ;
1241
1242 // TODO: find a better implementation : while we can get the
1243 // line metrics of a certain line, we don't get its starting
1244 // position, so it would probably be rather a binary search
1245 // for the start position
1246 long xpos = 0, ypos = 0 ;
1247 int lastHeight = 0 ;
1248 ItemCount n ;
1249
1250 lastpos = GetLastPosition() ;
1251 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1252 {
1253 if ( y == ypos && x == xpos )
1254 return n ;
1255
1256 TXNOffsetToPoint( m_txn, n, &curpt ) ;
1257
1258 if ( curpt.v > lastHeight )
1259 {
1260 xpos = 0 ;
1261 if ( n > 0 )
1262 ++ypos ;
1263
1264 lastHeight = curpt.v ;
1265 }
1266 else
1267 ++xpos ;
1268 }
1269
1270 return 0 ;
1271 }
1272
PositionToXY(long pos,long * x,long * y) const1273 bool wxMacMLTEControl::PositionToXY( long pos, long *x, long *y ) const
1274 {
1275 Point curpt ;
1276 wxTextPos lastpos ;
1277
1278 if ( y )
1279 *y = 0 ;
1280 if ( x )
1281 *x = 0 ;
1282
1283 lastpos = GetLastPosition() ;
1284 if ( pos <= lastpos )
1285 {
1286 // TODO: find a better implementation - while we can get the
1287 // line metrics of a certain line, we don't get its starting
1288 // position, so it would probably be rather a binary search
1289 // for the start position
1290 long xpos = 0, ypos = 0 ;
1291 int lastHeight = 0 ;
1292 ItemCount n ;
1293
1294 for ( n = 0 ; n <= (ItemCount) pos ; ++n )
1295 {
1296 TXNOffsetToPoint( m_txn, n, &curpt ) ;
1297
1298 if ( curpt.v > lastHeight )
1299 {
1300 xpos = 0 ;
1301 if ( n > 0 )
1302 ++ypos ;
1303
1304 lastHeight = curpt.v ;
1305 }
1306 else
1307 ++xpos ;
1308 }
1309
1310 if ( y )
1311 *y = ypos ;
1312 if ( x )
1313 *x = xpos ;
1314 }
1315
1316 return false ;
1317 }
1318
ShowPosition(long pos)1319 void wxMacMLTEControl::ShowPosition( long pos )
1320 {
1321 Point current, desired ;
1322 TXNOffset selstart, selend;
1323
1324 TXNGetSelection( m_txn, &selstart, &selend );
1325 TXNOffsetToPoint( m_txn, selstart, ¤t );
1326 TXNOffsetToPoint( m_txn, pos, &desired );
1327
1328 // TODO: use HIPoints for 10.3 and above
1329
1330 OSErr theErr = noErr;
1331 long dv = desired.v - current.v;
1332 long dh = desired.h - current.h;
1333 TXNShowSelection( m_txn, kTXNShowStart ) ; // NB: should this be kTXNShowStart or kTXNShowEnd ??
1334 theErr = TXNScroll( m_txn, kTXNScrollUnitsInPixels, kTXNScrollUnitsInPixels, &dv, &dh );
1335
1336 // there will be an error returned for classic MLTE implementation when the control is
1337 // invisible, but HITextView works correctly, so we don't assert that one
1338 // wxASSERT_MSG( theErr == noErr, wxT("TXNScroll returned an error!") );
1339 }
1340
SetTXNData(const wxString & st,TXNOffset start,TXNOffset end)1341 void wxMacMLTEControl::SetTXNData( const wxString& st, TXNOffset start, TXNOffset end )
1342 {
1343 #if wxUSE_UNICODE
1344 wxMBConvUTF16 converter ;
1345 ByteCount byteBufferLen = converter.WC2MB( NULL, st.wc_str(), 0 ) ;
1346 wxASSERT_MSG( byteBufferLen != wxCONV_FAILED,
1347 wxT("Conversion to UTF-16 unexpectedly failed") );
1348 UniChar *unibuf = (UniChar*)malloc( byteBufferLen + 2 ) ; // 2 for NUL in UTF-16
1349 converter.WC2MB( (char*)unibuf, st.wc_str(), byteBufferLen + 2 ) ;
1350 TXNSetData( m_txn, kTXNUnicodeTextData, (void*)unibuf, byteBufferLen, start, end ) ;
1351 free( unibuf ) ;
1352 #else // !wxUSE_UNICODE
1353 wxCharBuffer text = st.mb_str( wxConvLocal ) ;
1354 TXNSetData( m_txn, kTXNTextData, (void*)text.data(), strlen( text ), start, end ) ;
1355 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
1356 }
1357
GetLineText(long lineNo) const1358 wxString wxMacMLTEControl::GetLineText(long lineNo) const
1359 {
1360 wxString line ;
1361
1362 if ( lineNo < GetNumberOfLines() )
1363 {
1364 Point firstPoint;
1365 Fixed lineWidth, lineHeight, currentHeight;
1366 long ypos ;
1367
1368 // get the first possible position in the control
1369 TXNOffsetToPoint(m_txn, 0, &firstPoint);
1370
1371 // Iterate through the lines until we reach the one we want,
1372 // adding to our current y pixel point position
1373 ypos = 0 ;
1374 currentHeight = 0;
1375 while (ypos < lineNo)
1376 {
1377 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
1378 currentHeight += lineHeight;
1379 }
1380
1381 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
1382 TXNOffset theOffset;
1383 TXNPointToOffset(m_txn, thePoint, &theOffset);
1384
1385 wxString content = GetStringValue() ;
1386 Point currentPoint = thePoint;
1387 while (thePoint.v == currentPoint.v && theOffset < content.length())
1388 {
1389 line += content[theOffset];
1390 TXNOffsetToPoint(m_txn, ++theOffset, ¤tPoint);
1391 }
1392 }
1393
1394 return line ;
1395 }
1396
GetLineLength(long lineNo) const1397 int wxMacMLTEControl::GetLineLength(long lineNo) const
1398 {
1399 int theLength = 0;
1400
1401 if ( lineNo < GetNumberOfLines() )
1402 {
1403 Point firstPoint;
1404 Fixed lineWidth, lineHeight, currentHeight;
1405 long ypos;
1406
1407 // get the first possible position in the control
1408 TXNOffsetToPoint(m_txn, 0, &firstPoint);
1409
1410 // Iterate through the lines until we reach the one we want,
1411 // adding to our current y pixel point position
1412 ypos = 0;
1413 currentHeight = 0;
1414 while (ypos < lineNo)
1415 {
1416 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
1417 currentHeight += lineHeight;
1418 }
1419
1420 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
1421 TXNOffset theOffset;
1422 TXNPointToOffset(m_txn, thePoint, &theOffset);
1423
1424 wxString content = GetStringValue() ;
1425 Point currentPoint = thePoint;
1426 while (thePoint.v == currentPoint.v && theOffset < content.length())
1427 {
1428 ++theLength;
1429 TXNOffsetToPoint(m_txn, ++theOffset, ¤tPoint);
1430 }
1431 }
1432
1433 return theLength ;
1434 }
1435
1436 // ----------------------------------------------------------------------------
1437 // MLTE control implementation (OSX part)
1438 // ----------------------------------------------------------------------------
1439
1440 // tiger multi-line textcontrols with no CR in the entire content
1441 // don't scroll automatically, so we need a hack.
1442 // This attempt only works 'before' the key (ie before CallNextEventHandler)
1443 // is processed, thus the scrolling always occurs one character too late, but
1444 // better than nothing ...
1445
1446 static const EventTypeSpec eventList[] =
1447 {
1448 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
1449 } ;
1450
wxMacUnicodeTextEventHandler(EventHandlerCallRef handler,EventRef event,void * data)1451 static pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
1452 {
1453 OSStatus result = eventNotHandledErr ;
1454 wxMacMLTEHIViewControl* focus = (wxMacMLTEHIViewControl*) data ;
1455
1456 switch ( GetEventKind( event ) )
1457 {
1458 case kEventTextInputUnicodeForKeyEvent :
1459 {
1460 TXNOffset from , to ;
1461 TXNGetSelection( focus->GetTXNObject() , &from , &to ) ;
1462 if ( from == to )
1463 TXNShowSelection( focus->GetTXNObject() , kTXNShowStart );
1464 result = CallNextEventHandler(handler,event);
1465 break;
1466 }
1467 default:
1468 break ;
1469 }
1470
1471 return result ;
1472 }
1473
wxMacTextControlEventHandler(EventHandlerCallRef handler,EventRef event,void * data)1474 static pascal OSStatus wxMacTextControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
1475 {
1476 OSStatus result = eventNotHandledErr ;
1477
1478 switch ( GetEventClass( event ) )
1479 {
1480 case kEventClassTextInput :
1481 result = wxMacUnicodeTextEventHandler( handler , event , data ) ;
1482 break ;
1483
1484 default :
1485 break ;
1486 }
1487 return result ;
1488 }
1489
DEFINE_ONE_SHOT_HANDLER_GETTER(wxMacTextControlEventHandler)1490 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacTextControlEventHandler )
1491
1492 wxMacMLTEHIViewControl::wxMacMLTEHIViewControl( wxTextCtrl *wxPeer,
1493 const wxString& str,
1494 const wxPoint& pos,
1495 const wxSize& size, long style ) : wxMacMLTEControl( wxPeer )
1496 {
1497 m_font = wxPeer->GetFont() ;
1498 m_windowStyle = style ;
1499 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
1500 wxString st = str ;
1501 wxMacConvertNewlines10To13( &st ) ;
1502
1503 HIRect hr = {
1504 { bounds.left , bounds.top },
1505 { bounds.right - bounds.left, bounds.bottom - bounds.top } } ;
1506
1507 m_scrollView = NULL ;
1508 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( style ) ;
1509 if (( frameOptions & (kTXNWantVScrollBarMask | kTXNWantHScrollBarMask)) || (frameOptions &kTXNSingleLineOnlyMask))
1510 {
1511 if ( frameOptions & (kTXNWantVScrollBarMask | kTXNWantHScrollBarMask) )
1512 {
1513 HIScrollViewCreate(
1514 (frameOptions & kTXNWantHScrollBarMask ? kHIScrollViewOptionsHorizScroll : 0)
1515 | (frameOptions & kTXNWantVScrollBarMask ? kHIScrollViewOptionsVertScroll : 0) ,
1516 &m_scrollView ) ;
1517 }
1518 else
1519 {
1520 HIScrollViewCreate(kHIScrollViewOptionsVertScroll,&m_scrollView);
1521 HIScrollViewSetScrollBarAutoHide(m_scrollView,true);
1522 }
1523
1524 HIViewSetFrame( m_scrollView, &hr );
1525 HIViewSetVisible( m_scrollView, true );
1526 }
1527
1528 m_textView = NULL ;
1529 HITextViewCreate( NULL , 0, frameOptions , &m_textView ) ;
1530 m_txn = HITextViewGetTXNObject( m_textView ) ;
1531 HIViewSetVisible( m_textView , true ) ;
1532 if ( m_scrollView )
1533 {
1534 HIViewAddSubview( m_scrollView , m_textView ) ;
1535 m_controlRef = m_scrollView ;
1536 InstallEventHandler( (WXWidget) m_textView ) ;
1537 }
1538 else
1539 {
1540 HIViewSetFrame( m_textView, &hr );
1541 m_controlRef = m_textView ;
1542 }
1543
1544 AdjustCreationAttributes( *wxWHITE , true ) ;
1545 #ifndef __LP64__
1546 wxMacWindowClipper c( GetWXPeer() ) ;
1547 #endif
1548 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
1549
1550 TXNSetSelection( m_txn, 0, 0 );
1551 TXNShowSelection( m_txn, kTXNShowStart );
1552
1553 ::InstallControlEventHandler( m_textView , GetwxMacTextControlEventHandlerUPP(),
1554 GetEventTypeCount(eventList), eventList, this,
1555 NULL);
1556 }
1557
~wxMacMLTEHIViewControl()1558 wxMacMLTEHIViewControl::~wxMacMLTEHIViewControl()
1559 {
1560 }
1561
SetFocus()1562 bool wxMacMLTEHIViewControl::SetFocus()
1563 {
1564 return SetKeyboardFocus( GetControlOwner( m_textView ), m_textView, kControlFocusNextPart ) == noErr ;
1565 }
1566
HasFocus() const1567 bool wxMacMLTEHIViewControl::HasFocus() const
1568 {
1569 ControlRef control ;
1570 if ( GetUserFocusWindow() == NULL )
1571 return false;
1572
1573 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
1574 return control == m_textView ;
1575 }
1576
SetBackgroundColour(const wxColour & col)1577 void wxMacMLTEHIViewControl::SetBackgroundColour(const wxColour& col )
1578 {
1579 HITextViewSetBackgroundColor( m_textView, col.GetPixel() );
1580 }
1581
1582 #endif // wxUSE_TEXTCTRL
1583