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