]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/textctrl.cpp
cleanup
[wxWidgets.git] / src / mac / carbon / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/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 #include "wx/wxprec.h"
13
14 #if wxUSE_TEXTCTRL
15
16 #include "wx/textctrl.h"
17
18 #ifndef WX_PRECOMP
19 #include "wx/intl.h"
20 #include "wx/app.h"
21 #include "wx/utils.h"
22 #include "wx/dc.h"
23 #include "wx/button.h"
24 #include "wx/menu.h"
25 #include "wx/settings.h"
26 #include "wx/msgdlg.h"
27 #include "wx/toplevel.h"
28 #endif
29
30 #ifdef __DARWIN__
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #else
34 #include <stat.h>
35 #endif
36
37 #if wxUSE_STD_IOSTREAM
38 #if wxUSE_IOSTREAMH
39 #include <fstream.h>
40 #else
41 #include <fstream>
42 #endif
43 #endif
44
45 #include "wx/filefn.h"
46 #include "wx/sysopt.h"
47
48 #if defined(__BORLANDC__) && !defined(__WIN32__)
49 #include <alloc.h>
50 #elif !defined(__MWERKS__) && !defined(__GNUWIN32) && !defined(__DARWIN__)
51 #include <malloc.h>
52 #endif
53
54 #ifndef __DARWIN__
55 #include <MacTextEditor.h>
56 #include <ATSUnicode.h>
57 #include <TextCommon.h>
58 #include <TextEncodingConverter.h>
59 #endif
60
61 #include "wx/mac/uma.h"
62 #include "wx/mac/carbon/private/mactext.h"
63
64 #ifndef __WXMAC_OSX__
65 enum
66 {
67 kTXNVisibilityTag = 'visb' // set the visibility state of the object
68 };
69 #endif
70
71
72 class wxMacFunctor
73 {
74 public :
75 wxMacFunctor() {}
76 virtual ~wxMacFunctor() {}
77
78 virtual void* operator()() = 0 ;
79
80 static void* CallBackProc( void *param )
81 {
82 wxMacFunctor* f = (wxMacFunctor*) param ;
83 void *result = (*f)() ;
84 return result ;
85 }
86 } ;
87
88 template<typename classtype, typename param1type>
89
90 class wxMacObjectFunctor1 : public wxMacFunctor
91 {
92 typedef void (classtype::*function)( param1type p1 ) ;
93 typedef void (classtype::*ref_function)( const param1type& p1 ) ;
94 public :
95 wxMacObjectFunctor1( classtype *obj , function f , param1type p1 ) :
96 wxMacFunctor()
97 {
98 m_object = obj ;
99 m_function = f ;
100 m_param1 = p1 ;
101 }
102
103 wxMacObjectFunctor1( classtype *obj , ref_function f , param1type p1 ) :
104 wxMacFunctor()
105 {
106 m_object = obj ;
107 m_refFunction = f ;
108 m_param1 = p1 ;
109 }
110
111 virtual ~wxMacObjectFunctor1() {}
112
113 virtual void* operator()()
114 {
115 (m_object->*m_function)( m_param1 ) ;
116 return NULL ;
117 }
118
119 private :
120 classtype* m_object ;
121 param1type m_param1 ;
122 union
123 {
124 function m_function ;
125 ref_function m_refFunction ;
126 } ;
127 } ;
128
129 template<typename classtype, typename param1type>
130 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
131 {
132 wxMacObjectFunctor1<classtype, param1type> params(object, function, p1) ;
133 void *result =
134 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
135 return result ;
136 }
137
138 template<typename classtype, typename param1type>
139 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
140 {
141 wxMacObjectFunctor1<classtype,param1type> params(object, function, p1) ;
142 void *result =
143 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
144 return result ;
145 }
146
147 template<typename classtype, typename param1type>
148 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
149 {
150 wxMutexGuiLeave() ;
151 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
152 wxMutexGuiEnter() ;
153 return result ;
154 }
155
156 template<typename classtype, typename param1type>
157 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
158 {
159 wxMutexGuiLeave() ;
160 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
161 wxMutexGuiEnter() ;
162 return result ;
163 }
164
165
166 // common parts for implementations based on MLTE
167
168 class wxMacMLTEControl : public wxMacTextControl
169 {
170 public :
171 wxMacMLTEControl( wxTextCtrl *peer ) ;
172
173 virtual wxString GetStringValue() const ;
174 virtual void SetStringValue( const wxString &str ) ;
175
176 static TXNFrameOptions FrameOptionsFromWXStyle( long wxStyle ) ;
177
178 void AdjustCreationAttributes( const wxColour& background, bool visible ) ;
179
180 virtual void SetFont( const wxFont & font, const wxColour& foreground, long windowStyle ) ;
181 virtual void SetBackground( const wxBrush &brush ) ;
182 virtual void SetStyle( long start, long end, const wxTextAttr& style ) ;
183 virtual void Copy() ;
184 virtual void Cut() ;
185 virtual void Paste() ;
186 virtual bool CanPaste() const ;
187 virtual void SetEditable( bool editable ) ;
188 virtual wxTextPos GetLastPosition() const ;
189 virtual void Replace( long from, long to, const wxString &str ) ;
190 virtual void Remove( long from, long to ) ;
191 virtual void GetSelection( long* from, long* to ) const ;
192 virtual void SetSelection( long from, long to ) ;
193
194 virtual void WriteText( const wxString& str ) ;
195
196 virtual bool HasOwnContextMenu() const
197 {
198 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
199 if ( UMAGetSystemVersion() >= 0x1040 )
200 {
201 TXNCommandEventSupportOptions options ;
202 TXNGetCommandEventSupport( m_txn , & options ) ;
203 return options & kTXNSupportEditCommandProcessing ;
204 }
205 #endif
206
207 return false ;
208 }
209
210 virtual void CheckSpelling(bool check)
211 {
212 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
213 TXNSetSpellCheckAsYouType( m_txn, (Boolean) check );
214 #endif
215 }
216 virtual void Clear() ;
217
218 virtual bool CanUndo() const ;
219 virtual void Undo() ;
220 virtual bool CanRedo() const;
221 virtual void Redo() ;
222 virtual int GetNumberOfLines() const ;
223 virtual long XYToPosition(long x, long y) const ;
224 virtual bool PositionToXY(long pos, long *x, long *y) const ;
225 virtual void ShowPosition( long pos ) ;
226 virtual int GetLineLength(long lineNo) const ;
227 virtual wxString GetLineText(long lineNo) const ;
228
229 void SetTXNData( const wxString& st , TXNOffset start , TXNOffset end ) ;
230 TXNObject GetTXNObject() { return m_txn ; }
231
232 protected :
233 void TXNSetAttribute( const wxTextAttr& style , long from , long to ) ;
234
235 TXNObject m_txn ;
236 } ;
237
238 #if TARGET_API_MAC_OSX
239
240 // implementation available under OSX
241
242 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
243
244 class wxMacMLTEHIViewControl : public wxMacMLTEControl
245 {
246 public :
247 wxMacMLTEHIViewControl( wxTextCtrl *wxPeer,
248 const wxString& str,
249 const wxPoint& pos,
250 const wxSize& size, long style ) ;
251 virtual ~wxMacMLTEHIViewControl() ;
252
253 virtual OSStatus SetFocus( ControlFocusPart focusPart ) ;
254 virtual bool HasFocus() const ;
255 virtual void SetBackground( const wxBrush &brush) ;
256
257 protected :
258 HIViewRef m_scrollView ;
259 HIViewRef m_textView ;
260 };
261
262 #endif
263
264 #endif
265
266 // 'classic' MLTE implementation
267
268 class wxMacMLTEClassicControl : public wxMacMLTEControl
269 {
270 public :
271 wxMacMLTEClassicControl( wxTextCtrl *wxPeer,
272 const wxString& str,
273 const wxPoint& pos,
274 const wxSize& size, long style ) ;
275 virtual ~wxMacMLTEClassicControl() ;
276
277 virtual void VisibilityChanged(bool shown) ;
278 virtual void SuperChangedPosition() ;
279
280 virtual void MacControlUserPaneDrawProc(wxInt16 part) ;
281 virtual wxInt16 MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y) ;
282 virtual wxInt16 MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc) ;
283 virtual void MacControlUserPaneIdleProc() ;
284 virtual wxInt16 MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers) ;
285 virtual void MacControlUserPaneActivateProc(bool activating) ;
286 virtual wxInt16 MacControlUserPaneFocusProc(wxInt16 action) ;
287 virtual void MacControlUserPaneBackgroundProc(void* info) ;
288
289 virtual bool SetupCursor( const wxPoint& WXUNUSED(pt) )
290 {
291 MacControlUserPaneIdleProc();
292 return true;
293 }
294
295 virtual void SetRect( Rect *r ) ;
296
297 protected :
298 OSStatus DoCreate();
299
300 void MacUpdatePosition() ;
301 void MacActivatePaneText(bool setActive) ;
302 void MacFocusPaneText(bool setFocus) ;
303 void MacSetObjectVisibility(bool vis) ;
304
305 private :
306 TXNFrameID m_txnFrameID ;
307 GrafPtr m_txnPort ;
308 WindowRef m_txnWindow ;
309 // bounds of the control as we last did set the txn frames
310 Rect m_txnControlBounds ;
311 Rect m_txnVisBounds ;
312
313 #ifdef __WXMAC_OSX__
314 static pascal void TXNScrollActionProc( ControlRef controlRef , ControlPartCode partCode ) ;
315 static pascal void TXNScrollInfoProc(
316 SInt32 iValue, SInt32 iMaximumValue,
317 TXNScrollBarOrientation iScrollBarOrientation, SInt32 iRefCon ) ;
318
319 ControlRef m_sbHorizontal ;
320 SInt32 m_lastHorizontalValue ;
321 ControlRef m_sbVertical ;
322 SInt32 m_lastVerticalValue ;
323 #endif
324 };
325
326
327 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxTextCtrlBase)
328
329 BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
330 EVT_ERASE_BACKGROUND( wxTextCtrl::OnEraseBackground )
331 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
332 EVT_CHAR(wxTextCtrl::OnChar)
333 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
334 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
335 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
336 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
337 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
338 EVT_MENU(wxID_CLEAR, wxTextCtrl::OnDelete)
339 EVT_MENU(wxID_SELECTALL, wxTextCtrl::OnSelectAll)
340
341 EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu)
342
343 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
344 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
345 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
346 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
347 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
348 EVT_UPDATE_UI(wxID_CLEAR, wxTextCtrl::OnUpdateDelete)
349 EVT_UPDATE_UI(wxID_SELECTALL, wxTextCtrl::OnUpdateSelectAll)
350 END_EVENT_TABLE()
351
352
353 void wxTextCtrl::Init()
354 {
355 m_editable = true ;
356 m_dirty = false;
357
358 m_maxLength = 0;
359 m_privateContextMenu = NULL;
360 m_triggerOnSetValue = true ;
361 }
362
363 wxTextCtrl::~wxTextCtrl()
364 {
365 delete m_privateContextMenu;
366 }
367
368 bool wxTextCtrl::Create( wxWindow *parent,
369 wxWindowID id,
370 const wxString& str,
371 const wxPoint& pos,
372 const wxSize& size,
373 long style,
374 const wxValidator& validator,
375 const wxString& name )
376 {
377 m_macIsUserPane = false ;
378 m_editable = true ;
379
380 if ( ! (style & wxNO_BORDER) )
381 style = (style & ~wxBORDER_MASK) | wxSUNKEN_BORDER ;
382
383 if ( !wxTextCtrlBase::Create( parent, id, pos, size, style & ~(wxHSCROLL | wxVSCROLL), validator, name ) )
384 return false;
385
386 if ( m_windowStyle & wxTE_MULTILINE )
387 {
388 // always turn on this style for multi-line controls
389 m_windowStyle |= wxTE_PROCESS_ENTER;
390 style |= wxTE_PROCESS_ENTER ;
391 }
392
393 CreatePeer( str, pos, size, style );
394
395 MacPostControlCreate(pos, size) ;
396
397 // only now the embedding is correct and we can do a positioning update
398
399 MacSuperChangedPosition() ;
400
401 if ( m_windowStyle & wxTE_READONLY)
402 SetEditable( false ) ;
403
404 SetCursor( wxCursor( wxCURSOR_IBEAM ) ) ;
405
406 return true;
407 }
408
409 void wxTextCtrl::CreatePeer(
410 const wxString& str,
411 const wxPoint& pos,
412 const wxSize& size, long style )
413 {
414 bool forceMLTE = false ;
415
416 #if wxUSE_SYSTEM_OPTIONS
417 if (wxSystemOptions::HasOption( wxMAC_TEXTCONTROL_USE_MLTE ) && (wxSystemOptions::GetOptionInt( wxMAC_TEXTCONTROL_USE_MLTE ) == 1))
418 {
419 forceMLTE = true ;
420 }
421 #endif
422
423 if ( UMAGetSystemVersion() >= 0x1050 )
424 forceMLTE = false;
425
426 if ( UMAGetSystemVersion() >= 0x1030 && !forceMLTE )
427 {
428 if ( m_windowStyle & wxTE_MULTILINE )
429 m_peer = new wxMacMLTEHIViewControl( this , str , pos , size , style ) ;
430 }
431
432 if ( !m_peer )
433 {
434 if ( !(m_windowStyle & wxTE_MULTILINE) && !forceMLTE )
435 {
436 m_peer = new wxMacUnicodeTextControl( this , str , pos , size , style ) ;
437 }
438 }
439
440 // the horizontal single line scrolling bug that made us keep the classic implementation
441 // is fixed in 10.5
442 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
443 if ( !m_peer )
444 m_peer = new wxMacMLTEClassicControl( this , str , pos , size , style ) ;
445 #endif
446 }
447
448 void wxTextCtrl::MacSuperChangedPosition()
449 {
450 wxWindow::MacSuperChangedPosition() ;
451 GetPeer()->SuperChangedPosition() ;
452 }
453
454 void wxTextCtrl::MacVisibilityChanged()
455 {
456 GetPeer()->VisibilityChanged( MacIsReallyShown() ) ;
457 }
458
459 void wxTextCtrl::MacEnabledStateChanged()
460 {
461 }
462
463 void wxTextCtrl::MacCheckSpelling(bool check)
464 {
465 GetPeer()->CheckSpelling(check);
466 }
467
468 wxString wxTextCtrl::GetValue() const
469 {
470 return GetPeer()->GetStringValue() ;
471 }
472
473 void wxTextCtrl::GetSelection(long* from, long* to) const
474 {
475 GetPeer()->GetSelection( from , to ) ;
476 }
477
478 void wxTextCtrl::DoSetValue(const wxString& str, int flags)
479 {
480 // optimize redraws
481 if ( GetValue() == str )
482 return;
483
484 GetPeer()->SetStringValue( str ) ;
485
486 if ( (flags & SetValue_SendEvent) && m_triggerOnSetValue )
487 {
488 SendTextUpdatedEvent();
489 }
490 }
491
492 void wxTextCtrl::SetMaxLength(unsigned long len)
493 {
494 m_maxLength = len ;
495 }
496
497 bool wxTextCtrl::SetFont( const wxFont& font )
498 {
499 if ( !wxTextCtrlBase::SetFont( font ) )
500 return false ;
501
502 GetPeer()->SetFont( font , GetForegroundColour() , GetWindowStyle() ) ;
503
504 return true ;
505 }
506
507 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
508 {
509 GetPeer()->SetStyle( start , end , style ) ;
510
511 return true ;
512 }
513
514 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
515 {
516 wxTextCtrlBase::SetDefaultStyle( style ) ;
517 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
518
519 return true ;
520 }
521
522 // Clipboard operations
523
524 void wxTextCtrl::Copy()
525 {
526 if (CanCopy())
527 GetPeer()->Copy() ;
528 }
529
530 void wxTextCtrl::Cut()
531 {
532 if (CanCut())
533 {
534 GetPeer()->Cut() ;
535
536 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, m_windowId );
537 event.SetEventObject( this );
538 GetEventHandler()->ProcessEvent( event );
539 }
540 }
541
542 void wxTextCtrl::Paste()
543 {
544 if (CanPaste())
545 {
546 GetPeer()->Paste() ;
547
548 // TODO: eventually we should add setting the default style again
549
550 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, m_windowId );
551 event.SetEventObject( this );
552 GetEventHandler()->ProcessEvent( event );
553 }
554 }
555
556 bool wxTextCtrl::CanCopy() const
557 {
558 // Can copy if there's a selection
559 long from, to;
560 GetSelection( &from, &to );
561
562 return (from != to);
563 }
564
565 bool wxTextCtrl::CanCut() const
566 {
567 if ( !IsEditable() )
568 return false;
569
570 // Can cut if there's a selection
571 long from, to;
572 GetSelection( &from, &to );
573
574 return (from != to);
575 }
576
577 bool wxTextCtrl::CanPaste() const
578 {
579 if (!IsEditable())
580 return false;
581
582 return GetPeer()->CanPaste() ;
583 }
584
585 void wxTextCtrl::SetEditable(bool editable)
586 {
587 if ( editable != m_editable )
588 {
589 m_editable = editable ;
590 GetPeer()->SetEditable( editable ) ;
591 }
592 }
593
594 void wxTextCtrl::SetInsertionPoint(long pos)
595 {
596 SetSelection( pos , pos ) ;
597 }
598
599 void wxTextCtrl::SetInsertionPointEnd()
600 {
601 wxTextPos pos = GetLastPosition();
602 SetInsertionPoint( pos );
603 }
604
605 long wxTextCtrl::GetInsertionPoint() const
606 {
607 long begin, end ;
608 GetSelection( &begin , &end ) ;
609
610 return begin ;
611 }
612
613 wxTextPos wxTextCtrl::GetLastPosition() const
614 {
615 return GetPeer()->GetLastPosition() ;
616 }
617
618 void wxTextCtrl::Replace(long from, long to, const wxString& str)
619 {
620 GetPeer()->Replace( from , to , str ) ;
621 }
622
623 void wxTextCtrl::Remove(long from, long to)
624 {
625 GetPeer()->Remove( from , to ) ;
626 }
627
628 void wxTextCtrl::SetSelection(long from, long to)
629 {
630 GetPeer()->SetSelection( from , to ) ;
631 }
632
633 void wxTextCtrl::WriteText(const wxString& str)
634 {
635 // TODO: this MPRemoting will be moved into a remoting peer proxy for any command
636 if ( !wxIsMainThread() )
637 {
638 // unfortunately CW 8 is not able to correctly deduce the template types,
639 // so we have to instantiate explicitly
640 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( this , &wxTextCtrl::WriteText , str ) ;
641
642 return ;
643 }
644
645 GetPeer()->WriteText( str ) ;
646 }
647
648 void wxTextCtrl::AppendText(const wxString& text)
649 {
650 SetInsertionPointEnd();
651 WriteText( text );
652 }
653
654 void wxTextCtrl::Clear()
655 {
656 GetPeer()->Clear() ;
657 }
658
659 bool wxTextCtrl::IsModified() const
660 {
661 return m_dirty;
662 }
663
664 bool wxTextCtrl::IsEditable() const
665 {
666 return IsEnabled() && m_editable ;
667 }
668
669 bool wxTextCtrl::AcceptsFocus() const
670 {
671 // we don't want focus if we can't be edited
672 return /*IsEditable() && */ wxControl::AcceptsFocus();
673 }
674
675 wxSize wxTextCtrl::DoGetBestSize() const
676 {
677 int wText, hText;
678
679 // these are the numbers from the HIG:
680 // we reduce them by the borders first
681 wText = 100 ;
682
683 switch ( m_windowVariant )
684 {
685 case wxWINDOW_VARIANT_NORMAL :
686 hText = 22 - 6 ;
687 break ;
688
689 case wxWINDOW_VARIANT_SMALL :
690 hText = 19 - 6 ;
691 break ;
692
693 case wxWINDOW_VARIANT_MINI :
694 hText = 15 - 6 ;
695 break ;
696
697 default :
698 hText = 22 - 6;
699 break ;
700 }
701
702 // as the above numbers have some free space around the text
703 // we get 5 lines like this anyway
704 if ( m_windowStyle & wxTE_MULTILINE )
705 hText *= 5 ;
706
707 if ( !HasFlag(wxNO_BORDER) )
708 hText += 6 ;
709
710 return wxSize(wText, hText);
711 }
712
713 // ----------------------------------------------------------------------------
714 // Undo/redo
715 // ----------------------------------------------------------------------------
716
717 void wxTextCtrl::Undo()
718 {
719 if (CanUndo())
720 GetPeer()->Undo() ;
721 }
722
723 void wxTextCtrl::Redo()
724 {
725 if (CanRedo())
726 GetPeer()->Redo() ;
727 }
728
729 bool wxTextCtrl::CanUndo() const
730 {
731 if ( !IsEditable() )
732 return false ;
733
734 return GetPeer()->CanUndo() ;
735 }
736
737 bool wxTextCtrl::CanRedo() const
738 {
739 if ( !IsEditable() )
740 return false ;
741
742 return GetPeer()->CanRedo() ;
743 }
744
745 void wxTextCtrl::MarkDirty()
746 {
747 m_dirty = true;
748 }
749
750 void wxTextCtrl::DiscardEdits()
751 {
752 m_dirty = false;
753 }
754
755 int wxTextCtrl::GetNumberOfLines() const
756 {
757 return GetPeer()->GetNumberOfLines() ;
758 }
759
760 long wxTextCtrl::XYToPosition(long x, long y) const
761 {
762 return GetPeer()->XYToPosition( x , y ) ;
763 }
764
765 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
766 {
767 return GetPeer()->PositionToXY( pos , x , y ) ;
768 }
769
770 void wxTextCtrl::ShowPosition(long pos)
771 {
772 return GetPeer()->ShowPosition(pos) ;
773 }
774
775 int wxTextCtrl::GetLineLength(long lineNo) const
776 {
777 return GetPeer()->GetLineLength(lineNo) ;
778 }
779
780 wxString wxTextCtrl::GetLineText(long lineNo) const
781 {
782 return GetPeer()->GetLineText(lineNo) ;
783 }
784
785 void wxTextCtrl::Command(wxCommandEvent & event)
786 {
787 SetValue(event.GetString());
788 ProcessCommand(event);
789 }
790
791 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
792 {
793 // By default, load the first file into the text window.
794 if (event.GetNumberOfFiles() > 0)
795 LoadFile( event.GetFiles()[0] );
796 }
797
798 void wxTextCtrl::OnEraseBackground(wxEraseEvent& event)
799 {
800 // all erasing should be done by the real mac control implementation
801 // while this is true for MLTE under classic, the HITextView is somehow
802 // transparent but background erase is not working correctly, so intercept
803 // things while we can...
804 event.Skip() ;
805 }
806
807 void wxTextCtrl::OnChar(wxKeyEvent& event)
808 {
809 int key = event.GetKeyCode() ;
810 bool eat_key = false ;
811
812 if ( key == 'a' && event.MetaDown() )
813 {
814 SelectAll() ;
815
816 return ;
817 }
818
819 if ( key == 'c' && event.MetaDown() )
820 {
821 if ( CanCopy() )
822 Copy() ;
823
824 return ;
825 }
826
827 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
828 !( key == WXK_RETURN && ( (m_windowStyle & wxTE_PROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
829 // && key != WXK_PAGEUP && key != WXK_PAGEDOWN && key != WXK_HOME && key != WXK_END
830 )
831 {
832 // eat it
833 return ;
834 }
835
836 // Check if we have reached the max # of chars (if it is set), but still
837 // allow navigation and deletion
838 if ( !IsMultiLine() && m_maxLength && GetValue().length() >= m_maxLength &&
839 key != WXK_LEFT && key != WXK_RIGHT && key != WXK_TAB &&
840 key != WXK_BACK && !( key == WXK_RETURN && (m_windowStyle & wxTE_PROCESS_ENTER) )
841 )
842 {
843 // eat it, we don't want to add more than allowed # of characters
844
845 // TODO: generate EVT_TEXT_MAXLEN()
846 return;
847 }
848
849 // assume that any key not processed yet is going to modify the control
850 m_dirty = true;
851
852 if ( key == 'v' && event.MetaDown() )
853 {
854 if ( CanPaste() )
855 Paste() ;
856
857 return ;
858 }
859
860 if ( key == 'x' && event.MetaDown() )
861 {
862 if ( CanCut() )
863 Cut() ;
864
865 return ;
866 }
867
868 switch ( key )
869 {
870 case WXK_RETURN:
871 if (m_windowStyle & wxTE_PROCESS_ENTER)
872 {
873 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
874 event.SetEventObject( this );
875 event.SetString( GetValue() );
876 if ( GetEventHandler()->ProcessEvent(event) )
877 return;
878 }
879
880 if ( !(m_windowStyle & wxTE_MULTILINE) )
881 {
882 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
883 if ( tlw && tlw->GetDefaultItem() )
884 {
885 wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
886 if ( def && def->IsEnabled() )
887 {
888 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
889 event.SetEventObject(def);
890 def->Command(event);
891
892 return ;
893 }
894 }
895
896 // this will make wxWidgets eat the ENTER key so that
897 // we actually prevent line wrapping in a single line text control
898 eat_key = true;
899 }
900 break;
901
902 case WXK_TAB:
903 if ( !(m_windowStyle & wxTE_PROCESS_TAB))
904 {
905 int flags = 0;
906 if (!event.ShiftDown())
907 flags |= wxNavigationKeyEvent::IsForward ;
908 if (event.ControlDown())
909 flags |= wxNavigationKeyEvent::WinChange ;
910 Navigate(flags);
911
912 return;
913 }
914 else
915 {
916 // This is necessary (don't know why);
917 // otherwise the tab will not be inserted.
918 WriteText(wxT("\t"));
919 eat_key = true;
920 }
921 break;
922
923 default:
924 break;
925 }
926
927 if (!eat_key)
928 {
929 // perform keystroke handling
930 event.Skip(true) ;
931 }
932
933 if ( ( key >= 0x20 && key < WXK_START ) ||
934 ( key >= WXK_NUMPAD0 && key <= WXK_DIVIDE ) ||
935 key == WXK_RETURN ||
936 key == WXK_DELETE ||
937 key == WXK_BACK)
938 {
939 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
940 event1.SetEventObject( this );
941 wxPostEvent( GetEventHandler(), event1 );
942 }
943 }
944
945 // ----------------------------------------------------------------------------
946 // standard handlers for standard edit menu events
947 // ----------------------------------------------------------------------------
948
949 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
950 {
951 Cut();
952 }
953
954 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
955 {
956 Copy();
957 }
958
959 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
960 {
961 Paste();
962 }
963
964 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
965 {
966 Undo();
967 }
968
969 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
970 {
971 Redo();
972 }
973
974 void wxTextCtrl::OnDelete(wxCommandEvent& WXUNUSED(event))
975 {
976 long from, to;
977
978 GetSelection( &from, &to );
979 if (from != -1 && to != -1)
980 Remove( from, to );
981 }
982
983 void wxTextCtrl::OnSelectAll(wxCommandEvent& WXUNUSED(event))
984 {
985 SetSelection(-1, -1);
986 }
987
988 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
989 {
990 event.Enable( CanCut() );
991 }
992
993 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
994 {
995 event.Enable( CanCopy() );
996 }
997
998 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
999 {
1000 event.Enable( CanPaste() );
1001 }
1002
1003 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1004 {
1005 event.Enable( CanUndo() );
1006 }
1007
1008 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1009 {
1010 event.Enable( CanRedo() );
1011 }
1012
1013 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent& event)
1014 {
1015 long from, to;
1016
1017 GetSelection( &from, &to );
1018 event.Enable( from != -1 && to != -1 && from != to && IsEditable() ) ;
1019 }
1020
1021 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event)
1022 {
1023 event.Enable(GetLastPosition() > 0);
1024 }
1025
1026 // CS: Context Menus only work with MLTE implementations or non-multiline HIViews at the moment
1027
1028 void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
1029 {
1030 if ( GetPeer()->HasOwnContextMenu() )
1031 {
1032 event.Skip() ;
1033 return ;
1034 }
1035
1036 if (m_privateContextMenu == NULL)
1037 {
1038 m_privateContextMenu = new wxMenu;
1039 m_privateContextMenu->Append(wxID_UNDO, _("&Undo"));
1040 m_privateContextMenu->Append(wxID_REDO, _("&Redo"));
1041 m_privateContextMenu->AppendSeparator();
1042 m_privateContextMenu->Append(wxID_CUT, _("Cu&t"));
1043 m_privateContextMenu->Append(wxID_COPY, _("&Copy"));
1044 m_privateContextMenu->Append(wxID_PASTE, _("&Paste"));
1045 m_privateContextMenu->Append(wxID_CLEAR, _("&Delete"));
1046 m_privateContextMenu->AppendSeparator();
1047 m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All"));
1048 }
1049
1050 if (m_privateContextMenu != NULL)
1051 PopupMenu(m_privateContextMenu);
1052 }
1053
1054 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1055 {
1056 if ( !GetPeer()->SetupCursor( pt ) )
1057 return wxWindow::MacSetupCursor( pt ) ;
1058 else
1059 return true ;
1060 }
1061
1062 #if !TARGET_API_MAC_OSX
1063
1064 // user pane implementation
1065
1066 void wxTextCtrl::MacControlUserPaneDrawProc(wxInt16 part)
1067 {
1068 GetPeer()->MacControlUserPaneDrawProc( part ) ;
1069 }
1070
1071 wxInt16 wxTextCtrl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
1072 {
1073 return GetPeer()->MacControlUserPaneHitTestProc( x , y ) ;
1074 }
1075
1076 wxInt16 wxTextCtrl::MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc)
1077 {
1078 return GetPeer()->MacControlUserPaneTrackingProc( x , y , actionProc ) ;
1079 }
1080
1081 void wxTextCtrl::MacControlUserPaneIdleProc()
1082 {
1083 GetPeer()->MacControlUserPaneIdleProc( ) ;
1084 }
1085
1086 wxInt16 wxTextCtrl::MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
1087 {
1088 return GetPeer()->MacControlUserPaneKeyDownProc( keyCode , charCode , modifiers ) ;
1089 }
1090
1091 void wxTextCtrl::MacControlUserPaneActivateProc(bool activating)
1092 {
1093 GetPeer()->MacControlUserPaneActivateProc( activating ) ;
1094 }
1095
1096 wxInt16 wxTextCtrl::MacControlUserPaneFocusProc(wxInt16 action)
1097 {
1098 return GetPeer()->MacControlUserPaneFocusProc( action ) ;
1099 }
1100
1101 void wxTextCtrl::MacControlUserPaneBackgroundProc(void* info)
1102 {
1103 GetPeer()->MacControlUserPaneBackgroundProc( info ) ;
1104 }
1105
1106 #endif
1107
1108 // ----------------------------------------------------------------------------
1109 // implementation base class
1110 // ----------------------------------------------------------------------------
1111
1112 wxMacTextControl::wxMacTextControl(wxTextCtrl* peer) :
1113 wxMacControl( peer )
1114 {
1115 }
1116
1117 wxMacTextControl::~wxMacTextControl()
1118 {
1119 }
1120
1121 void wxMacTextControl::SetStyle(long WXUNUSED(start),
1122 long WXUNUSED(end),
1123 const wxTextAttr& WXUNUSED(style))
1124 {
1125 }
1126
1127 void wxMacTextControl::Copy()
1128 {
1129 }
1130
1131 void wxMacTextControl::Cut()
1132 {
1133 }
1134
1135 void wxMacTextControl::Paste()
1136 {
1137 }
1138
1139 bool wxMacTextControl::CanPaste() const
1140 {
1141 return false ;
1142 }
1143
1144 void wxMacTextControl::SetEditable(bool WXUNUSED(editable))
1145 {
1146 }
1147
1148 wxTextPos wxMacTextControl::GetLastPosition() const
1149 {
1150 return GetStringValue().length() ;
1151 }
1152
1153 void wxMacTextControl::Replace( long from , long to , const wxString &val )
1154 {
1155 SetSelection( from , to ) ;
1156 WriteText( val ) ;
1157 }
1158
1159 void wxMacTextControl::Remove( long from , long to )
1160 {
1161 SetSelection( from , to ) ;
1162 WriteText( wxEmptyString) ;
1163 }
1164
1165 void wxMacTextControl::Clear()
1166 {
1167 SetStringValue( wxEmptyString ) ;
1168 }
1169
1170 bool wxMacTextControl::CanUndo() const
1171 {
1172 return false ;
1173 }
1174
1175 void wxMacTextControl::Undo()
1176 {
1177 }
1178
1179 bool wxMacTextControl::CanRedo() const
1180 {
1181 return false ;
1182 }
1183
1184 void wxMacTextControl::Redo()
1185 {
1186 }
1187
1188 long wxMacTextControl::XYToPosition(long WXUNUSED(x), long WXUNUSED(y)) const
1189 {
1190 return 0 ;
1191 }
1192
1193 bool wxMacTextControl::PositionToXY(long WXUNUSED(pos),
1194 long *WXUNUSED(x),
1195 long *WXUNUSED(y)) const
1196 {
1197 return false ;
1198 }
1199
1200 void wxMacTextControl::ShowPosition( long WXUNUSED(pos) )
1201 {
1202 }
1203
1204 int wxMacTextControl::GetNumberOfLines() const
1205 {
1206 ItemCount lines = 0 ;
1207 wxString content = GetStringValue() ;
1208 lines = 1;
1209
1210 for (size_t i = 0; i < content.length() ; i++)
1211 {
1212 if (content[i] == '\r')
1213 lines++;
1214 }
1215
1216 return lines ;
1217 }
1218
1219 wxString wxMacTextControl::GetLineText(long lineNo) const
1220 {
1221 // TODO: change this if possible to reflect real lines
1222 wxString content = GetStringValue() ;
1223
1224 // Find line first
1225 int count = 0;
1226 for (size_t i = 0; i < content.length() ; i++)
1227 {
1228 if (count == lineNo)
1229 {
1230 // Add chars in line then
1231 wxString tmp;
1232
1233 for (size_t j = i; j < content.length(); j++)
1234 {
1235 if (content[j] == '\n')
1236 return tmp;
1237
1238 tmp += content[j];
1239 }
1240
1241 return tmp;
1242 }
1243
1244 if (content[i] == '\n')
1245 count++;
1246 }
1247
1248 return wxEmptyString ;
1249 }
1250
1251 int wxMacTextControl::GetLineLength(long lineNo) const
1252 {
1253 // TODO: change this if possible to reflect real lines
1254 wxString content = GetStringValue() ;
1255
1256 // Find line first
1257 int count = 0;
1258 for (size_t i = 0; i < content.length() ; i++)
1259 {
1260 if (count == lineNo)
1261 {
1262 // Count chars in line then
1263 count = 0;
1264 for (size_t j = i; j < content.length(); j++)
1265 {
1266 count++;
1267 if (content[j] == '\n')
1268 return count;
1269 }
1270
1271 return count;
1272 }
1273
1274 if (content[i] == '\n')
1275 count++;
1276 }
1277
1278 return 0 ;
1279 }
1280
1281 // ----------------------------------------------------------------------------
1282 // standard unicode control implementation
1283 // ----------------------------------------------------------------------------
1284
1285 #if TARGET_API_MAC_OSX
1286
1287 // the current unicode textcontrol implementation has a bug : only if the control
1288 // is currently having the focus, the selection can be retrieved by the corresponding
1289 // data tag. So we have a mirroring using a member variable
1290 // TODO : build event table using virtual member functions for wxMacControl
1291
1292 static const EventTypeSpec unicodeTextControlEventList[] =
1293 {
1294 { kEventClassControl , kEventControlSetFocusPart } ,
1295 } ;
1296
1297 static pascal OSStatus wxMacUnicodeTextControlControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
1298 {
1299 OSStatus result = eventNotHandledErr ;
1300 wxMacUnicodeTextControl* focus = (wxMacUnicodeTextControl*) data ;
1301 wxMacCarbonEvent cEvent( event ) ;
1302
1303 switch ( GetEventKind( event ) )
1304 {
1305 case kEventControlSetFocusPart :
1306 {
1307 ControlPartCode controlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
1308 if ( controlPart == kControlFocusNoPart )
1309 {
1310 // about to loose focus -> store selection to field
1311 focus->GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &focus->m_selection );
1312 }
1313 result = CallNextEventHandler(handler,event) ;
1314 if ( controlPart != kControlFocusNoPart )
1315 {
1316 // about to gain focus -> set selection from field
1317 focus->SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &focus->m_selection );
1318 }
1319 break;
1320 }
1321 default:
1322 break ;
1323 }
1324
1325 return result ;
1326 }
1327
1328 static pascal OSStatus wxMacUnicodeTextControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
1329 {
1330 OSStatus result = eventNotHandledErr ;
1331
1332 switch ( GetEventClass( event ) )
1333 {
1334 case kEventClassControl :
1335 result = wxMacUnicodeTextControlControlEventHandler( handler , event , data ) ;
1336 break ;
1337
1338 default :
1339 break ;
1340 }
1341 return result ;
1342 }
1343
1344 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacUnicodeTextControlEventHandler )
1345
1346 wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxTextCtrl *wxPeer ) : wxMacTextControl( wxPeer )
1347 {
1348 }
1349
1350 wxMacUnicodeTextControl::wxMacUnicodeTextControl( wxTextCtrl *wxPeer,
1351 const wxString& str,
1352 const wxPoint& pos,
1353 const wxSize& size, long style )
1354 : wxMacTextControl( wxPeer )
1355 {
1356 Create( wxPeer, str, pos, size, style );
1357 }
1358
1359 bool wxMacUnicodeTextControl::Create( wxTextCtrl *wxPeer,
1360 const wxString& str,
1361 const wxPoint& pos,
1362 const wxSize& size, long style )
1363 {
1364 m_font = wxPeer->GetFont() ;
1365 m_windowStyle = style ;
1366 m_selection.selStart = m_selection.selEnd = 0;
1367 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
1368 wxString st = str ;
1369 wxMacConvertNewlines10To13( &st ) ;
1370 wxMacCFStringHolder cf(st , m_font.GetEncoding()) ;
1371 CFStringRef cfr = cf ;
1372
1373 m_valueTag = kControlEditTextCFStringTag ;
1374 CreateControl( wxPeer, &bounds, cfr );
1375
1376 if ( !(m_windowStyle & wxTE_MULTILINE) )
1377 SetData<Boolean>( kControlEditTextPart , kControlEditTextSingleLineTag , true ) ;
1378
1379 InstallControlEventHandler( m_controlRef , GetwxMacUnicodeTextControlEventHandlerUPP(),
1380 GetEventTypeCount(unicodeTextControlEventList), unicodeTextControlEventList, this,
1381 NULL);
1382
1383 return true;
1384 }
1385
1386 wxMacUnicodeTextControl::~wxMacUnicodeTextControl()
1387 {
1388 }
1389
1390 void wxMacUnicodeTextControl::VisibilityChanged(bool shown)
1391 {
1392 if ( !(m_windowStyle & wxTE_MULTILINE) && shown )
1393 {
1394 // work around a refresh issue insofar as not always the entire content is shown,
1395 // even if this would be possible
1396 ControlEditTextSelectionRec sel ;
1397 CFStringRef value = NULL ;
1398
1399 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
1400 verify_noerr( GetData<CFStringRef>( 0, m_valueTag, &value ) );
1401 verify_noerr( SetData<CFStringRef>( 0, m_valueTag, &value ) );
1402 verify_noerr( SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) );
1403
1404 CFRelease( value ) ;
1405 }
1406 }
1407
1408 wxString wxMacUnicodeTextControl::GetStringValue() const
1409 {
1410 wxString result ;
1411 CFStringRef value = GetData<CFStringRef>(0, m_valueTag) ;
1412 if ( value )
1413 {
1414 wxMacCFStringHolder cf(value) ;
1415 result = cf.AsString() ;
1416 }
1417
1418 #if '\n' == 10
1419 wxMacConvertNewlines13To10( &result ) ;
1420 #else
1421 wxMacConvertNewlines10To13( &result ) ;
1422 #endif
1423
1424 return result ;
1425 }
1426
1427 void wxMacUnicodeTextControl::SetStringValue( const wxString &str )
1428 {
1429 wxString st = str ;
1430 wxMacConvertNewlines10To13( &st ) ;
1431 wxMacCFStringHolder cf( st , m_font.GetEncoding() ) ;
1432 verify_noerr( SetData<CFStringRef>( 0, m_valueTag , cf ) ) ;
1433 }
1434
1435 void wxMacUnicodeTextControl::CreateControl( wxTextCtrl* peer, const Rect* bounds, CFStringRef cfr )
1436 {
1437 Boolean isPassword = ( m_windowStyle & wxTE_PASSWORD ) != 0 ;
1438 if ( isPassword )
1439 {
1440 m_valueTag = kControlEditTextPasswordCFStringTag ;
1441 }
1442 OSStatus err = CreateEditUnicodeTextControl(
1443 MAC_WXHWND(peer->MacGetTopLevelWindowRef()), bounds , cfr ,
1444 isPassword , NULL , &m_controlRef ) ;
1445 verify_noerr( err );
1446 }
1447
1448 void wxMacUnicodeTextControl::Copy()
1449 {
1450 SendHICommand( kHICommandCopy ) ;
1451 }
1452
1453 void wxMacUnicodeTextControl::Cut()
1454 {
1455 SendHICommand( kHICommandCut ) ;
1456 }
1457
1458 void wxMacUnicodeTextControl::Paste()
1459 {
1460 SendHICommand( kHICommandPaste ) ;
1461 }
1462
1463 bool wxMacUnicodeTextControl::CanPaste() const
1464 {
1465 return true ;
1466 }
1467
1468 void wxMacUnicodeTextControl::SetEditable(bool WXUNUSED(editable))
1469 {
1470 #if 0 // leads to problem because text cannot be selected anymore
1471 SetData<Boolean>( kControlEditTextPart , kControlEditTextLockedTag , (Boolean) !editable ) ;
1472 #endif
1473 }
1474
1475 void wxMacUnicodeTextControl::GetSelection( long* from, long* to ) const
1476 {
1477 ControlEditTextSelectionRec sel ;
1478 if (HasFocus())
1479 verify_noerr( GetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ) ;
1480 else
1481 sel = m_selection ;
1482
1483 if ( from )
1484 *from = sel.selStart ;
1485 if ( to )
1486 *to = sel.selEnd ;
1487 }
1488
1489 void wxMacUnicodeTextControl::SetSelection( long from , long to )
1490 {
1491 ControlEditTextSelectionRec sel ;
1492 wxString result ;
1493 int textLength = 0 ;
1494 CFStringRef value = GetData<CFStringRef>(0, m_valueTag) ;
1495 if ( value )
1496 {
1497 wxMacCFStringHolder cf(value) ;
1498 textLength = cf.AsString().length() ;
1499 }
1500
1501 if ((from == -1) && (to == -1))
1502 {
1503 from = 0 ;
1504 to = textLength ;
1505 }
1506 else
1507 {
1508 from = wxMin(textLength,wxMax(from,0)) ;
1509 to = wxMax(0,wxMin(textLength,to)) ;
1510 }
1511
1512 sel.selStart = from ;
1513 sel.selEnd = to ;
1514 if ( HasFocus() )
1515 SetData<ControlEditTextSelectionRec>( 0, kControlEditTextSelectionTag, &sel ) ;
1516 else
1517 m_selection = sel;
1518 }
1519
1520 void wxMacUnicodeTextControl::WriteText( const wxString& str )
1521 {
1522 wxString st = str ;
1523 wxMacConvertNewlines10To13( &st ) ;
1524
1525 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
1526 if ( HasFocus() )
1527 {
1528 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1529 CFStringRef value = cf ;
1530 SetData<CFStringRef>( 0, kControlEditTextInsertCFStringRefTag, &value );
1531 }
1532 else
1533 #endif
1534 {
1535 wxString val = GetStringValue() ;
1536 long start , end ;
1537 GetSelection( &start , &end ) ;
1538 val.Remove( start , end - start ) ;
1539 val.insert( start , str ) ;
1540 SetStringValue( val ) ;
1541 SetSelection( start + str.length() , start + str.length() ) ;
1542 }
1543 }
1544
1545 #endif
1546
1547 // ----------------------------------------------------------------------------
1548 // MLTE control implementation (common part)
1549 // ----------------------------------------------------------------------------
1550
1551 // if MTLE is read only, no changes at all are allowed, not even from
1552 // procedural API, in order to allow changes via API all the same we must undo
1553 // the readonly status while we are executing, this class helps to do so
1554
1555 class wxMacEditHelper
1556 {
1557 public :
1558 wxMacEditHelper( TXNObject txn )
1559 {
1560 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1561 m_txn = txn ;
1562 TXNGetTXNObjectControls( m_txn , 1 , tag , m_data ) ;
1563 if ( m_data[0].uValue == kTXNReadOnly )
1564 {
1565 TXNControlData data[] = { { kTXNReadWrite } } ;
1566 TXNSetTXNObjectControls( m_txn , false , 1 , tag , data ) ;
1567 }
1568 }
1569
1570 ~wxMacEditHelper()
1571 {
1572 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1573 if ( m_data[0].uValue == kTXNReadOnly )
1574 TXNSetTXNObjectControls( m_txn , false , 1 , tag , m_data ) ;
1575 }
1576
1577 protected :
1578 TXNObject m_txn ;
1579 TXNControlData m_data[1] ;
1580 } ;
1581
1582 wxMacMLTEControl::wxMacMLTEControl( wxTextCtrl *peer )
1583 : wxMacTextControl( peer )
1584 {
1585 SetNeedsFocusRect( true ) ;
1586 }
1587
1588 wxString wxMacMLTEControl::GetStringValue() const
1589 {
1590 wxString result ;
1591 OSStatus err ;
1592 Size actualSize = 0;
1593
1594 {
1595 #if wxUSE_UNICODE
1596 Handle theText ;
1597 err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNUnicodeTextData );
1598
1599 // all done
1600 if ( err != noErr )
1601 {
1602 actualSize = 0 ;
1603 }
1604 else
1605 {
1606 actualSize = GetHandleSize( theText ) / sizeof(UniChar) ;
1607 if ( actualSize > 0 )
1608 {
1609 wxChar *ptr = NULL ;
1610
1611 #if SIZEOF_WCHAR_T == 2
1612 ptr = new wxChar[actualSize + 1] ;
1613 wxStrncpy( ptr , (wxChar*)(*theText) , actualSize ) ;
1614 #else
1615 SetHandleSize( theText, (actualSize + 1) * sizeof(UniChar) ) ;
1616 HLock( theText ) ;
1617 (((UniChar*)*theText)[actualSize]) = 0 ;
1618 wxMBConvUTF16 converter ;
1619 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
1620 wxASSERT_MSG( noChars != wxCONV_FAILED, _T("Unable to count the number of characters in this string!") );
1621 ptr = new wxChar[noChars + 1] ;
1622
1623 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars + 1 ) ;
1624 wxASSERT_MSG( noChars != wxCONV_FAILED, _T("Conversion of string failed!") );
1625 ptr[noChars] = 0 ;
1626 HUnlock( theText ) ;
1627 #endif
1628
1629 ptr[actualSize] = 0 ;
1630 result = wxString( ptr ) ;
1631 delete [] ptr ;
1632 }
1633
1634 DisposeHandle( theText ) ;
1635 }
1636 #else
1637 Handle theText ;
1638 err = TXNGetDataEncoded( m_txn , kTXNStartOffset, kTXNEndOffset, &theText, kTXNTextData );
1639
1640 // all done
1641 if ( err != noErr )
1642 {
1643 actualSize = 0 ;
1644 }
1645 else
1646 {
1647 actualSize = GetHandleSize( theText ) ;
1648 if ( actualSize > 0 )
1649 {
1650 HLock( theText ) ;
1651 result = wxString( *theText , wxConvLocal , actualSize ) ;
1652 HUnlock( theText ) ;
1653 }
1654
1655 DisposeHandle( theText ) ;
1656 }
1657 #endif
1658 }
1659
1660 #if '\n' == 10
1661 wxMacConvertNewlines13To10( &result ) ;
1662 #else
1663 wxMacConvertNewlines10To13( &result ) ;
1664 #endif
1665
1666 return result ;
1667 }
1668
1669 void wxMacMLTEControl::SetStringValue( const wxString &str )
1670 {
1671 wxString st = str;
1672 wxMacConvertNewlines10To13( &st );
1673
1674 {
1675 #ifndef __LP64__
1676 wxMacWindowClipper c( m_peer ) ;
1677 #endif
1678
1679 {
1680 wxMacEditHelper help( m_txn );
1681 SetTXNData( st, kTXNStartOffset, kTXNEndOffset );
1682 }
1683
1684 TXNSetSelection( m_txn, 0, 0 );
1685 TXNShowSelection( m_txn, kTXNShowStart );
1686 }
1687 }
1688
1689 TXNFrameOptions wxMacMLTEControl::FrameOptionsFromWXStyle( long wxStyle )
1690 {
1691 TXNFrameOptions frameOptions = kTXNDontDrawCaretWhenInactiveMask;
1692
1693 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1694 frameOptions |= kTXNDoFontSubstitutionMask;
1695 #endif
1696
1697 if ( ! (wxStyle & wxTE_NOHIDESEL) )
1698 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
1699
1700 if ( wxStyle & (wxHSCROLL | wxTE_DONTWRAP) )
1701 frameOptions |= kTXNWantHScrollBarMask ;
1702
1703 if ( wxStyle & wxTE_MULTILINE )
1704 {
1705 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
1706
1707 if ( !(wxStyle & wxTE_NO_VSCROLL) )
1708 {
1709 frameOptions |= kTXNWantVScrollBarMask ;
1710
1711 // The following code causes drawing problems on 10.4. Perhaps it can be restored for
1712 // older versions of the OS, but I'm not sure it's appropriate to put a grow icon here
1713 // anyways, as AFAIK users can't actually use it to resize the text ctrl.
1714 // if ( frameOptions & kTXNWantHScrollBarMask )
1715 // frameOptions |= kTXNDrawGrowIconMask ;
1716 }
1717 }
1718 else
1719 {
1720 frameOptions |= kTXNSingleLineOnlyMask ;
1721 }
1722
1723 return frameOptions ;
1724 }
1725
1726 void wxMacMLTEControl::AdjustCreationAttributes(const wxColour &background,
1727 bool WXUNUSED(visible))
1728 {
1729 TXNControlTag iControlTags[] =
1730 {
1731 kTXNDoFontSubstitution,
1732 kTXNWordWrapStateTag ,
1733 };
1734 TXNControlData iControlData[] =
1735 {
1736 { true },
1737 { kTXNNoAutoWrap },
1738 };
1739
1740 int toptag = WXSIZEOF( iControlTags ) ;
1741
1742 if ( m_windowStyle & wxTE_MULTILINE )
1743 {
1744 iControlData[1].uValue =
1745 (m_windowStyle & wxTE_DONTWRAP)
1746 ? kTXNNoAutoWrap
1747 : kTXNAutoWrap;
1748 }
1749
1750 OSStatus err = TXNSetTXNObjectControls( m_txn, false, toptag, iControlTags, iControlData ) ;
1751 verify_noerr( err );
1752
1753 // setting the default font:
1754 // under 10.2 this causes a visible caret, therefore we avoid it
1755
1756 if ( UMAGetSystemVersion() >= 0x1030 )
1757 {
1758 Str255 fontName ;
1759 SInt16 fontSize ;
1760 Style fontStyle ;
1761
1762 GetThemeFont( kThemeSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
1763
1764 TXNTypeAttributes typeAttr[] =
1765 {
1766 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
1767 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
1768 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
1769 } ;
1770
1771 err = TXNSetTypeAttributes(
1772 m_txn, sizeof(typeAttr) / sizeof(TXNTypeAttributes),
1773 typeAttr, kTXNStartOffset, kTXNEndOffset );
1774 verify_noerr( err );
1775 }
1776
1777 if ( m_windowStyle & wxTE_PASSWORD )
1778 {
1779 UniChar c = 0x00A5 ;
1780 err = TXNEchoMode( m_txn , c , 0 , true );
1781 verify_noerr( err );
1782 }
1783
1784 TXNBackground tback;
1785 tback.bgType = kTXNBackgroundTypeRGB;
1786 tback.bg.color = MAC_WXCOLORREF( background.GetPixel() );
1787 TXNSetBackground( m_txn , &tback );
1788
1789 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
1790 if ( UMAGetSystemVersion() >= 0x1040 )
1791 {
1792 TXNCommandEventSupportOptions options ;
1793 if ( TXNGetCommandEventSupport( m_txn, &options ) == noErr )
1794 {
1795 options |=
1796 kTXNSupportEditCommandProcessing
1797 | kTXNSupportEditCommandUpdating
1798 | kTXNSupportFontCommandProcessing
1799 | kTXNSupportFontCommandUpdating;
1800
1801 // only spell check when not read-only
1802 // use system options for the default
1803 bool checkSpelling = false ;
1804 if ( !(m_windowStyle & wxTE_READONLY) )
1805 {
1806 #if wxUSE_SYSTEM_OPTIONS
1807 if ( wxSystemOptions::HasOption( wxMAC_TEXTCONTROL_USE_SPELL_CHECKER ) && (wxSystemOptions::GetOptionInt( wxMAC_TEXTCONTROL_USE_SPELL_CHECKER ) == 1) )
1808 {
1809 checkSpelling = true ;
1810 }
1811 #endif
1812 }
1813
1814 if ( checkSpelling )
1815 options |=
1816 kTXNSupportSpellCheckCommandProcessing
1817 | kTXNSupportSpellCheckCommandUpdating;
1818
1819 TXNSetCommandEventSupport( m_txn , options ) ;
1820 }
1821 }
1822 #endif
1823 }
1824
1825 void wxMacMLTEControl::SetBackground( const wxBrush &brush )
1826 {
1827 // currently only solid background are supported
1828 TXNBackground tback;
1829
1830 tback.bgType = kTXNBackgroundTypeRGB;
1831 tback.bg.color = MAC_WXCOLORREF( brush.GetColour().GetPixel() );
1832 TXNSetBackground( m_txn , &tback );
1833 }
1834
1835 void wxMacMLTEControl::TXNSetAttribute( const wxTextAttr& style , long from , long to )
1836 {
1837 TXNTypeAttributes typeAttr[4] ;
1838 RGBColor color ;
1839 size_t typeAttrCount = 0 ;
1840
1841 TXNMargins margins;
1842 TXNControlTag controlTags[4];
1843 TXNControlData controlData[4];
1844 size_t controlAttrCount = 0;
1845
1846 TXNTab* tabs = NULL;
1847
1848 bool relayout = false;
1849
1850 if ( style.HasFont() )
1851 {
1852 wxASSERT( typeAttrCount < WXSIZEOF(typeAttr) );
1853 const wxFont &font = style.GetFont() ;
1854 typeAttr[typeAttrCount].tag = kTXNATSUIStyle ;
1855 typeAttr[typeAttrCount].size = kTXNATSUIStyleSize ;
1856 typeAttr[typeAttrCount].data.dataPtr = font.MacGetATSUStyle() ;
1857 typeAttrCount++ ;
1858 }
1859
1860 if ( style.HasTextColour() )
1861 {
1862 wxASSERT( typeAttrCount < WXSIZEOF(typeAttr) );
1863 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
1864
1865 typeAttr[typeAttrCount].tag = kTXNQDFontColorAttribute ;
1866 typeAttr[typeAttrCount].size = kTXNQDFontColorAttributeSize ;
1867 typeAttr[typeAttrCount].data.dataPtr = (void*) &color ;
1868 typeAttrCount++ ;
1869 }
1870
1871 if ( style.HasAlignment() )
1872 {
1873 wxASSERT( controlAttrCount < WXSIZEOF(controlTags) );
1874 SInt32 align;
1875
1876 switch ( style.GetAlignment() )
1877 {
1878 case wxTEXT_ALIGNMENT_LEFT:
1879 align = kTXNFlushLeft;
1880 break;
1881 case wxTEXT_ALIGNMENT_CENTRE:
1882 align = kTXNCenter;
1883 break;
1884 case wxTEXT_ALIGNMENT_RIGHT:
1885 align = kTXNFlushRight;
1886 break;
1887 case wxTEXT_ALIGNMENT_JUSTIFIED:
1888 align = kTXNFullJust;
1889 break;
1890 default :
1891 case wxTEXT_ALIGNMENT_DEFAULT:
1892 align = kTXNFlushDefault;
1893 break;
1894 }
1895
1896 controlTags[controlAttrCount] = kTXNJustificationTag ;
1897 controlData[controlAttrCount].sValue = align ;
1898 controlAttrCount++ ;
1899 }
1900
1901 if ( style.HasLeftIndent() || style.HasRightIndent() )
1902 {
1903 wxASSERT( controlAttrCount < WXSIZEOF(controlTags) );
1904 controlTags[controlAttrCount] = kTXNMarginsTag;
1905 controlData[controlAttrCount].marginsPtr = &margins;
1906 verify_noerr( TXNGetTXNObjectControls (m_txn, 1 ,
1907 &controlTags[controlAttrCount], &controlData[controlAttrCount]) );
1908 if ( style.HasLeftIndent() )
1909 {
1910 margins.leftMargin = style.GetLeftIndent() / 254.0 * 72 + 0.5;
1911 }
1912 if ( style.HasRightIndent() )
1913 {
1914 margins.rightMargin = style.GetRightIndent() / 254.0 * 72 + 0.5;
1915 }
1916 controlAttrCount++ ;
1917 }
1918
1919 if ( style.HasTabs() )
1920 {
1921 const wxArrayInt& tabarray = style.GetTabs();
1922 // unfortunately Mac only applies a tab distance, not individually different tabs
1923 controlTags[controlAttrCount] = kTXNTabSettingsTag;
1924 if ( tabarray.size() > 0 )
1925 controlData[controlAttrCount].tabValue.value = tabarray[0] / 254.0 * 72 + 0.5;
1926 else
1927 controlData[controlAttrCount].tabValue.value = 72 ;
1928
1929 controlData[controlAttrCount].tabValue.tabType = kTXNLeftTab;
1930 controlAttrCount++ ;
1931 }
1932
1933 // unfortunately the relayout is not automatic
1934 if ( controlAttrCount > 0 )
1935 {
1936 verify_noerr( TXNSetTXNObjectControls (m_txn, false /* don't clear all */, controlAttrCount,
1937 controlTags, controlData) );
1938 relayout = true;
1939 }
1940
1941 if ( typeAttrCount > 0 )
1942 {
1943 verify_noerr( TXNSetTypeAttributes( m_txn , typeAttrCount, typeAttr, from , to ) );
1944 relayout = true;
1945 }
1946
1947 if ( tabs != NULL )
1948 {
1949 delete[] tabs;
1950 }
1951
1952 if ( relayout )
1953 {
1954 TXNRecalcTextLayout( m_txn );
1955 }
1956 }
1957
1958 void wxMacMLTEControl::SetFont(const wxFont & font,
1959 const wxColour& foreground,
1960 long WXUNUSED(windowStyle))
1961 {
1962 wxMacEditHelper help( m_txn ) ;
1963 TXNSetAttribute( wxTextAttr( foreground, wxNullColour, font ), kTXNStartOffset, kTXNEndOffset ) ;
1964 }
1965
1966 void wxMacMLTEControl::SetStyle( long start, long end, const wxTextAttr& style )
1967 {
1968 wxMacEditHelper help( m_txn ) ;
1969 TXNSetAttribute( style, start, end ) ;
1970 }
1971
1972 void wxMacMLTEControl::Copy()
1973 {
1974 TXNCopy( m_txn );
1975 }
1976
1977 void wxMacMLTEControl::Cut()
1978 {
1979 TXNCut( m_txn );
1980 }
1981
1982 void wxMacMLTEControl::Paste()
1983 {
1984 TXNPaste( m_txn );
1985 }
1986
1987 bool wxMacMLTEControl::CanPaste() const
1988 {
1989 return TXNIsScrapPastable() ;
1990 }
1991
1992 void wxMacMLTEControl::SetEditable(bool editable)
1993 {
1994 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1995 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1996 TXNSetTXNObjectControls( m_txn, false, WXSIZEOF(tag), tag, data ) ;
1997 }
1998
1999 wxTextPos wxMacMLTEControl::GetLastPosition() const
2000 {
2001 wxTextPos actualsize = 0 ;
2002
2003 Handle theText ;
2004 OSErr err = TXNGetDataEncoded( m_txn, kTXNStartOffset, kTXNEndOffset, &theText, kTXNTextData );
2005
2006 // all done
2007 if ( err == noErr )
2008 {
2009 actualsize = GetHandleSize( theText ) ;
2010 DisposeHandle( theText ) ;
2011 }
2012 else
2013 {
2014 actualsize = 0 ;
2015 }
2016
2017 return actualsize ;
2018 }
2019
2020 void wxMacMLTEControl::Replace( long from , long to , const wxString &str )
2021 {
2022 wxString value = str ;
2023 wxMacConvertNewlines10To13( &value ) ;
2024
2025 wxMacEditHelper help( m_txn ) ;
2026 #ifndef __LP64__
2027 wxMacWindowClipper c( m_peer ) ;
2028 #endif
2029
2030 TXNSetSelection( m_txn, from, to ) ;
2031 TXNClear( m_txn ) ;
2032 SetTXNData( value, kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
2033 }
2034
2035 void wxMacMLTEControl::Remove( long from , long to )
2036 {
2037 #ifndef __LP64__
2038 wxMacWindowClipper c( m_peer ) ;
2039 #endif
2040 wxMacEditHelper help( m_txn ) ;
2041 TXNSetSelection( m_txn , from , to ) ;
2042 TXNClear( m_txn ) ;
2043 }
2044
2045 void wxMacMLTEControl::GetSelection( long* from, long* to) const
2046 {
2047 TXNOffset f,t ;
2048 TXNGetSelection( m_txn , &f , &t ) ;
2049 *from = f;
2050 *to = t;
2051 }
2052
2053 void wxMacMLTEControl::SetSelection( long from , long to )
2054 {
2055 #ifndef __LP64__
2056 wxMacWindowClipper c( m_peer ) ;
2057 #endif
2058
2059 // change the selection
2060 if ((from == -1) && (to == -1))
2061 TXNSelectAll( m_txn );
2062 else
2063 TXNSetSelection( m_txn, from, to );
2064
2065 TXNShowSelection( m_txn, kTXNShowStart );
2066 }
2067
2068 void wxMacMLTEControl::WriteText( const wxString& str )
2069 {
2070 wxString st = str ;
2071 wxMacConvertNewlines10To13( &st ) ;
2072
2073 long start , end , dummy ;
2074
2075 GetSelection( &start , &dummy ) ;
2076 #ifndef __LP64__
2077 wxMacWindowClipper c( m_peer ) ;
2078 #endif
2079
2080 {
2081 wxMacEditHelper helper( m_txn ) ;
2082 SetTXNData( st, kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
2083 }
2084
2085 GetSelection( &dummy, &end ) ;
2086
2087 // TODO: SetStyle( start , end , GetDefaultStyle() ) ;
2088 }
2089
2090 void wxMacMLTEControl::Clear()
2091 {
2092 #ifndef __LP64__
2093 wxMacWindowClipper c( m_peer ) ;
2094 #endif
2095 wxMacEditHelper st( m_txn ) ;
2096 TXNSetSelection( m_txn , kTXNStartOffset , kTXNEndOffset ) ;
2097 TXNClear( m_txn ) ;
2098 }
2099
2100 bool wxMacMLTEControl::CanUndo() const
2101 {
2102 return TXNCanUndo( m_txn , NULL ) ;
2103 }
2104
2105 void wxMacMLTEControl::Undo()
2106 {
2107 TXNUndo( m_txn ) ;
2108 }
2109
2110 bool wxMacMLTEControl::CanRedo() const
2111 {
2112 return TXNCanRedo( m_txn , NULL ) ;
2113 }
2114
2115 void wxMacMLTEControl::Redo()
2116 {
2117 TXNRedo( m_txn ) ;
2118 }
2119
2120 int wxMacMLTEControl::GetNumberOfLines() const
2121 {
2122 ItemCount lines = 0 ;
2123 TXNGetLineCount( m_txn, &lines ) ;
2124
2125 return lines ;
2126 }
2127
2128 long wxMacMLTEControl::XYToPosition(long x, long y) const
2129 {
2130 Point curpt ;
2131 wxTextPos lastpos ;
2132
2133 // TODO: find a better implementation : while we can get the
2134 // line metrics of a certain line, we don't get its starting
2135 // position, so it would probably be rather a binary search
2136 // for the start position
2137 long xpos = 0, ypos = 0 ;
2138 int lastHeight = 0 ;
2139 ItemCount n ;
2140
2141 lastpos = GetLastPosition() ;
2142 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
2143 {
2144 if ( y == ypos && x == xpos )
2145 return n ;
2146
2147 TXNOffsetToPoint( m_txn, n, &curpt ) ;
2148
2149 if ( curpt.v > lastHeight )
2150 {
2151 xpos = 0 ;
2152 if ( n > 0 )
2153 ++ypos ;
2154
2155 lastHeight = curpt.v ;
2156 }
2157 else
2158 ++xpos ;
2159 }
2160
2161 return 0 ;
2162 }
2163
2164 bool wxMacMLTEControl::PositionToXY( long pos, long *x, long *y ) const
2165 {
2166 Point curpt ;
2167 wxTextPos lastpos ;
2168
2169 if ( y )
2170 *y = 0 ;
2171 if ( x )
2172 *x = 0 ;
2173
2174 lastpos = GetLastPosition() ;
2175 if ( pos <= lastpos )
2176 {
2177 // TODO: find a better implementation - while we can get the
2178 // line metrics of a certain line, we don't get its starting
2179 // position, so it would probably be rather a binary search
2180 // for the start position
2181 long xpos = 0, ypos = 0 ;
2182 int lastHeight = 0 ;
2183 ItemCount n ;
2184
2185 for ( n = 0 ; n <= (ItemCount) pos ; ++n )
2186 {
2187 TXNOffsetToPoint( m_txn, n, &curpt ) ;
2188
2189 if ( curpt.v > lastHeight )
2190 {
2191 xpos = 0 ;
2192 if ( n > 0 )
2193 ++ypos ;
2194
2195 lastHeight = curpt.v ;
2196 }
2197 else
2198 ++xpos ;
2199 }
2200
2201 if ( y )
2202 *y = ypos ;
2203 if ( x )
2204 *x = xpos ;
2205 }
2206
2207 return false ;
2208 }
2209
2210 void wxMacMLTEControl::ShowPosition( long pos )
2211 {
2212 Point current, desired ;
2213 TXNOffset selstart, selend;
2214
2215 TXNGetSelection( m_txn, &selstart, &selend );
2216 TXNOffsetToPoint( m_txn, selstart, &current );
2217 TXNOffsetToPoint( m_txn, pos, &desired );
2218
2219 // TODO: use HIPoints for 10.3 and above
2220
2221 OSErr theErr = noErr;
2222 long dv = desired.v - current.v;
2223 long dh = desired.h - current.h;
2224 TXNShowSelection( m_txn, kTXNShowStart ) ; // NB: should this be kTXNShowStart or kTXNShowEnd ??
2225 theErr = TXNScroll( m_txn, kTXNScrollUnitsInPixels, kTXNScrollUnitsInPixels, &dv, &dh );
2226
2227 // there will be an error returned for classic MLTE implementation when the control is
2228 // invisible, but HITextView works correctly, so we don't assert that one
2229 // wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
2230 }
2231
2232 void wxMacMLTEControl::SetTXNData( const wxString& st, TXNOffset start, TXNOffset end )
2233 {
2234 #if wxUSE_UNICODE
2235 #if SIZEOF_WCHAR_T == 2
2236 size_t len = st.length() ;
2237 TXNSetData( m_txn, kTXNUnicodeTextData, (void*)st.wc_str(), len * 2, start, end );
2238 #else
2239 wxMBConvUTF16 converter ;
2240 ByteCount byteBufferLen = converter.WC2MB( NULL, st.wc_str(), 0 ) ;
2241 UniChar *unibuf = (UniChar*)malloc( byteBufferLen ) ;
2242 converter.WC2MB( (char*)unibuf, st.wc_str(), byteBufferLen ) ;
2243 TXNSetData( m_txn, kTXNUnicodeTextData, (void*)unibuf, byteBufferLen, start, end ) ;
2244 free( unibuf ) ;
2245 #endif
2246 #else
2247 wxCharBuffer text = st.mb_str( wxConvLocal ) ;
2248 TXNSetData( m_txn, kTXNTextData, (void*)text.data(), strlen( text ), start, end ) ;
2249 #endif
2250 }
2251
2252 wxString wxMacMLTEControl::GetLineText(long lineNo) const
2253 {
2254 wxString line ;
2255
2256 if ( lineNo < GetNumberOfLines() )
2257 {
2258 Point firstPoint;
2259 Fixed lineWidth, lineHeight, currentHeight;
2260 long ypos ;
2261
2262 // get the first possible position in the control
2263 TXNOffsetToPoint(m_txn, 0, &firstPoint);
2264
2265 // Iterate through the lines until we reach the one we want,
2266 // adding to our current y pixel point position
2267 ypos = 0 ;
2268 currentHeight = 0;
2269 while (ypos < lineNo)
2270 {
2271 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
2272 currentHeight += lineHeight;
2273 }
2274
2275 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
2276 TXNOffset theOffset;
2277 TXNPointToOffset(m_txn, thePoint, &theOffset);
2278
2279 wxString content = GetStringValue() ;
2280 Point currentPoint = thePoint;
2281 while (thePoint.v == currentPoint.v && theOffset < content.length())
2282 {
2283 line += content[theOffset];
2284 TXNOffsetToPoint(m_txn, ++theOffset, &currentPoint);
2285 }
2286 }
2287
2288 return line ;
2289 }
2290
2291 int wxMacMLTEControl::GetLineLength(long lineNo) const
2292 {
2293 int theLength = 0;
2294
2295 if ( lineNo < GetNumberOfLines() )
2296 {
2297 Point firstPoint;
2298 Fixed lineWidth, lineHeight, currentHeight;
2299 long ypos;
2300
2301 // get the first possible position in the control
2302 TXNOffsetToPoint(m_txn, 0, &firstPoint);
2303
2304 // Iterate through the lines until we reach the one we want,
2305 // adding to our current y pixel point position
2306 ypos = 0;
2307 currentHeight = 0;
2308 while (ypos < lineNo)
2309 {
2310 TXNGetLineMetrics(m_txn, ypos++, &lineWidth, &lineHeight);
2311 currentHeight += lineHeight;
2312 }
2313
2314 Point thePoint = { firstPoint.v + (currentHeight >> 16), firstPoint.h + (0) };
2315 TXNOffset theOffset;
2316 TXNPointToOffset(m_txn, thePoint, &theOffset);
2317
2318 wxString content = GetStringValue() ;
2319 Point currentPoint = thePoint;
2320 while (thePoint.v == currentPoint.v && theOffset < content.length())
2321 {
2322 ++theLength;
2323 TXNOffsetToPoint(m_txn, ++theOffset, &currentPoint);
2324 }
2325 }
2326
2327 return theLength ;
2328 }
2329
2330 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
2331
2332 // ----------------------------------------------------------------------------
2333 // MLTE control implementation (classic part)
2334 // ----------------------------------------------------------------------------
2335
2336 // OS X Notes : We still don't have a full replacement for MLTE, so this implementation
2337 // has to live on. We have different problems coming from outdated implementations on the
2338 // various OS X versions. Most deal with the scrollbars: they are not correctly embedded
2339 // while this can be solved on 10.3 by reassigning them the correct place, on 10.2 there is
2340 // no way out, therefore we are using our own implementation and our own scrollbars ....
2341
2342 #ifdef __WXMAC_OSX__
2343
2344 TXNScrollInfoUPP gTXNScrollInfoProc = NULL ;
2345 ControlActionUPP gTXNScrollActionProc = NULL ;
2346
2347 pascal void wxMacMLTEClassicControl::TXNScrollInfoProc(
2348 SInt32 iValue, SInt32 iMaximumValue,
2349 TXNScrollBarOrientation iScrollBarOrientation, SInt32 iRefCon )
2350 {
2351 wxMacMLTEClassicControl* mlte = (wxMacMLTEClassicControl*) iRefCon ;
2352 SInt32 value = wxMax( iValue , 0 ) ;
2353 SInt32 maximum = wxMax( iMaximumValue , 0 ) ;
2354
2355 if ( iScrollBarOrientation == kTXNHorizontal )
2356 {
2357 if ( mlte->m_sbHorizontal )
2358 {
2359 SetControl32BitValue( mlte->m_sbHorizontal , value ) ;
2360 SetControl32BitMaximum( mlte->m_sbHorizontal , maximum ) ;
2361 mlte->m_lastHorizontalValue = value ;
2362 }
2363 }
2364 else if ( iScrollBarOrientation == kTXNVertical )
2365 {
2366 if ( mlte->m_sbVertical )
2367 {
2368 SetControl32BitValue( mlte->m_sbVertical , value ) ;
2369 SetControl32BitMaximum( mlte->m_sbVertical , maximum ) ;
2370 mlte->m_lastVerticalValue = value ;
2371 }
2372 }
2373 }
2374
2375 pascal void wxMacMLTEClassicControl::TXNScrollActionProc( ControlRef controlRef , ControlPartCode partCode )
2376 {
2377 wxMacMLTEClassicControl* mlte = (wxMacMLTEClassicControl*) GetControlReference( controlRef ) ;
2378 if ( mlte == NULL )
2379 return ;
2380
2381 if ( controlRef != mlte->m_sbVertical && controlRef != mlte->m_sbHorizontal )
2382 return ;
2383
2384 OSStatus err ;
2385 bool isHorizontal = ( controlRef == mlte->m_sbHorizontal ) ;
2386
2387 SInt32 minimum = 0 ;
2388 SInt32 maximum = GetControl32BitMaximum( controlRef ) ;
2389 SInt32 value = GetControl32BitValue( controlRef ) ;
2390 SInt32 delta = 0;
2391
2392 switch ( partCode )
2393 {
2394 case kControlDownButtonPart :
2395 delta = 10 ;
2396 break ;
2397
2398 case kControlUpButtonPart :
2399 delta = -10 ;
2400 break ;
2401
2402 case kControlPageDownPart :
2403 delta = GetControlViewSize( controlRef ) ;
2404 break ;
2405
2406 case kControlPageUpPart :
2407 delta = -GetControlViewSize( controlRef ) ;
2408 break ;
2409
2410 case kControlIndicatorPart :
2411 delta = value - (isHorizontal ? mlte->m_lastHorizontalValue : mlte->m_lastVerticalValue) ;
2412 break ;
2413
2414 default :
2415 break ;
2416 }
2417
2418 if ( delta != 0 )
2419 {
2420 SInt32 newValue = value ;
2421
2422 if ( partCode != kControlIndicatorPart )
2423 {
2424 if ( value + delta < minimum )
2425 delta = minimum - value ;
2426 if ( value + delta > maximum )
2427 delta = maximum - value ;
2428
2429 SetControl32BitValue( controlRef , value + delta ) ;
2430 newValue = value + delta ;
2431 }
2432
2433 SInt32 verticalDelta = isHorizontal ? 0 : delta ;
2434 SInt32 horizontalDelta = isHorizontal ? delta : 0 ;
2435
2436 err = TXNScroll(
2437 mlte->m_txn, kTXNScrollUnitsInPixels, kTXNScrollUnitsInPixels,
2438 &verticalDelta, &horizontalDelta );
2439 verify_noerr( err );
2440
2441 if ( isHorizontal )
2442 mlte->m_lastHorizontalValue = newValue ;
2443 else
2444 mlte->m_lastVerticalValue = newValue ;
2445 }
2446 }
2447 #endif
2448
2449 // make correct activations
2450 void wxMacMLTEClassicControl::MacActivatePaneText(bool setActive)
2451 {
2452 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(m_controlRef);
2453
2454 wxMacWindowClipper clipper( textctrl ) ;
2455 TXNActivate( m_txn, m_txnFrameID, setActive );
2456
2457 ControlRef controlFocus = 0 ;
2458 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
2459 if ( controlFocus == m_controlRef )
2460 TXNFocus( m_txn, setActive );
2461 }
2462
2463 void wxMacMLTEClassicControl::MacFocusPaneText(bool setFocus)
2464 {
2465 TXNFocus( m_txn, setFocus );
2466 }
2467
2468 // guards against inappropriate redraw (hidden objects drawing onto window)
2469
2470 void wxMacMLTEClassicControl::MacSetObjectVisibility(bool vis)
2471 {
2472 ControlRef controlFocus = 0 ;
2473 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
2474
2475 if ( !vis && (controlFocus == m_controlRef ) )
2476 SetKeyboardFocus( m_txnWindow , m_controlRef , kControlFocusNoPart ) ;
2477
2478 TXNControlTag iControlTags[1] = { kTXNVisibilityTag };
2479 TXNControlData iControlData[1] = { { (UInt32)false } };
2480
2481 verify_noerr( TXNGetTXNObjectControls( m_txn , 1, iControlTags, iControlData ) ) ;
2482
2483 if ( iControlData[0].uValue != vis )
2484 {
2485 iControlData[0].uValue = vis ;
2486 verify_noerr( TXNSetTXNObjectControls( m_txn, false , 1, iControlTags, iControlData ) ) ;
2487 }
2488
2489 // currently, we always clip as partial visibility (overlapped) visibility is also a problem,
2490 // if we run into further problems we might set the FrameBounds to an empty rect here
2491 }
2492
2493 // make sure that the TXNObject is at the right position
2494
2495 void wxMacMLTEClassicControl::MacUpdatePosition()
2496 {
2497 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2498 if ( textctrl == NULL )
2499 return ;
2500
2501 Rect bounds ;
2502 UMAGetControlBoundsInWindowCoords( m_controlRef, &bounds );
2503
2504 wxRect visRect = textctrl->MacGetClippedClientRect() ;
2505 Rect visBounds = { visRect.y , visRect.x , visRect.y + visRect.height , visRect.x + visRect.width } ;
2506 int x , y ;
2507 x = y = 0 ;
2508 textctrl->MacWindowToRootWindow( &x , &y ) ;
2509 OffsetRect( &visBounds , x , y ) ;
2510
2511 if ( !EqualRect( &bounds, &m_txnControlBounds ) || !EqualRect( &visBounds, &m_txnVisBounds ) )
2512 {
2513 m_txnControlBounds = bounds ;
2514 m_txnVisBounds = visBounds ;
2515 wxMacWindowClipper cl( textctrl ) ;
2516
2517 #ifdef __WXMAC_OSX__
2518 if ( m_sbHorizontal || m_sbVertical )
2519 {
2520 int w = bounds.right - bounds.left ;
2521 int h = bounds.bottom - bounds.top ;
2522
2523 if ( m_sbHorizontal )
2524 {
2525 Rect sbBounds ;
2526
2527 sbBounds.left = -1 ;
2528 sbBounds.top = h - 14 ;
2529 sbBounds.right = w + 1 ;
2530 sbBounds.bottom = h + 1 ;
2531
2532 SetControlBounds( m_sbHorizontal , &sbBounds ) ;
2533 SetControlViewSize( m_sbHorizontal , w ) ;
2534 }
2535
2536 if ( m_sbVertical )
2537 {
2538 Rect sbBounds ;
2539
2540 sbBounds.left = w - 14 ;
2541 sbBounds.top = -1 ;
2542 sbBounds.right = w + 1 ;
2543 sbBounds.bottom = m_sbHorizontal ? h - 14 : h + 1 ;
2544
2545 SetControlBounds( m_sbVertical , &sbBounds ) ;
2546 SetControlViewSize( m_sbVertical , h ) ;
2547 }
2548 }
2549
2550 Rect oldviewRect ;
2551 TXNLongRect olddestRect ;
2552 TXNGetRectBounds( m_txn , &oldviewRect , &olddestRect , NULL ) ;
2553
2554 Rect viewRect = { m_txnControlBounds.top, m_txnControlBounds.left,
2555 m_txnControlBounds.bottom - ( m_sbHorizontal ? 14 : 0 ) ,
2556 m_txnControlBounds.right - ( m_sbVertical ? 14 : 0 ) } ;
2557 TXNLongRect destRect = { m_txnControlBounds.top, m_txnControlBounds.left,
2558 m_txnControlBounds.bottom - ( m_sbHorizontal ? 14 : 0 ) ,
2559 m_txnControlBounds.right - ( m_sbVertical ? 14 : 0 ) } ;
2560
2561 if ( olddestRect.right >= 10000 )
2562 destRect.right = destRect.left + 32000 ;
2563
2564 if ( olddestRect.bottom >= 0x20000000 )
2565 destRect.bottom = destRect.top + 0x40000000 ;
2566
2567 SectRect( &viewRect , &visBounds , &viewRect ) ;
2568 TXNSetRectBounds( m_txn , &viewRect , &destRect , true ) ;
2569
2570 #if 0
2571 TXNSetFrameBounds(
2572 m_txn,
2573 m_txnControlBounds.top,
2574 m_txnControlBounds.left,
2575 m_txnControlBounds.bottom - (m_sbHorizontal ? 14 : 0),
2576 m_txnControlBounds.right - (m_sbVertical ? 14 : 0),
2577 m_txnFrameID );
2578 #endif
2579 #else
2580
2581 TXNSetFrameBounds(
2582 m_txn, m_txnControlBounds.top, m_txnControlBounds.left,
2583 wxMax( m_txnControlBounds.bottom, m_txnControlBounds.top ),
2584 wxMax( m_txnControlBounds.right, m_txnControlBounds.left ), m_txnFrameID );
2585 #endif
2586
2587 // the SetFrameBounds method under Classic sometimes does not correctly scroll a selection into sight after a
2588 // movement, therefore we have to force it
2589
2590 // this problem has been reported in OSX as well, so we use this here once again
2591
2592 TXNLongRect textRect ;
2593 TXNGetRectBounds( m_txn , NULL , NULL , &textRect ) ;
2594 if ( textRect.left < m_txnControlBounds.left )
2595 TXNShowSelection( m_txn , kTXNShowStart ) ;
2596 }
2597 }
2598
2599 void wxMacMLTEClassicControl::SetRect( Rect *r )
2600 {
2601 wxMacControl::SetRect( r ) ;
2602 MacUpdatePosition() ;
2603 }
2604
2605 void wxMacMLTEClassicControl::MacControlUserPaneDrawProc(wxInt16 WXUNUSED(thePart))
2606 {
2607 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2608 if ( textctrl == NULL )
2609 return ;
2610
2611 if ( textctrl->MacIsReallyShown() )
2612 {
2613 wxMacWindowClipper clipper( textctrl ) ;
2614 TXNDraw( m_txn , NULL ) ;
2615 }
2616 }
2617
2618 wxInt16 wxMacMLTEClassicControl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
2619 {
2620 Point where = { y , x } ;
2621 ControlPartCode result = kControlNoPart;
2622
2623 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference( m_controlRef );
2624 if ( (textctrl != NULL) && textctrl->MacIsReallyShown() )
2625 {
2626 if (PtInRect( where, &m_txnControlBounds ))
2627 {
2628 result = kControlEditTextPart ;
2629 }
2630 else
2631 {
2632 // sometimes we get the coords also in control local coordinates, therefore test again
2633 int x = 0 , y = 0 ;
2634 textctrl->MacClientToRootWindow( &x , &y ) ;
2635 where.h += x ;
2636 where.v += y ;
2637
2638 if (PtInRect( where, &m_txnControlBounds ))
2639 result = kControlEditTextPart ;
2640 }
2641 }
2642
2643 return result;
2644 }
2645
2646 wxInt16 wxMacMLTEClassicControl::MacControlUserPaneTrackingProc( wxInt16 x, wxInt16 y, void* WXUNUSED(actionProc) )
2647 {
2648 ControlPartCode result = kControlNoPart;
2649
2650 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference( m_controlRef );
2651 if ( (textctrl != NULL) && textctrl->MacIsReallyShown() )
2652 {
2653 Point startPt = { y , x } ;
2654
2655 // for compositing, we must convert these into toplevel window coordinates, because hittesting expects them
2656 int x = 0 , y = 0 ;
2657 textctrl->MacClientToRootWindow( &x , &y ) ;
2658 startPt.h += x ;
2659 startPt.v += y ;
2660
2661 switch (MacControlUserPaneHitTestProc( startPt.h , startPt.v ))
2662 {
2663 case kControlEditTextPart :
2664 {
2665 wxMacWindowClipper clipper( textctrl ) ;
2666 EventRecord rec ;
2667
2668 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
2669 TXNClick( m_txn, &rec );
2670 }
2671 break;
2672
2673 default :
2674 break;
2675 }
2676 }
2677
2678 return result;
2679 }
2680
2681 void wxMacMLTEClassicControl::MacControlUserPaneIdleProc()
2682 {
2683 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2684 if ( textctrl == NULL )
2685 return ;
2686
2687 if (textctrl->MacIsReallyShown())
2688 {
2689 if (IsControlActive(m_controlRef))
2690 {
2691 Point mousep;
2692
2693 wxMacWindowClipper clipper( textctrl ) ;
2694 GetMouse(&mousep);
2695
2696 TXNIdle(m_txn);
2697
2698 if (PtInRect(mousep, &m_txnControlBounds))
2699 {
2700 RgnHandle theRgn = NewRgn();
2701 RectRgn(theRgn, &m_txnControlBounds);
2702 TXNAdjustCursor(m_txn, theRgn);
2703 DisposeRgn(theRgn);
2704 }
2705 }
2706 }
2707 }
2708
2709 wxInt16 wxMacMLTEClassicControl::MacControlUserPaneKeyDownProc (wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
2710 {
2711 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2712 if ( textctrl == NULL )
2713 return kControlNoPart;
2714
2715 wxMacWindowClipper clipper( textctrl ) ;
2716
2717 EventRecord ev ;
2718 memset( &ev , 0 , sizeof( ev ) ) ;
2719 ev.what = keyDown ;
2720 ev.modifiers = modifiers ;
2721 ev.message = ((keyCode << 8) & keyCodeMask) | (charCode & charCodeMask);
2722 TXNKeyDown( m_txn , &ev );
2723
2724 return kControlEntireControl;
2725 }
2726
2727 void wxMacMLTEClassicControl::MacControlUserPaneActivateProc(bool activating)
2728 {
2729 MacActivatePaneText( activating );
2730 }
2731
2732 wxInt16 wxMacMLTEClassicControl::MacControlUserPaneFocusProc(wxInt16 action)
2733 {
2734 ControlPartCode focusResult = kControlFocusNoPart;
2735
2736 wxTextCtrl* textctrl = (wxTextCtrl*)GetControlReference( m_controlRef );
2737 if ( textctrl == NULL )
2738 return focusResult;
2739
2740 wxMacWindowClipper clipper( textctrl ) ;
2741
2742 ControlRef controlFocus = NULL ;
2743 GetKeyboardFocus( m_txnWindow , &controlFocus ) ;
2744 bool wasFocused = ( controlFocus == m_controlRef ) ;
2745
2746 switch (action)
2747 {
2748 case kControlFocusPrevPart:
2749 case kControlFocusNextPart:
2750 MacFocusPaneText( !wasFocused );
2751 focusResult = (!wasFocused ? (ControlPartCode) kControlEditTextPart : (ControlPartCode) kControlFocusNoPart);
2752 break;
2753
2754 case kControlFocusNoPart:
2755 default:
2756 MacFocusPaneText( false );
2757 focusResult = kControlFocusNoPart;
2758 break;
2759 }
2760
2761 return focusResult;
2762 }
2763
2764 void wxMacMLTEClassicControl::MacControlUserPaneBackgroundProc( void *WXUNUSED(info) )
2765 {
2766 }
2767
2768 wxMacMLTEClassicControl::wxMacMLTEClassicControl( wxTextCtrl *wxPeer,
2769 const wxString& str,
2770 const wxPoint& pos,
2771 const wxSize& size, long style )
2772 : wxMacMLTEControl( wxPeer )
2773 {
2774 m_font = wxPeer->GetFont() ;
2775 m_windowStyle = style ;
2776 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
2777
2778 short featureSet =
2779 kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
2780 | kControlWantsActivate | kControlHandlesTracking
2781 // | kControlHasSpecialBackground
2782 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
2783
2784 OSStatus err = ::CreateUserPaneControl(
2785 MAC_WXHWND(wxPeer->GetParent()->MacGetTopLevelWindowRef()),
2786 &bounds, featureSet, &m_controlRef );
2787 verify_noerr( err );
2788
2789 DoCreate();
2790
2791 AdjustCreationAttributes( *wxWHITE , true ) ;
2792
2793 MacSetObjectVisibility( wxPeer->MacIsReallyShown() ) ;
2794
2795 {
2796 wxString st = str ;
2797 wxMacConvertNewlines10To13( &st ) ;
2798 wxMacWindowClipper clipper( m_peer ) ;
2799 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
2800 TXNSetSelection( m_txn, 0, 0 ) ;
2801 }
2802 }
2803
2804 wxMacMLTEClassicControl::~wxMacMLTEClassicControl()
2805 {
2806 TXNDeleteObject( m_txn );
2807 m_txn = NULL ;
2808 }
2809
2810 void wxMacMLTEClassicControl::VisibilityChanged(bool shown)
2811 {
2812 MacSetObjectVisibility( shown ) ;
2813 wxMacControl::VisibilityChanged( shown ) ;
2814 }
2815
2816 void wxMacMLTEClassicControl::SuperChangedPosition()
2817 {
2818 MacUpdatePosition() ;
2819 wxMacControl::SuperChangedPosition() ;
2820 }
2821
2822 #ifdef __WXMAC_OSX__
2823
2824 ControlUserPaneDrawUPP gTPDrawProc = NULL;
2825 ControlUserPaneHitTestUPP gTPHitProc = NULL;
2826 ControlUserPaneTrackingUPP gTPTrackProc = NULL;
2827 ControlUserPaneIdleUPP gTPIdleProc = NULL;
2828 ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
2829 ControlUserPaneActivateUPP gTPActivateProc = NULL;
2830 ControlUserPaneFocusUPP gTPFocusProc = NULL;
2831
2832 static pascal void wxMacControlUserPaneDrawProc(ControlRef control, SInt16 part)
2833 {
2834 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2835 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2836 if ( win )
2837 win->MacControlUserPaneDrawProc( part ) ;
2838 }
2839
2840 static pascal ControlPartCode wxMacControlUserPaneHitTestProc(ControlRef control, Point where)
2841 {
2842 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2843 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2844 if ( win )
2845 return win->MacControlUserPaneHitTestProc( where.h , where.v ) ;
2846 else
2847 return kControlNoPart ;
2848 }
2849
2850 static pascal ControlPartCode wxMacControlUserPaneTrackingProc(ControlRef control, Point startPt, ControlActionUPP actionProc)
2851 {
2852 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2853 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2854 if ( win )
2855 return win->MacControlUserPaneTrackingProc( startPt.h , startPt.v , (void*) actionProc ) ;
2856 else
2857 return kControlNoPart ;
2858 }
2859
2860 static pascal void wxMacControlUserPaneIdleProc(ControlRef control)
2861 {
2862 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2863 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2864 if ( win )
2865 win->MacControlUserPaneIdleProc() ;
2866 }
2867
2868 static pascal ControlPartCode wxMacControlUserPaneKeyDownProc(ControlRef control, SInt16 keyCode, SInt16 charCode, SInt16 modifiers)
2869 {
2870 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2871 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2872 if ( win )
2873 return win->MacControlUserPaneKeyDownProc( keyCode, charCode, modifiers ) ;
2874 else
2875 return kControlNoPart ;
2876 }
2877
2878 static pascal void wxMacControlUserPaneActivateProc(ControlRef control, Boolean activating)
2879 {
2880 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2881 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2882 if ( win )
2883 win->MacControlUserPaneActivateProc( activating ) ;
2884 }
2885
2886 static pascal ControlPartCode wxMacControlUserPaneFocusProc(ControlRef control, ControlFocusPart action)
2887 {
2888 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2889 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2890 if ( win )
2891 return win->MacControlUserPaneFocusProc( action ) ;
2892 else
2893 return kControlNoPart ;
2894 }
2895
2896 #if 0
2897 static pascal void wxMacControlUserPaneBackgroundProc(ControlRef control, ControlBackgroundPtr info)
2898 {
2899 wxTextCtrl *textCtrl = wxDynamicCast( wxFindControlFromMacControl(control) , wxTextCtrl ) ;
2900 wxMacMLTEClassicControl * win = textCtrl ? (wxMacMLTEClassicControl*)(textCtrl->GetPeer()) : NULL ;
2901 if ( win )
2902 win->MacControlUserPaneBackgroundProc(info) ;
2903 }
2904 #endif
2905
2906 #endif // __WXMAC_OSX__
2907
2908 // TXNRegisterScrollInfoProc
2909
2910 OSStatus wxMacMLTEClassicControl::DoCreate()
2911 {
2912 Rect bounds;
2913 OSStatus err = noErr ;
2914
2915 // set up our globals
2916 #ifdef __WXMAC_OSX__
2917 if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(wxMacControlUserPaneDrawProc);
2918 if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(wxMacControlUserPaneHitTestProc);
2919 if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(wxMacControlUserPaneTrackingProc);
2920 if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(wxMacControlUserPaneIdleProc);
2921 if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(wxMacControlUserPaneKeyDownProc);
2922 if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(wxMacControlUserPaneActivateProc);
2923 if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(wxMacControlUserPaneFocusProc);
2924
2925 if (gTXNScrollInfoProc == NULL ) gTXNScrollInfoProc = NewTXNScrollInfoUPP(TXNScrollInfoProc) ;
2926 if (gTXNScrollActionProc == NULL ) gTXNScrollActionProc = NewControlActionUPP(TXNScrollActionProc) ;
2927 #endif
2928
2929 // set the initial settings for our private data
2930
2931 m_txnWindow = GetControlOwner(m_controlRef);
2932 m_txnPort = (GrafPtr) GetWindowPort(m_txnWindow);
2933
2934 #ifdef __WXMAC_OSX__
2935 // set up the user pane procedures
2936 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
2937 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
2938 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
2939 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
2940 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
2941 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
2942 SetControlData(m_controlRef, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
2943 #endif
2944
2945 // calculate the rectangles used by the control
2946 UMAGetControlBoundsInWindowCoords( m_controlRef, &bounds );
2947
2948 m_txnControlBounds = bounds ;
2949 m_txnVisBounds = bounds ;
2950
2951 CGrafPtr origPort ;
2952 GDHandle origDev ;
2953
2954 GetGWorld( &origPort, &origDev ) ;
2955 SetPort( m_txnPort );
2956
2957 // create the new edit field
2958 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( m_windowStyle );
2959
2960 #ifdef __WXMAC_OSX__
2961 // the scrollbars are not correctly embedded but are inserted at the root:
2962 // this gives us problems as we have erratic redraws even over the structure area
2963
2964 m_sbHorizontal = 0 ;
2965 m_sbVertical = 0 ;
2966 m_lastHorizontalValue = 0 ;
2967 m_lastVerticalValue = 0 ;
2968
2969 Rect sb = { 0 , 0 , 0 , 0 } ;
2970 if ( frameOptions & kTXNWantVScrollBarMask )
2971 {
2972 CreateScrollBarControl( m_txnWindow, &sb, 0, 0, 100, 1, true, gTXNScrollActionProc, &m_sbVertical );
2973 SetControlReference( m_sbVertical, (SInt32)this );
2974 SetControlAction( m_sbVertical, gTXNScrollActionProc );
2975 ShowControl( m_sbVertical );
2976 EmbedControl( m_sbVertical , m_controlRef );
2977 frameOptions &= ~kTXNWantVScrollBarMask;
2978 }
2979
2980 if ( frameOptions & kTXNWantHScrollBarMask )
2981 {
2982 CreateScrollBarControl( m_txnWindow, &sb, 0, 0, 100, 1, true, gTXNScrollActionProc, &m_sbHorizontal );
2983 SetControlReference( m_sbHorizontal, (SInt32)this );
2984 SetControlAction( m_sbHorizontal, gTXNScrollActionProc );
2985 ShowControl( m_sbHorizontal );
2986 EmbedControl( m_sbHorizontal, m_controlRef );
2987 frameOptions &= ~(kTXNWantHScrollBarMask | kTXNDrawGrowIconMask);
2988 }
2989
2990 #endif
2991
2992 err = TXNNewObject(
2993 NULL, m_txnWindow, &bounds, frameOptions,
2994 kTXNTextEditStyleFrameType, kTXNTextensionFile, kTXNSystemDefaultEncoding,
2995 &m_txn, &m_txnFrameID, NULL );
2996 verify_noerr( err );
2997
2998 #if 0
2999 TXNControlTag iControlTags[] = { kTXNUseCarbonEvents };
3000 TXNControlData iControlData[] = { { (UInt32)&cInfo } };
3001 int toptag = WXSIZEOF( iControlTags ) ;
3002 TXNCarbonEventInfo cInfo ;
3003 cInfo.useCarbonEvents = false ;
3004 cInfo.filler = 0 ;
3005 cInfo.flags = 0 ;
3006 cInfo.fDictionary = NULL ;
3007
3008 verify_noerr( TXNSetTXNObjectControls( m_txn, false, toptag, iControlTags, iControlData ) );
3009 #endif
3010
3011 #ifdef __WXMAC_OSX__
3012 TXNRegisterScrollInfoProc( m_txn, gTXNScrollInfoProc, (SInt32)this );
3013 #endif
3014
3015 SetGWorld( origPort , origDev ) ;
3016
3017 return err;
3018 }
3019 #endif
3020
3021 // ----------------------------------------------------------------------------
3022 // MLTE control implementation (OSX part)
3023 // ----------------------------------------------------------------------------
3024
3025 #if TARGET_API_MAC_OSX
3026
3027 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
3028
3029 // tiger multi-line textcontrols with no CR in the entire content
3030 // don't scroll automatically, so we need a hack.
3031 // This attempt only works 'before' the key (ie before CallNextEventHandler)
3032 // is processed, thus the scrolling always occurs one character too late, but
3033 // better than nothing ...
3034
3035 static const EventTypeSpec eventList[] =
3036 {
3037 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
3038 } ;
3039
3040 static pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
3041 {
3042 OSStatus result = eventNotHandledErr ;
3043 wxMacMLTEHIViewControl* focus = (wxMacMLTEHIViewControl*) data ;
3044
3045 switch ( GetEventKind( event ) )
3046 {
3047 case kEventTextInputUnicodeForKeyEvent :
3048 {
3049 if ( UMAGetSystemVersion() >= 0x1040 )
3050 {
3051 TXNOffset from , to ;
3052 TXNGetSelection( focus->GetTXNObject() , &from , &to ) ;
3053 if ( from == to )
3054 TXNShowSelection( focus->GetTXNObject() , kTXNShowStart );
3055 }
3056 result = CallNextEventHandler(handler,event);
3057 break;
3058 }
3059 default:
3060 break ;
3061 }
3062
3063 return result ;
3064 }
3065
3066 static pascal OSStatus wxMacTextControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
3067 {
3068 OSStatus result = eventNotHandledErr ;
3069
3070 switch ( GetEventClass( event ) )
3071 {
3072 case kEventClassTextInput :
3073 result = wxMacUnicodeTextEventHandler( handler , event , data ) ;
3074 break ;
3075
3076 default :
3077 break ;
3078 }
3079 return result ;
3080 }
3081
3082 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacTextControlEventHandler )
3083
3084 wxMacMLTEHIViewControl::wxMacMLTEHIViewControl( wxTextCtrl *wxPeer,
3085 const wxString& str,
3086 const wxPoint& pos,
3087 const wxSize& size, long style ) : wxMacMLTEControl( wxPeer )
3088 {
3089 m_font = wxPeer->GetFont() ;
3090 m_windowStyle = style ;
3091 Rect bounds = wxMacGetBoundsForControl( wxPeer , pos , size ) ;
3092 wxString st = str ;
3093 wxMacConvertNewlines10To13( &st ) ;
3094
3095 HIRect hr = {
3096 { bounds.left , bounds.top },
3097 { bounds.right - bounds.left, bounds.bottom - bounds.top } } ;
3098
3099 m_scrollView = NULL ;
3100 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( style ) ;
3101 if (( frameOptions & (kTXNWantVScrollBarMask | kTXNWantHScrollBarMask)) || !(frameOptions &kTXNSingleLineOnlyMask))
3102 {
3103 if ( frameOptions & (kTXNWantVScrollBarMask | kTXNWantHScrollBarMask) )
3104 {
3105 HIScrollViewCreate(
3106 (frameOptions & kTXNWantHScrollBarMask ? kHIScrollViewOptionsHorizScroll : 0)
3107 | (frameOptions & kTXNWantVScrollBarMask ? kHIScrollViewOptionsVertScroll : 0) ,
3108 &m_scrollView ) ;
3109 }
3110 else
3111 {
3112 HIScrollViewCreate(kHIScrollViewOptionsVertScroll,&m_scrollView);
3113 HIScrollViewSetScrollBarAutoHide(m_scrollView,true);
3114 }
3115
3116 HIViewSetFrame( m_scrollView, &hr );
3117 HIViewSetVisible( m_scrollView, true );
3118 }
3119
3120 m_textView = NULL ;
3121 HITextViewCreate( NULL , 0, frameOptions , &m_textView ) ;
3122 m_txn = HITextViewGetTXNObject( m_textView ) ;
3123 HIViewSetVisible( m_textView , true ) ;
3124 if ( m_scrollView )
3125 {
3126 HIViewAddSubview( m_scrollView , m_textView ) ;
3127 m_controlRef = m_scrollView ;
3128 wxPeer->MacInstallEventHandler( (WXWidget) m_textView ) ;
3129 }
3130 else
3131 {
3132 HIViewSetFrame( m_textView, &hr );
3133 m_controlRef = m_textView ;
3134 }
3135
3136 AdjustCreationAttributes( *wxWHITE , true ) ;
3137 #ifndef __LP64__
3138 wxMacWindowClipper c( m_peer ) ;
3139 #endif
3140 SetTXNData( st , kTXNStartOffset, kTXNEndOffset ) ;
3141
3142 TXNSetSelection( m_txn, 0, 0 );
3143 TXNShowSelection( m_txn, kTXNShowStart );
3144
3145 InstallControlEventHandler( m_textView , GetwxMacTextControlEventHandlerUPP(),
3146 GetEventTypeCount(eventList), eventList, this,
3147 NULL);
3148 }
3149
3150 wxMacMLTEHIViewControl::~wxMacMLTEHIViewControl()
3151 {
3152 }
3153
3154 OSStatus wxMacMLTEHIViewControl::SetFocus( ControlFocusPart focusPart )
3155 {
3156 return SetKeyboardFocus( GetControlOwner( m_textView ), m_textView, focusPart ) ;
3157 }
3158
3159 bool wxMacMLTEHIViewControl::HasFocus() const
3160 {
3161 ControlRef control ;
3162 if ( GetUserFocusWindow() == NULL )
3163 return false;
3164
3165 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
3166 return control == m_textView ;
3167 }
3168
3169 void wxMacMLTEHIViewControl::SetBackground( const wxBrush &brush )
3170 {
3171 wxMacMLTEControl::SetBackground( brush ) ;
3172
3173 #if 0
3174 CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
3175 RGBColor col = MAC_WXCOLORREF(brush.GetColour().GetPixel()) ;
3176
3177 float component[4] ;
3178 component[0] = col.red / 65536.0 ;
3179 component[1] = col.green / 65536.0 ;
3180 component[2] = col.blue / 65536.0 ;
3181 component[3] = 1.0 ; // alpha
3182
3183 CGColorRef color = CGColorCreate( rgbSpace , component );
3184 HITextViewSetBackgroundColor( m_textView , color );
3185 CGColorSpaceRelease( rgbSpace );
3186 #endif
3187 }
3188
3189 #endif // MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
3190
3191
3192 #endif
3193
3194 #endif // wxUSE_TEXTCTRL