added MLTE support for 10.2 via classic implementation
[wxWidgets.git] / src / mac / carbon / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "textctrl.h"
14 #endif
15
16 #include "wx/defs.h"
17
18 #if wxUSE_TEXTCTRL
19
20
21 #ifdef __DARWIN__
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #else
25 #include <stat.h>
26 #endif
27
28 #include "wx/msgdlg.h"
29
30 #if wxUSE_STD_IOSTREAM
31 #if wxUSE_IOSTREAMH
32 #include <fstream.h>
33 #else
34 #include <fstream>
35 #endif
36 #endif
37
38 #include "wx/app.h"
39 #include "wx/dc.h"
40 #include "wx/button.h"
41 #include "wx/toplevel.h"
42 #include "wx/textctrl.h"
43 #include "wx/notebook.h"
44 #include "wx/tabctrl.h"
45 #include "wx/settings.h"
46 #include "wx/filefn.h"
47 #include "wx/utils.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 // if this is set to 1 then under OSX 10.2 the 'classic' MLTE implementation will be used
60 // if set to 0 then the unicode textctrl will be used
61 #ifndef wxMAC_AWAYS_USE_MLTE
62 #define wxMAC_AWAYS_USE_MLTE 1
63 #endif
64
65 #include <MacTextEditor.h>
66 #include <ATSUnicode.h>
67 #include <TextCommon.h>
68 #include <TextEncodingConverter.h>
69 #include "wx/mac/uma.h"
70
71 class wxMacFunctor
72 {
73 public :
74 wxMacFunctor(){}
75 virtual ~wxMacFunctor() {}
76 virtual void* operator()() = 0 ;
77 static void* CallBackProc(void *param)
78 {
79 wxMacFunctor* f = (wxMacFunctor*) param ;
80 void *result = (*f)() ;
81 return result ;
82 }
83 } ;
84
85 template<typename classtype,typename param1type>
86 class wxMacObjectFunctor1 : public wxMacFunctor
87 {
88 typedef void (classtype::*function)( param1type p1 ) ;
89 typedef void (classtype::*ref_function)( const param1type& p1 ) ;
90 public :
91 wxMacObjectFunctor1( classtype *obj , function f , param1type p1 ) :
92 wxMacFunctor( )
93 {
94 m_object = obj ;
95 m_function = f ;
96 m_param1 = p1 ;
97 }
98
99 wxMacObjectFunctor1( classtype *obj , ref_function f , param1type p1 ) :
100 wxMacFunctor( )
101 {
102 m_object = obj ;
103 m_refFunction = f ;
104 m_param1 = p1 ;
105 }
106
107 ~wxMacObjectFunctor1() {}
108
109 virtual void* operator()()
110 {
111 (m_object->*m_function)(m_param1) ;
112 return NULL ;
113 }
114 private :
115 classtype* m_object ;
116 param1type m_param1 ;
117 union
118 {
119 function m_function ;
120 ref_function m_refFunction ;
121 } ;
122 } ;
123
124 template<typename classtype, typename param1type>
125 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
126 {
127 wxMacObjectFunctor1<classtype,param1type> params(object,function,p1) ;
128 void *result =
129 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
130 return result ;
131 }
132
133 template<typename classtype, typename param1type>
134 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
135 {
136 wxMacObjectFunctor1<classtype,param1type> params(object,function,p1) ;
137 void *result =
138 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
139 return result ;
140 }
141
142 template<typename classtype, typename param1type>
143 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
144 {
145 wxMutexGuiLeave() ;
146 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
147 wxMutexGuiEnter() ;
148 return result ;
149 }
150
151 template<typename classtype, typename param1type>
152 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
153 {
154 wxMutexGuiLeave() ;
155 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
156 wxMutexGuiEnter() ;
157 return result ;
158 }
159 // common interface for all implementations
160 class wxMacTextControl : public wxMacControl
161 {
162 public :
163 wxMacTextControl() ;
164 ~wxMacTextControl() ;
165
166 virtual wxString GetStringValue() const = 0 ;
167 virtual void SetStringValue( const wxString &val ) = 0 ;
168 virtual void SetStyle(long start, long end, const wxTextAttr& style) ;
169 virtual void Copy() ;
170 virtual void Cut() ;
171 virtual void Paste() ;
172 virtual bool CanPaste() const ;
173 virtual void SetEditable(bool editable) ;
174 virtual long GetLastPosition() const ;
175 virtual void Replace( long from , long to , const wxString str ) ;
176 virtual void Remove( long from , long to ) = 0 ;
177 virtual void SetSelection( long from , long to ) = 0 ;
178 virtual void GetSelection( long* from, long* to) const = 0 ;
179 virtual void WriteText(const wxString& str) = 0 ;
180
181 virtual void Clear() ;
182 virtual bool CanUndo() const;
183 virtual void Undo() ;
184 virtual bool CanRedo() const;
185 virtual void Redo() ;
186 virtual int GetNumberOfLines() const ;
187 virtual long XYToPosition(long x, long y) const;
188 virtual bool PositionToXY(long pos, long *x, long *y) const ;
189 virtual void ShowPosition( long WXUNUSED(pos) ) ;
190 virtual int GetLineLength(long lineNo) const ;
191 virtual wxString GetLineText(long lineNo) const ;
192 } ;
193
194 // common parts for implementations based on MLTE
195
196 class wxMacMLTEControl : public wxMacTextControl
197 {
198 public :
199 virtual wxString GetStringValue() const ;
200 virtual void SetStringValue( const wxString &str) ;
201
202 static int ConvertAttribute( const wxTextAttr& style , TXNTypeAttributes attr[] ) ;
203 static TXNFrameOptions FrameOptionsFromWXStyle( long wxStyle ) ;
204 void AdjustCreationAttributes( const wxColour& background , bool visible ) ;
205
206 virtual void SetFont( const wxFont & font , const wxColour& foreground , long windowStyle ) ;
207 virtual void SetStyle(long start, long end, const wxTextAttr& style) ;
208 virtual void Copy() ;
209 virtual void Cut() ;
210 virtual void Paste() ;
211 virtual bool CanPaste() const ;
212 virtual void SetEditable(bool editable) ;
213 virtual long GetLastPosition() const ;
214 virtual void Replace( long from , long to , const wxString str ) ;
215 virtual void Remove( long from , long to ) ;
216 virtual void GetSelection( long* from, long* to) const ;
217 virtual void SetSelection( long from , long to ) ;
218
219 virtual void WriteText(const wxString& str) ;
220 virtual void Clear() ;
221
222 virtual bool CanUndo() const ;
223 virtual void Undo() ;
224 virtual bool CanRedo() const;
225 virtual void Redo() ;
226 virtual int GetNumberOfLines() const ;
227 virtual long XYToPosition(long x, long y) const ;
228 virtual bool PositionToXY(long pos, long *x, long *y) const ;
229 virtual void ShowPosition( long pos ) ;
230 virtual int GetLineLength(long lineNo) const ;
231 virtual wxString GetLineText(long lineNo) const ;
232
233 void SetTXNData( const wxString& st , TXNOffset start , TXNOffset end ) ;
234
235 protected :
236 TXNObject m_txn ;
237 } ;
238
239 #if TARGET_API_MAC_OSX
240
241 // implementation available under OSX
242
243 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
244
245 class wxMacMLTEHIViewControl : public wxMacMLTEControl
246 {
247 public :
248 wxMacMLTEHIViewControl( wxWindow *wxPeer,
249 const wxString& str,
250 const wxPoint& pos,
251 const wxSize& size, long style ) ;
252 virtual OSStatus SetFocus( ControlFocusPart focusPart ) ;
253 virtual bool HasFocus() const ;
254 virtual bool NeedsFocusRect() const ;
255 protected :
256 HIViewRef m_scrollView ;
257 HIViewRef m_textView ;
258 } ;
259
260 #endif
261
262 class wxMacUnicodeTextControl : public wxMacTextControl
263 {
264 public :
265 wxMacUnicodeTextControl( wxWindow *wxPeer,
266 const wxString& str,
267 const wxPoint& pos,
268 const wxSize& size, long style ) ;
269 ~wxMacUnicodeTextControl();
270 virtual void VisibilityChanged(bool shown);
271 virtual wxString GetStringValue() const ;
272 virtual void SetStringValue( const wxString &str) ;
273 virtual void Copy();
274 virtual void Cut();
275 virtual void Paste();
276 virtual bool CanPaste() const;
277 virtual void SetEditable(bool editable) ;
278 virtual void Remove( long from , long to ) ;
279 virtual void GetSelection( long* from, long* to) const ;
280 virtual void SetSelection( long from , long to ) ;
281 virtual void WriteText(const wxString& str) ;
282 protected :
283 // contains the tag for the content (is different for password and non-password controls)
284 OSType m_valueTag ;
285 } ;
286
287 #endif
288
289 // implementation available under classic
290
291 class STPTextPaneVars ;
292
293 class wxMacMLTEClassicControl : public wxMacMLTEControl
294 {
295 public :
296 wxMacMLTEClassicControl( wxWindow *wxPeer,
297 const wxString& str,
298 const wxPoint& pos,
299 const wxSize& size, long style ) ;
300 ~wxMacMLTEClassicControl() ;
301 virtual void VisibilityChanged(bool shown) ;
302 protected :
303 OSStatus DoCreate();
304 public :
305 // hack to make public until we have migrated all procs
306 STPTextPaneVars* m_macTXNvars ;
307 } ;
308
309 #define TE_UNLIMITED_LENGTH 0xFFFFFFFFUL
310
311 #if !USE_SHARED_LIBRARY
312 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
313
314 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
315 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
316 EVT_CHAR(wxTextCtrl::OnChar)
317 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
318 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
319 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
320 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
321 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
322
323 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
324 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
325 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
326 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
327 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
328 END_EVENT_TABLE()
329 #endif
330
331 // Text item
332 void wxTextCtrl::Init()
333 {
334 m_editable = true ;
335 m_dirty = false;
336
337 m_maxLength = TE_UNLIMITED_LENGTH ;
338 }
339
340 wxTextCtrl::~wxTextCtrl()
341 {
342 }
343
344
345 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
346 const wxString& str,
347 const wxPoint& pos,
348 const wxSize& size, long style,
349 const wxValidator& validator,
350 const wxString& name)
351 {
352 m_macIsUserPane = FALSE ;
353 m_editable = true ;
354
355 if ( !HasFlag(wxNO_BORDER) )
356 style |= wxSUNKEN_BORDER ;
357
358 if ( !wxTextCtrlBase::Create(parent, id, pos, size, style & ~(wxHSCROLL|wxVSCROLL), validator, name) )
359 return FALSE;
360
361 wxSize mySize = size ;
362
363 Rect bounds = wxMacGetBoundsForControl( this , pos , size ) ;
364
365 if ( m_windowStyle & wxTE_MULTILINE )
366 {
367 wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
368 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
369
370 m_windowStyle |= wxTE_PROCESS_ENTER;
371 style |= wxTE_PROCESS_ENTER ;
372 }
373
374 #if TARGET_API_MAC_OSX
375 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
376 if ( UMAGetSystemVersion() >= 0x1030 )
377 {
378 m_peer = new wxMacMLTEHIViewControl( this , str , pos , size , style ) ;
379 }
380 #endif
381 #if !wxMAC_AWAYS_USE_MLTE
382 if ( !m_peer )
383 {
384 m_peer = new wxMacUnicodeTextControl( this , str , pos , size , style ) ;
385 }
386 #endif
387 #endif
388 if ( !m_peer )
389 {
390 // this control draws the border itself
391 if ( !HasFlag(wxNO_BORDER) )
392 m_windowStyle &= ~wxSUNKEN_BORDER ;
393 m_peer = new wxMacMLTEClassicControl( this , str , pos , size , style ) ;
394 }
395
396 MacPostControlCreate(pos,size) ;
397
398 if ( m_windowStyle & wxTE_READONLY)
399 {
400 SetEditable( false ) ;
401 }
402
403
404 return TRUE;
405 }
406
407 void wxTextCtrl::MacVisibilityChanged()
408 {
409 GetPeer()->VisibilityChanged( MacIsReallyShown() ) ;
410 }
411
412 void wxTextCtrl::MacEnabledStateChanged()
413 {
414 }
415
416 wxString wxTextCtrl::GetValue() const
417 {
418 return GetPeer()->GetStringValue() ;
419 }
420
421 void wxTextCtrl::GetSelection(long* from, long* to) const
422 {
423 GetPeer()->GetSelection( from , to ) ;
424 }
425
426 void wxTextCtrl::SetValue(const wxString& str)
427 {
428 // optimize redraws
429 if ( GetValue() == str )
430 return ;
431
432 GetPeer()->SetStringValue(str) ;
433 }
434
435 void wxTextCtrl::SetMaxLength(unsigned long len)
436 {
437 m_maxLength = len ;
438 }
439
440 bool wxTextCtrl::SetFont( const wxFont& font )
441 {
442 if ( !wxTextCtrlBase::SetFont( font ) )
443 return FALSE ;
444
445 GetPeer()->SetFont( font , GetForegroundColour() , GetWindowStyle() ) ;
446 return true ;
447 }
448
449 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
450 {
451 GetPeer()->SetStyle( start , end , style ) ;
452 return true ;
453 }
454
455 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
456 {
457 wxTextCtrlBase::SetDefaultStyle( style ) ;
458 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
459 return TRUE ;
460 }
461
462 // Clipboard operations
463 void wxTextCtrl::Copy()
464 {
465 if (CanCopy())
466 {
467 GetPeer()->Copy() ;
468 }
469 }
470
471 void wxTextCtrl::Cut()
472 {
473 if (CanCut())
474 {
475 GetPeer()->Cut() ;
476
477 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
478 event.SetString( GetValue() ) ;
479 event.SetEventObject( this );
480 GetEventHandler()->ProcessEvent(event);
481 }
482 }
483
484 void wxTextCtrl::Paste()
485 {
486 if (CanPaste())
487 {
488 GetPeer()->Paste() ;
489 // eventually we should add setting the default style again
490
491 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
492 event.SetString( GetValue() ) ;
493 event.SetEventObject( this );
494 GetEventHandler()->ProcessEvent(event);
495 }
496 }
497
498 bool wxTextCtrl::CanCopy() const
499 {
500 // Can copy if there's a selection
501 long from, to;
502 GetSelection(& from, & to);
503 return (from != to);
504 }
505
506 bool wxTextCtrl::CanCut() const
507 {
508 if ( !IsEditable() )
509 {
510 return false ;
511 }
512 // Can cut if there's a selection
513 long from, to;
514 GetSelection(& from, & to);
515 return (from != to);
516 }
517
518 bool wxTextCtrl::CanPaste() const
519 {
520 if (!IsEditable())
521 return FALSE;
522
523 return GetPeer()->CanPaste() ;
524 }
525
526 void wxTextCtrl::SetEditable(bool editable)
527 {
528 if ( editable != m_editable )
529 {
530 m_editable = editable ;
531 GetPeer()->SetEditable( editable ) ;
532 }
533 }
534
535 void wxTextCtrl::SetInsertionPoint(long pos)
536 {
537 SetSelection( pos , pos ) ;
538 }
539
540 void wxTextCtrl::SetInsertionPointEnd()
541 {
542 long pos = GetLastPosition();
543 SetInsertionPoint(pos);
544 }
545
546 long wxTextCtrl::GetInsertionPoint() const
547 {
548 long begin,end ;
549 GetSelection( &begin , &end ) ;
550 return begin ;
551 }
552
553 long wxTextCtrl::GetLastPosition() const
554 {
555 return GetPeer()->GetLastPosition( ) ;
556 }
557
558 void wxTextCtrl::Replace(long from, long to, const wxString& str)
559 {
560 GetPeer()->Replace( from , to , str) ;
561 }
562
563 void wxTextCtrl::Remove(long from, long to)
564 {
565 GetPeer()->Remove( from , to ) ;
566 }
567
568 void wxTextCtrl::SetSelection(long from, long to)
569 {
570 GetPeer()->SetSelection( from , to ) ;
571 }
572
573 bool wxTextCtrl::LoadFile(const wxString& file)
574 {
575 if ( wxTextCtrlBase::LoadFile(file) )
576 {
577 return TRUE;
578 }
579
580 return FALSE;
581 }
582
583 void wxTextCtrl::WriteText(const wxString& str)
584 {
585 // TODO this MPRemoting will be moved into a remoting peer proxy for any command
586 if ( !wxIsMainThread() )
587 {
588 // unfortunately CW 8 is not able to correctly deduce the template types, so we have
589 // to instantiate explicitely
590 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( this , &wxTextCtrl::WriteText , str ) ;
591 return ;
592 }
593 else
594 {
595 GetPeer()->WriteText( str ) ;
596 }
597 }
598
599 void wxTextCtrl::AppendText(const wxString& text)
600 {
601 SetInsertionPointEnd();
602 WriteText(text);
603 }
604
605 void wxTextCtrl::Clear()
606 {
607 GetPeer()->Clear() ;
608 }
609
610 bool wxTextCtrl::IsModified() const
611 {
612 return m_dirty;
613 }
614
615 bool wxTextCtrl::IsEditable() const
616 {
617 return IsEnabled() && m_editable ;
618 }
619
620 bool wxTextCtrl::AcceptsFocus() const
621 {
622 // we don't want focus if we can't be edited
623 return /*IsEditable() && */ wxControl::AcceptsFocus();
624 }
625
626 wxSize wxTextCtrl::DoGetBestSize() const
627 {
628 int wText = 100 ;
629
630 int hText;
631
632 switch( m_windowVariant )
633 {
634 case wxWINDOW_VARIANT_NORMAL :
635 hText = 22 ;
636 break ;
637 case wxWINDOW_VARIANT_SMALL :
638 hText = 19 ;
639 break ;
640 case wxWINDOW_VARIANT_MINI :
641 hText= 15 ;
642 break ;
643 default :
644 hText = 22 ;
645 break ;
646 }
647
648 if ( HasFlag(wxNO_BORDER) )
649 hText -= 6 ;
650
651 if ( m_windowStyle & wxTE_MULTILINE )
652 {
653 hText *= 5 ;
654 }
655
656 return wxSize(wText, hText);
657 }
658
659 // ----------------------------------------------------------------------------
660 // Undo/redo
661 // ----------------------------------------------------------------------------
662
663 void wxTextCtrl::Undo()
664 {
665 if (CanUndo())
666 {
667 GetPeer()->Undo() ;
668 }
669 }
670
671 void wxTextCtrl::Redo()
672 {
673 if (CanRedo())
674 {
675 GetPeer()->Redo() ;
676 }
677 }
678
679 bool wxTextCtrl::CanUndo() const
680 {
681 if ( !IsEditable() )
682 {
683 return false ;
684 }
685 return GetPeer()->CanUndo() ;
686 }
687
688 bool wxTextCtrl::CanRedo() const
689 {
690 if ( !IsEditable() )
691 {
692 return false ;
693 }
694 return GetPeer()->CanRedo() ;
695 }
696
697 void wxTextCtrl::MarkDirty()
698 {
699 m_dirty = true;
700 }
701
702 void wxTextCtrl::DiscardEdits()
703 {
704 m_dirty = false;
705 }
706
707 int wxTextCtrl::GetNumberOfLines() const
708 {
709 return GetPeer()->GetNumberOfLines() ;
710 }
711
712 long wxTextCtrl::XYToPosition(long x, long y) const
713 {
714 return GetPeer()->XYToPosition( x , y ) ;
715 }
716
717 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
718 {
719 return GetPeer()->PositionToXY(pos , x , y ) ;
720 }
721
722 void wxTextCtrl::ShowPosition(long pos)
723 {
724 return GetPeer()->ShowPosition(pos) ;
725 }
726
727 int wxTextCtrl::GetLineLength(long lineNo) const
728 {
729 return GetPeer()->GetLineLength(lineNo) ;
730 }
731
732 wxString wxTextCtrl::GetLineText(long lineNo) const
733 {
734 return GetPeer()->GetLineText(lineNo) ;
735 }
736
737 /*
738 * Text item
739 */
740
741 void wxTextCtrl::Command(wxCommandEvent & event)
742 {
743 SetValue (event.GetString());
744 ProcessCommand (event);
745 }
746
747 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
748 {
749 // By default, load the first file into the text window.
750 if (event.GetNumberOfFiles() > 0)
751 {
752 LoadFile(event.GetFiles()[0]);
753 }
754 }
755
756 void wxTextCtrl::OnChar(wxKeyEvent& event)
757 {
758 int key = event.GetKeyCode() ;
759 bool eat_key = false ;
760
761 if ( key == 'c' && event.MetaDown() )
762 {
763 if ( CanCopy() )
764 Copy() ;
765 return ;
766 }
767
768 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
769 !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
770 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
771 )
772 {
773 // eat it
774 return ;
775 }
776
777 // assume that any key not processed yet is going to modify the control
778 m_dirty = true;
779
780 if ( key == 'v' && event.MetaDown() )
781 {
782 if ( CanPaste() )
783 Paste() ;
784 return ;
785 }
786 if ( key == 'x' && event.MetaDown() )
787 {
788 if ( CanCut() )
789 Cut() ;
790 return ;
791 }
792 switch ( key )
793 {
794 case WXK_RETURN:
795 if (m_windowStyle & wxPROCESS_ENTER)
796 {
797 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
798 event.SetEventObject( this );
799 event.SetString( GetValue() );
800 if ( GetEventHandler()->ProcessEvent(event) )
801 return;
802 }
803 if ( !(m_windowStyle & wxTE_MULTILINE) )
804 {
805 wxWindow *parent = GetParent();
806 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
807 parent = parent->GetParent() ;
808 }
809 if ( parent && parent->GetDefaultItem() )
810 {
811 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
812 wxButton);
813 if ( def && def->IsEnabled() )
814 {
815 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
816 event.SetEventObject(def);
817 def->Command(event);
818 return ;
819 }
820 }
821
822 // this will make wxWidgets eat the ENTER key so that
823 // we actually prevent line wrapping in a single line
824 // text control
825 eat_key = TRUE;
826 }
827
828 break;
829
830 case WXK_TAB:
831 if ( !(m_windowStyle & wxTE_PROCESS_TAB))
832 {
833 int flags = 0;
834 if (!event.ShiftDown())
835 flags |= wxNavigationKeyEvent::IsForward ;
836 if (event.ControlDown())
837 flags |= wxNavigationKeyEvent::WinChange ;
838 Navigate(flags);
839 return;
840 }
841 else
842 {
843 // This is necessary (don't know why) or the tab will not
844 // be inserted.
845 WriteText(wxT("\t"));
846 }
847
848 break;
849 }
850
851 if (!eat_key)
852 {
853 // perform keystroke handling
854 if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
855 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
856 else
857 {
858 EventRecord rec ;
859 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
860 {
861 EventRecord *ev = &rec ;
862 short keycode ;
863 short keychar ;
864 keychar = short(ev->message & charCodeMask);
865 keycode = short(ev->message & keyCodeMask) >> 8 ;
866
867 m_peer->HandleKey( keycode , keychar , ev->modifiers ) ;
868 }
869 }
870 }
871 if ( ( key >= 0x20 && key < WXK_START ) ||
872 key == WXK_RETURN ||
873 key == WXK_DELETE ||
874 key == WXK_BACK)
875 {
876 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
877 event1.SetString( GetValue() ) ;
878 event1.SetEventObject( this );
879 wxPostEvent(GetEventHandler(),event1);
880 }
881 }
882
883 // ----------------------------------------------------------------------------
884 // standard handlers for standard edit menu events
885 // ----------------------------------------------------------------------------
886
887 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
888 {
889 Cut();
890 }
891
892 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
893 {
894 Copy();
895 }
896
897 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
898 {
899 Paste();
900 }
901
902 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
903 {
904 Undo();
905 }
906
907 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
908 {
909 Redo();
910 }
911
912 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
913 {
914 event.Enable( CanCut() );
915 }
916
917 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
918 {
919 event.Enable( CanCopy() );
920 }
921
922 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
923 {
924 event.Enable( CanPaste() );
925 }
926
927 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
928 {
929 event.Enable( CanUndo() );
930 }
931
932 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
933 {
934 event.Enable( CanRedo() );
935 }
936
937 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
938 {
939 return true ;
940 }
941
942 // user pane implementation
943
944 void wxTextCtrl::MacControlUserPaneDrawProc(wxInt16 part)
945 {
946 }
947
948 wxInt16 wxTextCtrl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
949 {
950 return kControlNoPart ;
951 }
952
953 wxInt16 wxTextCtrl::MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc)
954 {
955 return kControlNoPart ;
956 }
957
958 void wxTextCtrl::MacControlUserPaneIdleProc()
959 {
960 }
961
962 wxInt16 wxTextCtrl::MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
963 {
964 return kControlNoPart ;
965 }
966
967 void wxTextCtrl::MacControlUserPaneActivateProc(bool activating)
968 {
969 }
970
971 wxInt16 wxTextCtrl::MacControlUserPaneFocusProc(wxInt16 action)
972 {
973 return kControlNoPart ;
974 }
975
976 void wxTextCtrl::MacControlUserPaneBackgroundProc(void* info)
977 {
978 }
979
980 // ----------------------------------------------------------------------------
981 // implementation base class
982 // ----------------------------------------------------------------------------
983
984 wxMacTextControl::wxMacTextControl()
985 {
986 }
987
988 wxMacTextControl::~wxMacTextControl()
989 {
990 }
991
992 void wxMacTextControl::SetStyle(long start, long end, const wxTextAttr& style)
993 {
994 }
995
996 void wxMacTextControl::Copy()
997 {
998 }
999
1000 void wxMacTextControl::Cut()
1001 {
1002 }
1003
1004 void wxMacTextControl::Paste()
1005 {
1006 }
1007
1008 bool wxMacTextControl::CanPaste() const
1009 {
1010 return false ;
1011 }
1012
1013 void wxMacTextControl::SetEditable(bool editable)
1014 {
1015 }
1016
1017 long wxMacTextControl::GetLastPosition() const
1018 {
1019 return GetStringValue().Length() ;
1020 }
1021
1022 void wxMacTextControl::Replace( long from , long to , const wxString str )
1023 {
1024 }
1025
1026 void wxMacTextControl::Clear()
1027 {
1028 SetStringValue( wxEmptyString ) ;
1029 }
1030
1031 bool wxMacTextControl::CanUndo() const
1032 {
1033 return false ;
1034 }
1035
1036 void wxMacTextControl::Undo() { }
1037
1038 bool wxMacTextControl::CanRedo() const
1039 {
1040 return false ;
1041 }
1042
1043 void wxMacTextControl::Redo()
1044 {
1045 }
1046
1047 long wxMacTextControl::XYToPosition(long x, long y) const
1048 {
1049 return 0 ;
1050 }
1051
1052 bool wxMacTextControl::PositionToXY(long pos, long *x, long *y) const
1053 {
1054 return false ;
1055 }
1056
1057 void wxMacTextControl::ShowPosition( long WXUNUSED(pos) )
1058 {
1059 }
1060
1061 int wxMacTextControl::GetNumberOfLines() const
1062 {
1063 ItemCount lines = 0 ;
1064 wxString content = GetStringValue() ;
1065 lines = 1;
1066 for (size_t i = 0; i < content.Length() ; i++)
1067 {
1068 if (content[i] == '\r') lines++;
1069 }
1070 return lines ;
1071 }
1072
1073 wxString wxMacTextControl::GetLineText(long lineNo) const
1074 {
1075 // TODO change this if possible to reflect real lines
1076 wxString content = GetStringValue() ;
1077
1078 // Find line first
1079 int count = 0;
1080 for (size_t i = 0; i < content.Length() ; i++)
1081 {
1082 if (count == lineNo)
1083 {
1084 // Add chars in line then
1085 wxString tmp;
1086
1087 for (size_t j = i; j < content.Length(); j++)
1088 {
1089 if (content[j] == '\n')
1090 return tmp;
1091
1092 tmp += content[j];
1093 }
1094
1095 return tmp;
1096 }
1097 if (content[i] == '\n') count++;
1098 }
1099 return wxEmptyString ;
1100 }
1101
1102 int wxMacTextControl::GetLineLength(long lineNo) const
1103 {
1104 // TODO change this if possible to reflect real lines
1105 wxString content = GetStringValue() ;
1106
1107 // Find line first
1108 int count = 0;
1109 for (size_t i = 0; i < content.Length() ; i++)
1110 {
1111 if (count == lineNo)
1112 {
1113 // Count chars in line then
1114 count = 0;
1115 for (size_t j = i; j < content.Length(); j++)
1116 {
1117 count++;
1118 if (content[j] == '\n') return count;
1119 }
1120
1121 return count;
1122 }
1123 if (content[i] == '\n') count++;
1124 }
1125 return 0 ;
1126 }
1127
1128 // ----------------------------------------------------------------------------
1129 // standard unicode control implementation
1130 // ----------------------------------------------------------------------------
1131
1132 #if TARGET_API_MAC_OSX
1133
1134 wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxWindow *wxPeer,
1135 const wxString& str,
1136 const wxPoint& pos,
1137 const wxSize& size, long style )
1138 {
1139 m_font = wxPeer->GetFont() ;
1140 m_windowStyle = style ;
1141 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
1142 wxString st = str ;
1143 wxMacConvertNewlines13To10( &st ) ;
1144 wxMacCFStringHolder cf(st , m_font.GetEncoding()) ;
1145 CFStringRef cfr = cf ;
1146 Boolean isPassword = ( m_windowStyle & wxTE_PASSWORD ) != 0 ;
1147 m_valueTag = isPassword ? kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag ;
1148 CreateEditUnicodeTextControl( MAC_WXHWND(wxPeer->MacGetTopLevelWindowRef()), &bounds , cfr , isPassword , NULL , &m_controlRef ) ;
1149
1150 if ( !(m_windowStyle & wxTE_MULTILINE) )
1151 {
1152 SetData<Boolean>( kControlEditTextPart , kControlEditTextSingleLineTag , true ) ;
1153 }
1154 }
1155
1156 wxMacUnicodeTextControl::~wxMacUnicodeTextControl()
1157 {
1158 }
1159
1160 void wxMacUnicodeTextControl::VisibilityChanged(bool shown)
1161 {
1162 if ( !(m_windowStyle & wxTE_MULTILINE) && shown )
1163 {
1164 // work around a refresh issue insofar as not always the entire content is shown even if this would be possible
1165 ControlEditTextSelectionRec sel ;
1166 CFStringRef value = NULL ;
1167
1168 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
1169 verify_noerr( GetData<CFStringRef>( 0, m_valueTag , &value ) );
1170 verify_noerr( SetData<CFStringRef>( 0, m_valueTag, &value ) );
1171 verify_noerr( SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
1172
1173 CFRelease( value ) ;
1174 }
1175 }
1176 wxString wxMacUnicodeTextControl::GetStringValue() const
1177 {
1178 wxString result ;
1179 CFStringRef value = GetData<CFStringRef>(0,m_valueTag) ;
1180 if ( value )
1181 {
1182 wxMacCFStringHolder cf(value) ;
1183 result = cf.AsString() ;
1184 }
1185 wxMacConvertNewlines10To13( &result ) ;
1186 return result ;
1187 }
1188 void wxMacUnicodeTextControl::SetStringValue( const wxString &str)
1189 {
1190 wxString st = str ;
1191 wxMacConvertNewlines13To10( &st ) ;
1192 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1193 verify_noerr( SetData<CFStringRef>( 0, m_valueTag , cf ) ) ;
1194 }
1195 void wxMacUnicodeTextControl::Copy()
1196 {
1197 SendHICommand( kHICommandCopy ) ;
1198 }
1199 void wxMacUnicodeTextControl::Cut()
1200 {
1201 SendHICommand( kHICommandCut ) ;
1202 }
1203 void wxMacUnicodeTextControl::Paste()
1204 {
1205 SendHICommand( kHICommandPaste ) ;
1206 }
1207 bool wxMacUnicodeTextControl::CanPaste() const
1208 {
1209 return true ;
1210 }
1211 void wxMacUnicodeTextControl::SetEditable(bool editable)
1212 {
1213 SetData<Boolean>( 0 , kControlEditTextLockedTag , (Boolean) !editable ) ;
1214 }
1215 void wxMacUnicodeTextControl::Remove( long from , long to )
1216 {
1217 }
1218
1219 void wxMacUnicodeTextControl::GetSelection( long* from, long* to) const
1220 {
1221 ControlEditTextSelectionRec sel ;
1222 verify_noerr(GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ) ;
1223 if ( from ) *from = sel.selStart ;
1224 if ( to ) *to = sel.selEnd ;
1225 }
1226
1227 void wxMacUnicodeTextControl::SetSelection( long from , long to )
1228 {
1229 ControlEditTextSelectionRec sel ;
1230 sel.selStart = from ;
1231 sel.selEnd = to ;
1232 SetData<ControlEditTextSelectionRec>( 0 , kControlEditTextSelectionTag, &sel ) ;
1233 }
1234
1235 void wxMacUnicodeTextControl::WriteText(const wxString& str)
1236 {
1237 wxString st = str ;
1238 wxMacConvertNewlines13To10( &st ) ;
1239 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
1240 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1241 CFStringRef value = cf ;
1242 SetData<CFStringRef>( 0, kControlEditTextInsertCFStringRefTag, &value );
1243 #else
1244 wxString val = GetStringValue() ;
1245 long start , end ;
1246 GetSelection( &start , &end ) ;
1247 val.Remove( start , end - start ) ;
1248 val.insert( start , str ) ;
1249 SetStringValue( val ) ;
1250 SetInsertionPoint( start + str.Length() ) ;
1251 #endif
1252 }
1253
1254 #endif
1255
1256 // ----------------------------------------------------------------------------
1257 // MLTE control implementation (common part)
1258 // ----------------------------------------------------------------------------
1259
1260 #if TARGET_API_MAC_OSX == 0
1261 // declaration needed because of one line in the code...
1262 static void TPUpdateVisibility(ControlRef theControl) ;
1263 #endif
1264
1265 // if mlte is on read only , no changes at all are allowed, not even from
1266 // procedural API, in order to allow changes via API all the same we must undo
1267 // the readonly status while we are executing, this class helps to do so
1268
1269 class EditHelper
1270 {
1271 public :
1272 EditHelper( TXNObject txn )
1273 {
1274 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1275 m_txn = txn ;
1276 TXNGetTXNObjectControls( m_txn , 1 , tag , m_data ) ;
1277 if ( m_data[0].uValue == kTXNReadOnly )
1278 {
1279 TXNControlData data[] = { { kTXNReadWrite } } ;
1280 TXNSetTXNObjectControls( m_txn , false , 1 , tag , data ) ;
1281 }
1282 }
1283 ~EditHelper()
1284 {
1285 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1286 if ( m_data[0].uValue == kTXNReadOnly )
1287 {
1288 TXNSetTXNObjectControls( m_txn , false , 1 , tag , m_data ) ;
1289 }
1290 }
1291 protected :
1292 TXNObject m_txn ;
1293 TXNControlData m_data[1] ;
1294 } ;
1295
1296 wxString wxMacMLTEControl::GetStringValue() const
1297 {
1298 wxString result ;
1299 OSStatus err ;
1300 Size actualSize = 0;
1301 {
1302 #if wxUSE_UNICODE
1303 Handle theText ;
1304 err = TXNGetDataEncoded( m_txn , kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
1305 // all done
1306 if ( err )
1307 {
1308 actualSize = 0 ;
1309 }
1310 else
1311 {
1312 actualSize = GetHandleSize( theText ) / sizeof( UniChar) ;
1313 if ( actualSize > 0 )
1314 {
1315 wxChar *ptr = NULL ;
1316 #if SIZEOF_WCHAR_T == 2
1317 ptr = new wxChar[actualSize + 1 ] ;
1318 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
1319
1320 #else
1321 SetHandleSize( theText , ( actualSize + 1 ) * sizeof( UniChar ) ) ;
1322 HLock( theText ) ;
1323 (((UniChar*)*theText)[actualSize]) = 0 ;
1324 wxMBConvUTF16BE converter ;
1325 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
1326 ptr = new wxChar[noChars + 1] ;
1327
1328 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars ) ;
1329 ptr[noChars] = 0 ;
1330 HUnlock( theText ) ;
1331 #endif
1332 ptr[actualSize] = 0 ;
1333 result = wxString( ptr ) ;
1334 delete[] ptr ;
1335 }
1336 DisposeHandle( theText ) ;
1337 }
1338 #else
1339 Handle theText ;
1340 err = TXNGetDataEncoded( m_txn , kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1341 // all done
1342 if ( err )
1343 {
1344 actualSize = 0 ;
1345 }
1346 else
1347 {
1348 actualSize = GetHandleSize( theText ) ;
1349 if ( actualSize > 0 )
1350 {
1351 HLock( theText ) ;
1352 result = wxString( *theText , wxConvLocal , actualSize ) ;
1353 HUnlock( theText ) ;
1354 }
1355 DisposeHandle( theText ) ;
1356 }
1357 #endif
1358 }
1359 wxMacConvertNewlines10To13( &result ) ;
1360 return result ;
1361 }
1362
1363 void wxMacMLTEControl::SetStringValue( const wxString &str)
1364 {
1365 wxString st = str ;
1366 wxMacConvertNewlines13To10( &st ) ;
1367 EditHelper help(m_txn) ;
1368
1369 // wxMacWindowClipper c( this ) ;
1370 #if !TARGET_API_MAC_OSX
1371 // otherwise scrolling might have problems ?
1372 TPUpdateVisibility( m_controlRef ) ;
1373 #endif
1374 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
1375 TXNSetSelection( m_txn, 0, 0);
1376 TXNShowSelection( m_txn, kTXNShowStart);
1377 }
1378
1379 TXNFrameOptions wxMacMLTEControl::FrameOptionsFromWXStyle( long wxStyle )
1380 {
1381 TXNFrameOptions frameOptions =
1382 kTXNDontDrawCaretWhenInactiveMask ;
1383 if ( ! ( wxStyle & wxTE_NOHIDESEL ) )
1384 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
1385
1386 if ( wxStyle & wxTE_MULTILINE )
1387 {
1388 if ( ! ( wxStyle & wxTE_DONTWRAP ) )
1389 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
1390 else
1391 {
1392 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
1393 frameOptions |= kTXNWantHScrollBarMask ;
1394 }
1395
1396 if ( !(wxStyle & wxTE_NO_VSCROLL ) )
1397 frameOptions |= kTXNWantVScrollBarMask ;
1398 }
1399 else
1400 frameOptions |= kTXNSingleLineOnlyMask ;
1401
1402 if ( wxStyle & wxHSCROLL )
1403 frameOptions |= kTXNWantHScrollBarMask ;
1404
1405 return frameOptions ;
1406 }
1407
1408 void wxMacMLTEControl::AdjustCreationAttributes( const wxColour &background, bool visible )
1409 {
1410 TXNControlTag iControlTags[3] = { kTXNDoFontSubstitution, kTXNWordWrapStateTag };
1411 TXNControlData iControlData[3] = { {false}, {kTXNNoAutoWrap} };
1412 int toptag = 2 ;
1413 #if TARGET_API_MAC_OSX
1414 iControlTags[2] = kTXNVisibilityTag ;
1415 iControlData[2].uValue = visible ;
1416 toptag++ ;
1417 #endif
1418
1419 if ( m_windowStyle & wxTE_MULTILINE )
1420 {
1421 if (m_windowStyle & wxTE_DONTWRAP)
1422 iControlData[1].uValue = kTXNNoAutoWrap ;
1423 else
1424 iControlData[1].uValue = kTXNAutoWrap ;
1425
1426 }
1427 verify_noerr( TXNSetTXNObjectControls( m_txn, false, toptag,
1428 iControlTags, iControlData )) ;
1429
1430 // setting the default font
1431
1432 Str255 fontName ;
1433 SInt16 fontSize ;
1434 Style fontStyle ;
1435
1436 GetThemeFont(kThemeSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
1437
1438 TXNTypeAttributes typeAttr[] =
1439 {
1440 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
1441 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
1442 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
1443 } ;
1444
1445 verify_noerr( TXNSetTypeAttributes (m_txn, sizeof( typeAttr ) / sizeof(TXNTypeAttributes) , typeAttr,
1446 kTXNStartOffset,
1447 kTXNEndOffset) );
1448
1449 if ( m_windowStyle & wxTE_PASSWORD )
1450 {
1451 UniChar c = 0xA5 ;
1452 verify_noerr(TXNEchoMode( m_txn , c , 0 , true )) ;
1453 }
1454
1455 TXNBackground tback;
1456 tback.bgType = kTXNBackgroundTypeRGB;
1457 tback.bg.color = MAC_WXCOLORREF( background.GetPixel() );
1458 TXNSetBackground( m_txn , &tback);
1459 }
1460
1461 int wxMacMLTEControl::ConvertAttribute( const wxTextAttr& style , TXNTypeAttributes typeAttr[] )
1462 {
1463 Str255 fontName = "\pMonaco" ;
1464 SInt16 fontSize = 12 ;
1465 Style fontStyle = normal ;
1466 RGBColor color ;
1467 int attrCounter = 0 ;
1468 if ( style.HasFont() )
1469 {
1470 const wxFont &font = style.GetFont() ;
1471 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
1472 fontSize = font.GetPointSize() ;
1473 if ( font.GetUnderlined() )
1474 fontStyle |= underline ;
1475 if ( font.GetWeight() == wxBOLD )
1476 fontStyle |= bold ;
1477 if ( font.GetStyle() == wxITALIC )
1478 fontStyle |= italic ;
1479
1480 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
1481 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
1482 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
1483 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
1484 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
1485 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
1486 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
1487 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
1488 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
1489 attrCounter += 3 ;
1490
1491 }
1492 if ( style.HasTextColour() )
1493 {
1494 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
1495 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
1496 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
1497 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
1498 attrCounter += 1 ;
1499 }
1500 return attrCounter ;
1501 }
1502
1503 void wxMacMLTEControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle )
1504 {
1505 EditHelper help(m_txn) ;
1506 wxTextAttr style(wxNullColour,wxNullColour,font) ;
1507 TXNTypeAttributes typeAttr[4] ;
1508 int attrCounter = ConvertAttribute( style , typeAttr ) ;
1509 if ( attrCounter > 0 )
1510 {
1511 verify_noerr( TXNSetTypeAttributes ( m_txn , attrCounter , typeAttr, kTXNStartOffset,kTXNEndOffset) );
1512 }
1513 }
1514 void wxMacMLTEControl::SetStyle(long start, long end, const wxTextAttr& style)
1515 {
1516 EditHelper help(m_txn) ;
1517 TXNTypeAttributes typeAttr[4] ;
1518 int attrCounter = ConvertAttribute( style , typeAttr ) ;
1519 if ( attrCounter > 0 )
1520 {
1521 verify_noerr( TXNSetTypeAttributes ( m_txn , attrCounter , typeAttr, start,end) );
1522 }
1523 }
1524
1525 void wxMacMLTEControl::Copy()
1526 {
1527 ClearCurrentScrap();
1528 TXNCopy(m_txn);
1529 TXNConvertToPublicScrap();
1530 }
1531
1532 void wxMacMLTEControl::Cut()
1533 {
1534 ClearCurrentScrap();
1535 TXNCut(m_txn);
1536 TXNConvertToPublicScrap();
1537 }
1538
1539 void wxMacMLTEControl::Paste()
1540 {
1541 TXNConvertFromPublicScrap();
1542 TXNPaste(m_txn);
1543 }
1544
1545 bool wxMacMLTEControl::CanPaste() const
1546 {
1547 return TXNIsScrapPastable() ;
1548 }
1549
1550 void wxMacMLTEControl::SetEditable(bool editable)
1551 {
1552 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1553 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1554 TXNSetTXNObjectControls( m_txn , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ;
1555 }
1556
1557 long wxMacMLTEControl::GetLastPosition() const
1558 {
1559 long actualsize = 0 ;
1560
1561 Handle theText ;
1562 OSErr err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1563 /* all done */
1564 if ( err )
1565 {
1566 actualsize = 0 ;
1567 }
1568 else
1569 {
1570 actualsize = GetHandleSize( theText ) ;
1571 DisposeHandle( theText ) ;
1572 }
1573
1574 return actualsize ;
1575 }
1576
1577 void wxMacMLTEControl::Replace( long from , long to , const wxString str )
1578 {
1579 wxString value = str ;
1580 wxMacConvertNewlines13To10( &value ) ;
1581
1582 EditHelper help( m_txn ) ;
1583
1584 TXNSetSelection(m_txn , from , to ) ;
1585 TXNClear( m_txn ) ;
1586 SetTXNData( str , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1587 }
1588
1589 void wxMacMLTEControl::Remove( long from , long to )
1590 {
1591 EditHelper help( m_txn ) ;
1592
1593 TXNSetSelection(m_txn , from , to ) ;
1594 TXNClear( m_txn ) ;
1595 }
1596
1597 void wxMacMLTEControl::GetSelection( long* from, long* to) const
1598 {
1599 TXNGetSelection( m_txn , (TXNOffset*) from , (TXNOffset*) to ) ;
1600 }
1601
1602 void wxMacMLTEControl::SetSelection( long from , long to )
1603 {
1604 /* change the selection */
1605 if ((from == -1) && (to == -1))
1606 TXNSelectAll(m_txn);
1607 else
1608 TXNSetSelection( m_txn, from, to);
1609 TXNShowSelection( m_txn, kTXNShowStart);
1610 }
1611
1612 void wxMacMLTEControl::WriteText(const wxString& str)
1613 {
1614 EditHelper helper( m_txn ) ;
1615 wxString st = str ;
1616 wxMacConvertNewlines13To10( &st ) ;
1617
1618 long start , end , dummy ;
1619 GetSelection( &start , &dummy ) ;
1620 SetTXNData( st , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1621 GetSelection( &dummy , &end ) ;
1622 // TODO SetStyle( start , end , GetDefaultStyle() ) ;
1623 }
1624
1625 void wxMacMLTEControl::Clear()
1626 {
1627 EditHelper st(m_txn) ;
1628 TXNSetSelection( m_txn , kTXNStartOffset , kTXNEndOffset ) ;
1629 TXNClear(m_txn);
1630 }
1631
1632 bool wxMacMLTEControl::CanUndo() const
1633 {
1634 return TXNCanUndo( m_txn , NULL ) ;
1635 }
1636
1637 void wxMacMLTEControl::Undo()
1638 {
1639 TXNUndo( m_txn ) ;
1640 }
1641
1642 bool wxMacMLTEControl::CanRedo() const
1643 {
1644 return TXNCanRedo( m_txn , NULL ) ;
1645 }
1646
1647 void wxMacMLTEControl::Redo()
1648 {
1649 TXNRedo( m_txn ) ;
1650 }
1651
1652 int wxMacMLTEControl::GetNumberOfLines() const
1653 {
1654 ItemCount lines = 0 ;
1655 TXNGetLineCount(m_txn, &lines ) ;
1656 return lines ;
1657 }
1658
1659 long wxMacMLTEControl::XYToPosition(long x, long y) const
1660 {
1661 Point curpt ;
1662
1663 long lastpos = GetLastPosition() ;
1664
1665 // TODO find a better implementation : while we can get the
1666 // line metrics of a certain line, we don't get its starting
1667 // position, so it would probably be rather a binary search
1668 // for the start position
1669 long xpos = 0 ;
1670 long ypos = 0 ;
1671 int lastHeight = 0 ;
1672
1673 ItemCount n ;
1674 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1675 {
1676 if ( y == ypos && x == xpos )
1677 return n ;
1678
1679 TXNOffsetToPoint( m_txn , n , &curpt);
1680
1681 if ( curpt.v > lastHeight )
1682 {
1683 xpos = 0 ;
1684 if ( n > 0 )
1685 ++ypos ;
1686 lastHeight = curpt.v ;
1687 }
1688 else
1689 ++xpos ;
1690 }
1691 return 0 ;
1692 }
1693
1694 bool wxMacMLTEControl::PositionToXY(long pos, long *x, long *y) const
1695 {
1696 Point curpt ;
1697
1698 long lastpos = GetLastPosition() ;
1699
1700 if ( y ) *y = 0 ;
1701 if ( x ) *x = 0 ;
1702
1703 if ( pos <= lastpos )
1704 {
1705 // TODO find a better implementation : while we can get the
1706 // line metrics of a certain line, we don't get its starting
1707 // position, so it would probably be rather a binary search
1708 // for the start position
1709 long xpos = 0 ;
1710 long ypos = 0 ;
1711 int lastHeight = 0 ;
1712
1713 ItemCount n ;
1714 for ( n = 0 ; n <= (ItemCount) pos ; ++n )
1715 {
1716 TXNOffsetToPoint(m_txn , n , &curpt);
1717
1718 if ( curpt.v > lastHeight )
1719 {
1720 xpos = 0 ;
1721 if ( n > 0 )
1722 ++ypos ;
1723 lastHeight = curpt.v ;
1724 }
1725 else
1726 ++xpos ;
1727 }
1728 if ( y ) *y = ypos ;
1729 if ( x ) *x = xpos ;
1730 }
1731
1732 return FALSE ;
1733 }
1734
1735 void wxMacMLTEControl::ShowPosition( long pos )
1736 {
1737 #if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER)
1738 {
1739 Point current ;
1740 Point desired ;
1741 TXNOffset selstart , selend ;
1742 TXNGetSelection( m_txn , &selstart , &selend) ;
1743 TXNOffsetToPoint( m_txn, selstart , &current);
1744 TXNOffsetToPoint( m_txn, pos , &desired);
1745 //TODO use HIPoints for 10.3 and above
1746 if ( (UInt32) TXNScroll != (UInt32) kUnresolvedCFragSymbolAddress )
1747 {
1748 OSErr theErr = noErr;
1749 SInt32 dv = desired.v - current.v ;
1750 SInt32 dh = desired.h - current.h ;
1751 TXNShowSelection( m_txn , true ) ;
1752 theErr = TXNScroll( m_txn, kTXNScrollUnitsInPixels , kTXNScrollUnitsInPixels , &dv , &dh );
1753 wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
1754 }
1755 }
1756 #endif
1757 }
1758
1759 void wxMacMLTEControl::SetTXNData( const wxString& st , TXNOffset start , TXNOffset end )
1760 {
1761 #if wxUSE_UNICODE
1762 #if SIZEOF_WCHAR_T == 2
1763 size_t len = st.Len() ;
1764 TXNSetData( m_txn , kTXNUnicodeTextData, (void*)st.wc_str(), len * 2,
1765 start, end);
1766 #else
1767 wxMBConvUTF16BE converter ;
1768 ByteCount byteBufferLen = converter.WC2MB( NULL , st.wc_str() , 0 ) ;
1769 UniChar *unibuf = (UniChar*) malloc(byteBufferLen) ;
1770 converter.WC2MB( (char*) unibuf , st.wc_str() , byteBufferLen ) ;
1771 TXNSetData( m_txn , kTXNUnicodeTextData, (void*)unibuf, byteBufferLen ,
1772 start, end);
1773 free( unibuf ) ;
1774 #endif
1775 #else
1776 wxCharBuffer text = st.mb_str(wxConvLocal) ;
1777 TXNSetData( m_txn , kTXNTextData, (void*)text.data(), strlen( text ) ,
1778 start, end);
1779 #endif
1780 }
1781
1782
1783 wxString wxMacMLTEControl::GetLineText(long lineNo) const
1784 {
1785 wxString line ;
1786 Point curpt ;
1787 wxString content = GetStringValue() ;
1788
1789 if ( lineNo < GetNumberOfLines() )
1790 {
1791 // TODO find a better implementation : while we can get the
1792 // line metrics of a certain line, we don't get its starting
1793 // position, so it would probably be rather a binary search
1794 // for the start position
1795 long xpos = 0 ;
1796 long ypos = 0 ;
1797 int lastHeight = 0 ;
1798 long lastpos = GetLastPosition() ;
1799
1800 ItemCount n ;
1801 for ( n = 0 ; n <= (ItemCount)lastpos ; ++n )
1802 {
1803 TXNOffsetToPoint( m_txn, n , &curpt);
1804
1805 if ( curpt.v > lastHeight )
1806 {
1807 if ( ypos == lineNo )
1808 return line ;
1809
1810 xpos = 0 ;
1811 if ( n > 0 )
1812 ++ypos ;
1813 lastHeight = curpt.v ;
1814 }
1815 else
1816 {
1817 if ( ypos == lineNo )
1818 line += content[n] ;
1819 ++xpos ;
1820 }
1821 }
1822 }
1823 return line ;
1824 }
1825
1826 int wxMacMLTEControl::GetLineLength(long lineNo) const
1827 {
1828 Point curpt ;
1829 if ( lineNo < GetNumberOfLines() )
1830 {
1831 // TODO find a better implementation : while we can get the
1832 // line metrics of a certain line, we don't get its starting
1833 // position, so it would probably be rather a binary search
1834 // for the start position
1835 long xpos = 0 ;
1836 long ypos = 0 ;
1837 int lastHeight = 0 ;
1838 long lastpos = GetLastPosition() ;
1839
1840 ItemCount n ;
1841 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1842 {
1843 TXNOffsetToPoint( m_txn , n , &curpt);
1844
1845 if ( curpt.v > lastHeight )
1846 {
1847 if ( ypos == lineNo )
1848 return xpos ;
1849
1850 xpos = 0 ;
1851 if ( n > 0 )
1852 ++ypos ;
1853 lastHeight = curpt.v ;
1854 }
1855 else
1856 ++xpos ;
1857 }
1858 }
1859 return 0 ;
1860 }
1861
1862
1863 // ----------------------------------------------------------------------------
1864 // MLTE control implementation (classic part)
1865 // ----------------------------------------------------------------------------
1866
1867 // CS:TODO we still have a problem getting properly at the text events of a control because under Carbon
1868 // the MLTE engine registers itself for the key events thus the normal flow never occurs, the only measure for the
1869 // moment is to avoid setting the true focus on the control, the proper solution at the end would be to have
1870 // an alternate path for carbon key events that routes automatically into the same wx flow of events
1871
1872 /* part codes */
1873
1874 /* kmUPTextPart is the part code we return to indicate the user has clicked
1875 in the text area of our control */
1876 #define kmUPTextPart 1
1877
1878
1879 /* routines for using existing user pane controls.
1880 These routines are useful for cases where you would like to use an
1881 existing user pane control in, say, a dialog window as a scrolling
1882 text edit field.*/
1883
1884 /* Utility Routines */
1885
1886 /* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus
1887 routine. In our focus switching routine this part code is understood
1888 as meaning 'the user has clicked in the control and we need to switch
1889 the current focus to ourselves before we can continue'. */
1890 #define kUserClickedToFocusPart 100
1891
1892 /* STPTextPaneVars is a structure used for storing the the mUP Control's
1893 internal variables and state information. A handle to this record is
1894 stored in the pane control's reference value field using the
1895 SetControlReference routine. */
1896
1897 class STPTextPaneVars {
1898 public :
1899 /* OS records referenced */
1900 TXNObject fTXNRec; /* the txn record */
1901 TXNFrameID fTXNFrame; /* the txn frame ID */
1902 ControlRef fUserPaneRec; /* handle to the user pane control */
1903 WindowPtr fOwner; /* window containing control */
1904 GrafPtr fDrawingEnvironment; /* grafport where control is drawn */
1905 /* flags */
1906 Boolean fInFocus; /* true while the focus rect is drawn around the control */
1907 Boolean fIsActive; /* true while the control is drawn in the active state */
1908 Boolean fTXNObjectActive; /* reflects the activation state of the text edit record */
1909 Boolean fFocusDrawState; /* true if focus is drawn (default: true) */
1910 /* calculated locations */
1911 Rect fRBounds; /* control bounds */
1912 Rect fRTextArea; /* area where the text is drawn */
1913 Rect fRFocusOutline; /* rectangle used to draw the focus box */
1914 Rect fRTextOutline; /* rectangle used to draw the border */
1915 RgnHandle fRTextOutlineRegion; /* background region for the text, erased before calling TEUpdate */
1916 /* our focus advance override routine */
1917 EventHandlerUPP handlerUPP;
1918 EventHandlerRef handlerRef;
1919 bool fNoBorders ;
1920 bool fMultiline ;
1921 bool fVisible ;
1922 } ;
1923
1924 /* Univerals Procedure Pointer variables used by the
1925 mUP Control. These variables are set up
1926 the first time that mUPOpenControl is called. */
1927 ControlUserPaneDrawUPP gTPDrawProc = NULL;
1928 ControlUserPaneHitTestUPP gTPHitProc = NULL;
1929 ControlUserPaneTrackingUPP gTPTrackProc = NULL;
1930 ControlUserPaneIdleUPP gTPIdleProc = NULL;
1931 ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
1932 ControlUserPaneActivateUPP gTPActivateProc = NULL;
1933 ControlUserPaneFocusUPP gTPFocusProc = NULL;
1934
1935 // one place for calculating all
1936 static void TPCalculateBounds(STPTextPaneVars *varsp, const Rect& bounds)
1937 {
1938 SetRect(&varsp->fRBounds, bounds.left, bounds.top, bounds.right, bounds.bottom);
1939 SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
1940 // eventually make TextOutline inset 1,1
1941 SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
1942 if ( !varsp->fNoBorders )
1943 {
1944 SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) ,
1945 bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2));
1946 }
1947 else
1948 {
1949 SetRect(&varsp->fRTextArea, bounds.left , bounds.top ,
1950 bounds.right, bounds.bottom);
1951 }
1952 }
1953
1954 OSStatus MLTESetObjectVisibility( STPTextPaneVars *varsp, Boolean vis , long wxStyle)
1955 {
1956 OSStatus err = noErr ;
1957 #if TARGET_API_MAC_OSX
1958 TXNControlTag iControlTags[1] = { kTXNVisibilityTag };
1959 TXNControlData iControlData[1] = {{ vis }};
1960 err = ::TXNSetTXNObjectControls( varsp->fTXNRec, false, 1, iControlTags, iControlData );
1961 #endif
1962 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
1963 if ( vis && textctrl )
1964 {
1965 Rect bounds ;
1966 UMAGetControlBoundsInWindowCoords( varsp->fUserPaneRec, &bounds);
1967 TPCalculateBounds( varsp , bounds ) ;
1968 wxMacWindowClipper cl(textctrl) ;
1969 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left,
1970 varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame);
1971 TXNShowSelection( varsp->fTXNRec, kTXNShowStart);
1972 }
1973 return err ;
1974 }
1975
1976 // make sure we don't miss changes as carbon events are not available for these under classic
1977 static void TPUpdateVisibility(ControlRef theControl) {
1978 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
1979 if ( textctrl == NULL )
1980 return ;
1981
1982 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
1983
1984 Rect bounds ;
1985 UMAGetControlBoundsInWindowCoords(theControl, &bounds);
1986 if ( textctrl->MacIsReallyShown() != varsp->fVisible )
1987 {
1988 // invalidate old position
1989 // InvalWindowRect( GetControlOwner( theControl ) , &varsp->fRBounds ) ;
1990 varsp->fVisible = textctrl->MacIsReallyShown() ;
1991 }
1992 if ( !EqualRect( &bounds , &varsp->fRBounds ) )
1993 {
1994 // old position
1995 Rect oldBounds = varsp->fRBounds ;
1996 TPCalculateBounds( varsp , bounds ) ;
1997 // we only recalculate when visible, otherwise scrollbars get drawn at incorrect places
1998 if ( varsp->fVisible )
1999 {
2000 wxMacWindowClipper cl(textctrl) ;
2001 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left,
2002 varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame);
2003 }
2004 InvalWindowRect( GetControlOwner( theControl ) , &oldBounds ) ;
2005 InvalWindowRect( GetControlOwner( theControl ) , &varsp->fRBounds ) ;
2006 }
2007 }
2008
2009 // make correct activations
2010 static void TPActivatePaneText(STPTextPaneVars *varsp, Boolean setActive) {
2011
2012 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
2013 if (varsp->fTXNObjectActive != setActive && textctrl->MacIsReallyShown() )
2014 {
2015 varsp->fTXNObjectActive = setActive;
2016 TXNActivate(varsp->fTXNRec, varsp->fTXNFrame, varsp->fTXNObjectActive);
2017 if (varsp->fInFocus)
2018 TXNFocus( varsp->fTXNRec, varsp->fTXNObjectActive);
2019 }
2020 }
2021
2022 // update focus outlines
2023 static void TPRedrawFocusOutline(STPTextPaneVars *varsp) {
2024
2025 /* state changed */
2026 if (varsp->fFocusDrawState != (varsp->fIsActive && varsp->fInFocus))
2027 {
2028 varsp->fFocusDrawState = (varsp->fIsActive && varsp->fInFocus);
2029 DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fFocusDrawState);
2030 }
2031 }
2032
2033 // update TXN focus state
2034 static void TPFocusPaneText(STPTextPaneVars *varsp, Boolean setFocus) {
2035 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
2036
2037 if (varsp->fInFocus != setFocus && textctrl->MacIsReallyShown()) {
2038 varsp->fInFocus = setFocus;
2039 TXNFocus( varsp->fTXNRec, varsp->fInFocus);
2040 }
2041 }
2042
2043 // draw the control
2044 static pascal void TPPaneDrawProc(ControlRef theControl, ControlPartCode thePart) {
2045 /* set up our globals */
2046
2047 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2048 if ( textctrl == NULL )
2049 return ;
2050 TPUpdateVisibility( theControl ) ;
2051
2052 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2053 if ( textctrl->MacIsReallyShown() )
2054 {
2055 wxMacWindowClipper clipper( textctrl ) ;
2056 TXNDraw(varsp->fTXNRec, NULL);
2057 if ( !varsp->fNoBorders )
2058 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
2059 TPRedrawFocusOutline( varsp ) ;
2060 }
2061
2062 }
2063
2064
2065 /* TPPaneHitTestProc is called when the control manager would
2066 like to determine what part of the control the mouse resides over.
2067 We also call this routine from our tracking proc to determine how
2068 to handle mouse clicks. */
2069 static pascal ControlPartCode TPPaneHitTestProc(ControlRef theControl, Point where) {
2070 ControlPartCode result;
2071 /* set up our locals and lock down our globals*/
2072 result = 0;
2073 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2074 if ( textctrl == NULL )
2075 return 0 ;
2076 TPUpdateVisibility( theControl ) ;
2077 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2078 if (textctrl->MacIsReallyShown() )
2079 {
2080 if (PtInRect(where, &varsp->fRBounds))
2081 result = kmUPTextPart;
2082 else
2083 {
2084 // sometimes we get the coords also in control local coordinates, therefore test again
2085 if ( textctrl->MacGetTopLevelWindow()->MacUsesCompositing() )
2086 {
2087 int x = 0 , y = 0 ;
2088 textctrl->MacClientToRootWindow( &x , &y ) ;
2089 where.h += x ;
2090 where.v += y ;
2091 }
2092 if (PtInRect(where, &varsp->fRBounds))
2093 result = kmUPTextPart;
2094 else
2095 result = 0;
2096 }
2097 }
2098 return result;
2099 }
2100
2101
2102
2103
2104
2105 /* TPPaneTrackingProc is called when the mouse is being held down
2106 over our control. This routine handles clicks in the text area
2107 and in the scroll bar. */
2108 static pascal ControlPartCode TPPaneTrackingProc(ControlRef theControl, Point startPt, ControlActionUPP actionProc) {
2109
2110 ControlPartCode partCodeResult;
2111 /* make sure we have some variables... */
2112 partCodeResult = 0;
2113 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2114 if ( textctrl == NULL )
2115 return 0;
2116 TPUpdateVisibility( theControl ) ;
2117 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2118 if (textctrl->MacIsReallyShown() )
2119 {
2120 /* we don't do any of these functions unless we're in focus */
2121 if ( ! varsp->fInFocus) {
2122 WindowPtr owner;
2123 owner = GetControlOwner(theControl);
2124 ClearKeyboardFocus(owner);
2125 SetKeyboardFocus(owner, theControl, kUserClickedToFocusPart);
2126 }
2127 /* find the location for the click */
2128 // for compositing, we must convert these into toplevel window coordinates, because hittesting expects them
2129 if ( textctrl->MacGetTopLevelWindow()->MacUsesCompositing() )
2130 {
2131 int x = 0 , y = 0 ;
2132 textctrl->MacClientToRootWindow( &x , &y ) ;
2133 startPt.h += x ;
2134 startPt.v += y ;
2135 }
2136
2137 switch (TPPaneHitTestProc(theControl, startPt))
2138 {
2139
2140 /* handle clicks in the text part */
2141 case kmUPTextPart:
2142 {
2143 wxMacWindowClipper clipper( textctrl ) ;
2144
2145 EventRecord rec ;
2146 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
2147 TXNClick( varsp->fTXNRec, &rec );
2148
2149 }
2150 break;
2151
2152 }
2153 }
2154 return partCodeResult;
2155 }
2156
2157
2158 /* TPPaneIdleProc is our user pane idle routine. When our text field
2159 is active and in focus, we use this routine to set the cursor. */
2160 static pascal void TPPaneIdleProc(ControlRef theControl) {
2161 /* set up locals */
2162 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2163 if ( textctrl == NULL )
2164 return ;
2165 TPUpdateVisibility( theControl ) ;
2166 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2167 if (textctrl->MacIsReallyShown()) {
2168 /* if we're not active, then we have nothing to say about the cursor */
2169 if (varsp->fIsActive) {
2170 Rect bounds;
2171 Point mousep;
2172
2173 wxMacWindowClipper clipper( textctrl ) ;
2174 GetMouse(&mousep);
2175 /* there's a 'focus thing' and an 'unfocused thing' */
2176 if (varsp->fInFocus) {
2177 /* flash the cursor */
2178 SetPort(varsp->fDrawingEnvironment);
2179 TXNIdle(varsp->fTXNRec);
2180 /* set the cursor */
2181 if (PtInRect(mousep, &varsp->fRTextArea)) {
2182 RgnHandle theRgn;
2183 RectRgn((theRgn = NewRgn()), &varsp->fRTextArea);
2184 TXNAdjustCursor(varsp->fTXNRec, theRgn);
2185 DisposeRgn(theRgn);
2186 }
2187 else
2188 {
2189 // SetThemeCursor(kThemeArrowCursor);
2190 }
2191 } else {
2192 /* if it's in our bounds, set the cursor */
2193 UMAGetControlBoundsInWindowCoords(theControl, &bounds);
2194 if (PtInRect(mousep, &bounds))
2195 {
2196 // SetThemeCursor(kThemeArrowCursor);
2197 }
2198 }
2199 }
2200 }
2201 }
2202
2203
2204 /* TPPaneKeyDownProc is called whenever a keydown event is directed
2205 at our control. Here, we direct the keydown event to the text
2206 edit record and redraw the scroll bar and text field as appropriate. */
2207 static pascal ControlPartCode TPPaneKeyDownProc(ControlRef theControl,
2208 SInt16 keyCode, SInt16 charCode, SInt16 modifiers) {
2209
2210 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2211 if ( textctrl == NULL )
2212 return 0;
2213 TPUpdateVisibility( theControl ) ;
2214
2215 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2216 if (varsp->fInFocus)
2217 {
2218 /* turn autoscrolling on and send the key event to text edit */
2219 wxMacWindowClipper clipper( textctrl ) ;
2220 EventRecord ev ;
2221 memset( &ev , 0 , sizeof( ev ) ) ;
2222 ev.what = keyDown ;
2223 ev.modifiers = modifiers ;
2224 ev.message = (( keyCode << 8 ) & keyCodeMask ) + ( charCode & charCodeMask ) ;
2225 TXNKeyDown( varsp->fTXNRec, &ev);
2226 }
2227 return kControlEntireControl;
2228 }
2229
2230
2231 /* TPPaneActivateProc is called when the window containing
2232 the user pane control receives activate events. Here, we redraw
2233 the control and it's text as necessary for the activation state. */
2234 static pascal void TPPaneActivateProc(ControlRef theControl, Boolean activating) {
2235 /* set up locals */
2236 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2237
2238 if ( textctrl == NULL )
2239 return ;
2240 TPUpdateVisibility( theControl ) ;
2241
2242 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2243
2244 varsp->fIsActive = activating;
2245 wxMacWindowClipper clipper( textctrl ) ;
2246 TPActivatePaneText(varsp, varsp->fIsActive && varsp->fInFocus);
2247 /* redraw the frame */
2248 if ( textctrl->MacIsReallyShown() )
2249 {
2250 if ( !varsp->fNoBorders )
2251 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
2252 TPRedrawFocusOutline( varsp ) ;
2253 }
2254 }
2255
2256
2257 /* TPPaneFocusProc is called when every the focus changes to or
2258 from our control. Herein, switch the focus appropriately
2259 according to the parameters and redraw the control as
2260 necessary. */
2261 static pascal ControlPartCode TPPaneFocusProc(ControlRef theControl, ControlFocusPart action) {
2262 ControlPartCode focusResult;
2263
2264 focusResult = kControlFocusNoPart;
2265 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2266 if ( textctrl == NULL )
2267 return 0;
2268 TPUpdateVisibility( theControl ) ;
2269 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2270 /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is
2271 tabbing forwards (or shift tabbing backwards) through the items in the dialog,
2272 and kControlFocusNextPart will be received. When the user clicks in our field
2273 and it is not the current focus, then the constant kUserClickedToFocusPart will
2274 be received. The constant kControlFocusNoPart will be received when our control
2275 is the current focus and the user clicks in another control. In your focus routine,
2276 you should respond to these codes as follows:
2277
2278 kControlFocusNoPart - turn off focus and return kControlFocusNoPart. redraw
2279 the control and the focus rectangle as necessary.
2280
2281 kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off
2282 depending on its current state. redraw the control and the focus rectangle
2283 as appropriate for the new focus state. If the focus state is 'off', return the constant
2284 kControlFocusNoPart, otherwise return a non-zero part code.
2285 kUserClickedToFocusPart - is a constant defined for this example. You should
2286 define your own value for handling click-to-focus type events. */
2287 /* calculate the next highlight state */
2288 switch (action) {
2289 default:
2290 case kControlFocusNoPart:
2291 TPFocusPaneText(varsp, false);
2292 focusResult = kControlFocusNoPart;
2293 break;
2294 case kUserClickedToFocusPart:
2295 TPFocusPaneText(varsp, true);
2296 focusResult = 1;
2297 break;
2298 case kControlFocusPrevPart:
2299 case kControlFocusNextPart:
2300 TPFocusPaneText(varsp, ( ! varsp->fInFocus));
2301 focusResult = varsp->fInFocus ? 1 : kControlFocusNoPart;
2302 break;
2303 }
2304 TPActivatePaneText(varsp, varsp->fIsActive && varsp->fInFocus);
2305 /* redraw the text fram and focus rectangle to indicate the
2306 new focus state */
2307 if ( textctrl->MacIsReallyShown() )
2308 {
2309 wxMacWindowClipper c( textctrl ) ;
2310 if ( !varsp->fNoBorders )
2311 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
2312 TPRedrawFocusOutline( varsp ) ;
2313 }
2314 return focusResult;
2315 }
2316
2317 wxMacMLTEClassicControl::wxMacMLTEClassicControl( wxWindow *wxPeer,
2318 const wxString& str,
2319 const wxPoint& pos,
2320 const wxSize& size, long style )
2321 {
2322 m_font = wxPeer->GetFont() ;
2323 m_windowStyle = style ;
2324 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
2325 wxString st = str ;
2326 wxMacConvertNewlines13To10( &st ) ;
2327
2328 wxMacConvertNewlines13To10( &st ) ;
2329
2330 short featurSet;
2331
2332 featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
2333 | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground
2334 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
2335 /* create the control */
2336
2337 verify_noerr( ::CreateUserPaneControl( MAC_WXHWND(wxPeer->GetParent()->MacGetTopLevelWindowRef()), &bounds, featurSet, &m_controlRef ) );
2338
2339 {
2340 // wxMacWindowClipper c(wxPeer) ;
2341 DoCreate();
2342 }
2343
2344 if ( wxPeer->MacIsReallyShown() )
2345 MLTESetObjectVisibility( (STPTextPaneVars*) m_macTXNvars, true , style ) ;
2346
2347 {
2348 // wxMacWindowClipper clipper( wxPeer ) ;
2349
2350 TPUpdateVisibility( m_controlRef ) ;
2351
2352 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
2353
2354 TXNSetSelection( m_txn, 0, 0);
2355 TXNShowSelection( m_txn, kTXNShowStart);
2356 }
2357
2358 AdjustCreationAttributes( *wxWHITE , true ) ;
2359 }
2360
2361 wxMacMLTEClassicControl::~wxMacMLTEClassicControl()
2362 {
2363 // SetControlReference(m_controlRef , 0) ;
2364 TXNDeleteObject(m_txn);
2365 free(m_macTXNvars);
2366 }
2367
2368 void wxMacMLTEClassicControl::VisibilityChanged(bool shown)
2369 {
2370 MLTESetObjectVisibility((STPTextPaneVars*) m_macTXNvars , shown , m_windowStyle ) ;
2371 if ( !shown )
2372 InvalWindowRect( GetControlOwner( m_controlRef ) , &((STPTextPaneVars *)m_macTXNvars)->fRBounds ) ;
2373 }
2374
2375 OSStatus wxMacMLTEClassicControl::DoCreate()
2376 {
2377 Rect bounds;
2378 WindowRef theWindow;
2379
2380 OSStatus err = noErr ;
2381
2382 /* set up our globals */
2383 if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(TPPaneDrawProc);
2384 if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(TPPaneHitTestProc);
2385 if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(TPPaneTrackingProc);
2386 if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(TPPaneIdleProc);
2387 if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc);
2388 if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(TPPaneActivateProc);
2389 if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(TPPaneFocusProc);
2390
2391 /* allocate our private storage */
2392 m_macTXNvars = (STPTextPaneVars *) malloc(sizeof(STPTextPaneVars));
2393
2394 /* set the initial settings for our private data */
2395 m_macTXNvars->fMultiline = m_windowStyle & wxTE_MULTILINE ;
2396 m_macTXNvars->fNoBorders = m_windowStyle & wxNO_BORDER ;
2397 m_macTXNvars->fInFocus = false;
2398 m_macTXNvars->fIsActive = true;
2399 m_macTXNvars->fTXNObjectActive = false;
2400 m_macTXNvars->fFocusDrawState = false ;
2401 m_macTXNvars->fUserPaneRec = m_controlRef ;
2402 m_macTXNvars->fVisible = true ;
2403
2404 theWindow = m_macTXNvars->fOwner = GetControlOwner(m_controlRef);
2405
2406 m_macTXNvars->fDrawingEnvironment = (GrafPtr) GetWindowPort(theWindow);
2407
2408 /* set up the user pane procedures */
2409 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
2410 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
2411 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
2412 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
2413 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
2414 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
2415 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
2416
2417 /* calculate the rectangles used by the control */
2418 UMAGetControlBoundsInWindowCoords(m_controlRef, &bounds);
2419 m_macTXNvars->fRTextOutlineRegion = NewRgn() ;
2420 TPCalculateBounds( m_macTXNvars , bounds ) ;
2421
2422 /* set up the drawing environment */
2423 SetPort(m_macTXNvars->fDrawingEnvironment);
2424
2425 /* create the new edit field */
2426
2427 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( m_windowStyle ) ;
2428
2429 verify_noerr(TXNNewObject(NULL, m_macTXNvars->fOwner, &m_macTXNvars->fRTextArea,
2430 frameOptions ,
2431 kTXNTextEditStyleFrameType,
2432 kTXNTextensionFile,
2433 kTXNSystemDefaultEncoding,
2434 &m_macTXNvars->fTXNRec, &m_macTXNvars->fTXNFrame, (TXNObjectRefcon) m_macTXNvars));
2435 m_txn = m_macTXNvars->fTXNRec ;
2436
2437 /* perform final activations and setup for our text field. Here,
2438 we assume that the window is going to be the 'active' window. */
2439 TPActivatePaneText(m_macTXNvars, m_macTXNvars->fIsActive && m_macTXNvars->fInFocus);
2440 /* all done */
2441 return err;
2442 }
2443
2444 // ----------------------------------------------------------------------------
2445 // MLTE control implementation (OSX part)
2446 // ----------------------------------------------------------------------------
2447
2448 #if TARGET_API_MAC_OSX
2449
2450 wxMacMLTEHIViewControl::wxMacMLTEHIViewControl( wxWindow *wxPeer,
2451 const wxString& str,
2452 const wxPoint& pos,
2453 const wxSize& size, long style )
2454 {
2455 m_font = wxPeer->GetFont() ;
2456 m_windowStyle = style ;
2457 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
2458 wxString st = str ;
2459 wxMacConvertNewlines13To10( &st ) ;
2460
2461 HIRect hr = { bounds.left , bounds.top , bounds.right - bounds.left , bounds.bottom- bounds.top } ;
2462
2463 m_scrollView = NULL ;
2464 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( style ) ;
2465 if ( frameOptions & (kTXNWantVScrollBarMask|kTXNWantHScrollBarMask) )
2466 {
2467 HIScrollViewCreate(( frameOptions & kTXNWantHScrollBarMask ? kHIScrollViewOptionsHorizScroll : 0) |
2468 ( frameOptions & kTXNWantVScrollBarMask ? kHIScrollViewOptionsVertScroll: 0 ) , &m_scrollView ) ;
2469
2470 HIViewSetFrame( m_scrollView, &hr );
2471 HIViewSetVisible( m_scrollView, true );
2472 }
2473
2474 m_textView = NULL ;
2475 HITextViewCreate( NULL , 0, frameOptions , &m_textView ) ;
2476 m_txn = HITextViewGetTXNObject( m_textView) ;
2477 HIViewSetVisible( m_textView , true ) ;
2478 if ( m_scrollView )
2479 {
2480 HIViewAddSubview( m_scrollView , m_textView ) ;
2481 m_controlRef = m_scrollView ;
2482 wxPeer->MacInstallEventHandler( (WXWidget) m_textView ) ;
2483 }
2484 else
2485 {
2486 HIViewSetFrame( m_textView, &hr );
2487 m_controlRef = m_textView ;
2488 }
2489
2490
2491 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
2492
2493 TXNSetSelection( m_txn, 0, 0);
2494 TXNShowSelection( m_txn, kTXNShowStart);
2495
2496 AdjustCreationAttributes( *wxWHITE , true ) ;
2497 }
2498
2499 OSStatus wxMacMLTEHIViewControl::SetFocus( ControlFocusPart focusPart )
2500 {
2501 return SetKeyboardFocus( GetControlOwner( m_textView ) ,
2502 m_textView , focusPart ) ;
2503 }
2504
2505 bool wxMacMLTEHIViewControl::HasFocus() const
2506 {
2507 ControlRef control ;
2508 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
2509 return control == m_textView ;
2510 }
2511
2512 bool wxMacMLTEHIViewControl::NeedsFocusRect() const
2513 {
2514 return true ;
2515 }
2516
2517 #endif
2518
2519 #endif // wxUSE_TEXTCTRL