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