]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/textctrl.cpp
Removed #include <typeinfo> (since C++ RTTI is no longer used)
[wxWidgets.git] / src / osx / carbon / textctrl.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
524c47aa 2// Name: src/osx/carbon/textctrl.cpp
489468fe
SC
3// Purpose: wxTextCtrl
4// Author: Stefan Csomor
5// Modified by: Ryan Norton (MLTE GetLineLength and GetLineText)
6// Created: 1998-01-01
7// RCS-ID: $Id$
8// Copyright: (c) Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#if wxUSE_TEXTCTRL
15
16#include "wx/textctrl.h"
17
18#ifndef WX_PRECOMP
19 #include "wx/intl.h"
20 #include "wx/app.h"
21 #include "wx/utils.h"
22 #include "wx/dc.h"
23 #include "wx/button.h"
24 #include "wx/menu.h"
25 #include "wx/settings.h"
26 #include "wx/msgdlg.h"
27 #include "wx/toplevel.h"
28#endif
29
30#ifdef __DARWIN__
31 #include <sys/types.h>
32 #include <sys/stat.h>
33#else
34 #include <stat.h>
35#endif
36
37#if wxUSE_STD_IOSTREAM
38 #if wxUSE_IOSTREAMH
39 #include <fstream.h>
40 #else
41 #include <fstream>
42 #endif
43#endif
44
45#include "wx/filefn.h"
46#include "wx/sysopt.h"
47#include "wx/thread.h"
48
524c47aa 49#include "wx/osx/private.h"
1f0c8f31 50#include "wx/osx/carbon/private/mactext.h"
489468fe
SC
51
52class wxMacFunctor
53{
54public :
55 wxMacFunctor() {}
56 virtual ~wxMacFunctor() {}
57
58 virtual void* operator()() = 0 ;
59
60 static void* CallBackProc( void *param )
61 {
62 wxMacFunctor* f = (wxMacFunctor*) param ;
63 void *result = (*f)() ;
64 return result ;
65 }
66} ;
67
68template<typename classtype, typename param1type>
69
70class wxMacObjectFunctor1 : public wxMacFunctor
71{
72 typedef void (classtype::*function)( param1type p1 ) ;
73 typedef void (classtype::*ref_function)( const param1type& p1 ) ;
74public :
75 wxMacObjectFunctor1( classtype *obj , function f , param1type p1 ) :
76 wxMacFunctor()
77 {
78 m_object = obj ;
79 m_function = f ;
80 m_param1 = p1 ;
81 }
82
83 wxMacObjectFunctor1( classtype *obj , ref_function f , param1type p1 ) :
84 wxMacFunctor()
85 {
86 m_object = obj ;
87 m_refFunction = f ;
88 m_param1 = p1 ;
89 }
90
91 virtual ~wxMacObjectFunctor1() {}
92
93 virtual void* operator()()
94 {
95 (m_object->*m_function)( m_param1 ) ;
96 return NULL ;
97 }
98
99private :
100 classtype* m_object ;
101 param1type m_param1 ;
102 union
103 {
104 function m_function ;
105 ref_function m_refFunction ;
106 } ;
107} ;
108
109template<typename classtype, typename param1type>
110void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
111{
112 wxMacObjectFunctor1<classtype, param1type> params(object, function, p1) ;
113 void *result =
114 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
115 return result ;
116}
117
118template<typename classtype, typename param1type>
119void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
120{
121 wxMacObjectFunctor1<classtype,param1type> params(object, function, p1) ;
122 void *result =
123 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
124 return result ;
125}
126
127template<typename classtype, typename param1type>
128void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
129{
130 wxMutexGuiLeave() ;
131 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
132 wxMutexGuiEnter() ;
133 return result ;
134}
135
136template<typename classtype, typename param1type>
137void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
138{
139 wxMutexGuiLeave() ;
140 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
141 wxMutexGuiEnter() ;
142 return result ;
143}
144
145class WXDLLEXPORT wxMacPortSaver
146{
147 DECLARE_NO_COPY_CLASS(wxMacPortSaver)
148
149public:
150 wxMacPortSaver( GrafPtr port );
151 ~wxMacPortSaver();
152private :
153 GrafPtr m_port;
154};
155
156
157/*
158 Clips to the visible region of a control within the current port
159 */
160
161class WXDLLEXPORT wxMacWindowClipper : public wxMacPortSaver
162{
163 DECLARE_NO_COPY_CLASS(wxMacWindowClipper)
164
165public:
166 wxMacWindowClipper( const wxWindow* win );
167 ~wxMacWindowClipper();
168private:
169 GrafPtr m_newPort;
170 RgnHandle m_formerClip;
171 RgnHandle m_newClip;
172};
173
174wxMacPortSaver::wxMacPortSaver( GrafPtr port )
175{
176 ::GetPort( &m_port );
177 ::SetPort( port );
178}
179
180wxMacPortSaver::~wxMacPortSaver()
181{
182 ::SetPort( m_port );
183}
184
185wxMacWindowClipper::wxMacWindowClipper( const wxWindow* win ) :
186wxMacPortSaver( (GrafPtr) GetWindowPort( (WindowRef) win->MacGetTopLevelWindowRef() ) )
187{
188 m_newPort = (GrafPtr) GetWindowPort( (WindowRef) win->MacGetTopLevelWindowRef() ) ;
189 m_formerClip = NewRgn() ;
190 m_newClip = NewRgn() ;
191 GetClip( m_formerClip ) ;
192
193 if ( win )
194 {
195 // guard against half constructed objects, this just leads to a empty clip
196 if ( win->GetPeer() )
197 {
198 int x = 0 , y = 0;
199 win->MacWindowToRootWindow( &x, &y ) ;
200
201 // get area including focus rect
202 HIShapeGetAsQDRgn( ((wxWindow*)win)->MacGetVisibleRegion(true).GetWXHRGN() , m_newClip );
203 if ( !EmptyRgn( m_newClip ) )
204 OffsetRgn( m_newClip , x , y ) ;
205 }
206
207 SetClip( m_newClip ) ;
208 }
209}
210
211wxMacWindowClipper::~wxMacWindowClipper()
212{
213 SetPort( m_newPort ) ;
214 SetClip( m_formerClip ) ;
215 DisposeRgn( m_newClip ) ;
216 DisposeRgn( m_formerClip ) ;
217}
218
219// common parts for implementations based on MLTE
220
1e181c7a 221class wxMacMLTEControl : public wxMacControl, public wxTextWidgetImpl
489468fe
SC
222{
223public :
224 wxMacMLTEControl( wxTextCtrl *peer ) ;
1e181c7a 225 ~wxMacMLTEControl() {}
489468fe
SC
226 virtual wxString GetStringValue() const ;
227 virtual void SetStringValue( const wxString &str ) ;
228
229 static TXNFrameOptions FrameOptionsFromWXStyle( long wxStyle ) ;
230
231 void AdjustCreationAttributes( const wxColour& background, bool visible ) ;
232
233 virtual void SetFont( const wxFont & font, const wxColour& foreground, long windowStyle ) ;
234 virtual void SetBackgroundColour(const wxColour& col );
235 virtual void SetStyle( long start, long end, const wxTextAttr& style ) ;
236 virtual void Copy() ;
237 virtual void Cut() ;
238 virtual void Paste() ;
239 virtual bool CanPaste() const ;
240 virtual void SetEditable( bool editable ) ;
0b6a49c2 241 virtual long GetLastPosition() const ;
489468fe
SC
242 virtual void Replace( long from, long to, const wxString &str ) ;
243 virtual void Remove( long from, long to ) ;
244 virtual void GetSelection( long* from, long* to ) const ;
245 virtual void SetSelection( long from, long to ) ;
246
247 virtual void WriteText( const wxString& str ) ;
248
249 virtual bool HasOwnContextMenu() const
250 {
251 TXNCommandEventSupportOptions options ;
252 TXNGetCommandEventSupport( m_txn , & options ) ;
253 return options & kTXNSupportEditCommandProcessing ;
254 }
255
256 virtual void CheckSpelling(bool check)
257 {
258 TXNSetSpellCheckAsYouType( m_txn, (Boolean) check );
259 }
260 virtual void Clear() ;
261
262 virtual bool CanUndo() const ;
263 virtual void Undo() ;
264 virtual bool CanRedo() const;
265 virtual void Redo() ;
266 virtual int GetNumberOfLines() const ;
267 virtual long XYToPosition(long x, long y) const ;
268 virtual bool PositionToXY(long pos, long *x, long *y) const ;
269 virtual void ShowPosition( long pos ) ;
270 virtual int GetLineLength(long lineNo) const ;
271 virtual wxString GetLineText(long lineNo) const ;
272
273 void SetTXNData( const wxString& st , TXNOffset start , TXNOffset end ) ;
274 TXNObject GetTXNObject() { return m_txn ; }
275
276protected :
277 void TXNSetAttribute( const wxTextAttr& style , long from , long to ) ;
278
279 TXNObject m_txn ;
280} ;
281
282// implementation available under OSX
283
284class wxMacMLTEHIViewControl : public wxMacMLTEControl
285{
286public :
287 wxMacMLTEHIViewControl( wxTextCtrl *wxPeer,
288 const wxString& str,
289 const wxPoint& pos,
290 const wxSize& size, long style ) ;
291 virtual ~wxMacMLTEHIViewControl() ;
292
293 virtual OSStatus SetFocus( ControlFocusPart focusPart ) ;
294 virtual bool HasFocus() const ;
295 virtual void SetBackgroundColour(const wxColour& col ) ;
296
297protected :
298 HIViewRef m_scrollView ;
299 HIViewRef m_textView ;
300};
301
302// 'classic' MLTE implementation
303
304class wxMacMLTEClassicControl : public wxMacMLTEControl
305{
306public :
307 wxMacMLTEClassicControl( wxTextCtrl *wxPeer,
308 const wxString& str,
309 const wxPoint& pos,
310 const wxSize& size, long style ) ;
311 virtual ~wxMacMLTEClassicControl() ;
312
313 virtual void VisibilityChanged(bool shown) ;
314 virtual void SuperChangedPosition() ;
315
316 virtual void MacControlUserPaneDrawProc(wxInt16 part) ;
317 virtual wxInt16 MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y) ;
318 virtual wxInt16 MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc) ;
319 virtual void MacControlUserPaneIdleProc() ;
320 virtual wxInt16 MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers) ;
321 virtual void MacControlUserPaneActivateProc(bool activating) ;
322 virtual wxInt16 MacControlUserPaneFocusProc(wxInt16 action) ;
323 virtual void MacControlUserPaneBackgroundProc(void* info) ;
324
325 virtual bool SetupCursor( const wxPoint& WXUNUSED(pt) )
326 {
327 MacControlUserPaneIdleProc();
328 return true;
329 }
330
b2680ced 331 virtual void Move(int x, int y, int width, int height);
489468fe
SC
332
333protected :
334 OSStatus DoCreate();
335
336 void MacUpdatePosition() ;
337 void MacActivatePaneText(bool setActive) ;
338 void MacFocusPaneText(bool setFocus) ;
339 void MacSetObjectVisibility(bool vis) ;
340
341private :
342 TXNFrameID m_txnFrameID ;
343 GrafPtr m_txnPort ;
344 WindowRef m_txnWindow ;
345 // bounds of the control as we last did set the txn frames
346 Rect m_txnControlBounds ;
347 Rect m_txnVisBounds ;
348
349 static pascal void TXNScrollActionProc( ControlRef controlRef , ControlPartCode partCode ) ;
350 static pascal void TXNScrollInfoProc(
351 SInt32 iValue, SInt32 iMaximumValue,
352 TXNScrollBarOrientation iScrollBarOrientation, SInt32 iRefCon ) ;
353
354 ControlRef m_sbHorizontal ;
355 SInt32 m_lastHorizontalValue ;
356 ControlRef m_sbVertical ;
357 SInt32 m_lastVerticalValue ;
358};
359
524c47aa
SC
360wxWidgetImplType* wxWidgetImpl::CreateTextControl( wxTextCtrl* wxpeer,
361 wxWindowMac* parent,
362 wxWindowID id,
363 const wxString& str,
364 const wxPoint& pos,
365 const wxSize& size,
366 long style,
367 long extraStyle)
489468fe
SC
368{
369 bool forceMLTE = false ;
370
371#if wxUSE_SYSTEM_OPTIONS
372 if (wxSystemOptions::HasOption( wxMAC_TEXTCONTROL_USE_MLTE ) && (wxSystemOptions::GetOptionInt( wxMAC_TEXTCONTROL_USE_MLTE ) == 1))
373 {
374 forceMLTE = true ;
375 }
376#endif
377
378 if ( UMAGetSystemVersion() >= 0x1050 )
379 forceMLTE = false;
380
1e181c7a 381 wxMacControl* peer = NULL;
524c47aa 382
489468fe
SC
383 if ( !forceMLTE )
384 {
524c47aa
SC
385 if ( style & wxTE_MULTILINE || ( UMAGetSystemVersion() >= 0x1050 ) )
386 peer = new wxMacMLTEHIViewControl( wxpeer , str , pos , size , style ) ;
489468fe
SC
387 }
388
524c47aa 389 if ( !peer )
489468fe 390 {
524c47aa 391 if ( !(style & wxTE_MULTILINE) && !forceMLTE )
489468fe 392 {
524c47aa 393 peer = new wxMacUnicodeTextControl( wxpeer , str , pos , size , style ) ;
489468fe
SC
394 }
395 }
396
397 // the horizontal single line scrolling bug that made us keep the classic implementation
398 // is fixed in 10.5
399#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
524c47aa
SC
400 if ( !peer )
401 peer = new wxMacMLTEClassicControl( wxpeer , str , pos , size , style ) ;
489468fe 402#endif
524c47aa 403 return peer;
489468fe
SC
404}
405
406// ----------------------------------------------------------------------------
407// standard unicode control implementation
408// ----------------------------------------------------------------------------
409
410// the current unicode textcontrol implementation has a bug : only if the control
411// is currently having the focus, the selection can be retrieved by the corresponding
412// data tag. So we have a mirroring using a member variable
413// TODO : build event table using virtual member functions for wxMacControl
414
415static const EventTypeSpec unicodeTextControlEventList[] =
416{
417 { kEventClassControl , kEventControlSetFocusPart } ,
418} ;
419
420static pascal OSStatus wxMacUnicodeTextControlControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
421{
422 OSStatus result = eventNotHandledErr ;
423 wxMacUnicodeTextControl* focus = (wxMacUnicodeTextControl*) data ;
424 wxMacCarbonEvent cEvent( event ) ;
425
426 switch ( GetEventKind( event ) )
427 {
428 case kEventControlSetFocusPart :
429 {
430 ControlPartCode controlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
431 if ( controlPart == kControlFocusNoPart )
432 {
433 // about to loose focus -> store selection to field
434 focus->GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &focus->m_selection );
435 }
436 result = CallNextEventHandler(handler,event) ;
437 if ( controlPart != kControlFocusNoPart )
438 {
439 // about to gain focus -> set selection from field
440 focus->SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &focus->m_selection );
441 }
442 break;
443 }
444 default:
445 break ;
446 }
447
448 return result ;
449}
450
451static pascal OSStatus wxMacUnicodeTextControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
452{
453 OSStatus result = eventNotHandledErr ;
454
455 switch ( GetEventClass( event ) )
456 {
457 case kEventClassControl :
458 result = wxMacUnicodeTextControlControlEventHandler( handler , event , data ) ;
459 break ;
460
461 default :
462 break ;
463 }
464 return result ;
465}
466
467DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacUnicodeTextControlEventHandler )
468
1e181c7a 469wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxTextCtrl *wxPeer ) : wxMacControl( wxPeer )
489468fe
SC
470{
471}
472
473wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxTextCtrl *wxPeer,
474 const wxString& str,
475 const wxPoint& pos,
476 const wxSize& size, long style )
1e181c7a 477 : wxMacControl( wxPeer )
489468fe
SC
478{
479 m_font = wxPeer->GetFont() ;
480 m_windowStyle = style ;
481 m_selection.selStart = m_selection.selEnd = 0;
482 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
483 wxString st = str ;
484 wxMacConvertNewlines10To13( &st ) ;
485 wxCFStringRef cf(st , m_font.GetEncoding()) ;
489468fe
SC
486
487 m_valueTag = kControlEditTextCFStringTag ;
1e181c7a
SC
488 Boolean isPassword = ( m_windowStyle & wxTE_PASSWORD ) != 0 ;
489 if ( isPassword )
490 {
491 m_valueTag = kControlEditTextPasswordCFStringTag ;
492 }
493 OSStatus err = CreateEditUnicodeTextControl(
494 MAC_WXHWND(wxPeer->MacGetTopLevelWindowRef()), &bounds , cf ,
495 isPassword , NULL , &m_controlRef ) ;
496 verify_noerr( err );
489468fe
SC
497
498 if ( !(m_windowStyle & wxTE_MULTILINE) )
499 SetData<Boolean>( kControlEditTextPart , kControlEditTextSingleLineTag , true ) ;
500
1e181c7a
SC
501 InstallEventHandlers();
502}
503
504void wxMacUnicodeTextControl::InstallEventHandlers()
505{
b2680ced 506 ::InstallControlEventHandler( m_controlRef , GetwxMacUnicodeTextControlEventHandlerUPP(),
489468fe
SC
507 GetEventTypeCount(unicodeTextControlEventList), unicodeTextControlEventList, this,
508 NULL);
489468fe
SC
509}
510
511wxMacUnicodeTextControl::~wxMacUnicodeTextControl()
512{
513}
514
515void wxMacUnicodeTextControl::VisibilityChanged(bool shown)
516{
517 if ( !(m_windowStyle & wxTE_MULTILINE) && shown )
518 {
519 // work around a refresh issue insofar as not always the entire content is shown,
520 // even if this would be possible
521 ControlEditTextSelectionRec sel ;
522 CFStringRef value = NULL ;
523
524 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
525 verify_noerr( GetData<CFStringRef>( 0, m_valueTag, &value ) );
526 verify_noerr( SetData<CFStringRef>( 0, m_valueTag, &value ) );
527 verify_noerr( SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
528
529 CFRelease( value ) ;
530 }
531}
532
533wxString wxMacUnicodeTextControl::GetStringValue() const
534{
535 wxString result ;
536 CFStringRef value = GetData<CFStringRef>(0, m_valueTag) ;
537 if ( value )
538 {
539 wxCFStringRef cf(value) ;
540 result = cf.AsString() ;
541 }
542
543#if '\n' == 10
544 wxMacConvertNewlines13To10( &result ) ;
545#else
546 wxMacConvertNewlines10To13( &result ) ;
547#endif
548
549 return result ;
550}
551
552void wxMacUnicodeTextControl::SetStringValue( const wxString &str )
553{
554 wxString st = str ;
555 wxMacConvertNewlines10To13( &st ) ;
556 wxCFStringRef cf( st , m_font.GetEncoding() ) ;
557 verify_noerr( SetData<CFStringRef>( 0, m_valueTag , cf ) ) ;
558}
559
489468fe
SC
560void wxMacUnicodeTextControl::Copy()
561{
562 SendHICommand( kHICommandCopy ) ;
563}
564
565void wxMacUnicodeTextControl::Cut()
566{
567 SendHICommand( kHICommandCut ) ;
568}
569
570void wxMacUnicodeTextControl::Paste()
571{
572 SendHICommand( kHICommandPaste ) ;
573}
574
575bool wxMacUnicodeTextControl::CanPaste() const
576{
577 return true ;
578}
579
580void wxMacUnicodeTextControl::SetEditable(bool WXUNUSED(editable))
581{
582#if 0 // leads to problem because text cannot be selected anymore
583 SetData<Boolean>( kControlEditTextPart , kControlEditTextLockedTag , (Boolean) !editable ) ;
584#endif
585}
586
587void wxMacUnicodeTextControl::GetSelection( long* from, long* to ) const
588{
589 ControlEditTextSelectionRec sel ;
590 if (HasFocus())
591 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ) ;
592 else
593 sel = m_selection ;
594
595 if ( from )
596 *from = sel.selStart ;
597 if ( to )
598 *to = sel.selEnd ;
599}
600
601void wxMacUnicodeTextControl::SetSelection( long from , long to )
602{
603 ControlEditTextSelectionRec sel ;
604 wxString result ;
605 int textLength = 0 ;
606 CFStringRef value = GetData<CFStringRef>(0, m_valueTag) ;
607 if ( value )
608 {
609 wxCFStringRef cf(value) ;
610 textLength = cf.AsString().length() ;
611 }
612
613 if ((from == -1) && (to == -1))
614 {
615 from = 0 ;
616 to = textLength ;
617 }
618 else
619 {
620 from = wxMin(textLength,wxMax(from,0)) ;
621 if ( to == -1 )
622 to = textLength;
623 else
624 to = wxMax(0,wxMin(textLength,to)) ;
625 }
626
627 sel.selStart = from ;
628 sel.selEnd = to ;
629 if ( HasFocus() )
630 SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ;
631 else
632 m_selection = sel;
633}
634
635void wxMacUnicodeTextControl::WriteText( const wxString& str )
636{
524c47aa
SC
637 // TODO: this MPRemoting will be moved into a remoting peer proxy for any command
638 if ( !wxIsMainThread() )
639 {
640#if wxOSX_USE_CARBON
641 // unfortunately CW 8 is not able to correctly deduce the template types,
642 // so we have to instantiate explicitly
643 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( (wxTextCtrl*) GetWXPeer() , &wxTextCtrl::WriteText , str ) ;
644#endif
645 return ;
646 }
647
489468fe
SC
648 wxString st = str ;
649 wxMacConvertNewlines10To13( &st ) ;
650
651 if ( HasFocus() )
652 {
653 wxCFStringRef cf(st , m_font.GetEncoding() ) ;
654 CFStringRef value = cf ;
655 SetData<CFStringRef>( 0, kControlEditTextInsertCFStringRefTag, &value );
656 }
657 else
658 {
659 wxString val = GetStringValue() ;
660 long start , end ;
661 GetSelection( &start , &end ) ;
662 val.Remove( start , end - start ) ;
663 val.insert( start , str ) ;
664 SetStringValue( val ) ;
665 SetSelection( start + str.length() , start + str.length() ) ;
666 }
667}
668
669// ----------------------------------------------------------------------------
670// MLTE control implementation (common part)
671// ----------------------------------------------------------------------------
672
673// if MTLE is read only, no changes at all are allowed, not even from
674// procedural API, in order to allow changes via API all the same we must undo
675// the readonly status while we are executing, this class helps to do so
676
677class wxMacEditHelper
678{
679public :
680 wxMacEditHelper( TXNObject txn )
681 {
682 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
683 m_txn = txn ;
684 TXNGetTXNObjectControls( m_txn , 1 , tag , m_data ) ;
685 if ( m_data[0].uValue == kTXNReadOnly )
686 {
687 TXNControlData data[] = { { kTXNReadWrite } } ;
688 TXNSetTXNObjectControls( m_txn , false , 1 , tag , data ) ;
689 }
690 }
691
692 ~wxMacEditHelper()
693 {
694 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
695 if ( m_data[0].uValue == kTXNReadOnly )
696 TXNSetTXNObjectControls( m_txn , false , 1 , tag , m_data ) ;
697 }
698
699protected :
700 TXNObject m_txn ;
701 TXNControlData m_data[1] ;
702} ;
703
704wxMacMLTEControl::wxMacMLTEControl( wxTextCtrl *peer )
1e181c7a 705 : wxMacControl( peer )
489468fe
SC
706{
707 SetNeedsFocusRect( true ) ;
708}
709
710wxString wxMacMLTEControl::GetStringValue() const
711{
712 wxString result ;
713 OSStatus err ;
714 Size actualSize = 0;
715
716 {
717#if wxUSE_UNICODE
718 Handle theText ;
719 err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNUnicodeTextData );
720
721 // all done
722 if ( err != noErr )
723 {
724 actualSize = 0 ;
725 }
726 else
727 {
728 actualSize = GetHandleSize( theText ) / sizeof(UniChar) ;
729 if ( actualSize > 0 )
730 {
731 wxChar *ptr = NULL ;
732
733#if SIZEOF_WCHAR_T == 2
734 ptr = new wxChar[actualSize + 1] ;
735 wxStrncpy( ptr , (wxChar*)(*theText) , actualSize ) ;
736#else
737 SetHandleSize( theText, (actualSize + 1) * sizeof(UniChar) ) ;
738 HLock( theText ) ;
739 (((UniChar*)*theText)[actualSize]) = 0 ;
740 wxMBConvUTF16 converter ;
741 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
742 wxASSERT_MSG( noChars != wxCONV_FAILED, _T("Unable to count the number of characters in this string!") );
743 ptr = new wxChar[noChars + 1] ;
744
745 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars + 1 ) ;
746 wxASSERT_MSG( noChars != wxCONV_FAILED, _T("Conversion of string failed!") );
747 ptr[noChars] = 0 ;
748 HUnlock( theText ) ;
749#endif
750
751 ptr[actualSize] = 0 ;
752 result = wxString( ptr ) ;
753 delete [] ptr ;
754 }
755
756 DisposeHandle( theText ) ;
757 }
758#else
759 Handle theText ;
760 err = TXNGetDataEncoded( m_txn , kTXNStartOffset, kTXNEndOffset, &theText, kTXNTextData );
761
762 // all done
763 if ( err != noErr )
764 {
765 actualSize = 0 ;
766 }
767 else
768 {
769 actualSize = GetHandleSize( theText ) ;
770 if ( actualSize > 0 )
771 {
772 HLock( theText ) ;
773 result = wxString( *theText , wxConvLocal , actualSize ) ;
774 HUnlock( theText ) ;
775 }
776
777 DisposeHandle( theText ) ;
778 }
779#endif
780 }
781
782#if '\n' == 10
783 wxMacConvertNewlines13To10( &result ) ;
784#else
785 wxMacConvertNewlines10To13( &result ) ;
786#endif
787
788 return result ;
789}
790
791void wxMacMLTEControl::SetStringValue( const wxString &str )
792{
793 wxString st = str;
794 wxMacConvertNewlines10To13( &st );
795
796 {
797#ifndef __LP64__
b2680ced 798 wxMacWindowClipper c( GetWXPeer() ) ;
489468fe
SC
799#endif
800
801 {
802 wxMacEditHelper help( m_txn );
803 SetTXNData( st, kTXNStartOffset, kTXNEndOffset );
804 }
805
806 TXNSetSelection( m_txn, 0, 0 );
807 TXNShowSelection( m_txn, kTXNShowStart );
808 }
809}
810
811TXNFrameOptions wxMacMLTEControl::FrameOptionsFromWXStyle( long wxStyle )
812{
813 TXNFrameOptions frameOptions = kTXNDontDrawCaretWhenInactiveMask;
814
815 frameOptions |= kTXNDoFontSubstitutionMask;
816
817 if ( ! (wxStyle & wxTE_NOHIDESEL) )
818 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
819
820 if ( wxStyle & (wxHSCROLL | wxTE_DONTWRAP) )
821 frameOptions |= kTXNWantHScrollBarMask ;
822
823 if ( wxStyle & wxTE_MULTILINE )
824 {
825 if ( ! (wxStyle & wxTE_DONTWRAP ) )
826 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
827
828 if ( !(wxStyle & wxTE_NO_VSCROLL) )
829 {
830 frameOptions |= kTXNWantVScrollBarMask ;
831
832 // The following code causes drawing problems on 10.4. Perhaps it can be restored for
833 // older versions of the OS, but I'm not sure it's appropriate to put a grow icon here
834 // anyways, as AFAIK users can't actually use it to resize the text ctrl.
835// if ( frameOptions & kTXNWantHScrollBarMask )
836// frameOptions |= kTXNDrawGrowIconMask ;
837 }
838 }
839 else
840 {
841 frameOptions |= kTXNSingleLineOnlyMask ;
842 }
843
844 return frameOptions ;
845}
846
847void wxMacMLTEControl::AdjustCreationAttributes(const wxColour &background,
848 bool WXUNUSED(visible))
849{
850 TXNControlTag iControlTags[] =
851 {
852 kTXNDoFontSubstitution,
853 kTXNWordWrapStateTag ,
854 };
855 TXNControlData iControlData[] =
856 {
857 { true },
858 { kTXNNoAutoWrap },
859 };
860
861 int toptag = WXSIZEOF( iControlTags ) ;
862
863 if ( m_windowStyle & wxTE_MULTILINE )
864 {
865 iControlData[1].uValue =
866 (m_windowStyle & wxTE_DONTWRAP)
867 ? kTXNNoAutoWrap
868 : kTXNAutoWrap;
869 }
870
871 OSStatus err = TXNSetTXNObjectControls( m_txn, false, toptag, iControlTags, iControlData ) ;
872 verify_noerr( err );
873
874 // setting the default font:
875 // under 10.2 this causes a visible caret, therefore we avoid it
876
877 Str255 fontName ;
878 SInt16 fontSize ;
879 Style fontStyle ;
880
881 GetThemeFont( kThemeSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
882
883 TXNTypeAttributes typeAttr[] =
884 {
885 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
886 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
887 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
888 } ;
889
890 err = TXNSetTypeAttributes(
891 m_txn, sizeof(typeAttr) / sizeof(TXNTypeAttributes),
892 typeAttr, kTXNStartOffset, kTXNEndOffset );
893 verify_noerr( err );
894
895 if ( m_windowStyle & wxTE_PASSWORD )
896 {
897 UniChar c = 0x00A5 ;
898 err = TXNEchoMode( m_txn , c , 0 , true );
899 verify_noerr( err );
900 }
901
902 TXNBackground tback;
903 tback.bgType = kTXNBackgroundTypeRGB;
904 background.GetRGBColor( &tback.bg.color );
905 TXNSetBackground( m_txn , &tback );
906
907
908 TXNCommandEventSupportOptions options ;
909 if ( TXNGetCommandEventSupport( m_txn, &options ) == noErr )
910 {
911 options |=
912 kTXNSupportEditCommandProcessing
913 | kTXNSupportEditCommandUpdating
914 | kTXNSupportFontCommandProcessing
915 | kTXNSupportFontCommandUpdating;
916
917 // only spell check when not read-only
918 // use system options for the default
919 bool checkSpelling = false ;
920 if ( !(m_windowStyle & wxTE_READONLY) )
921 {
922#if wxUSE_SYSTEM_OPTIONS
923 if ( wxSystemOptions::HasOption( wxMAC_TEXTCONTROL_USE_SPELL_CHECKER ) && (wxSystemOptions::GetOptionInt( wxMAC_TEXTCONTROL_USE_SPELL_CHECKER ) == 1) )
924 {
925 checkSpelling = true ;
926 }
927#endif
928 }
929
930 if ( checkSpelling )
931 options |=
932 kTXNSupportSpellCheckCommandProcessing
933 | kTXNSupportSpellCheckCommandUpdating;
934
935 TXNSetCommandEventSupport( m_txn , options ) ;
936 }
937}
938
939void wxMacMLTEControl::SetBackgroundColour(const wxColour& col )
940{
941 TXNBackground tback;
942 tback.bgType = kTXNBackgroundTypeRGB;
943 col.GetRGBColor(&tback.bg.color);
944 TXNSetBackground( m_txn , &tback );
945}
946
947static inline int wxConvertToTXN(int x)
948{
949 return wx_static_cast(int, x / 254.0 * 72 + 0.5);
950}
951
952void wxMacMLTEControl::TXNSetAttribute( const wxTextAttr& style , long from , long to )
953{
954 TXNTypeAttributes typeAttr[4] ;
955 RGBColor color ;
956 size_t typeAttrCount = 0 ;
957
958 TXNMargins margins;
959 TXNControlTag controlTags[4];
960 TXNControlData controlData[4];
961 size_t controlAttrCount = 0;
962
963 TXNTab* tabs = NULL;
964
965 bool relayout = false;
966 wxFont font ;
967
968 if ( style.HasFont() )
969 {
970 wxASSERT( typeAttrCount < WXSIZEOF(typeAttr) );
971 font = style.GetFont() ;
972 typeAttr[typeAttrCount].tag = kTXNATSUIStyle ;
973 typeAttr[typeAttrCount].size = kTXNATSUIStyleSize ;
974 typeAttr[typeAttrCount].data.dataPtr = font.MacGetATSUStyle() ;
975 typeAttrCount++ ;
976 }
977
978 if ( style.HasTextColour() )
979 {
980 wxASSERT( typeAttrCount < WXSIZEOF(typeAttr) );
981 style.GetTextColour().GetRGBColor( &color );
982 typeAttr[typeAttrCount].tag = kTXNQDFontColorAttribute ;
983 typeAttr[typeAttrCount].size = kTXNQDFontColorAttributeSize ;
984 typeAttr[typeAttrCount].data.dataPtr = (void*) &color ;
985 typeAttrCount++ ;
986 }
987
988 if ( style.HasAlignment() )
989 {
990 wxASSERT( controlAttrCount < WXSIZEOF(controlTags) );
991 SInt32 align;
992
993 switch ( style.GetAlignment() )
994 {
995 case wxTEXT_ALIGNMENT_LEFT:
996 align = kTXNFlushLeft;
997 break;
998 case wxTEXT_ALIGNMENT_CENTRE:
999 align = kTXNCenter;
1000 break;
1001 case wxTEXT_ALIGNMENT_RIGHT:
1002 align = kTXNFlushRight;
1003 break;
1004 case wxTEXT_ALIGNMENT_JUSTIFIED:
1005 align = kTXNFullJust;
1006 break;
1007 default :
1008 case wxTEXT_ALIGNMENT_DEFAULT:
1009 align = kTXNFlushDefault;
1010 break;
1011 }
1012
1013 controlTags[controlAttrCount] = kTXNJustificationTag ;
1014 controlData[controlAttrCount].sValue = align ;
1015 controlAttrCount++ ;
1016 }
1017
1018 if ( style.HasLeftIndent() || style.HasRightIndent() )
1019 {
1020 wxASSERT( controlAttrCount < WXSIZEOF(controlTags) );
1021 controlTags[controlAttrCount] = kTXNMarginsTag;
1022 controlData[controlAttrCount].marginsPtr = &margins;
1023 verify_noerr( TXNGetTXNObjectControls (m_txn, 1 ,
1024 &controlTags[controlAttrCount], &controlData[controlAttrCount]) );
1025 if ( style.HasLeftIndent() )
1026 {
1027 margins.leftMargin = wxConvertToTXN(style.GetLeftIndent());
1028 }
1029 if ( style.HasRightIndent() )
1030 {
1031 margins.rightMargin = wxConvertToTXN(style.GetRightIndent());
1032 }
1033 controlAttrCount++ ;
1034 }
1035
1036 if ( style.HasTabs() )
1037 {
1038 const wxArrayInt& tabarray = style.GetTabs();
1039 // unfortunately Mac only applies a tab distance, not individually different tabs
1040 controlTags[controlAttrCount] = kTXNTabSettingsTag;
1041 if ( tabarray.size() > 0 )
1042 controlData[controlAttrCount].tabValue.value = wxConvertToTXN(tabarray[0]);
1043 else
1044 controlData[controlAttrCount].tabValue.value = 72 ;
1045
1046 controlData[controlAttrCount].tabValue.tabType = kTXNLeftTab;
1047 controlAttrCount++ ;
1048 }
1049
1050 // unfortunately the relayout is not automatic
1051 if ( controlAttrCount > 0 )
1052 {
1053 verify_noerr( TXNSetTXNObjectControls (m_txn, false /* don't clear all */, controlAttrCount,
1054 controlTags, controlData) );
1055 relayout = true;
1056 }
1057
1058 if ( typeAttrCount > 0 )
1059 {
1060 verify_noerr( TXNSetTypeAttributes( m_txn , typeAttrCount, typeAttr, from , to ) );
1061 relayout = true;
1062 }
1063
1064 if ( tabs != NULL )
1065 {
1066 delete[] tabs;
1067 }
1068
1069 if ( relayout )
1070 {
1071 TXNRecalcTextLayout( m_txn );
1072 }
1073}
1074
1075void wxMacMLTEControl::SetFont(const wxFont & font,
1076 const wxColour& foreground,
1077 long WXUNUSED(windowStyle))
1078{
1079 wxMacEditHelper help( m_txn ) ;
1080 TXNSetAttribute( wxTextAttr( foreground, wxNullColour, font ), kTXNStartOffset, kTXNEndOffset ) ;
1081}
1082
1083void wxMacMLTEControl::SetStyle( long start, long end, const wxTextAttr& style )
1084{
1085 wxMacEditHelper help( m_txn ) ;
1086 TXNSetAttribute( style, start, end ) ;
1087}
1088
1089void wxMacMLTEControl::Copy()
1090{
1091 TXNCopy( m_txn );
1092}
1093
1094void wxMacMLTEControl::Cut()
1095{
1096 TXNCut( m_txn );
1097}
1098
1099void wxMacMLTEControl::Paste()
1100{
1101 TXNPaste( m_txn );
1102}
1103
1104bool wxMacMLTEControl::CanPaste() const
1105{
1106 return TXNIsScrapPastable() ;
1107}
1108
1109void wxMacMLTEControl::SetEditable(bool editable)
1110{
1111 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1112 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1113 TXNSetTXNObjectControls( m_txn, false, WXSIZEOF(tag), tag, data ) ;
1114}
1115
0b6a49c2 1116long wxMacMLTEControl::GetLastPosition() const
489468fe
SC
1117{
1118 wxTextPos actualsize = 0 ;
1119
1120 Handle theText ;
1121 OSErr err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNTextData );
1122
1123 // all done
1124 if ( err == noErr )
1125 {
1126 actualsize = GetHandleSize( theText ) ;
1127 DisposeHandle( theText ) ;
1128 }
1129 else
1130 {
1131 actualsize = 0 ;
1132 }
1133
1134 return actualsize ;
1135}
1136
1137void wxMacMLTEControl::Replace( long from , long to , const wxString &str )
1138{
1139 wxString value = str ;
1140 wxMacConvertNewlines10To13( &value ) ;
1141
1142 wxMacEditHelper help( m_txn ) ;
1143#ifndef __LP64__
b2680ced 1144 wxMacWindowClipper c( GetWXPeer() ) ;
489468fe
SC
1145#endif
1146
1147 TXNSetSelection( m_txn, from, to == -1 ? kTXNEndOffset : to ) ;
1148 TXNClear( m_txn ) ;
1149 SetTXNData( value, kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1150}
1151
1152void wxMacMLTEControl::Remove( long from , long to )
1153{
1154#ifndef __LP64__
b2680ced 1155 wxMacWindowClipper c( GetWXPeer() ) ;
489468fe
SC
1156#endif
1157 wxMacEditHelper help( m_txn ) ;
1158 TXNSetSelection( m_txn , from , to ) ;
1159 TXNClear( m_txn ) ;
1160}
1161
1162void wxMacMLTEControl::GetSelection( long* from, long* to) const
1163{
1164 TXNOffset f,t ;
1165 TXNGetSelection( m_txn , &f , &t ) ;
1166 *from = f;
1167 *to = t;
1168}
1169
1170void wxMacMLTEControl::SetSelection( long from , long to )
1171{
1172#ifndef __LP64__
b2680ced 1173 wxMacWindowClipper c( GetWXPeer() ) ;
489468fe
SC
1174#endif
1175
1176 // change the selection
1177 if ((from == -1) && (to == -1))
1178 TXNSelectAll( m_txn );
1179 else
1180 TXNSetSelection( m_txn, from, to == -1 ? kTXNEndOffset : to );
1181
1182 TXNShowSelection( m_txn, kTXNShowStart );
1183}
1184
1185void wxMacMLTEControl::WriteText( const wxString& str )
1186{
524c47aa
SC
1187 // TODO: this MPRemoting will be moved into a remoting peer proxy for any command
1188 if ( !wxIsMainThread() )
1189 {
1190#if wxOSX_USE_CARBON
1191 // unfortunately CW 8 is not able to correctly deduce the template types,
1192 // so we have to instantiate explicitly
1193 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( (wxTextCtrl*) GetWXPeer() , &wxTextCtrl::WriteText , str ) ;
1194#endif
1195 return ;
1196 }
1197
489468fe
SC
1198 wxString st = str ;
1199 wxMacConvertNewlines10To13( &st ) ;
1200
1201 long start , end , dummy ;
1202
1203 GetSelection( &start , &dummy ) ;
1204#ifndef __LP64__
b2680ced 1205 wxMacWindowClipper c( GetWXPeer() ) ;
489468fe
SC
1206#endif
1207
1208 {
1209 wxMacEditHelper helper( m_txn ) ;
1210 SetTXNData( st, kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1211 }
1212
1213 GetSelection( &dummy, &end ) ;
1214
1215 // TODO: SetStyle( start , end , GetDefaultStyle() ) ;
1216}
1217
1218void wxMacMLTEControl::Clear()
1219{
1220#ifndef __LP64__
b2680ced 1221 wxMacWindowClipper c( GetWXPeer() ) ;
489468fe
SC
1222#endif
1223 wxMacEditHelper st( m_txn ) ;
1224 TXNSetSelection( m_txn , kTXNStartOffset , kTXNEndOffset ) ;
1225 TXNClear( m_txn ) ;
1226}
1227
1228bool wxMacMLTEControl::CanUndo() const
1229{
1230 return TXNCanUndo( m_txn , NULL ) ;
1231}
1232
1233void wxMacMLTEControl::Undo()
1234{
1235 TXNUndo( m_txn ) ;
1236}
1237
1238bool wxMacMLTEControl::CanRedo() const
1239{
1240 return TXNCanRedo( m_txn , NULL ) ;
1241}
1242
1243void wxMacMLTEControl::Redo()
1244{
1245 TXNRedo( m_txn ) ;
1246}
1247
1248int wxMacMLTEControl::GetNumberOfLines() const
1249{
1250 ItemCount lines = 0 ;
1251 TXNGetLineCount( m_txn, &lines ) ;
1252
1253 return lines ;
1254}
1255
1256long wxMacMLTEControl::XYToPosition(long x, long y) const
1257{
1258 Point curpt ;
1259 wxTextPos lastpos ;
1260
1261 // TODO: find a better implementation : while we can get the
1262 // line metrics of a certain line, we don't get its starting
1263 // position, so it would probably be rather a binary search
1264 // for the start position
1265 long xpos = 0, ypos = 0 ;
1266 int lastHeight = 0 ;
1267 ItemCount n ;
1268
1269 lastpos = GetLastPosition() ;
1270 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1271 {
1272 if ( y == ypos && x == xpos )
1273 return n ;
1274
1275 TXNOffsetToPoint( m_txn, n, &curpt ) ;
1276
1277 if ( curpt.v > lastHeight )
1278 {
1279 xpos = 0 ;
1280 if ( n > 0 )
1281 ++ypos ;
1282
1283 lastHeight = curpt.v ;
1284 }
1285 else
1286 ++xpos ;
1287 }
1288
1289 return 0 ;
1290}
1291
1292bool wxMacMLTEControl::PositionToXY( long pos, long *x, long *y ) const
1293{
1294 Point curpt ;
1295 wxTextPos lastpos ;
1296
1297 if ( y )
1298 *y = 0 ;
1299 if ( x )
1300 *x = 0 ;
1301
1302 lastpos = GetLastPosition() ;
1303 if ( pos <= lastpos )
1304 {
1305 // TODO: find a better implementation - while we can get the
1306 // line metrics of a certain line, we don't get its starting
1307 // position, so it would probably be rather a binary search
1308 // for the start position
1309 long xpos = 0, ypos = 0 ;
1310 int lastHeight = 0 ;
1311 ItemCount n ;
1312
1313 for ( n = 0 ; n <= (ItemCount) pos ; ++n )
1314 {
1315 TXNOffsetToPoint( m_txn, n, &curpt ) ;
1316
1317 if ( curpt.v > lastHeight )
1318 {
1319 xpos = 0 ;
1320 if ( n > 0 )
1321 ++ypos ;
1322
1323 lastHeight = curpt.v ;
1324 }
1325 else
1326 ++xpos ;
1327 }
1328
1329 if ( y )
1330 *y = ypos ;
1331 if ( x )
1332 *x = xpos ;
1333 }
1334
1335 return false ;
1336}
1337
1338void wxMacMLTEControl::ShowPosition( long pos )
1339{
1340 Point current, desired ;
1341 TXNOffset selstart, selend;
1342
1343 TXNGetSelection( m_txn, &selstart, &selend );
1344 TXNOffsetToPoint( m_txn, selstart, &current );
1345 TXNOffsetToPoint( m_txn, pos, &desired );
1346
1347 // TODO: use HIPoints for 10.3 and above
1348
1349 OSErr theErr = noErr;
1350 long dv = desired.v - current.v;
1351 long dh = desired.h - current.h;
1352 TXNShowSelection( m_txn, kTXNShowStart ) ; // NB: should this be kTXNShowStart or kTXNShowEnd ??
1353 theErr = TXNScroll( m_txn, kTXNScrollUnitsInPixels, kTXNScrollUnitsInPixels, &dv, &dh );
1354
1355 // there will be an error returned for classic MLTE implementation when the control is
1356 // invisible, but HITextView works correctly, so we don't assert that one
1357 // wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
1358}
1359
1360void wxMacMLTEControl::SetTXNData( const wxString& st, TXNOffset start, TXNOffset end )
1361{
1362#if wxUSE_UNICODE
1363#if SIZEOF_WCHAR_T == 2
1364 size_t len = st.length() ;
1365 TXNSetData( m_txn, kTXNUnicodeTextData, (void*)st.wc_str(), len * 2, start, end );
1366#else
1367 wxMBConvUTF16 converter ;
1368 ByteCount byteBufferLen = converter.WC2MB( NULL, st.wc_str(), 0 ) ;
1369 UniChar *unibuf = (UniChar*)malloc( byteBufferLen ) ;
1370 converter.WC2MB( (char*)unibuf, st.wc_str(), byteBufferLen ) ;
1371 TXNSetData( m_txn, kTXNUnicodeTextData, (void*)unibuf, byteBufferLen, start, end ) ;
1372 free( unibuf ) ;
1373#endif
1374#else
1375 wxCharBuffer text = st.mb_str( wxConvLocal ) ;
1376 TXNSetData( m_txn, kTXNTextData, (void*)text.data(), strlen( text ), start, end ) ;
1377#endif
1378}
1379
1380wxString wxMacMLTEControl::GetLineText(long lineNo) const
1381{
1382 wxString line ;
1383
1384 if ( lineNo < GetNumberOfLines() )
1385 {
1386 Point firstPoint;
1387 Fixed lineWidth, lineHeight, currentHeight;
1388 long ypos ;
1389
1390 // get the first possible position in the control
1391 TXNOffsetToPoint(m_txn, 0, &firstPoint);
1392
1393 // Iterate through the lines until we reach the one we want,
1394 // adding to our current y pixel point position
1395 ypos = 0 ;
1396 currentHeight = 0;
1397 while (ypos < lineNo)
1398 {
1399 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
1400 currentHeight += lineHeight;
1401 }
1402
1403 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
1404 TXNOffset theOffset;
1405 TXNPointToOffset(m_txn, thePoint, &theOffset);
1406
1407 wxString content = GetStringValue() ;
1408 Point currentPoint = thePoint;
1409 while (thePoint.v == currentPoint.v && theOffset < content.length())
1410 {
1411 line += content[theOffset];
1412 TXNOffsetToPoint(m_txn, ++theOffset, &currentPoint);
1413 }
1414 }
1415
1416 return line ;
1417}
1418
1419int wxMacMLTEControl::GetLineLength(long lineNo) const
1420{
1421 int theLength = 0;
1422
1423 if ( lineNo < GetNumberOfLines() )
1424 {
1425 Point firstPoint;
1426 Fixed lineWidth, lineHeight, currentHeight;
1427 long ypos;
1428
1429 // get the first possible position in the control
1430 TXNOffsetToPoint(m_txn, 0, &firstPoint);
1431
1432 // Iterate through the lines until we reach the one we want,
1433 // adding to our current y pixel point position
1434 ypos = 0;
1435 currentHeight = 0;
1436 while (ypos < lineNo)
1437 {
1438 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
1439 currentHeight += lineHeight;
1440 }
1441
1442 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
1443 TXNOffset theOffset;
1444 TXNPointToOffset(m_txn, thePoint, &theOffset);
1445
1446 wxString content = GetStringValue() ;
1447 Point currentPoint = thePoint;
1448 while (thePoint.v == currentPoint.v && theOffset < content.length())
1449 {
1450 ++theLength;
1451 TXNOffsetToPoint(m_txn, ++theOffset, &currentPoint);
1452 }
1453 }
1454
1455 return theLength ;
1456}
1457
1458#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
1459
1460// ----------------------------------------------------------------------------
1461// MLTE control implementation (classic part)
1462// ----------------------------------------------------------------------------
1463
1464// OS X Notes : We still don't have a full replacement for MLTE, so this implementation
1465// has to live on. We have different problems coming from outdated implementations on the
1466// various OS X versions. Most deal with the scrollbars: they are not correctly embedded
1467// while this can be solved on 10.3 by reassigning them the correct place, on 10.2 there is
1468// no way out, therefore we are using our own implementation and our own scrollbars ....
1469
1470TXNScrollInfoUPP gTXNScrollInfoProc = NULL ;
1471ControlActionUPP gTXNScrollActionProc = NULL ;
1472
1473pascal void wxMacMLTEClassicControl::TXNScrollInfoProc(
1474 SInt32 iValue, SInt32 iMaximumValue,
1475 TXNScrollBarOrientation iScrollBarOrientation, SInt32 iRefCon )
1476{
1477 wxMacMLTEClassicControl* mlte = (wxMacMLTEClassicControl*) iRefCon ;
1478 SInt32 value = wxMax( iValue , 0 ) ;
1479 SInt32 maximum = wxMax( iMaximumValue , 0 ) ;
1480
1481 if ( iScrollBarOrientation == kTXNHorizontal )
1482 {
1483 if ( mlte->m_sbHorizontal )
1484 {
1485 SetControl32BitValue( mlte->m_sbHorizontal , value ) ;
1486 SetControl32BitMaximum( mlte->m_sbHorizontal , maximum ) ;
1487 mlte->m_lastHorizontalValue = value ;
1488 }
1489 }
1490 else if ( iScrollBarOrientation == kTXNVertical )
1491 {
1492 if ( mlte->m_sbVertical )
1493 {
1494 SetControl32BitValue( mlte->m_sbVertical , value ) ;
1495 SetControl32BitMaximum( mlte->m_sbVertical , maximum ) ;
1496 mlte->m_lastVerticalValue = value ;
1497 }
1498 }
1499}
1500
1501pascal void wxMacMLTEClassicControl::TXNScrollActionProc( ControlRef controlRef , ControlPartCode partCode )
1502{
1503 wxMacMLTEClassicControl* mlte = (wxMacMLTEClassicControl*) GetControlReference( controlRef ) ;
1504 if ( mlte == NULL )
1505 return ;
1506
1507 if ( controlRef != mlte->m_sbVertical && controlRef != mlte->m_sbHorizontal )
1508 return ;
1509
1510 OSStatus err ;
1511 bool isHorizontal = ( controlRef == mlte->m_sbHorizontal ) ;
1512
1513 SInt32 minimum = 0 ;
1514 SInt32 maximum = GetControl32BitMaximum( controlRef ) ;
1515 SInt32 value = GetControl32BitValue( controlRef ) ;
1516 SInt32 delta = 0;
1517
1518 switch ( partCode )
1519 {
1520 case kControlDownButtonPart :
1521 delta = 10 ;
1522 break ;
1523
1524 case kControlUpButtonPart :
1525 delta = -10 ;
1526 break ;
1527
1528 case kControlPageDownPart :
1529 delta = GetControlViewSize( controlRef ) ;
1530 break ;
1531
1532 case kControlPageUpPart :
1533 delta = -GetControlViewSize( controlRef ) ;
1534 break ;
1535
1536 case kControlIndicatorPart :
1537 delta = value - (isHorizontal ? mlte->m_lastHorizontalValue : mlte->m_lastVerticalValue) ;
1538 break ;
1539
1540 default :
1541 break ;
1542 }
1543
1544 if ( delta != 0 )
1545 {
1546 SInt32 newValue = value ;
1547
1548 if ( partCode != kControlIndicatorPart )
1549 {
1550 if ( value + delta < minimum )
1551 delta = minimum - value ;
1552 if ( value + delta > maximum )
1553 delta = maximum - value ;
1554
1555 SetControl32BitValue( controlRef , value + delta ) ;
1556 newValue = value + delta ;
1557 }
1558
1559 SInt32 verticalDelta = isHorizontal ? 0 : delta ;
1560 SInt32 horizontalDelta = isHorizontal ? delta : 0 ;
1561
1562 err = TXNScroll(
1563 mlte->m_txn, kTXNScrollUnitsInPixels, kTXNScrollUnitsInPixels,
1564 &verticalDelta, &horizontalDelta );
1565 verify_noerr( err );
1566
1567 if ( isHorizontal )
1568 mlte->m_lastHorizontalValue = newValue ;
1569 else
1570 mlte->m_lastVerticalValue = newValue ;
1571 }
1572}
1573
1574// make correct activations
1575void wxMacMLTEClassicControl::MacActivatePaneText(bool setActive)
1576{
1577 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(m_controlRef);
1578
1579 wxMacWindowClipper clipper( textctrl ) ;
1580 TXNActivate( m_txn, m_txnFrameID, setActive );
1581
1582 ControlRef controlFocus = 0 ;
1583 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
1584 if ( controlFocus == m_controlRef )
1585 TXNFocus( m_txn, setActive );
1586}
1587
1588void wxMacMLTEClassicControl::MacFocusPaneText(bool setFocus)
1589{
1590 TXNFocus( m_txn, setFocus );
1591}
1592
1593// guards against inappropriate redraw (hidden objects drawing onto window)
1594
1595void wxMacMLTEClassicControl::MacSetObjectVisibility(bool vis)
1596{
1597 ControlRef controlFocus = 0 ;
1598 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
1599
1600 if ( !vis && (controlFocus == m_controlRef ) )
1601 SetKeyboardFocus( m_txnWindow , m_controlRef , kControlFocusNoPart ) ;
1602
1603 TXNControlTag iControlTags[1] = { kTXNVisibilityTag };
1604 TXNControlData iControlData[1] = { { (UInt32)false } };
1605
1606 verify_noerr( TXNGetTXNObjectControls( m_txn , 1, iControlTags, iControlData ) ) ;
1607
1608 if ( iControlData[0].uValue != vis )
1609 {
1610 iControlData[0].uValue = vis ;
1611 verify_noerr( TXNSetTXNObjectControls( m_txn, false , 1, iControlTags, iControlData ) ) ;
1612 }
1613
1614 // currently, we always clip as partial visibility (overlapped) visibility is also a problem,
1615 // if we run into further problems we might set the FrameBounds to an empty rect here
1616}
1617
1618// make sure that the TXNObject is at the right position
1619
1620void wxMacMLTEClassicControl::MacUpdatePosition()
1621{
1622 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
1623 if ( textctrl == NULL )
1624 return ;
1625
1626 Rect bounds ;
1627 GetRectInWindowCoords( &bounds );
1628
1629 wxRect visRect = textctrl->MacGetClippedClientRect() ;
1630 Rect visBounds = { visRect.y , visRect.x , visRect.y + visRect.height , visRect.x + visRect.width } ;
1631 int x , y ;
1632 x = y = 0 ;
1633 textctrl->MacWindowToRootWindow( &x , &y ) ;
1634 OffsetRect( &visBounds , x , y ) ;
1635
1636 if ( !EqualRect( &bounds, &m_txnControlBounds ) || !EqualRect( &visBounds, &m_txnVisBounds ) )
1637 {
1638 m_txnControlBounds = bounds ;
1639 m_txnVisBounds = visBounds ;
1640 wxMacWindowClipper cl( textctrl ) ;
1641
1642 if ( m_sbHorizontal || m_sbVertical )
1643 {
1644 int w = bounds.right - bounds.left ;
1645 int h = bounds.bottom - bounds.top ;
1646
1647 if ( m_sbHorizontal )
1648 {
1649 Rect sbBounds ;
1650
1651 sbBounds.left = -1 ;
1652 sbBounds.top = h - 14 ;
1653 sbBounds.right = w + 1 ;
1654 sbBounds.bottom = h + 1 ;
1655
1656 SetControlBounds( m_sbHorizontal , &sbBounds ) ;
1657 SetControlViewSize( m_sbHorizontal , w ) ;
1658 }
1659
1660 if ( m_sbVertical )
1661 {
1662 Rect sbBounds ;
1663
1664 sbBounds.left = w - 14 ;
1665 sbBounds.top = -1 ;
1666 sbBounds.right = w + 1 ;
1667 sbBounds.bottom = m_sbHorizontal ? h - 14 : h + 1 ;
1668
1669 SetControlBounds( m_sbVertical , &sbBounds ) ;
1670 SetControlViewSize( m_sbVertical , h ) ;
1671 }
1672 }
1673
1674 Rect oldviewRect ;
1675 TXNLongRect olddestRect ;
1676 TXNGetRectBounds( m_txn , &oldviewRect , &olddestRect , NULL ) ;
1677
1678 Rect viewRect = { m_txnControlBounds.top, m_txnControlBounds.left,
1679 m_txnControlBounds.bottom - ( m_sbHorizontal ? 14 : 0 ) ,
1680 m_txnControlBounds.right - ( m_sbVertical ? 14 : 0 ) } ;
1681 TXNLongRect destRect = { m_txnControlBounds.top, m_txnControlBounds.left,
1682 m_txnControlBounds.bottom - ( m_sbHorizontal ? 14 : 0 ) ,
1683 m_txnControlBounds.right - ( m_sbVertical ? 14 : 0 ) } ;
1684
1685 if ( olddestRect.right >= 10000 )
1686 destRect.right = destRect.left + 32000 ;
1687
1688 if ( olddestRect.bottom >= 0x20000000 )
1689 destRect.bottom = destRect.top + 0x40000000 ;
1690
1691 SectRect( &viewRect , &visBounds , &viewRect ) ;
1692 TXNSetRectBounds( m_txn , &viewRect , &destRect , true ) ;
1693
1694#if 0
1695 TXNSetFrameBounds(
1696 m_txn,
1697 m_txnControlBounds.top,
1698 m_txnControlBounds.left,
1699 m_txnControlBounds.bottom - (m_sbHorizontal ? 14 : 0),
1700 m_txnControlBounds.right - (m_sbVertical ? 14 : 0),
1701 m_txnFrameID );
1702#endif
1703
1704 // the SetFrameBounds method under Classic sometimes does not correctly scroll a selection into sight after a
1705 // movement, therefore we have to force it
1706
1707 // this problem has been reported in OSX as well, so we use this here once again
1708
1709 TXNLongRect textRect ;
1710 TXNGetRectBounds( m_txn , NULL , NULL , &textRect ) ;
1711 if ( textRect.left < m_txnControlBounds.left )
1712 TXNShowSelection( m_txn , kTXNShowStart ) ;
1713 }
1714}
1715
b2680ced 1716void wxMacMLTEClassicControl::Move(int x, int y, int width, int height)
489468fe 1717{
b2680ced 1718 wxMacControl::Move(x,y,width,height) ;
489468fe
SC
1719 MacUpdatePosition() ;
1720}
1721
1722void wxMacMLTEClassicControl::MacControlUserPaneDrawProc(wxInt16 WXUNUSED(thePart))
1723{
1724 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
1725 if ( textctrl == NULL )
1726 return ;
1727
1728 if ( textctrl->IsShownOnScreen() )
1729 {
1730 wxMacWindowClipper clipper( textctrl ) ;
1731 TXNDraw( m_txn , NULL ) ;
1732 }
1733}
1734
1735wxInt16 wxMacMLTEClassicControl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
1736{
1737 Point where = { y , x } ;
1738 ControlPartCode result = kControlNoPart;
1739
1740 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference( m_controlRef );
1741 if ( (textctrl != NULL) && textctrl->IsShownOnScreen() )
1742 {
1743 if (PtInRect( where, &m_txnControlBounds ))
1744 {
1745 result = kControlEditTextPart ;
1746 }
1747 else
1748 {
1749 // sometimes we get the coords also in control local coordinates, therefore test again
1750 int x = 0 , y = 0 ;
1751 textctrl->MacClientToRootWindow( &x , &y ) ;
1752 where.h += x ;
1753 where.v += y ;
1754
1755 if (PtInRect( where, &m_txnControlBounds ))
1756 result = kControlEditTextPart ;
1757 }
1758 }
1759
1760 return result;
1761}
1762
1763wxInt16 wxMacMLTEClassicControl::MacControlUserPaneTrackingProc( wxInt16 x, wxInt16 y, void* WXUNUSED(actionProc) )
1764{
1765 ControlPartCode result = kControlNoPart;
1766
1767 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference( m_controlRef );
1768 if ( (textctrl != NULL) && textctrl->IsShownOnScreen() )
1769 {
1770 Point startPt = { y , x } ;
1771
1772 // for compositing, we must convert these into toplevel window coordinates, because hittesting expects them
1773 int x = 0 , y = 0 ;
1774 textctrl->MacClientToRootWindow( &x , &y ) ;
1775 startPt.h += x ;
1776 startPt.v += y ;
1777
1778 switch (MacControlUserPaneHitTestProc( startPt.h , startPt.v ))
1779 {
1780 case kControlEditTextPart :
1781 {
1782 wxMacWindowClipper clipper( textctrl ) ;
1783 EventRecord rec ;
1784
1785 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
1786 TXNClick( m_txn, &rec );
1787 }
1788 break;
1789
1790 default :
1791 break;
1792 }
1793 }
1794
1795 return result;
1796}
1797
1798void wxMacMLTEClassicControl::MacControlUserPaneIdleProc()
1799{
1800 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
1801 if ( textctrl == NULL )
1802 return ;
1803
1804 if (textctrl->IsShownOnScreen())
1805 {
1806 if (IsControlActive(m_controlRef))
1807 {
1808 Point mousep;
1809
1810 wxMacWindowClipper clipper( textctrl ) ;
1811 GetMouse(&mousep);
1812
1813 TXNIdle(m_txn);
1814
1815 if (PtInRect(mousep, &m_txnControlBounds))
1816 {
1817 RgnHandle theRgn = NewRgn();
1818 RectRgn(theRgn, &m_txnControlBounds);
1819 TXNAdjustCursor(m_txn, theRgn);
1820 DisposeRgn(theRgn);
1821 }
1822 }
1823 }
1824}
1825
1826wxInt16 wxMacMLTEClassicControl::MacControlUserPaneKeyDownProc (wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
1827{
1828 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
1829 if ( textctrl == NULL )
1830 return kControlNoPart;
1831
1832 wxMacWindowClipper clipper( textctrl ) ;
1833
1834 EventRecord ev ;
1835 memset( &ev , 0 , sizeof( ev ) ) ;
1836 ev.what = keyDown ;
1837 ev.modifiers = modifiers ;
1838 ev.message = ((keyCode << 8) & keyCodeMask) | (charCode & charCodeMask);
1839 TXNKeyDown( m_txn , &ev );
1840
1841 return kControlEntireControl;
1842}
1843
1844void wxMacMLTEClassicControl::MacControlUserPaneActivateProc(bool activating)
1845{
1846 MacActivatePaneText( activating );
1847}
1848
1849wxInt16 wxMacMLTEClassicControl::MacControlUserPaneFocusProc(wxInt16 action)
1850{
1851 ControlPartCode focusResult = kControlFocusNoPart;
1852
1853 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
1854 if ( textctrl == NULL )
1855 return focusResult;
1856
1857 wxMacWindowClipper clipper( textctrl ) ;
1858
1859 ControlRef controlFocus = NULL ;
1860 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
1861 bool wasFocused = ( controlFocus == m_controlRef ) ;
1862
1863 switch (action)
1864 {
1865 case kControlFocusPrevPart:
1866 case kControlFocusNextPart:
1867 MacFocusPaneText( !wasFocused );
1868 focusResult = (!wasFocused ? (ControlPartCode) kControlEditTextPart : (ControlPartCode) kControlFocusNoPart);
1869 break;
1870
1871 case kControlFocusNoPart:
1872 default:
1873 MacFocusPaneText( false );
1874 focusResult = kControlFocusNoPart;
1875 break;
1876 }
1877
1878 return focusResult;
1879}
1880
1881void wxMacMLTEClassicControl::MacControlUserPaneBackgroundProc( void *WXUNUSED(info) )
1882{
1883}
1884
1885wxMacMLTEClassicControl::wxMacMLTEClassicControl( wxTextCtrl *wxPeer,
1886 const wxString& str,
1887 const wxPoint& pos,
1888 const wxSize& size, long style )
1889 : wxMacMLTEControl( wxPeer )
1890{
1891 m_font = wxPeer->GetFont() ;
1892 m_windowStyle = style ;
1893 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
1894
1895 short featureSet =
1896 kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
1897 | kControlWantsActivate | kControlHandlesTracking
1898// | kControlHasSpecialBackground
1899 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
1900
1901 OSStatus err = ::CreateUserPaneControl(
1902 MAC_WXHWND(wxPeer->GetParent()->MacGetTopLevelWindowRef()),
1903 &bounds, featureSet, &m_controlRef );
1904 verify_noerr( err );
1905
1906 DoCreate();
1907
1908 AdjustCreationAttributes( *wxWHITE , true ) ;
1909
1910 MacSetObjectVisibility( wxPeer->IsShownOnScreen() ) ;
1911
1912 {
1913 wxString st = str ;
1914 wxMacConvertNewlines10To13( &st ) ;
b2680ced 1915 wxMacWindowClipper clipper( GetWXPeer() ) ;
489468fe
SC
1916 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
1917 TXNSetSelection( m_txn, 0, 0 ) ;
1918 }
1919}
1920
1921wxMacMLTEClassicControl::~wxMacMLTEClassicControl()
1922{
1923 TXNDeleteObject( m_txn );
1924 m_txn = NULL ;
1925}
1926
1927void wxMacMLTEClassicControl::VisibilityChanged(bool shown)
1928{
1929 MacSetObjectVisibility( shown ) ;
1930 wxMacControl::VisibilityChanged( shown ) ;
1931}
1932
1933void wxMacMLTEClassicControl::SuperChangedPosition()
1934{
1935 MacUpdatePosition() ;
1936 wxMacControl::SuperChangedPosition() ;
1937}
1938
1939ControlUserPaneDrawUPP gTPDrawProc = NULL;
1940ControlUserPaneHitTestUPP gTPHitProc = NULL;
1941ControlUserPaneTrackingUPP gTPTrackProc = NULL;
1942ControlUserPaneIdleUPP gTPIdleProc = NULL;
1943ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
1944ControlUserPaneActivateUPP gTPActivateProc = NULL;
1945ControlUserPaneFocusUPP gTPFocusProc = NULL;
1946
1947static pascal void wxMacControlUserPaneDrawProc(ControlRef control, SInt16 part)
1948{
b2680ced 1949 wxTextCtrl *textCtrl = wxDynamicCast( wxFindWindowFromWXWidget( (WXWidget) control) , wxTextCtrl ) ;
489468fe
SC
1950 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
1951 if ( win )
1952 win->MacControlUserPaneDrawProc( part ) ;
1953}
1954
1955static pascal ControlPartCode wxMacControlUserPaneHitTestProc(ControlRef control, Point where)
1956{
b2680ced 1957 wxTextCtrl *textCtrl = wxDynamicCast( wxFindWindowFromWXWidget( (WXWidget) control) , wxTextCtrl ) ;
489468fe
SC
1958 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
1959 if ( win )
1960 return win->MacControlUserPaneHitTestProc( where.h , where.v ) ;
1961 else
1962 return kControlNoPart ;
1963}
1964
1965static pascal ControlPartCode wxMacControlUserPaneTrackingProc(ControlRef control, Point startPt, ControlActionUPP actionProc)
1966{
b2680ced 1967 wxTextCtrl *textCtrl = wxDynamicCast( wxFindWindowFromWXWidget( (WXWidget) control) , wxTextCtrl ) ;
489468fe
SC
1968 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
1969 if ( win )
1970 return win->MacControlUserPaneTrackingProc( startPt.h , startPt.v , (void*) actionProc ) ;
1971 else
1972 return kControlNoPart ;
1973}
1974
1975static pascal void wxMacControlUserPaneIdleProc(ControlRef control)
1976{
b2680ced 1977 wxTextCtrl *textCtrl = wxDynamicCast( wxFindWindowFromWXWidget((WXWidget) control) , wxTextCtrl ) ;
489468fe
SC
1978 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
1979 if ( win )
1980 win->MacControlUserPaneIdleProc() ;
1981}
1982
1983static pascal ControlPartCode wxMacControlUserPaneKeyDownProc(ControlRef control, SInt16 keyCode, SInt16 charCode, SInt16 modifiers)
1984{
b2680ced 1985 wxTextCtrl *textCtrl = wxDynamicCast( wxFindWindowFromWXWidget((WXWidget) control) , wxTextCtrl ) ;
489468fe
SC
1986 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
1987 if ( win )
1988 return win->MacControlUserPaneKeyDownProc( keyCode, charCode, modifiers ) ;
1989 else
1990 return kControlNoPart ;
1991}
1992
1993static pascal void wxMacControlUserPaneActivateProc(ControlRef control, Boolean activating)
1994{
b2680ced 1995 wxTextCtrl *textCtrl = wxDynamicCast( wxFindWindowFromWXWidget( (WXWidget)control) , wxTextCtrl ) ;
489468fe
SC
1996 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
1997 if ( win )
1998 win->MacControlUserPaneActivateProc( activating ) ;
1999}
2000
2001static pascal ControlPartCode wxMacControlUserPaneFocusProc(ControlRef control, ControlFocusPart action)
2002{
b2680ced 2003 wxTextCtrl *textCtrl = wxDynamicCast( wxFindWindowFromWXWidget((WXWidget) control) , wxTextCtrl ) ;
489468fe
SC
2004 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2005 if ( win )
2006 return win->MacControlUserPaneFocusProc( action ) ;
2007 else
2008 return kControlNoPart ;
2009}
2010
2011#if 0
2012static pascal void wxMacControlUserPaneBackgroundProc(ControlRef control, ControlBackgroundPtr info)
2013{
b2680ced 2014 wxTextCtrl *textCtrl = wxDynamicCast( wxFindWindowFromWXWidget(control) , wxTextCtrl ) ;
489468fe
SC
2015 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2016 if ( win )
2017 win->MacControlUserPaneBackgroundProc(info) ;
2018}
2019#endif
2020
2021// TXNRegisterScrollInfoProc
2022
2023OSStatus wxMacMLTEClassicControl::DoCreate()
2024{
2025 Rect bounds;
2026 OSStatus err = noErr ;
2027
2028 // set up our globals
2029 if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(wxMacControlUserPaneDrawProc);
2030 if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(wxMacControlUserPaneHitTestProc);
2031 if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(wxMacControlUserPaneTrackingProc);
2032 if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(wxMacControlUserPaneIdleProc);
2033 if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(wxMacControlUserPaneKeyDownProc);
2034 if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(wxMacControlUserPaneActivateProc);
2035 if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(wxMacControlUserPaneFocusProc);
2036
2037 if (gTXNScrollInfoProc == NULL ) gTXNScrollInfoProc = NewTXNScrollInfoUPP(TXNScrollInfoProc) ;
2038 if (gTXNScrollActionProc == NULL ) gTXNScrollActionProc = NewControlActionUPP(TXNScrollActionProc) ;
2039
2040 // set the initial settings for our private data
2041
2042 m_txnWindow = GetControlOwner(m_controlRef);
2043 m_txnPort = (GrafPtr) GetWindowPort(m_txnWindow);
2044
2045 // set up the user pane procedures
2046 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
2047 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
2048 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
2049 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
2050 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
2051 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
2052 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
2053
2054 // calculate the rectangles used by the control
2055 GetRectInWindowCoords( &bounds );
2056
2057 m_txnControlBounds = bounds ;
2058 m_txnVisBounds = bounds ;
2059
2060 CGrafPtr origPort ;
2061 GDHandle origDev ;
2062
2063 GetGWorld( &origPort, &origDev ) ;
2064 SetPort( m_txnPort );
2065
2066 // create the new edit field
2067 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( m_windowStyle );
2068
2069 // the scrollbars are not correctly embedded but are inserted at the root:
2070 // this gives us problems as we have erratic redraws even over the structure area
2071
2072 m_sbHorizontal = 0 ;
2073 m_sbVertical = 0 ;
2074 m_lastHorizontalValue = 0 ;
2075 m_lastVerticalValue = 0 ;
2076
2077 Rect sb = { 0 , 0 , 0 , 0 } ;
2078 if ( frameOptions & kTXNWantVScrollBarMask )
2079 {
2080 CreateScrollBarControl( m_txnWindow, &sb, 0, 0, 100, 1, true, gTXNScrollActionProc, &m_sbVertical );
2081 SetControlReference( m_sbVertical, (SInt32)this );
2082 SetControlAction( m_sbVertical, gTXNScrollActionProc );
2083 ShowControl( m_sbVertical );
2084 EmbedControl( m_sbVertical , m_controlRef );
2085 frameOptions &= ~kTXNWantVScrollBarMask;
2086 }
2087
2088 if ( frameOptions & kTXNWantHScrollBarMask )
2089 {
2090 CreateScrollBarControl( m_txnWindow, &sb, 0, 0, 100, 1, true, gTXNScrollActionProc, &m_sbHorizontal );
2091 SetControlReference( m_sbHorizontal, (SInt32)this );
2092 SetControlAction( m_sbHorizontal, gTXNScrollActionProc );
2093 ShowControl( m_sbHorizontal );
2094 EmbedControl( m_sbHorizontal, m_controlRef );
2095 frameOptions &= ~(kTXNWantHScrollBarMask | kTXNDrawGrowIconMask);
2096 }
2097
2098 err = TXNNewObject(
2099 NULL, m_txnWindow, &bounds, frameOptions,
2100 kTXNTextEditStyleFrameType, kTXNTextensionFile, kTXNSystemDefaultEncoding,
2101 &m_txn, &m_txnFrameID, NULL );
2102 verify_noerr( err );
2103
2104#if 0
2105 TXNControlTag iControlTags[] = { kTXNUseCarbonEvents };
2106 TXNControlData iControlData[] = { { (UInt32)&cInfo } };
2107 int toptag = WXSIZEOF( iControlTags ) ;
2108 TXNCarbonEventInfo cInfo ;
2109 cInfo.useCarbonEvents = false ;
2110 cInfo.filler = 0 ;
2111 cInfo.flags = 0 ;
2112 cInfo.fDictionary = NULL ;
2113
2114 verify_noerr( TXNSetTXNObjectControls( m_txn, false, toptag, iControlTags, iControlData ) );
2115#endif
2116
2117 TXNRegisterScrollInfoProc( m_txn, gTXNScrollInfoProc, (SInt32)this );
2118
2119 SetGWorld( origPort , origDev ) ;
2120
2121 return err;
2122}
2123#endif
2124
2125// ----------------------------------------------------------------------------
2126// MLTE control implementation (OSX part)
2127// ----------------------------------------------------------------------------
2128
2129// tiger multi-line textcontrols with no CR in the entire content
2130// don't scroll automatically, so we need a hack.
2131// This attempt only works 'before' the key (ie before CallNextEventHandler)
2132// is processed, thus the scrolling always occurs one character too late, but
2133// better than nothing ...
2134
2135static const EventTypeSpec eventList[] =
2136{
2137 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
2138} ;
2139
2140static pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
2141{
2142 OSStatus result = eventNotHandledErr ;
2143 wxMacMLTEHIViewControl* focus = (wxMacMLTEHIViewControl*) data ;
2144
2145 switch ( GetEventKind( event ) )
2146 {
2147 case kEventTextInputUnicodeForKeyEvent :
2148 {
2149 TXNOffset from , to ;
2150 TXNGetSelection( focus->GetTXNObject() , &from , &to ) ;
2151 if ( from == to )
2152 TXNShowSelection( focus->GetTXNObject() , kTXNShowStart );
2153 result = CallNextEventHandler(handler,event);
2154 break;
2155 }
2156 default:
2157 break ;
2158 }
2159
2160 return result ;
2161}
2162
2163static pascal OSStatus wxMacTextControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
2164{
2165 OSStatus result = eventNotHandledErr ;
2166
2167 switch ( GetEventClass( event ) )
2168 {
2169 case kEventClassTextInput :
2170 result = wxMacUnicodeTextEventHandler( handler , event , data ) ;
2171 break ;
2172
2173 default :
2174 break ;
2175 }
2176 return result ;
2177}
2178
2179DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacTextControlEventHandler )
2180
2181wxMacMLTEHIViewControl::wxMacMLTEHIViewControl( wxTextCtrl *wxPeer,
2182 const wxString& str,
2183 const wxPoint& pos,
2184 const wxSize& size, long style ) : wxMacMLTEControl( wxPeer )
2185{
2186 m_font = wxPeer->GetFont() ;
2187 m_windowStyle = style ;
2188 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
2189 wxString st = str ;
2190 wxMacConvertNewlines10To13( &st ) ;
2191
2192 HIRect hr = {
2193 { bounds.left , bounds.top },
2194 { bounds.right - bounds.left, bounds.bottom - bounds.top } } ;
2195
2196 m_scrollView = NULL ;
2197 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( style ) ;
2198 if (( frameOptions & (kTXNWantVScrollBarMask | kTXNWantHScrollBarMask)) || (frameOptions &kTXNSingleLineOnlyMask))
2199 {
2200 if ( frameOptions & (kTXNWantVScrollBarMask | kTXNWantHScrollBarMask) )
2201 {
2202 HIScrollViewCreate(
2203 (frameOptions & kTXNWantHScrollBarMask ? kHIScrollViewOptionsHorizScroll : 0)
2204 | (frameOptions & kTXNWantVScrollBarMask ? kHIScrollViewOptionsVertScroll : 0) ,
2205 &m_scrollView ) ;
2206 }
2207 else
2208 {
2209 HIScrollViewCreate(kHIScrollViewOptionsVertScroll,&m_scrollView);
2210 HIScrollViewSetScrollBarAutoHide(m_scrollView,true);
2211 }
2212
2213 HIViewSetFrame( m_scrollView, &hr );
2214 HIViewSetVisible( m_scrollView, true );
2215 }
2216
2217 m_textView = NULL ;
2218 HITextViewCreate( NULL , 0, frameOptions , &m_textView ) ;
2219 m_txn = HITextViewGetTXNObject( m_textView ) ;
2220 HIViewSetVisible( m_textView , true ) ;
2221 if ( m_scrollView )
2222 {
2223 HIViewAddSubview( m_scrollView , m_textView ) ;
2224 m_controlRef = m_scrollView ;
b2680ced 2225 wxMacControl::MacInstallEventHandler( m_textView, wxPeer ) ;
489468fe
SC
2226 }
2227 else
2228 {
2229 HIViewSetFrame( m_textView, &hr );
2230 m_controlRef = m_textView ;
2231 }
2232
2233 AdjustCreationAttributes( *wxWHITE , true ) ;
2234#ifndef __LP64__
b2680ced 2235 wxMacWindowClipper c( GetWXPeer() ) ;
489468fe
SC
2236#endif
2237 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
2238
2239 TXNSetSelection( m_txn, 0, 0 );
2240 TXNShowSelection( m_txn, kTXNShowStart );
2241
b2680ced 2242 ::InstallControlEventHandler( m_textView , GetwxMacTextControlEventHandlerUPP(),
489468fe
SC
2243 GetEventTypeCount(eventList), eventList, this,
2244 NULL);
2245}
2246
2247wxMacMLTEHIViewControl::~wxMacMLTEHIViewControl()
2248{
2249}
2250
2251OSStatus wxMacMLTEHIViewControl::SetFocus( ControlFocusPart focusPart )
2252{
2253 return SetKeyboardFocus( GetControlOwner( m_textView ), m_textView, focusPart ) ;
2254}
2255
2256bool wxMacMLTEHIViewControl::HasFocus() const
2257{
2258 ControlRef control ;
2259 if ( GetUserFocusWindow() == NULL )
2260 return false;
2261
2262 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
2263 return control == m_textView ;
2264}
2265
2266void wxMacMLTEHIViewControl::SetBackgroundColour(const wxColour& col )
2267{
2268 HITextViewSetBackgroundColor( m_textView, col.GetPixel() );
2269}
2270
2271#endif // wxUSE_TEXTCTRL