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