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