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