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