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