hacking around a missed-scroll bug in multi-line text fields in Tiger, in case there...
[wxWidgets.git] / src / mac / carbon / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/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 // 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 #endif
26
27 #ifdef __DARWIN__
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #else
31 #include <stat.h>
32 #endif
33
34 #include "wx/msgdlg.h"
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/toplevel.h"
45 #include "wx/settings.h"
46 #include "wx/filefn.h"
47 #include "wx/sysopt.h"
48
49 #if defined(__BORLANDC__) && !defined(__WIN32__)
50 #include <alloc.h>
51 #elif !defined(__MWERKS__) && !defined(__GNUWIN32) && !defined(__DARWIN__)
52 #include <malloc.h>
53 #endif
54
55 #ifndef __DARWIN__
56 #include <Scrap.h>
57 #endif
58
59 #ifndef __DARWIN__
60 #include <MacTextEditor.h>
61 #include <ATSUnicode.h>
62 #include <TextCommon.h>
63 #include <TextEncodingConverter.h>
64 #endif
65
66 #include "wx/mac/uma.h"
67
68
69 // if this is set to 1 then under OSX 10.2 the 'classic' MLTE implementation will be used
70 // if set to 0 then the unicode textctrl will be used
71 #ifndef wxMAC_AWAYS_USE_MLTE
72 #define wxMAC_AWAYS_USE_MLTE 1
73 #endif
74
75 #ifndef __WXMAC_OSX__
76 enum
77 {
78 kTXNVisibilityTag = 'visb' // set the visibility state of the object
79 };
80 #endif
81
82
83 class wxMacFunctor
84 {
85 public :
86 wxMacFunctor() {}
87 virtual ~wxMacFunctor() {}
88
89 virtual void* operator()() = 0 ;
90
91 static void* CallBackProc( void *param )
92 {
93 wxMacFunctor* f = (wxMacFunctor*) param ;
94 void *result = (*f)() ;
95 return result ;
96 }
97 } ;
98
99 template<typename classtype, typename param1type>
100
101 class wxMacObjectFunctor1 : public wxMacFunctor
102 {
103 typedef void (classtype::*function)( param1type p1 ) ;
104 typedef void (classtype::*ref_function)( const param1type& p1 ) ;
105 public :
106 wxMacObjectFunctor1( classtype *obj , function f , param1type p1 ) :
107 wxMacFunctor()
108 {
109 m_object = obj ;
110 m_function = f ;
111 m_param1 = p1 ;
112 }
113
114 wxMacObjectFunctor1( classtype *obj , ref_function f , param1type p1 ) :
115 wxMacFunctor()
116 {
117 m_object = obj ;
118 m_refFunction = f ;
119 m_param1 = p1 ;
120 }
121
122 ~wxMacObjectFunctor1() {}
123
124 virtual void* operator()()
125 {
126 (m_object->*m_function)( m_param1 ) ;
127 return NULL ;
128 }
129
130 private :
131 classtype* m_object ;
132 param1type m_param1 ;
133 union
134 {
135 function m_function ;
136 ref_function m_refFunction ;
137 } ;
138 } ;
139
140 template<typename classtype, typename param1type>
141 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
142 {
143 wxMacObjectFunctor1<classtype, param1type> params(object, function, p1) ;
144 void *result =
145 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
146 return result ;
147 }
148
149 template<typename classtype, typename param1type>
150 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
151 {
152 wxMacObjectFunctor1<classtype,param1type> params(object, function, p1) ;
153 void *result =
154 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
155 return result ;
156 }
157
158 template<typename classtype, typename param1type>
159 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
160 {
161 wxMutexGuiLeave() ;
162 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
163 wxMutexGuiEnter() ;
164 return result ;
165 }
166
167 template<typename classtype, typename param1type>
168 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
169 {
170 wxMutexGuiLeave() ;
171 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
172 wxMutexGuiEnter() ;
173 return result ;
174 }
175
176 // common interface for all implementations
177 class wxMacTextControl : public wxMacControl
178 {
179 public :
180 wxMacTextControl( wxTextCtrl *peer ) ;
181 ~wxMacTextControl() ;
182
183 virtual wxString GetStringValue() const = 0 ;
184 virtual void SetStringValue( const wxString &val ) = 0 ;
185 virtual void SetSelection( long from, long to ) = 0 ;
186 virtual void GetSelection( long* from, long* to ) const = 0 ;
187 virtual void WriteText( const wxString& str ) = 0 ;
188
189 virtual void SetStyle( long start, long end, const wxTextAttr& style ) ;
190 virtual void Copy() ;
191 virtual void Cut() ;
192 virtual void Paste() ;
193 virtual bool CanPaste() const ;
194 virtual void SetEditable( bool editable ) ;
195 virtual wxTextPos GetLastPosition() const ;
196 virtual void Replace( long from, long to, const wxString &str ) ;
197 virtual void Remove( long from, long to ) ;
198
199
200 virtual bool HasOwnContextMenu() const
201 { return false ; }
202
203 virtual bool SetupCursor( const wxPoint& pt )
204 { return false ; }
205
206 virtual void Clear() ;
207 virtual bool CanUndo() const;
208 virtual void Undo() ;
209 virtual bool CanRedo() const;
210 virtual void Redo() ;
211 virtual int GetNumberOfLines() const ;
212 virtual long XYToPosition(long x, long y) const;
213 virtual bool PositionToXY(long pos, long *x, long *y) const ;
214 virtual void ShowPosition(long WXUNUSED(pos)) ;
215 virtual int GetLineLength(long lineNo) const ;
216 virtual wxString GetLineText(long lineNo) const ;
217
218 #ifndef __WXMAC_OSX__
219 virtual void MacControlUserPaneDrawProc(wxInt16 part) = 0 ;
220 virtual wxInt16 MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y) = 0 ;
221 virtual wxInt16 MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc) = 0 ;
222 virtual void MacControlUserPaneIdleProc() = 0 ;
223 virtual wxInt16 MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers) = 0 ;
224 virtual void MacControlUserPaneActivateProc(bool activating) = 0 ;
225 virtual wxInt16 MacControlUserPaneFocusProc(wxInt16 action) = 0 ;
226 virtual void MacControlUserPaneBackgroundProc(void* info) = 0 ;
227 #endif
228 } ;
229
230 // common parts for implementations based on MLTE
231
232 class wxMacMLTEControl : public wxMacTextControl
233 {
234 public :
235 wxMacMLTEControl( wxTextCtrl *peer ) ;
236
237 virtual wxString GetStringValue() const ;
238 virtual void SetStringValue( const wxString &str ) ;
239
240 static TXNFrameOptions FrameOptionsFromWXStyle( long wxStyle ) ;
241
242 void AdjustCreationAttributes( const wxColour& background, bool visible ) ;
243
244 virtual void SetFont( const wxFont & font, const wxColour& foreground, long windowStyle ) ;
245 virtual void SetBackground( const wxBrush &brush ) ;
246 virtual void SetStyle( long start, long end, const wxTextAttr& style ) ;
247 virtual void Copy() ;
248 virtual void Cut() ;
249 virtual void Paste() ;
250 virtual bool CanPaste() const ;
251 virtual void SetEditable( bool editable ) ;
252 virtual wxTextPos GetLastPosition() const ;
253 virtual void Replace( long from, long to, const wxString &str ) ;
254 virtual void Remove( long from, long to ) ;
255 virtual void GetSelection( long* from, long* to ) const ;
256 virtual void SetSelection( long from, long to ) ;
257
258 virtual void WriteText( const wxString& str ) ;
259
260 virtual bool HasOwnContextMenu() const
261 {
262 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
263 if ( UMAGetSystemVersion() >= 0x1040 )
264 {
265 TXNCommandEventSupportOptions options ;
266 TXNGetCommandEventSupport( m_txn , & options ) ;
267 return options & kTXNSupportEditCommandProcessing ;
268 }
269 #endif
270
271 return false ;
272 }
273
274 virtual void Clear() ;
275
276 virtual bool CanUndo() const ;
277 virtual void Undo() ;
278 virtual bool CanRedo() const;
279 virtual void Redo() ;
280 virtual int GetNumberOfLines() const ;
281 virtual long XYToPosition(long x, long y) const ;
282 virtual bool PositionToXY(long pos, long *x, long *y) const ;
283 virtual void ShowPosition( long pos ) ;
284 virtual int GetLineLength(long lineNo) const ;
285 virtual wxString GetLineText(long lineNo) const ;
286
287 void SetTXNData( const wxString& st , TXNOffset start , TXNOffset end ) ;
288 TXNObject GetTXNObject() { return m_txn ; }
289
290 protected :
291 void TXNSetAttribute( const wxTextAttr& style , long from , long to ) ;
292
293 TXNObject m_txn ;
294 } ;
295
296 #if TARGET_API_MAC_OSX
297
298 // implementation available under OSX
299
300 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
301
302 class wxMacMLTEHIViewControl : public wxMacMLTEControl
303 {
304 public :
305 wxMacMLTEHIViewControl( wxTextCtrl *wxPeer,
306 const wxString& str,
307 const wxPoint& pos,
308 const wxSize& size, long style ) ;
309 ~wxMacMLTEHIViewControl() ;
310
311 virtual OSStatus SetFocus( ControlFocusPart focusPart ) ;
312 virtual bool HasFocus() const ;
313 virtual void SetBackground( const wxBrush &brush) ;
314
315 protected :
316 HIViewRef m_scrollView ;
317 HIViewRef m_textView ;
318 EventHandlerRef m_textEventHandlerRef ;
319 };
320
321 #endif
322
323 class wxMacUnicodeTextControl : public wxMacTextControl
324 {
325 public :
326 wxMacUnicodeTextControl( wxTextCtrl *wxPeer,
327 const wxString& str,
328 const wxPoint& pos,
329 const wxSize& size, long style ) ;
330 ~wxMacUnicodeTextControl();
331
332 virtual void VisibilityChanged(bool shown);
333 virtual wxString GetStringValue() const ;
334 virtual void SetStringValue( const wxString &str) ;
335 virtual void Copy();
336 virtual void Cut();
337 virtual void Paste();
338 virtual bool CanPaste() const;
339 virtual void SetEditable(bool editable) ;
340 virtual void GetSelection( long* from, long* to) const ;
341 virtual void SetSelection( long from , long to ) ;
342 virtual void WriteText(const wxString& str) ;
343
344 protected :
345 // contains the tag for the content (is different for password and non-password controls)
346 OSType m_valueTag ;
347 };
348
349 #endif
350
351 // 'classic' MLTE implementation
352
353 class wxMacMLTEClassicControl : public wxMacMLTEControl
354 {
355 public :
356 wxMacMLTEClassicControl( wxTextCtrl *wxPeer,
357 const wxString& str,
358 const wxPoint& pos,
359 const wxSize& size, long style ) ;
360 ~wxMacMLTEClassicControl() ;
361
362 virtual void VisibilityChanged(bool shown) ;
363 virtual void SuperChangedPosition() ;
364
365 virtual void MacControlUserPaneDrawProc(wxInt16 part) ;
366 virtual wxInt16 MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y) ;
367 virtual wxInt16 MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc) ;
368 virtual void MacControlUserPaneIdleProc() ;
369 virtual wxInt16 MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers) ;
370 virtual void MacControlUserPaneActivateProc(bool activating) ;
371 virtual wxInt16 MacControlUserPaneFocusProc(wxInt16 action) ;
372 virtual void MacControlUserPaneBackgroundProc(void* info) ;
373
374 virtual bool SetupCursor( const wxPoint& WXUNUSED(pt) )
375 {
376 MacControlUserPaneIdleProc();
377 return true;
378 }
379
380 virtual void SetRect( Rect *r ) ;
381
382 protected :
383 OSStatus DoCreate();
384
385 void MacUpdatePosition() ;
386 void MacActivatePaneText(bool setActive) ;
387 void MacFocusPaneText(bool setFocus) ;
388 void MacSetObjectVisibility(bool vis) ;
389
390 private :
391 TXNFrameID m_txnFrameID ;
392 GrafPtr m_txnPort ;
393 WindowRef m_txnWindow ;
394 // bounds of the control as we last did set the txn frames
395 Rect m_txnControlBounds ;
396 Rect m_txnVisBounds ;
397
398 #ifdef __WXMAC_OSX__
399 static pascal void TXNScrollActionProc( ControlRef controlRef , ControlPartCode partCode ) ;
400 static pascal void TXNScrollInfoProc(
401 SInt32 iValue, SInt32 iMaximumValue,
402 TXNScrollBarOrientation iScrollBarOrientation, SInt32 iRefCon ) ;
403
404 ControlRef m_sbHorizontal ;
405 SInt32 m_lastHorizontalValue ;
406 ControlRef m_sbVertical ;
407 SInt32 m_lastVerticalValue ;
408 #endif
409 };
410
411
412 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
413
414 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
415 EVT_ERASE_BACKGROUND( wxTextCtrl::OnEraseBackground )
416 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
417 EVT_CHAR(wxTextCtrl::OnChar)
418 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
419 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
420 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
421 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
422 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
423 EVT_MENU(wxID_CLEAR, wxTextCtrl::OnDelete)
424 EVT_MENU(wxID_SELECTALL, wxTextCtrl::OnSelectAll)
425
426 EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu)
427
428 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
429 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
430 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
431 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
432 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
433 EVT_UPDATE_UI(wxID_CLEAR, wxTextCtrl::OnUpdateDelete)
434 EVT_UPDATE_UI(wxID_SELECTALL, wxTextCtrl::OnUpdateSelectAll)
435 END_EVENT_TABLE()
436
437
438 void wxTextCtrl::Init()
439 {
440 m_editable = true ;
441 m_dirty = false;
442
443 m_maxLength = 0;
444 m_privateContextMenu = NULL;
445 m_triggerOnSetValue = true ;
446 }
447
448 wxTextCtrl::~wxTextCtrl()
449 {
450 delete m_privateContextMenu;
451 }
452
453 bool wxTextCtrl::Create( wxWindow *parent,
454 wxWindowID id,
455 const wxString& str,
456 const wxPoint& pos,
457 const wxSize& size,
458 long style,
459 const wxValidator& validator,
460 const wxString& name )
461 {
462 m_macIsUserPane = false ;
463 m_editable = true ;
464
465 if ( ! (style & wxNO_BORDER) )
466 style = (style & ~wxBORDER_MASK) | wxSUNKEN_BORDER ;
467
468 if ( !wxTextCtrlBase::Create( parent, id, pos, size, style & ~(wxHSCROLL | wxVSCROLL), validator, name ) )
469 return false;
470
471 if ( m_windowStyle & wxTE_MULTILINE )
472 {
473 wxASSERT_MSG(
474 !(m_windowStyle & wxTE_PROCESS_ENTER),
475 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
476
477 m_windowStyle |= wxTE_PROCESS_ENTER;
478 style |= wxTE_PROCESS_ENTER ;
479 }
480
481 bool forceMLTE = false ;
482
483 #if wxUSE_SYSTEM_OPTIONS
484 if (wxSystemOptions::HasOption( wxMAC_TEXTCONTROL_USE_MLTE ) && (wxSystemOptions::GetOptionInt( wxMAC_TEXTCONTROL_USE_MLTE ) == 1))
485 {
486 forceMLTE = true ;
487 }
488 #endif
489
490 #ifdef __WXMAC_OSX__
491 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
492 if ( UMAGetSystemVersion() >= 0x1030 && !forceMLTE )
493 {
494 if ( m_windowStyle & wxTE_MULTILINE )
495 m_peer = new wxMacMLTEHIViewControl( this , str , pos , size , style ) ;
496 }
497 #endif
498
499 if ( !m_peer )
500 {
501 if ( !(m_windowStyle & wxTE_MULTILINE) && !forceMLTE )
502 m_peer = new wxMacUnicodeTextControl( this , str , pos , size , style ) ;
503 }
504 #endif
505
506 if ( !m_peer )
507 m_peer = new wxMacMLTEClassicControl( this , str , pos , size , style ) ;
508
509 MacPostControlCreate(pos, size) ;
510
511 // only now the embedding is correct and we can do a positioning update
512
513 MacSuperChangedPosition() ;
514
515 if ( m_windowStyle & wxTE_READONLY)
516 SetEditable( false ) ;
517
518 SetCursor( wxCursor( wxCURSOR_IBEAM ) ) ;
519
520 return true;
521 }
522
523 void wxTextCtrl::MacSuperChangedPosition()
524 {
525 wxWindow::MacSuperChangedPosition() ;
526 GetPeer()->SuperChangedPosition() ;
527 }
528
529 void wxTextCtrl::MacVisibilityChanged()
530 {
531 GetPeer()->VisibilityChanged( MacIsReallyShown() ) ;
532 }
533
534 void wxTextCtrl::MacEnabledStateChanged()
535 {
536 }
537
538 wxString wxTextCtrl::GetValue() const
539 {
540 return GetPeer()->GetStringValue() ;
541 }
542
543 void wxTextCtrl::GetSelection(long* from, long* to) const
544 {
545 GetPeer()->GetSelection( from , to ) ;
546 }
547
548 void wxTextCtrl::SetValue(const wxString& str)
549 {
550 // optimize redraws
551 if ( GetValue() == str )
552 return ;
553
554 GetPeer()->SetStringValue( str ) ;
555
556 if ( m_triggerOnSetValue )
557 {
558 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, m_windowId );
559 event.SetString( GetValue() );
560 event.SetEventObject( this );
561 GetEventHandler()->ProcessEvent( event );
562 }
563 }
564
565 void wxTextCtrl::SetMaxLength(unsigned long len)
566 {
567 m_maxLength = len ;
568 }
569
570 bool wxTextCtrl::SetFont( const wxFont& font )
571 {
572 if ( !wxTextCtrlBase::SetFont( font ) )
573 return false ;
574
575 GetPeer()->SetFont( font , GetForegroundColour() , GetWindowStyle() ) ;
576
577 return true ;
578 }
579
580 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
581 {
582 GetPeer()->SetStyle( start , end , style ) ;
583
584 return true ;
585 }
586
587 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
588 {
589 wxTextCtrlBase::SetDefaultStyle( style ) ;
590 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
591
592 return true ;
593 }
594
595 // Clipboard operations
596
597 void wxTextCtrl::Copy()
598 {
599 if (CanCopy())
600 GetPeer()->Copy() ;
601 }
602
603 void wxTextCtrl::Cut()
604 {
605 if (CanCut())
606 {
607 GetPeer()->Cut() ;
608
609 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, m_windowId );
610 event.SetEventObject( this );
611 GetEventHandler()->ProcessEvent( event );
612 }
613 }
614
615 void wxTextCtrl::Paste()
616 {
617 if (CanPaste())
618 {
619 GetPeer()->Paste() ;
620
621 // TODO: eventually we should add setting the default style again
622
623 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, m_windowId );
624 event.SetEventObject( this );
625 GetEventHandler()->ProcessEvent( event );
626 }
627 }
628
629 bool wxTextCtrl::CanCopy() const
630 {
631 // Can copy if there's a selection
632 long from, to;
633 GetSelection( &from, &to );
634
635 return (from != to);
636 }
637
638 bool wxTextCtrl::CanCut() const
639 {
640 if ( !IsEditable() )
641 return false;
642
643 // Can cut if there's a selection
644 long from, to;
645 GetSelection( &from, &to );
646
647 return (from != to);
648 }
649
650 bool wxTextCtrl::CanPaste() const
651 {
652 if (!IsEditable())
653 return false;
654
655 return GetPeer()->CanPaste() ;
656 }
657
658 void wxTextCtrl::SetEditable(bool editable)
659 {
660 if ( editable != m_editable )
661 {
662 m_editable = editable ;
663 GetPeer()->SetEditable( editable ) ;
664 }
665 }
666
667 void wxTextCtrl::SetInsertionPoint(long pos)
668 {
669 SetSelection( pos , pos ) ;
670 }
671
672 void wxTextCtrl::SetInsertionPointEnd()
673 {
674 wxTextPos pos = GetLastPosition();
675 SetInsertionPoint( pos );
676 }
677
678 long wxTextCtrl::GetInsertionPoint() const
679 {
680 long begin, end ;
681 GetSelection( &begin , &end ) ;
682
683 return begin ;
684 }
685
686 wxTextPos wxTextCtrl::GetLastPosition() const
687 {
688 return GetPeer()->GetLastPosition() ;
689 }
690
691 void wxTextCtrl::Replace(long from, long to, const wxString& str)
692 {
693 GetPeer()->Replace( from , to , str ) ;
694 }
695
696 void wxTextCtrl::Remove(long from, long to)
697 {
698 GetPeer()->Remove( from , to ) ;
699 }
700
701 void wxTextCtrl::SetSelection(long from, long to)
702 {
703 GetPeer()->SetSelection( from , to ) ;
704 }
705
706 bool wxTextCtrl::LoadFile(const wxString& file)
707 {
708 return wxTextCtrlBase::LoadFile( file );
709 }
710
711 void wxTextCtrl::WriteText(const wxString& str)
712 {
713 // TODO: this MPRemoting will be moved into a remoting peer proxy for any command
714 if ( !wxIsMainThread() )
715 {
716 // unfortunately CW 8 is not able to correctly deduce the template types,
717 // so we have to instantiate explicitly
718 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( this , &wxTextCtrl::WriteText , str ) ;
719
720 return ;
721 }
722
723 GetPeer()->WriteText( str ) ;
724 }
725
726 void wxTextCtrl::AppendText(const wxString& text)
727 {
728 SetInsertionPointEnd();
729 WriteText( text );
730 }
731
732 void wxTextCtrl::Clear()
733 {
734 GetPeer()->Clear() ;
735 }
736
737 bool wxTextCtrl::IsModified() const
738 {
739 return m_dirty;
740 }
741
742 bool wxTextCtrl::IsEditable() const
743 {
744 return IsEnabled() && m_editable ;
745 }
746
747 bool wxTextCtrl::AcceptsFocus() const
748 {
749 // we don't want focus if we can't be edited
750 return /*IsEditable() && */ wxControl::AcceptsFocus();
751 }
752
753 wxSize wxTextCtrl::DoGetBestSize() const
754 {
755 int wText, hText;
756
757 // these are the numbers from the HIG:
758 // we reduce them by the borders first
759 wText = 100 ;
760
761 switch ( m_windowVariant )
762 {
763 case wxWINDOW_VARIANT_NORMAL :
764 hText = 22 - 6 ;
765 break ;
766
767 case wxWINDOW_VARIANT_SMALL :
768 hText = 19 - 6 ;
769 break ;
770
771 case wxWINDOW_VARIANT_MINI :
772 hText = 15 - 6 ;
773 break ;
774
775 default :
776 hText = 22 - 6;
777 break ;
778 }
779
780 // as the above numbers have some free space around the text
781 // we get 5 lines like this anyway
782 if ( m_windowStyle & wxTE_MULTILINE )
783 hText *= 5 ;
784
785 if ( !HasFlag(wxNO_BORDER) )
786 hText += 6 ;
787
788 return wxSize(wText, hText);
789 }
790
791 // ----------------------------------------------------------------------------
792 // Undo/redo
793 // ----------------------------------------------------------------------------
794
795 void wxTextCtrl::Undo()
796 {
797 if (CanUndo())
798 GetPeer()->Undo() ;
799 }
800
801 void wxTextCtrl::Redo()
802 {
803 if (CanRedo())
804 GetPeer()->Redo() ;
805 }
806
807 bool wxTextCtrl::CanUndo() const
808 {
809 if ( !IsEditable() )
810 return false ;
811
812 return GetPeer()->CanUndo() ;
813 }
814
815 bool wxTextCtrl::CanRedo() const
816 {
817 if ( !IsEditable() )
818 return false ;
819
820 return GetPeer()->CanRedo() ;
821 }
822
823 void wxTextCtrl::MarkDirty()
824 {
825 m_dirty = true;
826 }
827
828 void wxTextCtrl::DiscardEdits()
829 {
830 m_dirty = false;
831 }
832
833 int wxTextCtrl::GetNumberOfLines() const
834 {
835 return GetPeer()->GetNumberOfLines() ;
836 }
837
838 long wxTextCtrl::XYToPosition(long x, long y) const
839 {
840 return GetPeer()->XYToPosition( x , y ) ;
841 }
842
843 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
844 {
845 return GetPeer()->PositionToXY( pos , x , y ) ;
846 }
847
848 void wxTextCtrl::ShowPosition(long pos)
849 {
850 return GetPeer()->ShowPosition(pos) ;
851 }
852
853 int wxTextCtrl::GetLineLength(long lineNo) const
854 {
855 return GetPeer()->GetLineLength(lineNo) ;
856 }
857
858 wxString wxTextCtrl::GetLineText(long lineNo) const
859 {
860 return GetPeer()->GetLineText(lineNo) ;
861 }
862
863 void wxTextCtrl::Command(wxCommandEvent & event)
864 {
865 SetValue(event.GetString());
866 ProcessCommand(event);
867 }
868
869 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
870 {
871 // By default, load the first file into the text window.
872 if (event.GetNumberOfFiles() > 0)
873 LoadFile( event.GetFiles()[0] );
874 }
875
876 void wxTextCtrl::OnEraseBackground(wxEraseEvent& event)
877 {
878 // all erasing should be done by the real mac control implementation
879 // while this is true for MLTE under classic, the HITextView is somehow
880 // transparent but background erase is not working correctly, so intercept
881 // things while we can...
882 event.Skip() ;
883 }
884
885 void wxTextCtrl::OnChar(wxKeyEvent& event)
886 {
887 int key = event.GetKeyCode() ;
888 bool eat_key = false ;
889
890 if ( key == 'a' && event.MetaDown() )
891 {
892 SelectAll() ;
893
894 return ;
895 }
896
897 if ( key == 'c' && event.MetaDown() )
898 {
899 if ( CanCopy() )
900 Copy() ;
901
902 return ;
903 }
904
905 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
906 !( key == WXK_RETURN && ( (m_windowStyle & wxTE_PROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
907 // && key != WXK_PAGEUP && key != WXK_PAGEDOWN && key != WXK_HOME && key != WXK_END
908 )
909 {
910 // eat it
911 return ;
912 }
913
914 // Check if we have reached the max # of chars (if it is set), but still
915 // allow navigation and deletion
916 if ( !IsMultiLine() && m_maxLength && GetValue().length() >= m_maxLength &&
917 key != WXK_LEFT && key != WXK_RIGHT && key != WXK_TAB &&
918 key != WXK_BACK && !( key == WXK_RETURN && (m_windowStyle & wxTE_PROCESS_ENTER) )
919 )
920 {
921 // eat it, we don't want to add more than allowed # of characters
922
923 // TODO: generate EVT_TEXT_MAXLEN()
924 return;
925 }
926
927 // assume that any key not processed yet is going to modify the control
928 m_dirty = true;
929
930 if ( key == 'v' && event.MetaDown() )
931 {
932 if ( CanPaste() )
933 Paste() ;
934
935 return ;
936 }
937
938 if ( key == 'x' && event.MetaDown() )
939 {
940 if ( CanCut() )
941 Cut() ;
942
943 return ;
944 }
945
946 switch ( key )
947 {
948 case WXK_RETURN:
949 if (m_windowStyle & wxTE_PROCESS_ENTER)
950 {
951 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
952 event.SetEventObject( this );
953 event.SetString( GetValue() );
954 if ( GetEventHandler()->ProcessEvent(event) )
955 return;
956 }
957
958 if ( !(m_windowStyle & wxTE_MULTILINE) )
959 {
960 wxWindow *parent = GetParent();
961 while ( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL )
962 {
963 parent = parent->GetParent() ;
964 }
965
966 if ( parent && parent->GetDefaultItem() )
967 {
968 wxButton *def = wxDynamicCast(parent->GetDefaultItem(), wxButton);
969 if ( def && def->IsEnabled() )
970 {
971 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
972 event.SetEventObject(def);
973 def->Command(event);
974
975 return ;
976 }
977 }
978
979 // this will make wxWidgets eat the ENTER key so that
980 // we actually prevent line wrapping in a single line text control
981 eat_key = true;
982 }
983 break;
984
985 case WXK_TAB:
986 if ( !(m_windowStyle & wxTE_PROCESS_TAB))
987 {
988 int flags = 0;
989 if (!event.ShiftDown())
990 flags |= wxNavigationKeyEvent::IsForward ;
991 if (event.ControlDown())
992 flags |= wxNavigationKeyEvent::WinChange ;
993 Navigate(flags);
994
995 return;
996 }
997 else
998 {
999 // This is necessary (don't know why);
1000 // otherwise the tab will not be inserted.
1001 WriteText(wxT("\t"));
1002 }
1003 break;
1004
1005 default:
1006 break;
1007 }
1008
1009 if (!eat_key)
1010 {
1011 // perform keystroke handling
1012 event.Skip(true) ;
1013 }
1014
1015 if ( ( key >= 0x20 && key < WXK_START ) ||
1016 key == WXK_RETURN ||
1017 key == WXK_DELETE ||
1018 key == WXK_BACK)
1019 {
1020 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1021 event1.SetEventObject( this );
1022 wxPostEvent( GetEventHandler(), event1 );
1023 }
1024 }
1025
1026 // ----------------------------------------------------------------------------
1027 // standard handlers for standard edit menu events
1028 // ----------------------------------------------------------------------------
1029
1030 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1031 {
1032 Cut();
1033 }
1034
1035 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1036 {
1037 Copy();
1038 }
1039
1040 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1041 {
1042 Paste();
1043 }
1044
1045 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1046 {
1047 Undo();
1048 }
1049
1050 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1051 {
1052 Redo();
1053 }
1054
1055 void wxTextCtrl::OnDelete(wxCommandEvent& WXUNUSED(event))
1056 {
1057 long from, to;
1058
1059 GetSelection( &from, &to );
1060 if (from != -1 && to != -1)
1061 Remove( from, to );
1062 }
1063
1064 void wxTextCtrl::OnSelectAll(wxCommandEvent& WXUNUSED(event))
1065 {
1066 SetSelection(-1, -1);
1067 }
1068
1069 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1070 {
1071 event.Enable( CanCut() );
1072 }
1073
1074 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1075 {
1076 event.Enable( CanCopy() );
1077 }
1078
1079 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1080 {
1081 event.Enable( CanPaste() );
1082 }
1083
1084 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1085 {
1086 event.Enable( CanUndo() );
1087 }
1088
1089 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1090 {
1091 event.Enable( CanRedo() );
1092 }
1093
1094 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent& event)
1095 {
1096 long from, to;
1097
1098 GetSelection( &from, &to );
1099 event.Enable( from != -1 && to != -1 && from != to && IsEditable() ) ;
1100 }
1101
1102 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event)
1103 {
1104 event.Enable(GetLastPosition() > 0);
1105 }
1106
1107 // CS: Context Menus only work with MLTE implementations or non-multiline HIViews at the moment
1108
1109 void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
1110 {
1111 if ( GetPeer()->HasOwnContextMenu() )
1112 {
1113 event.Skip() ;
1114 return ;
1115 }
1116
1117 if (m_privateContextMenu == NULL)
1118 {
1119 m_privateContextMenu = new wxMenu;
1120 m_privateContextMenu->Append(wxID_UNDO, _("&Undo"));
1121 m_privateContextMenu->Append(wxID_REDO, _("&Redo"));
1122 m_privateContextMenu->AppendSeparator();
1123 m_privateContextMenu->Append(wxID_CUT, _("Cu&t"));
1124 m_privateContextMenu->Append(wxID_COPY, _("&Copy"));
1125 m_privateContextMenu->Append(wxID_PASTE, _("&Paste"));
1126 m_privateContextMenu->Append(wxID_CLEAR, _("&Delete"));
1127 m_privateContextMenu->AppendSeparator();
1128 m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All"));
1129 }
1130
1131 if (m_privateContextMenu != NULL)
1132 PopupMenu(m_privateContextMenu);
1133 }
1134
1135 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1136 {
1137 if ( !GetPeer()->SetupCursor( pt ) )
1138 return wxWindow::MacSetupCursor( pt ) ;
1139 else
1140 return true ;
1141 }
1142
1143 #if !TARGET_API_MAC_OSX
1144
1145 // user pane implementation
1146
1147 void wxTextCtrl::MacControlUserPaneDrawProc(wxInt16 part)
1148 {
1149 GetPeer()->MacControlUserPaneDrawProc( part ) ;
1150 }
1151
1152 wxInt16 wxTextCtrl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
1153 {
1154 return GetPeer()->MacControlUserPaneHitTestProc( x , y ) ;
1155 }
1156
1157 wxInt16 wxTextCtrl::MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc)
1158 {
1159 return GetPeer()->MacControlUserPaneTrackingProc( x , y , actionProc ) ;
1160 }
1161
1162 void wxTextCtrl::MacControlUserPaneIdleProc()
1163 {
1164 GetPeer()->MacControlUserPaneIdleProc( ) ;
1165 }
1166
1167 wxInt16 wxTextCtrl::MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
1168 {
1169 return GetPeer()->MacControlUserPaneKeyDownProc( keyCode , charCode , modifiers ) ;
1170 }
1171
1172 void wxTextCtrl::MacControlUserPaneActivateProc(bool activating)
1173 {
1174 GetPeer()->MacControlUserPaneActivateProc( activating ) ;
1175 }
1176
1177 wxInt16 wxTextCtrl::MacControlUserPaneFocusProc(wxInt16 action)
1178 {
1179 return GetPeer()->MacControlUserPaneFocusProc( action ) ;
1180 }
1181
1182 void wxTextCtrl::MacControlUserPaneBackgroundProc(void* info)
1183 {
1184 GetPeer()->MacControlUserPaneBackgroundProc( info ) ;
1185 }
1186
1187 #endif
1188
1189 // ----------------------------------------------------------------------------
1190 // implementation base class
1191 // ----------------------------------------------------------------------------
1192
1193 wxMacTextControl::wxMacTextControl(wxTextCtrl* peer) :
1194 wxMacControl( peer )
1195 {
1196 }
1197
1198 wxMacTextControl::~wxMacTextControl()
1199 {
1200 }
1201
1202 void wxMacTextControl::SetStyle(long start, long end, const wxTextAttr& style)
1203 {
1204 }
1205
1206 void wxMacTextControl::Copy()
1207 {
1208 }
1209
1210 void wxMacTextControl::Cut()
1211 {
1212 }
1213
1214 void wxMacTextControl::Paste()
1215 {
1216 }
1217
1218 bool wxMacTextControl::CanPaste() const
1219 {
1220 return false ;
1221 }
1222
1223 void wxMacTextControl::SetEditable(bool editable)
1224 {
1225 }
1226
1227 wxTextPos wxMacTextControl::GetLastPosition() const
1228 {
1229 return GetStringValue().length() ;
1230 }
1231
1232 void wxMacTextControl::Replace( long from , long to , const wxString &val )
1233 {
1234 SetSelection( from , to ) ;
1235 WriteText( val ) ;
1236 }
1237
1238 void wxMacTextControl::Remove( long from , long to )
1239 {
1240 SetSelection( from , to ) ;
1241 WriteText( wxEmptyString) ;
1242 }
1243
1244 void wxMacTextControl::Clear()
1245 {
1246 SetStringValue( wxEmptyString ) ;
1247 }
1248
1249 bool wxMacTextControl::CanUndo() const
1250 {
1251 return false ;
1252 }
1253
1254 void wxMacTextControl::Undo()
1255 {
1256 }
1257
1258 bool wxMacTextControl::CanRedo() const
1259 {
1260 return false ;
1261 }
1262
1263 void wxMacTextControl::Redo()
1264 {
1265 }
1266
1267 long wxMacTextControl::XYToPosition(long x, long y) const
1268 {
1269 return 0 ;
1270 }
1271
1272 bool wxMacTextControl::PositionToXY(long pos, long *x, long *y) const
1273 {
1274 return false ;
1275 }
1276
1277 void wxMacTextControl::ShowPosition( long WXUNUSED(pos) )
1278 {
1279 }
1280
1281 int wxMacTextControl::GetNumberOfLines() const
1282 {
1283 ItemCount lines = 0 ;
1284 wxString content = GetStringValue() ;
1285 lines = 1;
1286
1287 for (size_t i = 0; i < content.length() ; i++)
1288 {
1289 if (content[i] == '\r')
1290 lines++;
1291 }
1292
1293 return lines ;
1294 }
1295
1296 wxString wxMacTextControl::GetLineText(long lineNo) const
1297 {
1298 // TODO: change this if possible to reflect real lines
1299 wxString content = GetStringValue() ;
1300
1301 // Find line first
1302 int count = 0;
1303 for (size_t i = 0; i < content.length() ; i++)
1304 {
1305 if (count == lineNo)
1306 {
1307 // Add chars in line then
1308 wxString tmp;
1309
1310 for (size_t j = i; j < content.length(); j++)
1311 {
1312 if (content[j] == '\n')
1313 return tmp;
1314
1315 tmp += content[j];
1316 }
1317
1318 return tmp;
1319 }
1320
1321 if (content[i] == '\n')
1322 count++;
1323 }
1324
1325 return wxEmptyString ;
1326 }
1327
1328 int wxMacTextControl::GetLineLength(long lineNo) const
1329 {
1330 // TODO: change this if possible to reflect real lines
1331 wxString content = GetStringValue() ;
1332
1333 // Find line first
1334 int count = 0;
1335 for (size_t i = 0; i < content.length() ; i++)
1336 {
1337 if (count == lineNo)
1338 {
1339 // Count chars in line then
1340 count = 0;
1341 for (size_t j = i; j < content.length(); j++)
1342 {
1343 count++;
1344 if (content[j] == '\n')
1345 return count;
1346 }
1347
1348 return count;
1349 }
1350
1351 if (content[i] == '\n')
1352 count++;
1353 }
1354
1355 return 0 ;
1356 }
1357
1358 // ----------------------------------------------------------------------------
1359 // standard unicode control implementation
1360 // ----------------------------------------------------------------------------
1361
1362 #if TARGET_API_MAC_OSX
1363
1364 wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxTextCtrl *wxPeer,
1365 const wxString& str,
1366 const wxPoint& pos,
1367 const wxSize& size, long style )
1368 : wxMacTextControl( wxPeer )
1369 {
1370 m_font = wxPeer->GetFont() ;
1371 m_windowStyle = style ;
1372 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
1373 wxString st = str ;
1374 wxMacConvertNewlines10To13( &st ) ;
1375 wxMacCFStringHolder cf(st , m_font.GetEncoding()) ;
1376 CFStringRef cfr = cf ;
1377 Boolean isPassword = ( m_windowStyle & wxTE_PASSWORD ) != 0 ;
1378 m_valueTag = isPassword ? kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag ;
1379
1380 OSStatus err = CreateEditUnicodeTextControl(
1381 MAC_WXHWND(wxPeer->MacGetTopLevelWindowRef()), &bounds , cfr ,
1382 isPassword , NULL , &m_controlRef ) ;
1383 verify_noerr( err );
1384
1385 if ( !(m_windowStyle & wxTE_MULTILINE) )
1386 SetData<Boolean>( kControlEditTextPart , kControlEditTextSingleLineTag , true ) ;
1387 }
1388
1389 wxMacUnicodeTextControl::~wxMacUnicodeTextControl()
1390 {
1391 }
1392
1393 void wxMacUnicodeTextControl::VisibilityChanged(bool shown)
1394 {
1395 if ( !(m_windowStyle & wxTE_MULTILINE) && shown )
1396 {
1397 // work around a refresh issue insofar as not always the entire content is shown,
1398 // even if this would be possible
1399 ControlEditTextSelectionRec sel ;
1400 CFStringRef value = NULL ;
1401
1402 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
1403 verify_noerr( GetData<CFStringRef>( 0, m_valueTag, &value ) );
1404 verify_noerr( SetData<CFStringRef>( 0, m_valueTag, &value ) );
1405 verify_noerr( SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
1406
1407 CFRelease( value ) ;
1408 }
1409 }
1410
1411 wxString wxMacUnicodeTextControl::GetStringValue() const
1412 {
1413 wxString result ;
1414 CFStringRef value = GetData<CFStringRef>(0, m_valueTag) ;
1415 if ( value )
1416 {
1417 wxMacCFStringHolder cf(value) ;
1418 result = cf.AsString() ;
1419 }
1420
1421 #if '\n' == 10
1422 wxMacConvertNewlines13To10( &result ) ;
1423 #else
1424 wxMacConvertNewlines10To13( &result ) ;
1425 #endif
1426
1427 return result ;
1428 }
1429
1430 void wxMacUnicodeTextControl::SetStringValue( const wxString &str )
1431 {
1432 wxString st = str ;
1433 wxMacConvertNewlines10To13( &st ) ;
1434 wxMacCFStringHolder cf( st , m_font.GetEncoding() ) ;
1435 verify_noerr( SetData<CFStringRef>( 0, m_valueTag , cf ) ) ;
1436 }
1437
1438 void wxMacUnicodeTextControl::Copy()
1439 {
1440 SendHICommand( kHICommandCopy ) ;
1441 }
1442
1443 void wxMacUnicodeTextControl::Cut()
1444 {
1445 SendHICommand( kHICommandCut ) ;
1446 }
1447
1448 void wxMacUnicodeTextControl::Paste()
1449 {
1450 SendHICommand( kHICommandPaste ) ;
1451 }
1452
1453 bool wxMacUnicodeTextControl::CanPaste() const
1454 {
1455 return true ;
1456 }
1457
1458 void wxMacUnicodeTextControl::SetEditable(bool editable)
1459 {
1460 #if 0 // leads to problem because text cannot be selected anymore
1461 SetData<Boolean>( kControlEditTextPart , kControlEditTextLockedTag , (Boolean) !editable ) ;
1462 #endif
1463 }
1464
1465 void wxMacUnicodeTextControl::GetSelection( long* from, long* to ) const
1466 {
1467 ControlEditTextSelectionRec sel ;
1468 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ) ;
1469 if ( from )
1470 *from = sel.selStart ;
1471 if ( to )
1472 *to = sel.selEnd ;
1473 }
1474
1475 void wxMacUnicodeTextControl::SetSelection( long from , long to )
1476 {
1477 ControlEditTextSelectionRec sel ;
1478 if ((from == -1) && (to == -1))
1479 {
1480 from = 0 ;
1481 to = 32767 ; // sel has 16 bit signed values, max is 32767
1482 }
1483
1484 sel.selStart = from ;
1485 sel.selEnd = to ;
1486 SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ;
1487 }
1488
1489 void wxMacUnicodeTextControl::WriteText( const wxString& str )
1490 {
1491 wxString st = str ;
1492 wxMacConvertNewlines10To13( &st ) ;
1493
1494 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
1495 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1496 CFStringRef value = cf ;
1497 SetData<CFStringRef>( 0, kControlEditTextInsertCFStringRefTag, &value );
1498 #else
1499 wxString val = GetStringValue() ;
1500 long start , end ;
1501 GetSelection( &start , &end ) ;
1502 val.Remove( start , end - start ) ;
1503 val.insert( start , str ) ;
1504 SetStringValue( val ) ;
1505 SetSelection( start + str.length() , start + str.length() ) ;
1506 #endif
1507 }
1508
1509 #endif
1510
1511 // ----------------------------------------------------------------------------
1512 // MLTE control implementation (common part)
1513 // ----------------------------------------------------------------------------
1514
1515 // if MTLE is read only, no changes at all are allowed, not even from
1516 // procedural API, in order to allow changes via API all the same we must undo
1517 // the readonly status while we are executing, this class helps to do so
1518
1519 class wxMacEditHelper
1520 {
1521 public :
1522 wxMacEditHelper( TXNObject txn )
1523 {
1524 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1525 m_txn = txn ;
1526 TXNGetTXNObjectControls( m_txn , 1 , tag , m_data ) ;
1527 if ( m_data[0].uValue == kTXNReadOnly )
1528 {
1529 TXNControlData data[] = { { kTXNReadWrite } } ;
1530 TXNSetTXNObjectControls( m_txn , false , 1 , tag , data ) ;
1531 }
1532 }
1533
1534 ~wxMacEditHelper()
1535 {
1536 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1537 if ( m_data[0].uValue == kTXNReadOnly )
1538 TXNSetTXNObjectControls( m_txn , false , 1 , tag , m_data ) ;
1539 }
1540
1541 protected :
1542 TXNObject m_txn ;
1543 TXNControlData m_data[1] ;
1544 } ;
1545
1546 wxMacMLTEControl::wxMacMLTEControl( wxTextCtrl *peer )
1547 : wxMacTextControl( peer )
1548 {
1549 SetNeedsFocusRect( true ) ;
1550 }
1551
1552 wxString wxMacMLTEControl::GetStringValue() const
1553 {
1554 wxString result ;
1555 OSStatus err ;
1556 Size actualSize = 0;
1557
1558 {
1559 #if wxUSE_UNICODE
1560 Handle theText ;
1561 err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNUnicodeTextData );
1562
1563 // all done
1564 if ( err != noErr )
1565 {
1566 actualSize = 0 ;
1567 }
1568 else
1569 {
1570 actualSize = GetHandleSize( theText ) / sizeof(UniChar) ;
1571 if ( actualSize > 0 )
1572 {
1573 wxChar *ptr = NULL ;
1574
1575 #if SIZEOF_WCHAR_T == 2
1576 ptr = new wxChar[actualSize + 1] ;
1577 wxStrncpy( ptr , (wxChar*)(*theText) , actualSize ) ;
1578 #else
1579 SetHandleSize( theText, (actualSize + 1) * sizeof(UniChar) ) ;
1580 HLock( theText ) ;
1581 (((UniChar*)*theText)[actualSize]) = 0 ;
1582 wxMBConvUTF16 converter ;
1583 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
1584 wxASSERT_MSG( noChars != wxCONV_FAILED, _T("Unable to count the number of characters in this string!") );
1585 ptr = new wxChar[noChars + 1] ;
1586
1587 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars + 1 ) ;
1588 wxASSERT_MSG( noChars != wxCONV_FAILED, _T("Conversion of string failed!") );
1589 ptr[noChars] = 0 ;
1590 HUnlock( theText ) ;
1591 #endif
1592
1593 ptr[actualSize] = 0 ;
1594 result = wxString( ptr ) ;
1595 delete [] ptr ;
1596 }
1597
1598 DisposeHandle( theText ) ;
1599 }
1600 #else
1601 Handle theText ;
1602 err = TXNGetDataEncoded( m_txn , kTXNStartOffset, kTXNEndOffset, &theText, kTXNTextData );
1603
1604 // all done
1605 if ( err != noErr )
1606 {
1607 actualSize = 0 ;
1608 }
1609 else
1610 {
1611 actualSize = GetHandleSize( theText ) ;
1612 if ( actualSize > 0 )
1613 {
1614 HLock( theText ) ;
1615 result = wxString( *theText , wxConvLocal , actualSize ) ;
1616 HUnlock( theText ) ;
1617 }
1618
1619 DisposeHandle( theText ) ;
1620 }
1621 #endif
1622 }
1623
1624 #if '\n' == 10
1625 wxMacConvertNewlines13To10( &result ) ;
1626 #else
1627 wxMacConvertNewlines10To13( &result ) ;
1628 #endif
1629
1630 return result ;
1631 }
1632
1633 void wxMacMLTEControl::SetStringValue( const wxString &str )
1634 {
1635 wxString st = str;
1636 wxMacConvertNewlines10To13( &st );
1637
1638 {
1639 wxMacWindowClipper c( m_peer );
1640
1641 {
1642 wxMacEditHelper help( m_txn );
1643 SetTXNData( st, kTXNStartOffset, kTXNEndOffset );
1644 }
1645
1646 TXNSetSelection( m_txn, 0, 0 );
1647 TXNShowSelection( m_txn, kTXNShowStart );
1648 }
1649 }
1650
1651 TXNFrameOptions wxMacMLTEControl::FrameOptionsFromWXStyle( long wxStyle )
1652 {
1653 TXNFrameOptions frameOptions = kTXNDontDrawCaretWhenInactiveMask;
1654
1655 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1656 frameOptions |= kTXNDoFontSubstitutionMask;
1657 #endif
1658
1659 if ( ! (wxStyle & wxTE_NOHIDESEL) )
1660 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
1661
1662 if ( wxStyle & (wxHSCROLL | wxTE_DONTWRAP) )
1663 frameOptions |= kTXNWantHScrollBarMask ;
1664
1665 if ( wxStyle & wxTE_MULTILINE )
1666 {
1667 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
1668
1669 if ( !(wxStyle & wxTE_NO_VSCROLL) )
1670 {
1671 frameOptions |= kTXNWantVScrollBarMask ;
1672
1673 // The following code causes drawing problems on 10.4. Perhaps it can be restored for
1674 // older versions of the OS, but I'm not sure it's appropriate to put a grow icon here
1675 // anyways, as AFAIK users can't actually use it to resize the text ctrl.
1676 // if ( frameOptions & kTXNWantHScrollBarMask )
1677 // frameOptions |= kTXNDrawGrowIconMask ;
1678 }
1679 }
1680 else
1681 {
1682 frameOptions |= kTXNSingleLineOnlyMask ;
1683 }
1684
1685 return frameOptions ;
1686 }
1687
1688 void wxMacMLTEControl::AdjustCreationAttributes( const wxColour &background, bool visible )
1689 {
1690 TXNControlTag iControlTags[] =
1691 {
1692 kTXNDoFontSubstitution,
1693 kTXNWordWrapStateTag ,
1694 };
1695 TXNControlData iControlData[] =
1696 {
1697 { true },
1698 { kTXNNoAutoWrap },
1699 };
1700
1701 int toptag = WXSIZEOF( iControlTags ) ;
1702
1703 if ( m_windowStyle & wxTE_MULTILINE )
1704 {
1705 iControlData[1].uValue =
1706 (m_windowStyle & wxTE_DONTWRAP)
1707 ? kTXNNoAutoWrap
1708 : kTXNAutoWrap;
1709 }
1710
1711 OSStatus err = TXNSetTXNObjectControls( m_txn, false, toptag, iControlTags, iControlData ) ;
1712 verify_noerr( err );
1713
1714 // setting the default font:
1715 // under 10.2 this causes a visible caret, therefore we avoid it
1716
1717 if ( UMAGetSystemVersion() >= 0x1030 )
1718 {
1719 Str255 fontName ;
1720 SInt16 fontSize ;
1721 Style fontStyle ;
1722
1723 GetThemeFont( kThemeSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
1724
1725 TXNTypeAttributes typeAttr[] =
1726 {
1727 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
1728 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
1729 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
1730 } ;
1731
1732 err = TXNSetTypeAttributes(
1733 m_txn, sizeof(typeAttr) / sizeof(TXNTypeAttributes),
1734 typeAttr, kTXNStartOffset, kTXNEndOffset );
1735 verify_noerr( err );
1736 }
1737
1738 if ( m_windowStyle & wxTE_PASSWORD )
1739 {
1740 UniChar c = 0x00A5 ;
1741 err = TXNEchoMode( m_txn , c , 0 , true );
1742 verify_noerr( err );
1743 }
1744
1745 TXNBackground tback;
1746 tback.bgType = kTXNBackgroundTypeRGB;
1747 tback.bg.color = MAC_WXCOLORREF( background.GetPixel() );
1748 TXNSetBackground( m_txn , &tback );
1749
1750 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1751 if ( UMAGetSystemVersion() >= 0x1040 )
1752 {
1753 TXNCommandEventSupportOptions options ;
1754 if ( TXNGetCommandEventSupport( m_txn, &options ) == noErr )
1755 {
1756 options |=
1757 kTXNSupportEditCommandProcessing
1758 | kTXNSupportEditCommandUpdating
1759 | kTXNSupportSpellCheckCommandProcessing
1760 | kTXNSupportSpellCheckCommandUpdating
1761 | kTXNSupportFontCommandProcessing
1762 | kTXNSupportFontCommandUpdating;
1763
1764 TXNSetCommandEventSupport( m_txn , options ) ;
1765 }
1766 }
1767 #endif
1768 }
1769
1770 void wxMacMLTEControl::SetBackground( const wxBrush &brush )
1771 {
1772 // currently only solid background are supported
1773 TXNBackground tback;
1774
1775 tback.bgType = kTXNBackgroundTypeRGB;
1776 tback.bg.color = MAC_WXCOLORREF( brush.GetColour().GetPixel() );
1777 TXNSetBackground( m_txn , &tback );
1778 }
1779
1780 void wxMacMLTEControl::TXNSetAttribute( const wxTextAttr& style , long from , long to )
1781 {
1782 TXNTypeAttributes typeAttr[4] ;
1783 RGBColor color ;
1784 int attrCount = 0 ;
1785
1786 if ( style.HasFont() )
1787 {
1788 const wxFont &font = style.GetFont() ;
1789
1790 #if 0 // old version
1791 Str255 fontName = "\pMonaco" ;
1792 SInt16 fontSize = 12 ;
1793 Style fontStyle = normal ;
1794 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
1795 fontSize = font.GetPointSize() ;
1796 if ( font.GetUnderlined() )
1797 fontStyle |= underline ;
1798 if ( font.GetWeight() == wxBOLD )
1799 fontStyle |= bold ;
1800 if ( font.GetStyle() == wxITALIC )
1801 fontStyle |= italic ;
1802
1803 typeAttr[attrCount].tag = kTXNQDFontNameAttribute ;
1804 typeAttr[attrCount].size = kTXNQDFontNameAttributeSize ;
1805 typeAttr[attrCount].data.dataPtr = (void*)fontName ;
1806 attrCount++ ;
1807
1808 typeAttr[attrCount].tag = kTXNQDFontSizeAttribute ;
1809 typeAttr[attrCount].size = kTXNFontSizeAttributeSize ;
1810 typeAttr[attrCount].data.dataValue = (fontSize << 16) ;
1811 attrCount++ ;
1812
1813 typeAttr[attrCount].tag = kTXNQDFontStyleAttribute ;
1814 typeAttr[attrCount].size = kTXNQDFontStyleAttributeSize ;
1815 typeAttr[attrCount].data.dataValue = fontStyle ;
1816 attrCount++ ;
1817 #else
1818 typeAttr[attrCount].tag = kTXNATSUIStyle ;
1819 typeAttr[attrCount].size = kTXNATSUIStyleSize ;
1820 typeAttr[attrCount].data.dataValue = (UInt32)font.MacGetATSUStyle() ;
1821 attrCount++ ;
1822 #endif
1823 }
1824
1825 if ( style.HasTextColour() )
1826 {
1827 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
1828
1829 typeAttr[attrCount].tag = kTXNQDFontColorAttribute ;
1830 typeAttr[attrCount].size = kTXNQDFontColorAttributeSize ;
1831 typeAttr[attrCount].data.dataPtr = (void*) &color ;
1832 attrCount++ ;
1833 }
1834
1835 if ( attrCount > 0 )
1836 {
1837 verify_noerr( TXNSetTypeAttributes( m_txn , attrCount , typeAttr, from , to ) );
1838 // unfortunately the relayout is not automatic
1839 TXNRecalcTextLayout( m_txn );
1840 }
1841 }
1842
1843 void wxMacMLTEControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle )
1844 {
1845 wxMacEditHelper help( m_txn ) ;
1846 TXNSetAttribute( wxTextAttr( foreground, wxNullColour, font ), kTXNStartOffset, kTXNEndOffset ) ;
1847 }
1848
1849 void wxMacMLTEControl::SetStyle( long start, long end, const wxTextAttr& style )
1850 {
1851 wxMacEditHelper help( m_txn ) ;
1852 TXNSetAttribute( style, start, end ) ;
1853 }
1854
1855 void wxMacMLTEControl::Copy()
1856 {
1857 ClearCurrentScrap();
1858 TXNCopy( m_txn );
1859 TXNConvertToPublicScrap();
1860 }
1861
1862 void wxMacMLTEControl::Cut()
1863 {
1864 ClearCurrentScrap();
1865 TXNCut( m_txn );
1866 TXNConvertToPublicScrap();
1867 }
1868
1869 void wxMacMLTEControl::Paste()
1870 {
1871 TXNConvertFromPublicScrap();
1872 TXNPaste( m_txn );
1873 }
1874
1875 bool wxMacMLTEControl::CanPaste() const
1876 {
1877 return TXNIsScrapPastable() ;
1878 }
1879
1880 void wxMacMLTEControl::SetEditable(bool editable)
1881 {
1882 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1883 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1884 TXNSetTXNObjectControls( m_txn, false, WXSIZEOF(tag), tag, data ) ;
1885 }
1886
1887 wxTextPos wxMacMLTEControl::GetLastPosition() const
1888 {
1889 wxTextPos actualsize = 0 ;
1890
1891 Handle theText ;
1892 OSErr err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNTextData );
1893
1894 // all done
1895 if ( err == noErr )
1896 {
1897 actualsize = GetHandleSize( theText ) ;
1898 DisposeHandle( theText ) ;
1899 }
1900 else
1901 {
1902 actualsize = 0 ;
1903 }
1904
1905 return actualsize ;
1906 }
1907
1908 void wxMacMLTEControl::Replace( long from , long to , const wxString &str )
1909 {
1910 wxString value = str ;
1911 wxMacConvertNewlines10To13( &value ) ;
1912
1913 wxMacEditHelper help( m_txn ) ;
1914 wxMacWindowClipper c( m_peer ) ;
1915
1916 TXNSetSelection( m_txn, from, to ) ;
1917 TXNClear( m_txn ) ;
1918 SetTXNData( value, kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1919 }
1920
1921 void wxMacMLTEControl::Remove( long from , long to )
1922 {
1923 wxMacWindowClipper c( m_peer ) ;
1924 wxMacEditHelper help( m_txn ) ;
1925 TXNSetSelection( m_txn , from , to ) ;
1926 TXNClear( m_txn ) ;
1927 }
1928
1929 void wxMacMLTEControl::GetSelection( long* from, long* to) const
1930 {
1931 TXNGetSelection( m_txn , (TXNOffset*) from , (TXNOffset*) to ) ;
1932 }
1933
1934 void wxMacMLTEControl::SetSelection( long from , long to )
1935 {
1936 wxMacWindowClipper c( m_peer ) ;
1937
1938 // change the selection
1939 if ((from == -1) && (to == -1))
1940 TXNSelectAll( m_txn );
1941 else
1942 TXNSetSelection( m_txn, from, to );
1943
1944 TXNShowSelection( m_txn, kTXNShowStart );
1945 }
1946
1947 void wxMacMLTEControl::WriteText( const wxString& str )
1948 {
1949 wxString st = str ;
1950 wxMacConvertNewlines10To13( &st ) ;
1951
1952 long start , end , dummy ;
1953
1954 GetSelection( &start , &dummy ) ;
1955 wxMacWindowClipper c( m_peer ) ;
1956
1957 {
1958 wxMacEditHelper helper( m_txn ) ;
1959 SetTXNData( st, kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1960 }
1961
1962 GetSelection( &dummy, &end ) ;
1963
1964 // TODO: SetStyle( start , end , GetDefaultStyle() ) ;
1965 }
1966
1967 void wxMacMLTEControl::Clear()
1968 {
1969 wxMacWindowClipper c( m_peer ) ;
1970 wxMacEditHelper st( m_txn ) ;
1971 TXNSetSelection( m_txn , kTXNStartOffset , kTXNEndOffset ) ;
1972 TXNClear( m_txn ) ;
1973 }
1974
1975 bool wxMacMLTEControl::CanUndo() const
1976 {
1977 return TXNCanUndo( m_txn , NULL ) ;
1978 }
1979
1980 void wxMacMLTEControl::Undo()
1981 {
1982 TXNUndo( m_txn ) ;
1983 }
1984
1985 bool wxMacMLTEControl::CanRedo() const
1986 {
1987 return TXNCanRedo( m_txn , NULL ) ;
1988 }
1989
1990 void wxMacMLTEControl::Redo()
1991 {
1992 TXNRedo( m_txn ) ;
1993 }
1994
1995 int wxMacMLTEControl::GetNumberOfLines() const
1996 {
1997 ItemCount lines = 0 ;
1998 TXNGetLineCount( m_txn, &lines ) ;
1999
2000 return lines ;
2001 }
2002
2003 long wxMacMLTEControl::XYToPosition(long x, long y) const
2004 {
2005 Point curpt ;
2006 wxTextPos lastpos ;
2007
2008 // TODO: find a better implementation : while we can get the
2009 // line metrics of a certain line, we don't get its starting
2010 // position, so it would probably be rather a binary search
2011 // for the start position
2012 long xpos = 0, ypos = 0 ;
2013 int lastHeight = 0 ;
2014 ItemCount n ;
2015
2016 lastpos = GetLastPosition() ;
2017 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
2018 {
2019 if ( y == ypos && x == xpos )
2020 return n ;
2021
2022 TXNOffsetToPoint( m_txn, n, &curpt ) ;
2023
2024 if ( curpt.v > lastHeight )
2025 {
2026 xpos = 0 ;
2027 if ( n > 0 )
2028 ++ypos ;
2029
2030 lastHeight = curpt.v ;
2031 }
2032 else
2033 ++xpos ;
2034 }
2035
2036 return 0 ;
2037 }
2038
2039 bool wxMacMLTEControl::PositionToXY( long pos, long *x, long *y ) const
2040 {
2041 Point curpt ;
2042 wxTextPos lastpos ;
2043
2044 if ( y )
2045 *y = 0 ;
2046 if ( x )
2047 *x = 0 ;
2048
2049 lastpos = GetLastPosition() ;
2050 if ( pos <= lastpos )
2051 {
2052 // TODO: find a better implementation - while we can get the
2053 // line metrics of a certain line, we don't get its starting
2054 // position, so it would probably be rather a binary search
2055 // for the start position
2056 long xpos = 0, ypos = 0 ;
2057 int lastHeight = 0 ;
2058 ItemCount n ;
2059
2060 for ( n = 0 ; n <= (ItemCount) pos ; ++n )
2061 {
2062 TXNOffsetToPoint( m_txn, n, &curpt ) ;
2063
2064 if ( curpt.v > lastHeight )
2065 {
2066 xpos = 0 ;
2067 if ( n > 0 )
2068 ++ypos ;
2069
2070 lastHeight = curpt.v ;
2071 }
2072 else
2073 ++xpos ;
2074 }
2075
2076 if ( y )
2077 *y = ypos ;
2078 if ( x )
2079 *x = xpos ;
2080 }
2081
2082 return false ;
2083 }
2084
2085 void wxMacMLTEControl::ShowPosition( long pos )
2086 {
2087 #if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER)
2088 {
2089 Point current, desired ;
2090 TXNOffset selstart, selend;
2091
2092 TXNGetSelection( m_txn, &selstart, &selend );
2093 TXNOffsetToPoint( m_txn, selstart, &current );
2094 TXNOffsetToPoint( m_txn, pos, &desired );
2095
2096 // TODO: use HIPoints for 10.3 and above
2097 if ( (UInt32)TXNScroll != (UInt32)kUnresolvedCFragSymbolAddress )
2098 {
2099 OSErr theErr = noErr;
2100 SInt32 dv = desired.v - current.v;
2101 SInt32 dh = desired.h - current.h;
2102 TXNShowSelection( m_txn, kTXNShowStart ) ; // NB: should this be kTXNShowStart or kTXNShowEnd ??
2103 theErr = TXNScroll( m_txn, kTXNScrollUnitsInPixels, kTXNScrollUnitsInPixels, &dv, &dh );
2104
2105 // there will be an error returned for classic MLTE implementation when the control is
2106 // invisible, but HITextView works correctly, so we don't assert that one
2107 // wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
2108 }
2109 }
2110 #endif
2111 }
2112
2113 void wxMacMLTEControl::SetTXNData( const wxString& st, TXNOffset start, TXNOffset end )
2114 {
2115 #if wxUSE_UNICODE
2116 #if SIZEOF_WCHAR_T == 2
2117 size_t len = st.Len() ;
2118 TXNSetData( m_txn, kTXNUnicodeTextData, (void*)st.wc_str(), len * 2, start, end );
2119 #else
2120 wxMBConvUTF16 converter ;
2121 ByteCount byteBufferLen = converter.WC2MB( NULL, st.wc_str(), 0 ) ;
2122 UniChar *unibuf = (UniChar*)malloc( byteBufferLen ) ;
2123 converter.WC2MB( (char*)unibuf, st.wc_str(), byteBufferLen ) ;
2124 TXNSetData( m_txn, kTXNUnicodeTextData, (void*)unibuf, byteBufferLen, start, end ) ;
2125 free( unibuf ) ;
2126 #endif
2127 #else
2128 wxCharBuffer text = st.mb_str( wxConvLocal ) ;
2129 TXNSetData( m_txn, kTXNTextData, (void*)text.data(), strlen( text ), start, end ) ;
2130 #endif
2131 }
2132
2133 wxString wxMacMLTEControl::GetLineText(long lineNo) const
2134 {
2135 wxString line ;
2136
2137 if ( lineNo < GetNumberOfLines() )
2138 {
2139 Point firstPoint;
2140 Fixed lineWidth, lineHeight, currentHeight;
2141 long ypos ;
2142
2143 // get the first possible position in the control
2144 TXNOffsetToPoint(m_txn, 0, &firstPoint);
2145
2146 // Iterate through the lines until we reach the one we want,
2147 // adding to our current y pixel point position
2148 ypos = 0 ;
2149 currentHeight = 0;
2150 while (ypos < lineNo)
2151 {
2152 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
2153 currentHeight += lineHeight;
2154 }
2155
2156 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
2157 TXNOffset theOffset;
2158 TXNPointToOffset(m_txn, thePoint, &theOffset);
2159
2160 wxString content = GetStringValue() ;
2161 Point currentPoint = thePoint;
2162 while (thePoint.v == currentPoint.v && theOffset < content.length())
2163 {
2164 line += content[theOffset];
2165 TXNOffsetToPoint(m_txn, ++theOffset, &currentPoint);
2166 }
2167 }
2168
2169 return line ;
2170 }
2171
2172 int wxMacMLTEControl::GetLineLength(long lineNo) const
2173 {
2174 int theLength = 0;
2175
2176 if ( lineNo < GetNumberOfLines() )
2177 {
2178 Point firstPoint;
2179 Fixed lineWidth, lineHeight, currentHeight;
2180 long ypos;
2181
2182 // get the first possible position in the control
2183 TXNOffsetToPoint(m_txn, 0, &firstPoint);
2184
2185 // Iterate through the lines until we reach the one we want,
2186 // adding to our current y pixel point position
2187 ypos = 0;
2188 currentHeight = 0;
2189 while (ypos < lineNo)
2190 {
2191 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
2192 currentHeight += lineHeight;
2193 }
2194
2195 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
2196 TXNOffset theOffset;
2197 TXNPointToOffset(m_txn, thePoint, &theOffset);
2198
2199 wxString content = GetStringValue() ;
2200 Point currentPoint = thePoint;
2201 while (thePoint.v == currentPoint.v && theOffset < content.length())
2202 {
2203 ++theLength;
2204 TXNOffsetToPoint(m_txn, ++theOffset, &currentPoint);
2205 }
2206 }
2207
2208 return theLength ;
2209 }
2210
2211 // ----------------------------------------------------------------------------
2212 // MLTE control implementation (classic part)
2213 // ----------------------------------------------------------------------------
2214
2215 // OS X Notes : We still don't have a full replacement for MLTE, so this implementation
2216 // has to live on. We have different problems coming from outdated implementations on the
2217 // various OS X versions. Most deal with the scrollbars: they are not correctly embedded
2218 // while this can be solved on 10.3 by reassigning them the correct place, on 10.2 there is
2219 // no way out, therefore we are using our own implementation and our own scrollbars ....
2220
2221 #ifdef __WXMAC_OSX__
2222
2223 TXNScrollInfoUPP gTXNScrollInfoProc = NULL ;
2224 ControlActionUPP gTXNScrollActionProc = NULL ;
2225
2226 pascal void wxMacMLTEClassicControl::TXNScrollInfoProc(
2227 SInt32 iValue, SInt32 iMaximumValue,
2228 TXNScrollBarOrientation iScrollBarOrientation, SInt32 iRefCon )
2229 {
2230 wxMacMLTEClassicControl* mlte = (wxMacMLTEClassicControl*) iRefCon ;
2231 SInt32 value = wxMax( iValue , 0 ) ;
2232 SInt32 maximum = wxMax( iMaximumValue , 0 ) ;
2233
2234 if ( iScrollBarOrientation == kTXNHorizontal )
2235 {
2236 if ( mlte->m_sbHorizontal )
2237 {
2238 SetControl32BitValue( mlte->m_sbHorizontal , value ) ;
2239 SetControl32BitMaximum( mlte->m_sbHorizontal , maximum ) ;
2240 mlte->m_lastHorizontalValue = value ;
2241 }
2242 }
2243 else if ( iScrollBarOrientation == kTXNVertical )
2244 {
2245 if ( mlte->m_sbVertical )
2246 {
2247 SetControl32BitValue( mlte->m_sbVertical , value ) ;
2248 SetControl32BitMaximum( mlte->m_sbVertical , maximum ) ;
2249 mlte->m_lastVerticalValue = value ;
2250 }
2251 }
2252 }
2253
2254 pascal void wxMacMLTEClassicControl::TXNScrollActionProc( ControlRef controlRef , ControlPartCode partCode )
2255 {
2256 wxMacMLTEClassicControl* mlte = (wxMacMLTEClassicControl*) GetControlReference( controlRef ) ;
2257 if ( mlte == NULL )
2258 return ;
2259
2260 if ( controlRef != mlte->m_sbVertical && controlRef != mlte->m_sbHorizontal )
2261 return ;
2262
2263 OSStatus err ;
2264 bool isHorizontal = ( controlRef == mlte->m_sbHorizontal ) ;
2265
2266 SInt32 minimum = 0 ;
2267 SInt32 maximum = GetControl32BitMaximum( controlRef ) ;
2268 SInt32 value = GetControl32BitValue( controlRef ) ;
2269 SInt32 delta = 0;
2270
2271 switch ( partCode )
2272 {
2273 case kControlDownButtonPart :
2274 delta = 10 ;
2275 break ;
2276
2277 case kControlUpButtonPart :
2278 delta = -10 ;
2279 break ;
2280
2281 case kControlPageDownPart :
2282 delta = GetControlViewSize( controlRef ) ;
2283 break ;
2284
2285 case kControlPageUpPart :
2286 delta = -GetControlViewSize( controlRef ) ;
2287 break ;
2288
2289 case kControlIndicatorPart :
2290 delta = value - (isHorizontal ? mlte->m_lastHorizontalValue : mlte->m_lastVerticalValue) ;
2291 break ;
2292
2293 default :
2294 break ;
2295 }
2296
2297 if ( delta != 0 )
2298 {
2299 SInt32 newValue = value ;
2300
2301 if ( partCode != kControlIndicatorPart )
2302 {
2303 if ( value + delta < minimum )
2304 delta = minimum - value ;
2305 if ( value + delta > maximum )
2306 delta = maximum - value ;
2307
2308 SetControl32BitValue( controlRef , value + delta ) ;
2309 newValue = value + delta ;
2310 }
2311
2312 SInt32 verticalDelta = isHorizontal ? 0 : delta ;
2313 SInt32 horizontalDelta = isHorizontal ? delta : 0 ;
2314
2315 err = TXNScroll(
2316 mlte->m_txn, kTXNScrollUnitsInPixels, kTXNScrollUnitsInPixels,
2317 &verticalDelta, &horizontalDelta );
2318 verify_noerr( err );
2319
2320 if ( isHorizontal )
2321 mlte->m_lastHorizontalValue = newValue ;
2322 else
2323 mlte->m_lastVerticalValue = newValue ;
2324 }
2325 }
2326 #endif
2327
2328 // make correct activations
2329 void wxMacMLTEClassicControl::MacActivatePaneText(bool setActive)
2330 {
2331 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(m_controlRef);
2332
2333 wxMacWindowClipper clipper( textctrl ) ;
2334 TXNActivate( m_txn, m_txnFrameID, setActive );
2335
2336 ControlRef controlFocus = 0 ;
2337 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
2338 if ( controlFocus == m_controlRef )
2339 TXNFocus( m_txn, setActive );
2340 }
2341
2342 void wxMacMLTEClassicControl::MacFocusPaneText(bool setFocus)
2343 {
2344 TXNFocus( m_txn, setFocus );
2345 }
2346
2347 // guards against inappropriate redraw (hidden objects drawing onto window)
2348
2349 void wxMacMLTEClassicControl::MacSetObjectVisibility(bool vis)
2350 {
2351 ControlRef controlFocus = 0 ;
2352 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
2353
2354 if ( !vis && (controlFocus == m_controlRef ) )
2355 SetKeyboardFocus( m_txnWindow , m_controlRef , kControlFocusNoPart ) ;
2356
2357 TXNControlTag iControlTags[1] = { kTXNVisibilityTag };
2358 TXNControlData iControlData[1] = { { (UInt32)false } };
2359
2360 verify_noerr( TXNGetTXNObjectControls( m_txn , 1, iControlTags, iControlData ) ) ;
2361
2362 if ( iControlData[0].uValue != vis )
2363 {
2364 iControlData[0].uValue = vis ;
2365 verify_noerr( TXNSetTXNObjectControls( m_txn, false , 1, iControlTags, iControlData ) ) ;
2366 }
2367
2368 // currently, we always clip as partial visibility (overlapped) visibility is also a problem,
2369 // if we run into further problems we might set the FrameBounds to an empty rect here
2370 }
2371
2372 // make sure that the TXNObject is at the right position
2373
2374 void wxMacMLTEClassicControl::MacUpdatePosition()
2375 {
2376 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2377 if ( textctrl == NULL )
2378 return ;
2379
2380 Rect bounds ;
2381 UMAGetControlBoundsInWindowCoords( m_controlRef, &bounds );
2382
2383 wxRect visRect = textctrl->MacGetClippedClientRect() ;
2384 Rect visBounds = { visRect.y , visRect.x , visRect.y + visRect.height , visRect.x + visRect.width } ;
2385 int x , y ;
2386 x = y = 0 ;
2387 textctrl->MacWindowToRootWindow( &x , &y ) ;
2388 OffsetRect( &visBounds , x , y ) ;
2389
2390 if ( !EqualRect( &bounds, &m_txnControlBounds ) || !EqualRect( &visBounds, &m_txnVisBounds ) )
2391 {
2392 m_txnControlBounds = bounds ;
2393 m_txnVisBounds = visBounds ;
2394 wxMacWindowClipper cl( textctrl ) ;
2395
2396 #ifdef __WXMAC_OSX__
2397 bool isCompositing = textctrl->MacGetTopLevelWindow()->MacUsesCompositing() ;
2398 if ( m_sbHorizontal || m_sbVertical )
2399 {
2400 int w = bounds.right - bounds.left ;
2401 int h = bounds.bottom - bounds.top ;
2402
2403 if ( m_sbHorizontal )
2404 {
2405 Rect sbBounds ;
2406
2407 sbBounds.left = -1 ;
2408 sbBounds.top = h - 14 ;
2409 sbBounds.right = w + 1 ;
2410 sbBounds.bottom = h + 1 ;
2411
2412 if ( !isCompositing )
2413 OffsetRect( &sbBounds , m_txnControlBounds.left , m_txnControlBounds.top ) ;
2414
2415 SetControlBounds( m_sbHorizontal , &sbBounds ) ;
2416 SetControlViewSize( m_sbHorizontal , w ) ;
2417 }
2418
2419 if ( m_sbVertical )
2420 {
2421 Rect sbBounds ;
2422
2423 sbBounds.left = w - 14 ;
2424 sbBounds.top = -1 ;
2425 sbBounds.right = w + 1 ;
2426 sbBounds.bottom = m_sbHorizontal ? h - 14 : h + 1 ;
2427
2428 if ( !isCompositing )
2429 OffsetRect( &sbBounds , m_txnControlBounds.left , m_txnControlBounds.top ) ;
2430
2431 SetControlBounds( m_sbVertical , &sbBounds ) ;
2432 SetControlViewSize( m_sbVertical , h ) ;
2433 }
2434 }
2435
2436 Rect oldviewRect ;
2437 TXNLongRect olddestRect ;
2438 TXNGetRectBounds( m_txn , &oldviewRect , &olddestRect , NULL ) ;
2439
2440 Rect viewRect = { m_txnControlBounds.top, m_txnControlBounds.left,
2441 m_txnControlBounds.bottom - ( m_sbHorizontal ? 14 : 0 ) ,
2442 m_txnControlBounds.right - ( m_sbVertical ? 14 : 0 ) } ;
2443 TXNLongRect destRect = { m_txnControlBounds.top, m_txnControlBounds.left,
2444 m_txnControlBounds.bottom - ( m_sbHorizontal ? 14 : 0 ) ,
2445 m_txnControlBounds.right - ( m_sbVertical ? 14 : 0 ) } ;
2446
2447 if ( olddestRect.right >= 10000 )
2448 destRect.right = destRect.left + 32000 ;
2449
2450 if ( olddestRect.bottom >= 0x20000000 )
2451 destRect.bottom = destRect.top + 0x40000000 ;
2452
2453 SectRect( &viewRect , &visBounds , &viewRect ) ;
2454 TXNSetRectBounds( m_txn , &viewRect , &destRect , true ) ;
2455
2456 #if 0
2457 TXNSetFrameBounds(
2458 m_txn,
2459 m_txnControlBounds.top,
2460 m_txnControlBounds.left,
2461 m_txnControlBounds.bottom - (m_sbHorizontal ? 14 : 0),
2462 m_txnControlBounds.right - (m_sbVertical ? 14 : 0),
2463 m_txnFrameID );
2464 #endif
2465 #else
2466
2467 TXNSetFrameBounds(
2468 m_txn, m_txnControlBounds.top, m_txnControlBounds.left,
2469 wxMax( m_txnControlBounds.bottom, m_txnControlBounds.top ),
2470 wxMax( m_txnControlBounds.right, m_txnControlBounds.left ), m_txnFrameID );
2471 #endif
2472
2473 // the SetFrameBounds method under Classic sometimes does not correctly scroll a selection into sight after a
2474 // movement, therefore we have to force it
2475
2476 // this problem has been reported in OSX as well, so we use this here once again
2477
2478 TXNLongRect textRect ;
2479 TXNGetRectBounds( m_txn , NULL , NULL , &textRect ) ;
2480 if ( textRect.left < m_txnControlBounds.left )
2481 TXNShowSelection( m_txn , kTXNShowStart ) ;
2482 }
2483 }
2484
2485 void wxMacMLTEClassicControl::SetRect( Rect *r )
2486 {
2487 wxMacControl::SetRect( r ) ;
2488 MacUpdatePosition() ;
2489 }
2490
2491 void wxMacMLTEClassicControl::MacControlUserPaneDrawProc(wxInt16 thePart)
2492 {
2493 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2494 if ( textctrl == NULL )
2495 return ;
2496
2497 if ( textctrl->MacIsReallyShown() )
2498 {
2499 wxMacWindowClipper clipper( textctrl ) ;
2500 TXNDraw( m_txn , NULL ) ;
2501 }
2502 }
2503
2504 wxInt16 wxMacMLTEClassicControl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
2505 {
2506 Point where = { y , x } ;
2507 ControlPartCode result = kControlNoPart;
2508
2509 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference( m_controlRef );
2510 if ( (textctrl != NULL) && textctrl->MacIsReallyShown() )
2511 {
2512 if (PtInRect( where, &m_txnControlBounds ))
2513 {
2514 result = kControlEditTextPart ;
2515 }
2516 else
2517 {
2518 // sometimes we get the coords also in control local coordinates, therefore test again
2519 if ( textctrl->MacGetTopLevelWindow()->MacUsesCompositing() )
2520 {
2521 int x = 0 , y = 0 ;
2522 textctrl->MacClientToRootWindow( &x , &y ) ;
2523 where.h += x ;
2524 where.v += y ;
2525 }
2526
2527 if (PtInRect( where, &m_txnControlBounds ))
2528 result = kControlEditTextPart ;
2529 }
2530 }
2531
2532 return result;
2533 }
2534
2535 wxInt16 wxMacMLTEClassicControl::MacControlUserPaneTrackingProc( wxInt16 x, wxInt16 y, void* actionProc )
2536 {
2537 ControlPartCode result = kControlNoPart;
2538
2539 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference( m_controlRef );
2540 if ( (textctrl != NULL) && textctrl->MacIsReallyShown() )
2541 {
2542 Point startPt = { y , x } ;
2543 // for compositing, we must convert these into toplevel window coordinates, because hittesting expects them
2544 if ( textctrl->MacGetTopLevelWindow()->MacUsesCompositing() )
2545 {
2546 int x = 0 , y = 0 ;
2547 textctrl->MacClientToRootWindow( &x , &y ) ;
2548 startPt.h += x ;
2549 startPt.v += y ;
2550 }
2551
2552 switch (MacControlUserPaneHitTestProc( startPt.h , startPt.v ))
2553 {
2554 case kControlEditTextPart :
2555 {
2556 wxMacWindowClipper clipper( textctrl ) ;
2557 EventRecord rec ;
2558
2559 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
2560 TXNClick( m_txn, &rec );
2561 }
2562 break;
2563
2564 default :
2565 break;
2566 }
2567 }
2568
2569 return result;
2570 }
2571
2572 void wxMacMLTEClassicControl::MacControlUserPaneIdleProc()
2573 {
2574 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2575 if ( textctrl == NULL )
2576 return ;
2577
2578 if (textctrl->MacIsReallyShown())
2579 {
2580 if (IsControlActive(m_controlRef))
2581 {
2582 Point mousep;
2583
2584 wxMacWindowClipper clipper( textctrl ) ;
2585 GetMouse(&mousep);
2586
2587 TXNIdle(m_txn);
2588
2589 if (PtInRect(mousep, &m_txnControlBounds))
2590 {
2591 RgnHandle theRgn = NewRgn();
2592 RectRgn(theRgn, &m_txnControlBounds);
2593 TXNAdjustCursor(m_txn, theRgn);
2594 DisposeRgn(theRgn);
2595 }
2596 }
2597 }
2598 }
2599
2600 wxInt16 wxMacMLTEClassicControl::MacControlUserPaneKeyDownProc (wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
2601 {
2602 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2603 if ( textctrl == NULL )
2604 return kControlNoPart;
2605
2606 wxMacWindowClipper clipper( textctrl ) ;
2607
2608 EventRecord ev ;
2609 memset( &ev , 0 , sizeof( ev ) ) ;
2610 ev.what = keyDown ;
2611 ev.modifiers = modifiers ;
2612 ev.message = ((keyCode << 8) & keyCodeMask) | (charCode & charCodeMask);
2613 TXNKeyDown( m_txn , &ev );
2614
2615 return kControlEntireControl;
2616 }
2617
2618 void wxMacMLTEClassicControl::MacControlUserPaneActivateProc(bool activating)
2619 {
2620 MacActivatePaneText( activating );
2621 }
2622
2623 wxInt16 wxMacMLTEClassicControl::MacControlUserPaneFocusProc(wxInt16 action)
2624 {
2625 ControlPartCode focusResult = kControlFocusNoPart;
2626
2627 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2628 if ( textctrl == NULL )
2629 return focusResult;
2630
2631 wxMacWindowClipper clipper( textctrl ) ;
2632
2633 ControlRef controlFocus = NULL ;
2634 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
2635 bool wasFocused = ( controlFocus == m_controlRef ) ;
2636
2637 switch (action)
2638 {
2639 case kControlFocusPrevPart:
2640 case kControlFocusNextPart:
2641 MacFocusPaneText( !wasFocused );
2642 focusResult = (!wasFocused ? (ControlPartCode) kControlEditTextPart : (ControlPartCode) kControlFocusNoPart);
2643 break;
2644
2645 case kControlFocusNoPart:
2646 default:
2647 MacFocusPaneText( false );
2648 focusResult = kControlFocusNoPart;
2649 break;
2650 }
2651
2652 return focusResult;
2653 }
2654
2655 void wxMacMLTEClassicControl::MacControlUserPaneBackgroundProc( void *info )
2656 {
2657 }
2658
2659 wxMacMLTEClassicControl::wxMacMLTEClassicControl( wxTextCtrl *wxPeer,
2660 const wxString& str,
2661 const wxPoint& pos,
2662 const wxSize& size, long style )
2663 : wxMacMLTEControl( wxPeer )
2664 {
2665 m_font = wxPeer->GetFont() ;
2666 m_windowStyle = style ;
2667 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
2668
2669 short featureSet =
2670 kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
2671 | kControlWantsActivate | kControlHandlesTracking
2672 // | kControlHasSpecialBackground
2673 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
2674
2675 OSStatus err = ::CreateUserPaneControl(
2676 MAC_WXHWND(wxPeer->GetParent()->MacGetTopLevelWindowRef()),
2677 &bounds, featureSet, &m_controlRef );
2678 verify_noerr( err );
2679
2680 DoCreate();
2681
2682 AdjustCreationAttributes( *wxWHITE , true ) ;
2683
2684 MacSetObjectVisibility( wxPeer->MacIsReallyShown() ) ;
2685
2686 {
2687 wxString st = str ;
2688 wxMacConvertNewlines10To13( &st ) ;
2689 wxMacWindowClipper clipper( m_peer ) ;
2690 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
2691 TXNSetSelection( m_txn, 0, 0 ) ;
2692 }
2693 }
2694
2695 wxMacMLTEClassicControl::~wxMacMLTEClassicControl()
2696 {
2697 TXNDeleteObject( m_txn );
2698 m_txn = NULL ;
2699 }
2700
2701 void wxMacMLTEClassicControl::VisibilityChanged(bool shown)
2702 {
2703 MacSetObjectVisibility( shown ) ;
2704 wxMacControl::VisibilityChanged( shown ) ;
2705 }
2706
2707 void wxMacMLTEClassicControl::SuperChangedPosition()
2708 {
2709 MacUpdatePosition() ;
2710 wxMacControl::SuperChangedPosition() ;
2711 }
2712
2713 #ifdef __WXMAC_OSX__
2714
2715 ControlUserPaneDrawUPP gTPDrawProc = NULL;
2716 ControlUserPaneHitTestUPP gTPHitProc = NULL;
2717 ControlUserPaneTrackingUPP gTPTrackProc = NULL;
2718 ControlUserPaneIdleUPP gTPIdleProc = NULL;
2719 ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
2720 ControlUserPaneActivateUPP gTPActivateProc = NULL;
2721 ControlUserPaneFocusUPP gTPFocusProc = NULL;
2722
2723 static pascal void wxMacControlUserPaneDrawProc(ControlRef control, SInt16 part)
2724 {
2725 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2726 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2727 if ( win )
2728 win->MacControlUserPaneDrawProc( part ) ;
2729 }
2730
2731 static pascal ControlPartCode wxMacControlUserPaneHitTestProc(ControlRef control, Point where)
2732 {
2733 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2734 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2735 if ( win )
2736 return win->MacControlUserPaneHitTestProc( where.h , where.v ) ;
2737 else
2738 return kControlNoPart ;
2739 }
2740
2741 static pascal ControlPartCode wxMacControlUserPaneTrackingProc(ControlRef control, Point startPt, ControlActionUPP actionProc)
2742 {
2743 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2744 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2745 if ( win )
2746 return win->MacControlUserPaneTrackingProc( startPt.h , startPt.v , (void*) actionProc ) ;
2747 else
2748 return kControlNoPart ;
2749 }
2750
2751 static pascal void wxMacControlUserPaneIdleProc(ControlRef control)
2752 {
2753 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2754 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2755 if ( win )
2756 win->MacControlUserPaneIdleProc() ;
2757 }
2758
2759 static pascal ControlPartCode wxMacControlUserPaneKeyDownProc(ControlRef control, SInt16 keyCode, SInt16 charCode, SInt16 modifiers)
2760 {
2761 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2762 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2763 if ( win )
2764 return win->MacControlUserPaneKeyDownProc( keyCode, charCode, modifiers ) ;
2765 else
2766 return kControlNoPart ;
2767 }
2768
2769 static pascal void wxMacControlUserPaneActivateProc(ControlRef control, Boolean activating)
2770 {
2771 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2772 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2773 if ( win )
2774 win->MacControlUserPaneActivateProc( activating ) ;
2775 }
2776
2777 static pascal ControlPartCode wxMacControlUserPaneFocusProc(ControlRef control, ControlFocusPart action)
2778 {
2779 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2780 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2781 if ( win )
2782 return win->MacControlUserPaneFocusProc( action ) ;
2783 else
2784 return kControlNoPart ;
2785 }
2786
2787 #if 0
2788 static pascal void wxMacControlUserPaneBackgroundProc(ControlRef control, ControlBackgroundPtr info)
2789 {
2790 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2791 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2792 if ( win )
2793 win->MacControlUserPaneBackgroundProc(info) ;
2794 }
2795 #endif
2796
2797 #endif // __WXMAC_OSX__
2798
2799 // TXNRegisterScrollInfoProc
2800
2801 OSStatus wxMacMLTEClassicControl::DoCreate()
2802 {
2803 Rect bounds;
2804 OSStatus err = noErr ;
2805
2806 // set up our globals
2807 #ifdef __WXMAC_OSX__
2808 if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(wxMacControlUserPaneDrawProc);
2809 if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(wxMacControlUserPaneHitTestProc);
2810 if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(wxMacControlUserPaneTrackingProc);
2811 if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(wxMacControlUserPaneIdleProc);
2812 if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(wxMacControlUserPaneKeyDownProc);
2813 if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(wxMacControlUserPaneActivateProc);
2814 if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(wxMacControlUserPaneFocusProc);
2815
2816 if (gTXNScrollInfoProc == NULL ) gTXNScrollInfoProc = NewTXNScrollInfoUPP(TXNScrollInfoProc) ;
2817 if (gTXNScrollActionProc == NULL ) gTXNScrollActionProc = NewControlActionUPP(TXNScrollActionProc) ;
2818 #endif
2819
2820 // set the initial settings for our private data
2821
2822 m_txnWindow = GetControlOwner(m_controlRef);
2823 m_txnPort = (GrafPtr) GetWindowPort(m_txnWindow);
2824
2825 #ifdef __WXMAC_OSX__
2826 // set up the user pane procedures
2827 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
2828 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
2829 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
2830 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
2831 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
2832 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
2833 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
2834 #endif
2835
2836 // calculate the rectangles used by the control
2837 UMAGetControlBoundsInWindowCoords( m_controlRef, &bounds );
2838
2839 m_txnControlBounds = bounds ;
2840 m_txnVisBounds = bounds ;
2841
2842 CGrafPtr origPort ;
2843 GDHandle origDev ;
2844
2845 GetGWorld( &origPort, &origDev ) ;
2846 SetPort( m_txnPort );
2847
2848 // create the new edit field
2849 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( m_windowStyle );
2850
2851 #ifdef __WXMAC_OSX__
2852 // the scrollbars are not correctly embedded but are inserted at the root:
2853 // this gives us problems as we have erratic redraws even over the structure area
2854
2855 m_sbHorizontal = 0 ;
2856 m_sbVertical = 0 ;
2857 m_lastHorizontalValue = 0 ;
2858 m_lastVerticalValue = 0 ;
2859
2860 Rect sb = { 0 , 0 , 0 , 0 } ;
2861 if ( frameOptions & kTXNWantVScrollBarMask )
2862 {
2863 CreateScrollBarControl( m_txnWindow, &sb, 0, 0, 100, 1, true, gTXNScrollActionProc, &m_sbVertical );
2864 SetControlReference( m_sbVertical, (SInt32)this );
2865 SetControlAction( m_sbVertical, gTXNScrollActionProc );
2866 ShowControl( m_sbVertical );
2867 EmbedControl( m_sbVertical , m_controlRef );
2868 frameOptions &= ~kTXNWantVScrollBarMask;
2869 }
2870
2871 if ( frameOptions & kTXNWantHScrollBarMask )
2872 {
2873 CreateScrollBarControl( m_txnWindow, &sb, 0, 0, 100, 1, true, gTXNScrollActionProc, &m_sbHorizontal );
2874 SetControlReference( m_sbHorizontal, (SInt32)this );
2875 SetControlAction( m_sbHorizontal, gTXNScrollActionProc );
2876 ShowControl( m_sbHorizontal );
2877 EmbedControl( m_sbHorizontal, m_controlRef );
2878 frameOptions &= ~(kTXNWantHScrollBarMask | kTXNDrawGrowIconMask);
2879 }
2880
2881 #endif
2882
2883 err = TXNNewObject(
2884 NULL, m_txnWindow, &bounds, frameOptions,
2885 kTXNTextEditStyleFrameType, kTXNTextensionFile, kTXNSystemDefaultEncoding,
2886 &m_txn, &m_txnFrameID, NULL );
2887 verify_noerr( err );
2888
2889 #if 0
2890 TXNControlTag iControlTags[] = { kTXNUseCarbonEvents };
2891 TXNControlData iControlData[] = { { (UInt32)&cInfo } };
2892 int toptag = WXSIZEOF( iControlTags ) ;
2893 TXNCarbonEventInfo cInfo ;
2894 cInfo.useCarbonEvents = false ;
2895 cInfo.filler = 0 ;
2896 cInfo.flags = 0 ;
2897 cInfo.fDictionary = NULL ;
2898
2899 verify_noerr( TXNSetTXNObjectControls( m_txn, false, toptag, iControlTags, iControlData ) );
2900 #endif
2901
2902 #ifdef __WXMAC_OSX__
2903 TXNRegisterScrollInfoProc( m_txn, gTXNScrollInfoProc, (SInt32)this );
2904 #endif
2905
2906 SetGWorld( origPort , origDev ) ;
2907
2908 return err;
2909 }
2910
2911 // ----------------------------------------------------------------------------
2912 // MLTE control implementation (OSX part)
2913 // ----------------------------------------------------------------------------
2914
2915 #if TARGET_API_MAC_OSX
2916
2917 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
2918
2919 // tiger multi-line textcontrols with no CR in the entire content
2920 // don't scroll automatically, so we need a hack.
2921 // This attempt only works 'before' the key (ie before CallNextEventHandler)
2922 // is processed, thus the scrolling always occurs one character too late, but
2923 // better than nothing ...
2924
2925 static const EventTypeSpec eventList[] =
2926 {
2927 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
2928 } ;
2929
2930 static pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
2931 {
2932 OSStatus result = eventNotHandledErr ;
2933 wxMacMLTEHIViewControl* focus = (wxMacMLTEHIViewControl*) data ;
2934
2935 switch ( GetEventKind( event ) )
2936 {
2937 case kEventTextInputUnicodeForKeyEvent :
2938 {
2939 if ( UMAGetSystemVersion() >= 0x1040 )
2940 {
2941 TXNOffset from , to ;
2942 TXNGetSelection( focus->GetTXNObject() , &from , &to ) ;
2943 if ( from == to )
2944 TXNShowSelection( focus->GetTXNObject() , kTXNShowStart );
2945 }
2946 result = CallNextEventHandler(handler,event);
2947 break;
2948 }
2949 default:
2950 break ;
2951 }
2952
2953 return result ;
2954 }
2955
2956 static pascal OSStatus wxMacTextControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
2957 {
2958 OSStatus result = eventNotHandledErr ;
2959
2960 switch ( GetEventClass( event ) )
2961 {
2962 case kEventClassTextInput :
2963 result = wxMacUnicodeTextEventHandler( handler , event , data ) ;
2964 break ;
2965
2966 default :
2967 break ;
2968 }
2969 return result ;
2970 }
2971
2972 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacTextControlEventHandler )
2973
2974 wxMacMLTEHIViewControl::wxMacMLTEHIViewControl( wxTextCtrl *wxPeer,
2975 const wxString& str,
2976 const wxPoint& pos,
2977 const wxSize& size, long style ) : wxMacMLTEControl( wxPeer )
2978 {
2979 m_font = wxPeer->GetFont() ;
2980 m_windowStyle = style ;
2981 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
2982 wxString st = str ;
2983 wxMacConvertNewlines10To13( &st ) ;
2984
2985 HIRect hr = {
2986 { bounds.left , bounds.top },
2987 { bounds.right - bounds.left, bounds.bottom - bounds.top } } ;
2988
2989 m_scrollView = NULL ;
2990 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( style ) ;
2991 if ( frameOptions & (kTXNWantVScrollBarMask | kTXNWantHScrollBarMask) )
2992 {
2993 HIScrollViewCreate(
2994 (frameOptions & kTXNWantHScrollBarMask ? kHIScrollViewOptionsHorizScroll : 0)
2995 | (frameOptions & kTXNWantVScrollBarMask ? kHIScrollViewOptionsVertScroll : 0) ,
2996 &m_scrollView ) ;
2997
2998 HIViewSetFrame( m_scrollView, &hr );
2999 HIViewSetVisible( m_scrollView, true );
3000 }
3001
3002 m_textView = NULL ;
3003 HITextViewCreate( NULL , 0, frameOptions , &m_textView ) ;
3004 m_txn = HITextViewGetTXNObject( m_textView ) ;
3005 HIViewSetVisible( m_textView , true ) ;
3006 if ( m_scrollView )
3007 {
3008 HIViewAddSubview( m_scrollView , m_textView ) ;
3009 m_controlRef = m_scrollView ;
3010 wxPeer->MacInstallEventHandler( (WXWidget) m_textView ) ;
3011 }
3012 else
3013 {
3014 HIViewSetFrame( m_textView, &hr );
3015 m_controlRef = m_textView ;
3016 }
3017
3018 AdjustCreationAttributes( *wxWHITE , true ) ;
3019
3020 wxMacWindowClipper c( m_peer ) ;
3021 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
3022
3023 TXNSetSelection( m_txn, 0, 0 );
3024 TXNShowSelection( m_txn, kTXNShowStart );
3025
3026 InstallControlEventHandler( m_textView , GetwxMacTextControlEventHandlerUPP(),
3027 GetEventTypeCount(eventList), eventList, this,
3028 &m_textEventHandlerRef);
3029 }
3030
3031 wxMacMLTEHIViewControl::~wxMacMLTEHIViewControl()
3032 {
3033 ::RemoveEventHandler( m_textEventHandlerRef ) ;
3034 }
3035
3036 OSStatus wxMacMLTEHIViewControl::SetFocus( ControlFocusPart focusPart )
3037 {
3038 return SetKeyboardFocus( GetControlOwner( m_textView ), m_textView, focusPart ) ;
3039 }
3040
3041 bool wxMacMLTEHIViewControl::HasFocus() const
3042 {
3043 ControlRef control ;
3044 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
3045 return control == m_textView ;
3046 }
3047
3048 void wxMacMLTEHIViewControl::SetBackground( const wxBrush &brush )
3049 {
3050 wxMacMLTEControl::SetBackground( brush ) ;
3051
3052 #if 0
3053 CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
3054 RGBColor col = MAC_WXCOLORREF(brush.GetColour().GetPixel()) ;
3055
3056 float component[4] ;
3057 component[0] = col.red / 65536.0 ;
3058 component[1] = col.green / 65536.0 ;
3059 component[2] = col.blue / 65536.0 ;
3060 component[3] = 1.0 ; // alpha
3061
3062 CGColorRef color = CGColorCreate( rgbSpace , component );
3063 HITextViewSetBackgroundColor( m_textView , color );
3064 CGColorSpaceRelease( rgbSpace );
3065 #endif
3066 }
3067
3068 #endif // MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
3069
3070
3071 #endif
3072
3073 #endif // wxUSE_TEXTCTRL