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