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