Honor value of SetMaxLength, at least when typing (pasting still circumvents it)...
[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 TXNFrameOptions FrameOptionsFromWXStyle( long wxStyle ) ;
203 void AdjustCreationAttributes( const wxColour& background , bool visible ) ;
204
205 virtual void SetFont( const wxFont & font , const wxColour& foreground , long windowStyle ) ;
206 virtual void SetBackground( const wxBrush &brush) ;
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 void TXNSetAttribute( const wxTextAttr& style , long from , long to ) ;
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 // Check if we have reached the max # of chars, but still allow navigation and deletion
795 if ( !IsMultiLine() && GetValue().Length() >= m_maxLength &&
796 key != WXK_LEFT && key != WXK_RIGHT && key != WXK_TAB &&
797 key != WXK_BACK && !( key == WXK_RETURN && (m_windowStyle & wxPROCESS_ENTER) )
798 )
799 {
800 // eat it, we don't want to add more than allowed # of characters
801 return;
802 }
803
804 // assume that any key not processed yet is going to modify the control
805 m_dirty = true;
806
807 if ( key == 'v' && event.MetaDown() )
808 {
809 if ( CanPaste() )
810 Paste() ;
811 return ;
812 }
813 if ( key == 'x' && event.MetaDown() )
814 {
815 if ( CanCut() )
816 Cut() ;
817 return ;
818 }
819 switch ( key )
820 {
821 case WXK_RETURN:
822 if (m_windowStyle & wxPROCESS_ENTER)
823 {
824 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
825 event.SetEventObject( this );
826 event.SetString( GetValue() );
827 if ( GetEventHandler()->ProcessEvent(event) )
828 return;
829 }
830 if ( !(m_windowStyle & wxTE_MULTILINE) )
831 {
832 wxWindow *parent = GetParent();
833 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
834 parent = parent->GetParent() ;
835 }
836 if ( parent && parent->GetDefaultItem() )
837 {
838 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
839 wxButton);
840 if ( def && def->IsEnabled() )
841 {
842 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
843 event.SetEventObject(def);
844 def->Command(event);
845 return ;
846 }
847 }
848
849 // this will make wxWidgets eat the ENTER key so that
850 // we actually prevent line wrapping in a single line
851 // text control
852 eat_key = TRUE;
853 }
854
855 break;
856
857 case WXK_TAB:
858 if ( !(m_windowStyle & wxTE_PROCESS_TAB))
859 {
860 int flags = 0;
861 if (!event.ShiftDown())
862 flags |= wxNavigationKeyEvent::IsForward ;
863 if (event.ControlDown())
864 flags |= wxNavigationKeyEvent::WinChange ;
865 Navigate(flags);
866 return;
867 }
868 else
869 {
870 // This is necessary (don't know why) or the tab will not
871 // be inserted.
872 WriteText(wxT("\t"));
873 }
874
875 break;
876 }
877
878 if (!eat_key)
879 {
880 // perform keystroke handling
881 if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
882 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
883 else
884 {
885 EventRecord rec ;
886 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
887 {
888 EventRecord *ev = &rec ;
889 short keycode ;
890 short keychar ;
891 keychar = short(ev->message & charCodeMask);
892 keycode = short(ev->message & keyCodeMask) >> 8 ;
893
894 m_peer->HandleKey( keycode , keychar , ev->modifiers ) ;
895 }
896 }
897 }
898 if ( ( key >= 0x20 && key < WXK_START ) ||
899 key == WXK_RETURN ||
900 key == WXK_DELETE ||
901 key == WXK_BACK)
902 {
903 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
904 event1.SetString( GetValue() ) ;
905 event1.SetEventObject( this );
906 wxPostEvent(GetEventHandler(),event1);
907 }
908 }
909
910 // ----------------------------------------------------------------------------
911 // standard handlers for standard edit menu events
912 // ----------------------------------------------------------------------------
913
914 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
915 {
916 Cut();
917 }
918
919 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
920 {
921 Copy();
922 }
923
924 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
925 {
926 Paste();
927 }
928
929 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
930 {
931 Undo();
932 }
933
934 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
935 {
936 Redo();
937 }
938
939 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
940 {
941 event.Enable( CanCut() );
942 }
943
944 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
945 {
946 event.Enable( CanCopy() );
947 }
948
949 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
950 {
951 event.Enable( CanPaste() );
952 }
953
954 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
955 {
956 event.Enable( CanUndo() );
957 }
958
959 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
960 {
961 event.Enable( CanRedo() );
962 }
963
964 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
965 {
966 return true ;
967 }
968
969 // user pane implementation
970
971 void wxTextCtrl::MacControlUserPaneDrawProc(wxInt16 part)
972 {
973 }
974
975 wxInt16 wxTextCtrl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
976 {
977 return kControlNoPart ;
978 }
979
980 wxInt16 wxTextCtrl::MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc)
981 {
982 return kControlNoPart ;
983 }
984
985 void wxTextCtrl::MacControlUserPaneIdleProc()
986 {
987 }
988
989 wxInt16 wxTextCtrl::MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
990 {
991 return kControlNoPart ;
992 }
993
994 void wxTextCtrl::MacControlUserPaneActivateProc(bool activating)
995 {
996 }
997
998 wxInt16 wxTextCtrl::MacControlUserPaneFocusProc(wxInt16 action)
999 {
1000 return kControlNoPart ;
1001 }
1002
1003 void wxTextCtrl::MacControlUserPaneBackgroundProc(void* info)
1004 {
1005 }
1006
1007 // ----------------------------------------------------------------------------
1008 // implementation base class
1009 // ----------------------------------------------------------------------------
1010
1011 wxMacTextControl::wxMacTextControl()
1012 {
1013 }
1014
1015 wxMacTextControl::~wxMacTextControl()
1016 {
1017 }
1018
1019 void wxMacTextControl::SetStyle(long start, long end, const wxTextAttr& style)
1020 {
1021 }
1022
1023 void wxMacTextControl::Copy()
1024 {
1025 }
1026
1027 void wxMacTextControl::Cut()
1028 {
1029 }
1030
1031 void wxMacTextControl::Paste()
1032 {
1033 }
1034
1035 bool wxMacTextControl::CanPaste() const
1036 {
1037 return false ;
1038 }
1039
1040 void wxMacTextControl::SetEditable(bool editable)
1041 {
1042 }
1043
1044 long wxMacTextControl::GetLastPosition() const
1045 {
1046 return GetStringValue().Length() ;
1047 }
1048
1049 void wxMacTextControl::Replace( long from , long to , const wxString str )
1050 {
1051 }
1052
1053 void wxMacTextControl::Clear()
1054 {
1055 SetStringValue( wxEmptyString ) ;
1056 }
1057
1058 bool wxMacTextControl::CanUndo() const
1059 {
1060 return false ;
1061 }
1062
1063 void wxMacTextControl::Undo() { }
1064
1065 bool wxMacTextControl::CanRedo() const
1066 {
1067 return false ;
1068 }
1069
1070 void wxMacTextControl::Redo()
1071 {
1072 }
1073
1074 long wxMacTextControl::XYToPosition(long x, long y) const
1075 {
1076 return 0 ;
1077 }
1078
1079 bool wxMacTextControl::PositionToXY(long pos, long *x, long *y) const
1080 {
1081 return false ;
1082 }
1083
1084 void wxMacTextControl::ShowPosition( long WXUNUSED(pos) )
1085 {
1086 }
1087
1088 int wxMacTextControl::GetNumberOfLines() const
1089 {
1090 ItemCount lines = 0 ;
1091 wxString content = GetStringValue() ;
1092 lines = 1;
1093 for (size_t i = 0; i < content.Length() ; i++)
1094 {
1095 if (content[i] == '\r') lines++;
1096 }
1097 return lines ;
1098 }
1099
1100 wxString wxMacTextControl::GetLineText(long lineNo) const
1101 {
1102 // TODO change this if possible to reflect real lines
1103 wxString content = GetStringValue() ;
1104
1105 // Find line first
1106 int count = 0;
1107 for (size_t i = 0; i < content.Length() ; i++)
1108 {
1109 if (count == lineNo)
1110 {
1111 // Add chars in line then
1112 wxString tmp;
1113
1114 for (size_t j = i; j < content.Length(); j++)
1115 {
1116 if (content[j] == '\n')
1117 return tmp;
1118
1119 tmp += content[j];
1120 }
1121
1122 return tmp;
1123 }
1124 if (content[i] == '\n') count++;
1125 }
1126 return wxEmptyString ;
1127 }
1128
1129 int wxMacTextControl::GetLineLength(long lineNo) const
1130 {
1131 // TODO change this if possible to reflect real lines
1132 wxString content = GetStringValue() ;
1133
1134 // Find line first
1135 int count = 0;
1136 for (size_t i = 0; i < content.Length() ; i++)
1137 {
1138 if (count == lineNo)
1139 {
1140 // Count chars in line then
1141 count = 0;
1142 for (size_t j = i; j < content.Length(); j++)
1143 {
1144 count++;
1145 if (content[j] == '\n') return count;
1146 }
1147
1148 return count;
1149 }
1150 if (content[i] == '\n') count++;
1151 }
1152 return 0 ;
1153 }
1154
1155 // ----------------------------------------------------------------------------
1156 // standard unicode control implementation
1157 // ----------------------------------------------------------------------------
1158
1159 #if TARGET_API_MAC_OSX
1160
1161 wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxWindow *wxPeer,
1162 const wxString& str,
1163 const wxPoint& pos,
1164 const wxSize& size, long style )
1165 {
1166 m_font = wxPeer->GetFont() ;
1167 m_windowStyle = style ;
1168 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
1169 wxString st = str ;
1170 wxMacConvertNewlines10To13( &st ) ;
1171 wxMacCFStringHolder cf(st , m_font.GetEncoding()) ;
1172 CFStringRef cfr = cf ;
1173 Boolean isPassword = ( m_windowStyle & wxTE_PASSWORD ) != 0 ;
1174 m_valueTag = isPassword ? kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag ;
1175 CreateEditUnicodeTextControl( MAC_WXHWND(wxPeer->MacGetTopLevelWindowRef()), &bounds , cfr , isPassword , NULL , &m_controlRef ) ;
1176
1177 if ( !(m_windowStyle & wxTE_MULTILINE) )
1178 {
1179 SetData<Boolean>( kControlEditTextPart , kControlEditTextSingleLineTag , true ) ;
1180 }
1181 }
1182
1183 wxMacUnicodeTextControl::~wxMacUnicodeTextControl()
1184 {
1185 }
1186
1187 void wxMacUnicodeTextControl::VisibilityChanged(bool shown)
1188 {
1189 if ( !(m_windowStyle & wxTE_MULTILINE) && shown )
1190 {
1191 // work around a refresh issue insofar as not always the entire content is shown even if this would be possible
1192 ControlEditTextSelectionRec sel ;
1193 CFStringRef value = NULL ;
1194
1195 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
1196 verify_noerr( GetData<CFStringRef>( 0, m_valueTag , &value ) );
1197 verify_noerr( SetData<CFStringRef>( 0, m_valueTag, &value ) );
1198 verify_noerr( SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
1199
1200 CFRelease( value ) ;
1201 }
1202 }
1203 wxString wxMacUnicodeTextControl::GetStringValue() const
1204 {
1205 wxString result ;
1206 CFStringRef value = GetData<CFStringRef>(0,m_valueTag) ;
1207 if ( value )
1208 {
1209 wxMacCFStringHolder cf(value) ;
1210 result = cf.AsString() ;
1211 }
1212 #if '\n' == 10
1213 wxMacConvertNewlines13To10( &result ) ;
1214 #else
1215 wxMacConvertNewlines10To13( &result ) ;
1216 #endif
1217 return result ;
1218 }
1219 void wxMacUnicodeTextControl::SetStringValue( const wxString &str)
1220 {
1221 wxString st = str ;
1222 wxMacConvertNewlines10To13( &st ) ;
1223 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1224 verify_noerr( SetData<CFStringRef>( 0, m_valueTag , cf ) ) ;
1225 }
1226 void wxMacUnicodeTextControl::Copy()
1227 {
1228 SendHICommand( kHICommandCopy ) ;
1229 }
1230 void wxMacUnicodeTextControl::Cut()
1231 {
1232 SendHICommand( kHICommandCut ) ;
1233 }
1234 void wxMacUnicodeTextControl::Paste()
1235 {
1236 SendHICommand( kHICommandPaste ) ;
1237 }
1238 bool wxMacUnicodeTextControl::CanPaste() const
1239 {
1240 return true ;
1241 }
1242 void wxMacUnicodeTextControl::SetEditable(bool editable)
1243 {
1244 SetData<Boolean>( 0 , kControlEditTextLockedTag , (Boolean) !editable ) ;
1245 }
1246 void wxMacUnicodeTextControl::Remove( long from , long to )
1247 {
1248 }
1249
1250 void wxMacUnicodeTextControl::GetSelection( long* from, long* to) const
1251 {
1252 ControlEditTextSelectionRec sel ;
1253 verify_noerr(GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ) ;
1254 if ( from ) *from = sel.selStart ;
1255 if ( to ) *to = sel.selEnd ;
1256 }
1257
1258 void wxMacUnicodeTextControl::SetSelection( long from , long to )
1259 {
1260 ControlEditTextSelectionRec sel ;
1261 sel.selStart = from ;
1262 sel.selEnd = to ;
1263 SetData<ControlEditTextSelectionRec>( 0 , kControlEditTextSelectionTag, &sel ) ;
1264 }
1265
1266 void wxMacUnicodeTextControl::WriteText(const wxString& str)
1267 {
1268 wxString st = str ;
1269 wxMacConvertNewlines10To13( &st ) ;
1270 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
1271 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1272 CFStringRef value = cf ;
1273 SetData<CFStringRef>( 0, kControlEditTextInsertCFStringRefTag, &value );
1274 #else
1275 wxString val = GetStringValue() ;
1276 long start , end ;
1277 GetSelection( &start , &end ) ;
1278 val.Remove( start , end - start ) ;
1279 val.insert( start , str ) ;
1280 SetStringValue( val ) ;
1281 SetSelection( start + str.Length() , start + str.Length() ) ;
1282 #endif
1283 }
1284
1285 #endif
1286
1287 // ----------------------------------------------------------------------------
1288 // MLTE control implementation (common part)
1289 // ----------------------------------------------------------------------------
1290
1291 #if TARGET_API_MAC_OSX == 0
1292 // declaration needed because of one line in the code...
1293 static void TPUpdateVisibility(ControlRef theControl) ;
1294 #endif
1295
1296 // if mlte is on read only , no changes at all are allowed, not even from
1297 // procedural API, in order to allow changes via API all the same we must undo
1298 // the readonly status while we are executing, this class helps to do so
1299
1300 class EditHelper
1301 {
1302 public :
1303 EditHelper( TXNObject txn )
1304 {
1305 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1306 m_txn = txn ;
1307 TXNGetTXNObjectControls( m_txn , 1 , tag , m_data ) ;
1308 if ( m_data[0].uValue == kTXNReadOnly )
1309 {
1310 TXNControlData data[] = { { kTXNReadWrite } } ;
1311 TXNSetTXNObjectControls( m_txn , false , 1 , tag , data ) ;
1312 }
1313 }
1314 ~EditHelper()
1315 {
1316 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1317 if ( m_data[0].uValue == kTXNReadOnly )
1318 {
1319 TXNSetTXNObjectControls( m_txn , false , 1 , tag , m_data ) ;
1320 }
1321 }
1322 protected :
1323 TXNObject m_txn ;
1324 TXNControlData m_data[1] ;
1325 } ;
1326
1327 wxString wxMacMLTEControl::GetStringValue() const
1328 {
1329 wxString result ;
1330 OSStatus err ;
1331 Size actualSize = 0;
1332 {
1333 #if wxUSE_UNICODE
1334 Handle theText ;
1335 err = TXNGetDataEncoded( m_txn , kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
1336 // all done
1337 if ( err )
1338 {
1339 actualSize = 0 ;
1340 }
1341 else
1342 {
1343 actualSize = GetHandleSize( theText ) / sizeof( UniChar) ;
1344 if ( actualSize > 0 )
1345 {
1346 wxChar *ptr = NULL ;
1347 #if SIZEOF_WCHAR_T == 2
1348 ptr = new wxChar[actualSize + 1 ] ;
1349 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
1350
1351 #else
1352 SetHandleSize( theText , ( actualSize + 1 ) * sizeof( UniChar ) ) ;
1353 HLock( theText ) ;
1354 (((UniChar*)*theText)[actualSize]) = 0 ;
1355 wxMBConvUTF16BE converter ;
1356 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
1357 ptr = new wxChar[noChars + 1] ;
1358
1359 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars ) ;
1360 ptr[noChars] = 0 ;
1361 HUnlock( theText ) ;
1362 #endif
1363 ptr[actualSize] = 0 ;
1364 result = wxString( ptr ) ;
1365 delete[] ptr ;
1366 }
1367 DisposeHandle( theText ) ;
1368 }
1369 #else
1370 Handle theText ;
1371 err = TXNGetDataEncoded( m_txn , kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1372 // all done
1373 if ( err )
1374 {
1375 actualSize = 0 ;
1376 }
1377 else
1378 {
1379 actualSize = GetHandleSize( theText ) ;
1380 if ( actualSize > 0 )
1381 {
1382 HLock( theText ) ;
1383 result = wxString( *theText , wxConvLocal , actualSize ) ;
1384 HUnlock( theText ) ;
1385 }
1386 DisposeHandle( theText ) ;
1387 }
1388 #endif
1389 }
1390 #if '\n' == 10
1391 wxMacConvertNewlines13To10( &result ) ;
1392 #else
1393 wxMacConvertNewlines10To13( &result ) ;
1394 #endif
1395 return result ;
1396 }
1397
1398 void wxMacMLTEControl::SetStringValue( const wxString &str)
1399 {
1400 wxString st = str ;
1401
1402 wxMacConvertNewlines10To13( &st ) ;
1403 EditHelper help(m_txn) ;
1404
1405 // wxMacWindowClipper c( this ) ;
1406 #if !TARGET_API_MAC_OSX
1407 // otherwise scrolling might have problems ?
1408 TPUpdateVisibility( m_controlRef ) ;
1409 #endif
1410 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
1411 TXNSetSelection( m_txn, 0, 0);
1412 TXNShowSelection( m_txn, kTXNShowStart);
1413 }
1414
1415 TXNFrameOptions wxMacMLTEControl::FrameOptionsFromWXStyle( long wxStyle )
1416 {
1417 TXNFrameOptions frameOptions =
1418 kTXNDontDrawCaretWhenInactiveMask ;
1419 if ( ! ( wxStyle & wxTE_NOHIDESEL ) )
1420 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
1421
1422 if ( wxStyle & wxTE_MULTILINE )
1423 {
1424 if ( ! ( wxStyle & wxTE_DONTWRAP ) )
1425 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
1426 else
1427 {
1428 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
1429 frameOptions |= kTXNWantHScrollBarMask ;
1430 }
1431
1432 if ( !(wxStyle & wxTE_NO_VSCROLL ) )
1433 frameOptions |= kTXNWantVScrollBarMask ;
1434 }
1435 else
1436 frameOptions |= kTXNSingleLineOnlyMask ;
1437
1438 if ( wxStyle & wxHSCROLL )
1439 frameOptions |= kTXNWantHScrollBarMask ;
1440
1441 return frameOptions ;
1442 }
1443
1444 void wxMacMLTEControl::AdjustCreationAttributes( const wxColour &background, bool visible )
1445 {
1446 TXNControlTag iControlTags[3] = { kTXNDoFontSubstitution, kTXNWordWrapStateTag };
1447 TXNControlData iControlData[3] = { {false}, {kTXNNoAutoWrap} };
1448 int toptag = 2 ;
1449 #if TARGET_API_MAC_OSX
1450 iControlTags[2] = kTXNVisibilityTag ;
1451 iControlData[2].uValue = visible ;
1452 toptag++ ;
1453 #endif
1454
1455 if ( m_windowStyle & wxTE_MULTILINE )
1456 {
1457 if (m_windowStyle & wxTE_DONTWRAP)
1458 iControlData[1].uValue = kTXNNoAutoWrap ;
1459 else
1460 iControlData[1].uValue = kTXNAutoWrap ;
1461
1462 }
1463 verify_noerr( TXNSetTXNObjectControls( m_txn, false, toptag,
1464 iControlTags, iControlData )) ;
1465
1466 // setting the default font
1467
1468 Str255 fontName ;
1469 SInt16 fontSize ;
1470 Style fontStyle ;
1471
1472 GetThemeFont(kThemeSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
1473
1474 TXNTypeAttributes typeAttr[] =
1475 {
1476 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
1477 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
1478 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
1479 } ;
1480
1481 verify_noerr( TXNSetTypeAttributes (m_txn, sizeof( typeAttr ) / sizeof(TXNTypeAttributes) , typeAttr,
1482 kTXNStartOffset,
1483 kTXNEndOffset) );
1484
1485 if ( m_windowStyle & wxTE_PASSWORD )
1486 {
1487 UniChar c = 0xA5 ;
1488 verify_noerr(TXNEchoMode( m_txn , c , 0 , true )) ;
1489 }
1490
1491 TXNBackground tback;
1492 tback.bgType = kTXNBackgroundTypeRGB;
1493 tback.bg.color = MAC_WXCOLORREF( background.GetPixel() );
1494 TXNSetBackground( m_txn , &tback);
1495 }
1496
1497 void wxMacMLTEControl::SetBackground( const wxBrush &brush )
1498 {
1499 // currently only solid background are supported
1500 TXNBackground tback;
1501 tback.bgType = kTXNBackgroundTypeRGB;
1502 tback.bg.color = MAC_WXCOLORREF( brush.GetColour().GetPixel() );
1503 TXNSetBackground( m_txn , &tback);
1504 }
1505
1506 void wxMacMLTEControl::TXNSetAttribute( const wxTextAttr& style , long from , long to)
1507 {
1508 TXNTypeAttributes typeAttr[4] ;
1509 Str255 fontName = "\pMonaco" ;
1510 SInt16 fontSize = 12 ;
1511 Style fontStyle = normal ;
1512 RGBColor color ;
1513 int attrCounter = 0 ;
1514 if ( style.HasFont() )
1515 {
1516 const wxFont &font = style.GetFont() ;
1517 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
1518 fontSize = font.GetPointSize() ;
1519 if ( font.GetUnderlined() )
1520 fontStyle |= underline ;
1521 if ( font.GetWeight() == wxBOLD )
1522 fontStyle |= bold ;
1523 if ( font.GetStyle() == wxITALIC )
1524 fontStyle |= italic ;
1525
1526 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
1527 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
1528 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
1529 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
1530 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
1531 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
1532 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
1533 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
1534 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
1535 attrCounter += 3 ;
1536 }
1537 if ( style.HasTextColour() )
1538 {
1539 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
1540 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
1541 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
1542 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
1543 attrCounter += 1 ;
1544 }
1545 if ( attrCounter > 0 )
1546 {
1547 verify_noerr( TXNSetTypeAttributes ( m_txn , attrCounter , typeAttr, from , to) );
1548 }
1549 }
1550
1551 void wxMacMLTEControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle )
1552 {
1553 EditHelper help(m_txn) ;
1554 TXNSetAttribute( wxTextAttr(foreground,wxNullColour,font) , kTXNStartOffset,kTXNEndOffset ) ;
1555 }
1556 void wxMacMLTEControl::SetStyle(long start, long end, const wxTextAttr& style)
1557 {
1558 EditHelper help(m_txn) ;
1559 TXNSetAttribute( style , start,end ) ;
1560 }
1561
1562 void wxMacMLTEControl::Copy()
1563 {
1564 ClearCurrentScrap();
1565 TXNCopy(m_txn);
1566 TXNConvertToPublicScrap();
1567 }
1568
1569 void wxMacMLTEControl::Cut()
1570 {
1571 ClearCurrentScrap();
1572 TXNCut(m_txn);
1573 TXNConvertToPublicScrap();
1574 }
1575
1576 void wxMacMLTEControl::Paste()
1577 {
1578 TXNConvertFromPublicScrap();
1579 TXNPaste(m_txn);
1580 }
1581
1582 bool wxMacMLTEControl::CanPaste() const
1583 {
1584 return TXNIsScrapPastable() ;
1585 }
1586
1587 void wxMacMLTEControl::SetEditable(bool editable)
1588 {
1589 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1590 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1591 TXNSetTXNObjectControls( m_txn , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ;
1592 }
1593
1594 long wxMacMLTEControl::GetLastPosition() const
1595 {
1596 long actualsize = 0 ;
1597
1598 Handle theText ;
1599 OSErr err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1600 /* all done */
1601 if ( err )
1602 {
1603 actualsize = 0 ;
1604 }
1605 else
1606 {
1607 actualsize = GetHandleSize( theText ) ;
1608 DisposeHandle( theText ) ;
1609 }
1610
1611 return actualsize ;
1612 }
1613
1614 void wxMacMLTEControl::Replace( long from , long to , const wxString str )
1615 {
1616 wxString value = str ;
1617 wxMacConvertNewlines10To13( &value ) ;
1618
1619 EditHelper help( m_txn ) ;
1620
1621 TXNSetSelection(m_txn , from , to ) ;
1622 TXNClear( m_txn ) ;
1623 SetTXNData( value , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1624 }
1625
1626 void wxMacMLTEControl::Remove( long from , long to )
1627 {
1628 EditHelper help( m_txn ) ;
1629
1630 TXNSetSelection(m_txn , from , to ) ;
1631 TXNClear( m_txn ) ;
1632 }
1633
1634 void wxMacMLTEControl::GetSelection( long* from, long* to) const
1635 {
1636 TXNGetSelection( m_txn , (TXNOffset*) from , (TXNOffset*) to ) ;
1637 }
1638
1639 void wxMacMLTEControl::SetSelection( long from , long to )
1640 {
1641 /* change the selection */
1642 if ((from == -1) && (to == -1))
1643 TXNSelectAll(m_txn);
1644 else
1645 TXNSetSelection( m_txn, from, to);
1646 TXNShowSelection( m_txn, kTXNShowStart);
1647 }
1648
1649 void wxMacMLTEControl::WriteText(const wxString& str)
1650 {
1651 EditHelper helper( m_txn ) ;
1652 wxString st = str ;
1653 wxMacConvertNewlines10To13( &st ) ;
1654
1655 long start , end , dummy ;
1656 GetSelection( &start , &dummy ) ;
1657 SetTXNData( st , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1658 GetSelection( &dummy , &end ) ;
1659 // TODO SetStyle( start , end , GetDefaultStyle() ) ;
1660 }
1661
1662 void wxMacMLTEControl::Clear()
1663 {
1664 EditHelper st(m_txn) ;
1665 TXNSetSelection( m_txn , kTXNStartOffset , kTXNEndOffset ) ;
1666 TXNClear(m_txn);
1667 }
1668
1669 bool wxMacMLTEControl::CanUndo() const
1670 {
1671 return TXNCanUndo( m_txn , NULL ) ;
1672 }
1673
1674 void wxMacMLTEControl::Undo()
1675 {
1676 TXNUndo( m_txn ) ;
1677 }
1678
1679 bool wxMacMLTEControl::CanRedo() const
1680 {
1681 return TXNCanRedo( m_txn , NULL ) ;
1682 }
1683
1684 void wxMacMLTEControl::Redo()
1685 {
1686 TXNRedo( m_txn ) ;
1687 }
1688
1689 int wxMacMLTEControl::GetNumberOfLines() const
1690 {
1691 ItemCount lines = 0 ;
1692 TXNGetLineCount(m_txn, &lines ) ;
1693 return lines ;
1694 }
1695
1696 long wxMacMLTEControl::XYToPosition(long x, long y) const
1697 {
1698 Point curpt ;
1699
1700 long lastpos = GetLastPosition() ;
1701
1702 // TODO find a better implementation : while we can get the
1703 // line metrics of a certain line, we don't get its starting
1704 // position, so it would probably be rather a binary search
1705 // for the start position
1706 long xpos = 0 ;
1707 long ypos = 0 ;
1708 int lastHeight = 0 ;
1709
1710 ItemCount n ;
1711 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1712 {
1713 if ( y == ypos && x == xpos )
1714 return 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 return 0 ;
1729 }
1730
1731 bool wxMacMLTEControl::PositionToXY(long pos, long *x, long *y) const
1732 {
1733 Point curpt ;
1734
1735 long lastpos = GetLastPosition() ;
1736
1737 if ( y ) *y = 0 ;
1738 if ( x ) *x = 0 ;
1739
1740 if ( pos <= lastpos )
1741 {
1742 // TODO find a better implementation : while we can get the
1743 // line metrics of a certain line, we don't get its starting
1744 // position, so it would probably be rather a binary search
1745 // for the start position
1746 long xpos = 0 ;
1747 long ypos = 0 ;
1748 int lastHeight = 0 ;
1749
1750 ItemCount n ;
1751 for ( n = 0 ; n <= (ItemCount) pos ; ++n )
1752 {
1753 TXNOffsetToPoint(m_txn , n , &curpt);
1754
1755 if ( curpt.v > lastHeight )
1756 {
1757 xpos = 0 ;
1758 if ( n > 0 )
1759 ++ypos ;
1760 lastHeight = curpt.v ;
1761 }
1762 else
1763 ++xpos ;
1764 }
1765 if ( y ) *y = ypos ;
1766 if ( x ) *x = xpos ;
1767 }
1768
1769 return FALSE ;
1770 }
1771
1772 void wxMacMLTEControl::ShowPosition( long pos )
1773 {
1774 #if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER)
1775 {
1776 Point current ;
1777 Point desired ;
1778 TXNOffset selstart , selend ;
1779 TXNGetSelection( m_txn , &selstart , &selend) ;
1780 TXNOffsetToPoint( m_txn, selstart , &current);
1781 TXNOffsetToPoint( m_txn, pos , &desired);
1782 //TODO use HIPoints for 10.3 and above
1783 if ( (UInt32) TXNScroll != (UInt32) kUnresolvedCFragSymbolAddress )
1784 {
1785 OSErr theErr = noErr;
1786 SInt32 dv = desired.v - current.v ;
1787 SInt32 dh = desired.h - current.h ;
1788 TXNShowSelection( m_txn , true ) ;
1789 theErr = TXNScroll( m_txn, kTXNScrollUnitsInPixels , kTXNScrollUnitsInPixels , &dv , &dh );
1790 wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
1791 }
1792 }
1793 #endif
1794 }
1795
1796 void wxMacMLTEControl::SetTXNData( const wxString& st , TXNOffset start , TXNOffset end )
1797 {
1798 #if wxUSE_UNICODE
1799 #if SIZEOF_WCHAR_T == 2
1800 size_t len = st.Len() ;
1801 TXNSetData( m_txn , kTXNUnicodeTextData, (void*)st.wc_str(), len * 2,
1802 start, end);
1803 #else
1804 wxMBConvUTF16BE converter ;
1805 ByteCount byteBufferLen = converter.WC2MB( NULL , st.wc_str() , 0 ) ;
1806 UniChar *unibuf = (UniChar*) malloc(byteBufferLen) ;
1807 converter.WC2MB( (char*) unibuf , st.wc_str() , byteBufferLen ) ;
1808 TXNSetData( m_txn , kTXNUnicodeTextData, (void*)unibuf, byteBufferLen ,
1809 start, end);
1810 free( unibuf ) ;
1811 #endif
1812 #else
1813 wxCharBuffer text = st.mb_str(wxConvLocal) ;
1814 TXNSetData( m_txn , kTXNTextData, (void*)text.data(), strlen( text ) ,
1815 start, end);
1816 #endif
1817 }
1818
1819
1820 wxString wxMacMLTEControl::GetLineText(long lineNo) const
1821 {
1822 wxString line ;
1823
1824 if ( lineNo < GetNumberOfLines() )
1825 {
1826 long ypos = 0 ;
1827
1828 Fixed lineWidth,
1829 lineHeight,
1830 currentHeight = 0;
1831
1832 // get the first possible position in the control
1833 Point firstPoint;
1834 TXNOffsetToPoint(m_txn, 0, &firstPoint);
1835
1836 // Iterate through the lines until we reach the one we want,
1837 // adding to our current y pixel point position
1838 while (ypos < lineNo)
1839 {
1840 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
1841 currentHeight += lineHeight;
1842 }
1843
1844 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
1845 TXNOffset theOffset;
1846 TXNPointToOffset(m_txn, thePoint, &theOffset);
1847
1848 wxString content = GetStringValue() ;
1849 Point currentPoint = thePoint;
1850 while(thePoint.v == currentPoint.v && theOffset < content.length())
1851 {
1852 line += content[theOffset];
1853 TXNOffsetToPoint(m_txn, ++theOffset, &currentPoint);
1854 }
1855 }
1856 return line ;
1857 }
1858
1859 int wxMacMLTEControl::GetLineLength(long lineNo) const
1860 {
1861 int theLength = 0;
1862
1863 if ( lineNo < GetNumberOfLines() )
1864 {
1865 long ypos = 0 ;
1866
1867 Fixed lineWidth,
1868 lineHeight,
1869 currentHeight = 0;
1870
1871 // get the first possible position in the control
1872 Point firstPoint;
1873 TXNOffsetToPoint(m_txn, 0, &firstPoint);
1874
1875 // Iterate through the lines until we reach the one we want,
1876 // adding to our current y pixel point position
1877 while (ypos < lineNo)
1878 {
1879 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
1880 currentHeight += lineHeight;
1881 }
1882
1883 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
1884 TXNOffset theOffset;
1885 TXNPointToOffset(m_txn, thePoint, &theOffset);
1886
1887 wxString content = GetStringValue() ;
1888 Point currentPoint = thePoint;
1889 while(thePoint.v == currentPoint.v && theOffset < content.length())
1890 {
1891 ++theLength;
1892 TXNOffsetToPoint(m_txn, ++theOffset, &currentPoint);
1893 }
1894 }
1895 return theLength ;
1896 }
1897
1898
1899 // ----------------------------------------------------------------------------
1900 // MLTE control implementation (classic part)
1901 // ----------------------------------------------------------------------------
1902
1903 // CS:TODO we still have a problem getting properly at the text events of a control because under Carbon
1904 // the MLTE engine registers itself for the key events thus the normal flow never occurs, the only measure for the
1905 // moment is to avoid setting the true focus on the control, the proper solution at the end would be to have
1906 // an alternate path for carbon key events that routes automatically into the same wx flow of events
1907
1908 /* part codes */
1909
1910 /* kmUPTextPart is the part code we return to indicate the user has clicked
1911 in the text area of our control */
1912 #define kmUPTextPart 1
1913
1914
1915 /* routines for using existing user pane controls.
1916 These routines are useful for cases where you would like to use an
1917 existing user pane control in, say, a dialog window as a scrolling
1918 text edit field.*/
1919
1920 /* Utility Routines */
1921
1922 /* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus
1923 routine. In our focus switching routine this part code is understood
1924 as meaning 'the user has clicked in the control and we need to switch
1925 the current focus to ourselves before we can continue'. */
1926 #define kUserClickedToFocusPart 100
1927
1928 /* STPTextPaneVars is a structure used for storing the the mUP Control's
1929 internal variables and state information. A handle to this record is
1930 stored in the pane control's reference value field using the
1931 SetControlReference routine. */
1932
1933 class STPTextPaneVars {
1934 public :
1935 /* OS records referenced */
1936 TXNObject fTXNRec; /* the txn record */
1937 TXNFrameID fTXNFrame; /* the txn frame ID */
1938 ControlRef fUserPaneRec; /* handle to the user pane control */
1939 WindowPtr fOwner; /* window containing control */
1940 GrafPtr fDrawingEnvironment; /* grafport where control is drawn */
1941 /* flags */
1942 Boolean fInFocus; /* true while the focus rect is drawn around the control */
1943 Boolean fIsActive; /* true while the control is drawn in the active state */
1944 Boolean fTXNObjectActive; /* reflects the activation state of the text edit record */
1945 Boolean fFocusDrawState; /* true if focus is drawn (default: true) */
1946 /* calculated locations */
1947 Rect fRBounds; /* control bounds */
1948 Rect fRTextArea; /* area where the text is drawn */
1949 Rect fRFocusOutline; /* rectangle used to draw the focus box */
1950 Rect fRTextOutline; /* rectangle used to draw the border */
1951 RgnHandle fRTextOutlineRegion; /* background region for the text, erased before calling TEUpdate */
1952 /* our focus advance override routine */
1953 EventHandlerUPP handlerUPP;
1954 EventHandlerRef handlerRef;
1955 bool fNoBorders ;
1956 bool fMultiline ;
1957 bool fVisible ;
1958 } ;
1959
1960 /* Univerals Procedure Pointer variables used by the
1961 mUP Control. These variables are set up
1962 the first time that mUPOpenControl is called. */
1963 ControlUserPaneDrawUPP gTPDrawProc = NULL;
1964 ControlUserPaneHitTestUPP gTPHitProc = NULL;
1965 ControlUserPaneTrackingUPP gTPTrackProc = NULL;
1966 ControlUserPaneIdleUPP gTPIdleProc = NULL;
1967 ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
1968 ControlUserPaneActivateUPP gTPActivateProc = NULL;
1969 ControlUserPaneFocusUPP gTPFocusProc = NULL;
1970
1971 // one place for calculating all
1972 static void TPCalculateBounds(STPTextPaneVars *varsp, const Rect& bounds)
1973 {
1974 SetRect(&varsp->fRBounds, bounds.left, bounds.top, bounds.right, bounds.bottom);
1975 SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
1976 // eventually make TextOutline inset 1,1
1977 SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
1978 if ( !varsp->fNoBorders )
1979 {
1980 SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) ,
1981 bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2));
1982 }
1983 else
1984 {
1985 SetRect(&varsp->fRTextArea, bounds.left , bounds.top ,
1986 bounds.right, bounds.bottom);
1987 }
1988 }
1989
1990 OSStatus MLTESetObjectVisibility( STPTextPaneVars *varsp, Boolean vis , long wxStyle)
1991 {
1992 OSStatus err = noErr ;
1993 #if TARGET_API_MAC_OSX
1994 TXNControlTag iControlTags[1] = { kTXNVisibilityTag };
1995 TXNControlData iControlData[1] = {{ vis }};
1996 err = ::TXNSetTXNObjectControls( varsp->fTXNRec, false, 1, iControlTags, iControlData );
1997 #endif
1998 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
1999 if ( vis && textctrl )
2000 {
2001 Rect bounds ;
2002 UMAGetControlBoundsInWindowCoords( varsp->fUserPaneRec, &bounds);
2003 TPCalculateBounds( varsp , bounds ) ;
2004 wxMacWindowClipper cl(textctrl) ;
2005 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left,
2006 varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame);
2007 TXNShowSelection( varsp->fTXNRec, kTXNShowStart);
2008 }
2009 return err ;
2010 }
2011
2012 // make sure we don't miss changes as carbon events are not available for these under classic
2013 static void TPUpdateVisibility(ControlRef theControl) {
2014 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2015 if ( textctrl == NULL )
2016 return ;
2017
2018 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2019
2020 Rect bounds ;
2021 UMAGetControlBoundsInWindowCoords(theControl, &bounds);
2022 if ( textctrl->MacIsReallyShown() != varsp->fVisible )
2023 {
2024 // invalidate old position
2025 // InvalWindowRect( GetControlOwner( theControl ) , &varsp->fRBounds ) ;
2026 varsp->fVisible = textctrl->MacIsReallyShown() ;
2027 }
2028 if ( !EqualRect( &bounds , &varsp->fRBounds ) )
2029 {
2030 // old position
2031 Rect oldBounds = varsp->fRBounds ;
2032 TPCalculateBounds( varsp , bounds ) ;
2033 // we only recalculate when visible, otherwise scrollbars get drawn at incorrect places
2034 if ( varsp->fVisible )
2035 {
2036 wxMacWindowClipper cl(textctrl) ;
2037 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left,
2038 varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame);
2039 }
2040 InvalWindowRect( GetControlOwner( theControl ) , &oldBounds ) ;
2041 InvalWindowRect( GetControlOwner( theControl ) , &varsp->fRBounds ) ;
2042 }
2043 }
2044
2045 // make correct activations
2046 static void TPActivatePaneText(STPTextPaneVars *varsp, Boolean setActive) {
2047
2048 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
2049 if (varsp->fTXNObjectActive != setActive && textctrl->MacIsReallyShown() )
2050 {
2051 varsp->fTXNObjectActive = setActive;
2052 TXNActivate(varsp->fTXNRec, varsp->fTXNFrame, varsp->fTXNObjectActive);
2053 if (varsp->fInFocus)
2054 TXNFocus( varsp->fTXNRec, varsp->fTXNObjectActive);
2055 }
2056 }
2057
2058 // update focus outlines
2059 static void TPRedrawFocusOutline(STPTextPaneVars *varsp) {
2060
2061 /* state changed */
2062 if (varsp->fFocusDrawState != (varsp->fIsActive && varsp->fInFocus))
2063 {
2064 varsp->fFocusDrawState = (varsp->fIsActive && varsp->fInFocus);
2065 DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fFocusDrawState);
2066 }
2067 }
2068
2069 // update TXN focus state
2070 static void TPFocusPaneText(STPTextPaneVars *varsp, Boolean setFocus) {
2071 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
2072
2073 if (varsp->fInFocus != setFocus && textctrl->MacIsReallyShown()) {
2074 varsp->fInFocus = setFocus;
2075 TXNFocus( varsp->fTXNRec, varsp->fInFocus);
2076 }
2077 }
2078
2079 // draw the control
2080 static pascal void TPPaneDrawProc(ControlRef theControl, ControlPartCode thePart) {
2081 /* set up our globals */
2082
2083 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2084 if ( textctrl == NULL )
2085 return ;
2086 TPUpdateVisibility( theControl ) ;
2087
2088 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2089 if ( textctrl->MacIsReallyShown() )
2090 {
2091 wxMacWindowClipper clipper( textctrl ) ;
2092 TXNDraw(varsp->fTXNRec, NULL);
2093 if ( !varsp->fNoBorders )
2094 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
2095 TPRedrawFocusOutline( varsp ) ;
2096 }
2097
2098 }
2099
2100
2101 /* TPPaneHitTestProc is called when the control manager would
2102 like to determine what part of the control the mouse resides over.
2103 We also call this routine from our tracking proc to determine how
2104 to handle mouse clicks. */
2105 static pascal ControlPartCode TPPaneHitTestProc(ControlRef theControl, Point where) {
2106 ControlPartCode result;
2107 /* set up our locals and lock down our globals*/
2108 result = 0;
2109 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2110 if ( textctrl == NULL )
2111 return 0 ;
2112 TPUpdateVisibility( theControl ) ;
2113 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2114 if (textctrl->MacIsReallyShown() )
2115 {
2116 if (PtInRect(where, &varsp->fRBounds))
2117 result = kmUPTextPart;
2118 else
2119 {
2120 // sometimes we get the coords also in control local coordinates, therefore test again
2121 if ( textctrl->MacGetTopLevelWindow()->MacUsesCompositing() )
2122 {
2123 int x = 0 , y = 0 ;
2124 textctrl->MacClientToRootWindow( &x , &y ) ;
2125 where.h += x ;
2126 where.v += y ;
2127 }
2128 if (PtInRect(where, &varsp->fRBounds))
2129 result = kmUPTextPart;
2130 else
2131 result = 0;
2132 }
2133 }
2134 return result;
2135 }
2136
2137
2138
2139
2140
2141 /* TPPaneTrackingProc is called when the mouse is being held down
2142 over our control. This routine handles clicks in the text area
2143 and in the scroll bar. */
2144 static pascal ControlPartCode TPPaneTrackingProc(ControlRef theControl, Point startPt, ControlActionUPP actionProc) {
2145
2146 ControlPartCode partCodeResult;
2147 /* make sure we have some variables... */
2148 partCodeResult = 0;
2149 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2150 if ( textctrl == NULL )
2151 return 0;
2152 TPUpdateVisibility( theControl ) ;
2153 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2154 if (textctrl->MacIsReallyShown() )
2155 {
2156 /* we don't do any of these functions unless we're in focus */
2157 if ( ! varsp->fInFocus) {
2158 WindowPtr owner;
2159 owner = GetControlOwner(theControl);
2160 ClearKeyboardFocus(owner);
2161 SetKeyboardFocus(owner, theControl, kUserClickedToFocusPart);
2162 }
2163 /* find the location for the click */
2164 // for compositing, we must convert these into toplevel window coordinates, because hittesting expects them
2165 if ( textctrl->MacGetTopLevelWindow()->MacUsesCompositing() )
2166 {
2167 int x = 0 , y = 0 ;
2168 textctrl->MacClientToRootWindow( &x , &y ) ;
2169 startPt.h += x ;
2170 startPt.v += y ;
2171 }
2172
2173 switch (TPPaneHitTestProc(theControl, startPt))
2174 {
2175
2176 /* handle clicks in the text part */
2177 case kmUPTextPart:
2178 {
2179 wxMacWindowClipper clipper( textctrl ) ;
2180
2181 EventRecord rec ;
2182 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
2183 TXNClick( varsp->fTXNRec, &rec );
2184
2185 }
2186 break;
2187
2188 }
2189 }
2190 return partCodeResult;
2191 }
2192
2193
2194 /* TPPaneIdleProc is our user pane idle routine. When our text field
2195 is active and in focus, we use this routine to set the cursor. */
2196 static pascal void TPPaneIdleProc(ControlRef theControl) {
2197 /* set up locals */
2198 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2199 if ( textctrl == NULL )
2200 return ;
2201 TPUpdateVisibility( theControl ) ;
2202 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2203 if (textctrl->MacIsReallyShown()) {
2204 /* if we're not active, then we have nothing to say about the cursor */
2205 if (varsp->fIsActive) {
2206 Rect bounds;
2207 Point mousep;
2208
2209 wxMacWindowClipper clipper( textctrl ) ;
2210 GetMouse(&mousep);
2211 /* there's a 'focus thing' and an 'unfocused thing' */
2212 if (varsp->fInFocus) {
2213 /* flash the cursor */
2214 SetPort(varsp->fDrawingEnvironment);
2215 TXNIdle(varsp->fTXNRec);
2216 /* set the cursor */
2217 if (PtInRect(mousep, &varsp->fRTextArea)) {
2218 RgnHandle theRgn;
2219 RectRgn((theRgn = NewRgn()), &varsp->fRTextArea);
2220 TXNAdjustCursor(varsp->fTXNRec, theRgn);
2221 DisposeRgn(theRgn);
2222 }
2223 else
2224 {
2225 // SetThemeCursor(kThemeArrowCursor);
2226 }
2227 } else {
2228 /* if it's in our bounds, set the cursor */
2229 UMAGetControlBoundsInWindowCoords(theControl, &bounds);
2230 if (PtInRect(mousep, &bounds))
2231 {
2232 // SetThemeCursor(kThemeArrowCursor);
2233 }
2234 }
2235 }
2236 }
2237 }
2238
2239
2240 /* TPPaneKeyDownProc is called whenever a keydown event is directed
2241 at our control. Here, we direct the keydown event to the text
2242 edit record and redraw the scroll bar and text field as appropriate. */
2243 static pascal ControlPartCode TPPaneKeyDownProc(ControlRef theControl,
2244 SInt16 keyCode, SInt16 charCode, SInt16 modifiers) {
2245
2246 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2247 if ( textctrl == NULL )
2248 return 0;
2249 TPUpdateVisibility( theControl ) ;
2250
2251 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2252 if (varsp->fInFocus)
2253 {
2254 /* turn autoscrolling on and send the key event to text edit */
2255 wxMacWindowClipper clipper( textctrl ) ;
2256 EventRecord ev ;
2257 memset( &ev , 0 , sizeof( ev ) ) ;
2258 ev.what = keyDown ;
2259 ev.modifiers = modifiers ;
2260 ev.message = (( keyCode << 8 ) & keyCodeMask ) + ( charCode & charCodeMask ) ;
2261 TXNKeyDown( varsp->fTXNRec, &ev);
2262 }
2263 return kControlEntireControl;
2264 }
2265
2266
2267 /* TPPaneActivateProc is called when the window containing
2268 the user pane control receives activate events. Here, we redraw
2269 the control and it's text as necessary for the activation state. */
2270 static pascal void TPPaneActivateProc(ControlRef theControl, Boolean activating) {
2271 /* set up locals */
2272 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2273
2274 if ( textctrl == NULL )
2275 return ;
2276 TPUpdateVisibility( theControl ) ;
2277
2278 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2279
2280 varsp->fIsActive = activating;
2281 wxMacWindowClipper clipper( textctrl ) ;
2282 TPActivatePaneText(varsp, varsp->fIsActive && varsp->fInFocus);
2283 /* redraw the frame */
2284 if ( textctrl->MacIsReallyShown() )
2285 {
2286 if ( !varsp->fNoBorders )
2287 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
2288 TPRedrawFocusOutline( varsp ) ;
2289 }
2290 }
2291
2292
2293 /* TPPaneFocusProc is called when every the focus changes to or
2294 from our control. Herein, switch the focus appropriately
2295 according to the parameters and redraw the control as
2296 necessary. */
2297 static pascal ControlPartCode TPPaneFocusProc(ControlRef theControl, ControlFocusPart action) {
2298 ControlPartCode focusResult;
2299
2300 focusResult = kControlFocusNoPart;
2301 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
2302 if ( textctrl == NULL )
2303 return 0;
2304 TPUpdateVisibility( theControl ) ;
2305 STPTextPaneVars *varsp = (STPTextPaneVars *) ((wxMacMLTEClassicControl*)textctrl->GetPeer())->m_macTXNvars ;
2306 /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is
2307 tabbing forwards (or shift tabbing backwards) through the items in the dialog,
2308 and kControlFocusNextPart will be received. When the user clicks in our field
2309 and it is not the current focus, then the constant kUserClickedToFocusPart will
2310 be received. The constant kControlFocusNoPart will be received when our control
2311 is the current focus and the user clicks in another control. In your focus routine,
2312 you should respond to these codes as follows:
2313
2314 kControlFocusNoPart - turn off focus and return kControlFocusNoPart. redraw
2315 the control and the focus rectangle as necessary.
2316
2317 kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off
2318 depending on its current state. redraw the control and the focus rectangle
2319 as appropriate for the new focus state. If the focus state is 'off', return the constant
2320 kControlFocusNoPart, otherwise return a non-zero part code.
2321 kUserClickedToFocusPart - is a constant defined for this example. You should
2322 define your own value for handling click-to-focus type events. */
2323 /* calculate the next highlight state */
2324 switch (action) {
2325 default:
2326 case kControlFocusNoPart:
2327 TPFocusPaneText(varsp, false);
2328 focusResult = kControlFocusNoPart;
2329 break;
2330 case kUserClickedToFocusPart:
2331 TPFocusPaneText(varsp, true);
2332 focusResult = 1;
2333 break;
2334 case kControlFocusPrevPart:
2335 case kControlFocusNextPart:
2336 TPFocusPaneText(varsp, ( ! varsp->fInFocus));
2337 focusResult = varsp->fInFocus ? 1 : kControlFocusNoPart;
2338 break;
2339 }
2340 TPActivatePaneText(varsp, varsp->fIsActive && varsp->fInFocus);
2341 /* redraw the text fram and focus rectangle to indicate the
2342 new focus state */
2343 if ( textctrl->MacIsReallyShown() )
2344 {
2345 wxMacWindowClipper c( textctrl ) ;
2346 if ( !varsp->fNoBorders )
2347 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
2348 TPRedrawFocusOutline( varsp ) ;
2349 }
2350 return focusResult;
2351 }
2352
2353 wxMacMLTEClassicControl::wxMacMLTEClassicControl( wxWindow *wxPeer,
2354 const wxString& str,
2355 const wxPoint& pos,
2356 const wxSize& size, long style )
2357 {
2358 m_font = wxPeer->GetFont() ;
2359 m_windowStyle = style ;
2360 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
2361 wxString st = str ;
2362 wxMacConvertNewlines10To13( &st ) ;
2363
2364 short featurSet;
2365
2366 featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
2367 | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground
2368 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
2369 /* create the control */
2370
2371 verify_noerr( ::CreateUserPaneControl( MAC_WXHWND(wxPeer->GetParent()->MacGetTopLevelWindowRef()), &bounds, featurSet, &m_controlRef ) );
2372
2373 {
2374 // wxMacWindowClipper c(wxPeer) ;
2375 DoCreate();
2376 }
2377
2378 if ( wxPeer->MacIsReallyShown() )
2379 MLTESetObjectVisibility( (STPTextPaneVars*) m_macTXNvars, true , style ) ;
2380
2381 {
2382 // wxMacWindowClipper clipper( wxPeer ) ;
2383
2384 TPUpdateVisibility( m_controlRef ) ;
2385
2386 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
2387
2388 TXNSetSelection( m_txn, 0, 0);
2389 TXNShowSelection( m_txn, kTXNShowStart);
2390 }
2391
2392 AdjustCreationAttributes( *wxWHITE , true ) ;
2393 }
2394
2395 wxMacMLTEClassicControl::~wxMacMLTEClassicControl()
2396 {
2397 // SetControlReference(m_controlRef , 0) ;
2398 TXNDeleteObject(m_txn);
2399 free(m_macTXNvars);
2400 }
2401
2402 void wxMacMLTEClassicControl::VisibilityChanged(bool shown)
2403 {
2404 MLTESetObjectVisibility((STPTextPaneVars*) m_macTXNvars , shown , m_windowStyle ) ;
2405 if ( !shown )
2406 InvalWindowRect( GetControlOwner( m_controlRef ) , &((STPTextPaneVars *)m_macTXNvars)->fRBounds ) ;
2407 }
2408
2409 OSStatus wxMacMLTEClassicControl::DoCreate()
2410 {
2411 Rect bounds;
2412 WindowRef theWindow;
2413
2414 OSStatus err = noErr ;
2415
2416 /* set up our globals */
2417 if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(TPPaneDrawProc);
2418 if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(TPPaneHitTestProc);
2419 if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(TPPaneTrackingProc);
2420 if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(TPPaneIdleProc);
2421 if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc);
2422 if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(TPPaneActivateProc);
2423 if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(TPPaneFocusProc);
2424
2425 /* allocate our private storage */
2426 m_macTXNvars = (STPTextPaneVars *) malloc(sizeof(STPTextPaneVars));
2427
2428 /* set the initial settings for our private data */
2429 m_macTXNvars->fMultiline = m_windowStyle & wxTE_MULTILINE ;
2430 m_macTXNvars->fNoBorders = m_windowStyle & wxNO_BORDER ;
2431 m_macTXNvars->fInFocus = false;
2432 m_macTXNvars->fIsActive = true;
2433 m_macTXNvars->fTXNObjectActive = false;
2434 m_macTXNvars->fFocusDrawState = false ;
2435 m_macTXNvars->fUserPaneRec = m_controlRef ;
2436 m_macTXNvars->fVisible = true ;
2437
2438 theWindow = m_macTXNvars->fOwner = GetControlOwner(m_controlRef);
2439
2440 m_macTXNvars->fDrawingEnvironment = (GrafPtr) GetWindowPort(theWindow);
2441
2442 /* set up the user pane procedures */
2443 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
2444 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
2445 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
2446 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
2447 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
2448 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
2449 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
2450
2451 /* calculate the rectangles used by the control */
2452 UMAGetControlBoundsInWindowCoords(m_controlRef, &bounds);
2453 m_macTXNvars->fRTextOutlineRegion = NewRgn() ;
2454 TPCalculateBounds( m_macTXNvars , bounds ) ;
2455
2456 /* set up the drawing environment */
2457 SetPort(m_macTXNvars->fDrawingEnvironment);
2458
2459 /* create the new edit field */
2460
2461 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( m_windowStyle ) ;
2462
2463 verify_noerr(TXNNewObject(NULL, m_macTXNvars->fOwner, &m_macTXNvars->fRTextArea,
2464 frameOptions ,
2465 kTXNTextEditStyleFrameType,
2466 kTXNTextensionFile,
2467 kTXNSystemDefaultEncoding,
2468 &m_macTXNvars->fTXNRec, &m_macTXNvars->fTXNFrame, (TXNObjectRefcon) m_macTXNvars));
2469 m_txn = m_macTXNvars->fTXNRec ;
2470
2471 /* perform final activations and setup for our text field. Here,
2472 we assume that the window is going to be the 'active' window. */
2473 TPActivatePaneText(m_macTXNvars, m_macTXNvars->fIsActive && m_macTXNvars->fInFocus);
2474 /* all done */
2475 return err;
2476 }
2477
2478 // ----------------------------------------------------------------------------
2479 // MLTE control implementation (OSX part)
2480 // ----------------------------------------------------------------------------
2481
2482 #if TARGET_API_MAC_OSX
2483
2484 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
2485
2486 wxMacMLTEHIViewControl::wxMacMLTEHIViewControl( wxWindow *wxPeer,
2487 const wxString& str,
2488 const wxPoint& pos,
2489 const wxSize& size, long style )
2490 {
2491 m_font = wxPeer->GetFont() ;
2492 m_windowStyle = style ;
2493 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
2494 wxString st = str ;
2495 wxMacConvertNewlines10To13( &st ) ;
2496
2497 HIRect hr = { bounds.left , bounds.top , bounds.right - bounds.left , bounds.bottom- bounds.top } ;
2498
2499 m_scrollView = NULL ;
2500 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( style ) ;
2501 if ( frameOptions & (kTXNWantVScrollBarMask|kTXNWantHScrollBarMask) )
2502 {
2503 HIScrollViewCreate(( frameOptions & kTXNWantHScrollBarMask ? kHIScrollViewOptionsHorizScroll : 0) |
2504 ( frameOptions & kTXNWantVScrollBarMask ? kHIScrollViewOptionsVertScroll: 0 ) , &m_scrollView ) ;
2505
2506 HIViewSetFrame( m_scrollView, &hr );
2507 HIViewSetVisible( m_scrollView, true );
2508 }
2509
2510 m_textView = NULL ;
2511 HITextViewCreate( NULL , 0, frameOptions , &m_textView ) ;
2512 m_txn = HITextViewGetTXNObject( m_textView) ;
2513 HIViewSetVisible( m_textView , true ) ;
2514 if ( m_scrollView )
2515 {
2516 HIViewAddSubview( m_scrollView , m_textView ) ;
2517 m_controlRef = m_scrollView ;
2518 wxPeer->MacInstallEventHandler( (WXWidget) m_textView ) ;
2519 }
2520 else
2521 {
2522 HIViewSetFrame( m_textView, &hr );
2523 m_controlRef = m_textView ;
2524 }
2525
2526
2527 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
2528
2529 TXNSetSelection( m_txn, 0, 0);
2530 TXNShowSelection( m_txn, kTXNShowStart);
2531
2532 AdjustCreationAttributes( *wxWHITE , true ) ;
2533 }
2534
2535 OSStatus wxMacMLTEHIViewControl::SetFocus( ControlFocusPart focusPart )
2536 {
2537 return SetKeyboardFocus( GetControlOwner( m_textView ) ,
2538 m_textView , focusPart ) ;
2539 }
2540
2541 bool wxMacMLTEHIViewControl::HasFocus() const
2542 {
2543 ControlRef control ;
2544 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
2545 return control == m_textView ;
2546 }
2547
2548 bool wxMacMLTEHIViewControl::NeedsFocusRect() const
2549 {
2550 return m_windowStyle & wxNO_BORDER ? false : true;
2551 }
2552
2553 #endif // MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
2554
2555
2556 #endif
2557
2558 #endif // wxUSE_TEXTCTRL