]> git.saurik.com Git - wxWidgets.git/blob - src/mac/textctrl.cpp
Fixed compilation error.
[wxWidgets.git] / src / mac / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        textctrl.cpp
3 // Purpose:     wxTextCtrl
4 // Author:      AUTHOR
5 // Modified by:
6 // Created:     ??/??/98
7 // RCS-ID:      $Id$
8 // Copyright:   (c) AUTHOR
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 #ifdef __DARWIN__
21   #include <sys/types.h>
22   #include <sys/stat.h>
23 #else
24   #include <stat.h>
25 #endif
26 #include <fstream.h>
27
28 #include "wx/app.h"
29 #include "wx/dc.h"
30 #include "wx/button.h"
31 #include "wx/toplevel.h"
32 #include "wx/textctrl.h"
33 #include "wx/notebook.h"
34 #include "wx/tabctrl.h"
35 #include "wx/settings.h"
36 #include "wx/filefn.h"
37 #include "wx/utils.h"
38
39 #if defined(__BORLANDC__) && !defined(__WIN32__)
40   #include <alloc.h>
41 #elif !defined(__MWERKS__) && !defined(__GNUWIN32) && !defined(__DARWIN__)
42   #include <malloc.h>
43 #endif
44
45 #ifndef __DARWIN__
46 #include <Scrap.h>
47 #include <MacTextEditor.h>
48 #endif
49 #include "wx/mac/uma.h"
50
51 #define wxUSE_MLTE 0
52
53 #if wxUSE_MLTE == 0 // old textctrl implementation
54
55 #if !USE_SHARED_LIBRARY
56 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
57
58 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
59     EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
60     EVT_CHAR(wxTextCtrl::OnChar)
61     EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
62     EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
63     EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
64     EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
65     EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
66
67     EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
68     EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
69     EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
70     EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
71     EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
72 END_EVENT_TABLE()
73 #endif
74
75 // Text item
76 wxTextCtrl::wxTextCtrl()
77 {
78 }
79
80 const short kVerticalMargin = 2 ;
81 const short kHorizontalMargin = 2 ;
82
83 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
84            const wxString& st,
85            const wxPoint& pos,
86            const wxSize& size, long style,
87            const wxValidator& validator,
88            const wxString& name)
89 {
90     // base initialization
91     if ( !CreateBase(parent, id, pos, size, style, validator, name) )
92         return FALSE;
93
94     wxSize mySize = size ;
95     if ( UMAHasAppearance() )
96     {
97         m_macHorizontalBorder = 5 ; // additional pixels around the real control
98         m_macVerticalBorder = 5 ;
99     }
100     else
101     {
102         m_macHorizontalBorder = 0 ; // additional pixels around the real control
103         m_macVerticalBorder = 0 ;
104     }
105
106
107     Rect bounds ;
108     Str255 title ;
109
110     if ( mySize.y == -1 )
111     {
112         if ( UMAHasAppearance() )
113             mySize.y = 13 ;
114         else
115             mySize.y = 24 ;
116         
117         mySize.y += 2 * m_macVerticalBorder ;
118     }
119
120     MacPreControlCreate( parent , id ,  "" , pos , mySize ,style, validator , name , &bounds , title ) ;
121
122     if ( m_windowStyle & wxTE_MULTILINE )
123     {
124         wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
125                       wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
126
127         m_windowStyle |= wxTE_PROCESS_ENTER;
128     }
129
130
131     m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , "\p" , true , 0 , 0 , 1, 
132         ( style & wxTE_PASSWORD ) ? kControlEditTextPasswordProc : kControlEditTextProc , (long) this ) ;
133     MacPostControlCreate() ;
134
135     wxString value ;
136     
137     {
138         TEHandle teH ;
139         long size ;
140    
141         ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
142         (*teH)->lineHeight = -1 ;
143     }
144     
145     if( wxApp::s_macDefaultEncodingIsPC )
146         value = wxMacMakeMacStringFromPC( st ) ;
147     else
148         value = st ;
149     ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , value.Length() , (char*) ((const char*)value) ) ;
150
151   return TRUE;
152 }
153
154 wxString wxTextCtrl::GetValue() const
155 {
156     Size actualsize;
157     ::GetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 32767 , wxBuffer , &actualsize) ;
158     wxBuffer[actualsize] = 0 ;
159     if( wxApp::s_macDefaultEncodingIsPC )
160         return wxMacMakePCStringFromMac( wxBuffer ) ;
161     else
162         return wxString(wxBuffer);
163 }
164
165 void wxTextCtrl::GetSelection(long* from, long* to) const
166 {
167    ControlEditTextSelectionRec selection ;
168    TEHandle teH ;
169    long size ;
170    
171    ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
172
173     *from = (**teH).selStart;
174     *to = (**teH).selEnd;
175 }
176
177 void wxTextCtrl::SetValue(const wxString& st)
178 {
179     wxString value ;
180     
181     if( wxApp::s_macDefaultEncodingIsPC )
182         value = wxMacMakeMacStringFromPC( st ) ;
183     else
184         value = st ;
185     ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , value.Length() , (char*) ((const char*)value) ) ;
186     MacRedrawControl() ;
187 }
188
189 // Clipboard operations
190 void wxTextCtrl::Copy()
191 {
192     if (CanCopy())
193     {
194         TEHandle teH ;
195         long size ;
196    
197                   ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
198                     TECopy( teH ) ;
199         ClearCurrentScrap();
200                     TEToScrap() ;
201     }
202 }
203
204 void wxTextCtrl::Cut()
205 {
206     if (CanCut())
207     {
208         TEHandle teH ;
209         long size ;
210    
211                   ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
212                     TECut( teH ) ;
213         ClearCurrentScrap();
214                     TEToScrap() ;
215                     //  MacInvalidateControl() ;
216           }
217 }
218
219 void wxTextCtrl::Paste()
220 {
221     if (CanPaste())
222     {
223         TEHandle teH ;
224         long size ;
225    
226         ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
227         TEFromScrap() ;
228         TEPaste( teH ) ;
229         MacRedrawControl() ;
230     }
231 }
232
233 bool wxTextCtrl::CanCopy() const
234 {
235     // Can copy if there's a selection
236     long from, to;
237     GetSelection(& from, & to);
238     return (from != to);
239 }
240
241 bool wxTextCtrl::CanCut() const
242 {
243     // Can cut if there's a selection
244     long from, to;
245     GetSelection(& from, & to);
246     return (from != to);
247 }
248
249 bool wxTextCtrl::CanPaste() const
250 {
251     if (!IsEditable())
252         return FALSE;
253
254     long offset ;
255 #if TARGET_CARBON
256     OSStatus err = noErr;
257     ScrapRef scrapRef;
258     
259     err = GetCurrentScrap( &scrapRef );
260     if ( err != noTypeErr && err != memFullErr )    
261     {
262         ScrapFlavorFlags    flavorFlags;
263         Size                byteCount;
264         
265         if (( err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags )) == noErr)
266         {
267             if (( err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount )) == noErr)
268             {
269                 return TRUE ;
270             }
271         }
272     }
273     return FALSE;
274     
275 #else
276     if ( GetScrap( NULL , 'TEXT' , &offset ) > 0 )
277     {
278         return TRUE ;
279     }
280 #endif
281     return FALSE ;
282 }
283
284 void wxTextCtrl::SetEditable(bool editable)
285 {
286     if ( editable )
287         UMAActivateControl( (ControlHandle) m_macControl ) ;
288     else
289         UMADeactivateControl( (ControlHandle) m_macControl ) ;
290 }
291
292 void wxTextCtrl::SetInsertionPoint(long pos)
293 {
294     SetSelection( pos , pos ) ;
295 }
296
297 void wxTextCtrl::SetInsertionPointEnd()
298 {
299     long pos = GetLastPosition();
300     SetInsertionPoint(pos);
301 }
302
303 long wxTextCtrl::GetInsertionPoint() const
304 {
305    ControlEditTextSelectionRec selection ;
306    TEHandle teH ;
307    long size ;
308    
309    ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
310 //   ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection , &size ) ;
311     return (**teH).selStart ;
312 }
313
314 long wxTextCtrl::GetLastPosition() const
315 {
316    ControlEditTextSelectionRec selection ;
317    TEHandle teH ;
318    long size ;
319    
320    ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
321    
322 //   ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection , &size ) ;
323     return (**teH).teLength ;
324 }
325
326 void wxTextCtrl::Replace(long from, long to, const wxString& value)
327 {
328     TEHandle teH ;
329     long size ;
330    
331     ControlEditTextSelectionRec selection ;
332    
333     selection.selStart = from ;
334     selection.selEnd = to ;
335     ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
336         ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
337     TESetSelect( from , to  , teH ) ;
338     TEDelete( teH ) ;
339         TEInsert( value , value.Length() , teH ) ;
340     Refresh() ;
341 }
342
343 void wxTextCtrl::Remove(long from, long to)
344 {
345     TEHandle teH ;
346     long size ;
347    
348     ControlEditTextSelectionRec selection ;
349    
350     selection.selStart = from ;
351     selection.selEnd = to ;
352     ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
353     ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
354     TEDelete( teH ) ;
355     Refresh() ;
356 }
357
358 void wxTextCtrl::SetSelection(long from, long to)
359 {
360    ControlEditTextSelectionRec selection ;
361    TEHandle teH ;
362    long size ;
363    
364    ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
365    
366    selection.selStart = from ;
367    selection.selEnd = to ;
368    
369    ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
370    TESetSelect( selection.selStart , selection.selEnd , teH ) ;
371 }
372
373 bool wxTextCtrl::LoadFile(const wxString& file)
374 {
375     if ( wxTextCtrlBase::LoadFile(file) )
376     {
377         return TRUE;
378     }
379
380     return FALSE;
381 }
382
383 void wxTextCtrl::WriteText(const wxString& text)
384 {
385     TEHandle teH ;
386     long size ;
387    
388     memcpy( wxBuffer, text , text.Length() ) ;
389     wxBuffer[text.Length() ] = 0 ;
390 //    wxMacConvertNewlines( wxBuffer , wxBuffer ) ;
391    
392     ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
393    
394         TEInsert( wxBuffer , strlen( wxBuffer) , teH ) ;
395         Refresh() ;
396 }
397
398 void wxTextCtrl::AppendText(const wxString& text)
399 {
400     SetInsertionPointEnd();
401     WriteText(text);
402 }
403
404 void wxTextCtrl::Clear()
405 {
406     ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 0 , (char*) ((const char*)NULL) ) ;
407     Refresh() ;
408 }
409
410 bool wxTextCtrl::IsModified() const
411 {
412     return TRUE;
413 }
414
415 bool wxTextCtrl::IsEditable() const
416 {
417     return IsEnabled();
418 }
419
420 bool wxTextCtrl::AcceptsFocus() const
421 {
422     // we don't want focus if we can't be edited
423     return IsEditable() && wxControl::AcceptsFocus();
424 }
425
426 wxSize wxTextCtrl::DoGetBestSize() const
427 {
428     int wText = 100 ;
429     
430     int hText ;
431         if ( UMAHasAppearance() )
432             hText = 13 ;
433         else
434             hText = 24 ;
435     hText += 2 * m_macHorizontalBorder ;
436 /*
437     int cx, cy;
438     wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
439
440     int wText = DEFAULT_ITEM_WIDTH;
441
442     int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
443
444     return wxSize(wText, hText);
445 */
446     if ( m_windowStyle & wxTE_MULTILINE )
447     {
448         hText *= wxMin(GetNumberOfLines(), 5);
449     }
450     //else: for single line control everything is ok
451     return wxSize(wText, hText);
452 }
453
454 // ----------------------------------------------------------------------------
455 // Undo/redo
456 // ----------------------------------------------------------------------------
457
458 void wxTextCtrl::Undo()
459 {
460     if (CanUndo())
461     {
462     }
463 }
464
465 void wxTextCtrl::Redo()
466 {
467     if (CanRedo())
468     {
469     }
470 }
471
472 bool wxTextCtrl::CanUndo() const
473 {
474     return FALSE ;
475 }
476
477 bool wxTextCtrl::CanRedo() const
478 {
479     return FALSE ;
480 }
481
482 // Makes 'unmodified'
483 void wxTextCtrl::DiscardEdits()
484 {
485     // TODO
486 }
487
488 int wxTextCtrl::GetNumberOfLines() const
489 {
490     Size actualsize;
491     ::GetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 32767 , wxBuffer , &actualsize) ;
492     
493     int count = 1;
494     for (int i = 0; i < actualsize; i++)
495     {
496         if (wxBuffer[i] == '\r') count++;
497     }
498     
499     return count;
500 }
501
502 long wxTextCtrl::XYToPosition(long x, long y) const
503 {
504     // TODO
505     return 0;
506 }
507
508 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
509 {
510     return FALSE ;
511 }
512
513 void wxTextCtrl::ShowPosition(long pos)
514 {
515     // TODO
516 }
517
518 int wxTextCtrl::GetLineLength(long lineNo) const
519 {
520     Size actualsize;
521     ::GetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 32767 , wxBuffer , &actualsize) ;
522     
523     // Find line first
524     int count = 0;
525     for (int i = 0; i < actualsize; i++)
526     {
527         if (count == lineNo)
528         {
529             // Count chars in line then
530             count = 0;
531             for (int j = i; j < actualsize; j++)
532             {
533                 count++;
534                 if (wxBuffer[j] == '\r') return count;
535             }
536             
537             return count;
538         }
539         if (wxBuffer[i] == '\r') count++;
540     }
541     
542     return 0;
543 }
544
545 wxString wxTextCtrl::GetLineText(long lineNo) const
546 {
547     Size actualsize;
548     ::GetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 32767 , wxBuffer , &actualsize) ;
549     
550     // Find line first
551     int count = 0;
552     for (int i = 0; i < actualsize; i++)
553     {
554         if (count == lineNo)
555         {
556             // Add chars in line then
557             wxString tmp("");
558             
559             for (int j = i; j < actualsize; j++)
560             {
561                 if (wxBuffer[j] == '\r')
562                     return tmp;
563                     
564                 tmp += wxBuffer[j];
565             }
566             
567             return tmp;
568         }
569         if (wxBuffer[i] == '\r') count++;
570     }
571     
572     return wxString("");
573 }
574
575 /*
576  * Text item
577  */
578  
579 void wxTextCtrl::Command(wxCommandEvent & event)
580 {
581     SetValue (event.GetString());
582     ProcessCommand (event);
583 }
584
585 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
586 {
587     // By default, load the first file into the text window.
588     if (event.GetNumberOfFiles() > 0)
589     {
590         LoadFile(event.GetFiles()[0]);
591     }
592 }
593
594 void wxTextCtrl::OnChar(wxKeyEvent& key_event)
595 {
596     bool eat_key = FALSE;
597
598     switch ( key_event.KeyCode() )
599     {
600         case WXK_RETURN:
601             if (m_windowStyle & wxPROCESS_ENTER)
602             {
603                 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
604                 event.SetEventObject( this );
605                 event.SetString( GetValue() );
606                 if ( GetEventHandler()->ProcessEvent(event) )
607                     return;
608             } 
609             if ( !(m_windowStyle & wxTE_MULTILINE) )
610             {
611                 wxWindow *parent = GetParent();
612                 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
613                   parent = parent->GetParent() ;
614                 }
615                 if ( parent && parent->GetDefaultItem() )
616                 {
617                     wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
618                                                           wxButton);
619                     if ( def && def->IsEnabled() )
620                     {
621                         wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
622                         event.SetEventObject(def);
623                         def->Command(event);
624                         return ;
625                    }
626                 }
627                
628                 // this will make wxWindows eat the ENTER key so that
629                 // we actually prevent line wrapping in a single line
630                 // text control
631                 eat_key = TRUE;
632             }
633
634             break;
635
636         case WXK_TAB:
637             // always produce navigation event - even if we process TAB
638             // ourselves the fact that we got here means that the user code
639             // decided to skip processing of this TAB - probably to let it
640             // do its default job.
641             {
642                 wxNavigationKeyEvent eventNav;
643                 eventNav.SetDirection(!key_event.ShiftDown());
644                 eventNav.SetWindowChange(key_event.ControlDown());
645                 eventNav.SetEventObject(this);
646
647                 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
648                     return;
649
650                 key_event.Skip() ;
651                 return;
652             }
653             break;
654     }
655     
656     EventRecord *ev = (EventRecord*) wxTheApp->MacGetCurrentEvent();
657     short keychar = short(ev->message & charCodeMask);
658     if (!eat_key)
659     {
660         short keycode = short(ev->message & keyCodeMask) >> 8 ;
661         ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers );
662     }
663     if ( keychar >= 0x20 ||
664          key_event.KeyCode() == WXK_RETURN ||
665          key_event.KeyCode() == WXK_DELETE || 
666          key_event.KeyCode() == WXK_BACK)
667     {
668         wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
669         event.SetString( GetValue() ) ;
670         event.SetEventObject( this );
671         GetEventHandler()->ProcessEvent(event);
672     }
673 }
674
675 // ----------------------------------------------------------------------------
676 // standard handlers for standard edit menu events
677 // ----------------------------------------------------------------------------
678
679 void wxTextCtrl::OnCut(wxCommandEvent& event)
680 {
681     Cut();
682 }
683
684 void wxTextCtrl::OnCopy(wxCommandEvent& event)
685 {
686     Copy();
687 }
688
689 void wxTextCtrl::OnPaste(wxCommandEvent& event)
690 {
691     Paste();
692 }
693
694 void wxTextCtrl::OnUndo(wxCommandEvent& event)
695 {
696     Undo();
697 }
698
699 void wxTextCtrl::OnRedo(wxCommandEvent& event)
700 {
701     Redo();
702 }
703
704 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
705 {
706     event.Enable( CanCut() );
707 }
708
709 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
710 {
711     event.Enable( CanCopy() );
712 }
713
714 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
715 {
716     event.Enable( CanPaste() );
717 }
718
719 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
720 {
721     event.Enable( CanUndo() );
722 }
723
724 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
725 {
726     event.Enable( CanRedo() );
727 }
728
729 #else
730
731 extern wxApp *wxTheApp ;
732 // CS:We will replace the TextEdit by using the MultiLanguageTextEngine based on the following code written by apple
733
734 /*
735     File: mUPControl.c
736     
737     Description:
738         mUPControl implementation.
739
740     Copyright:
741         Â© Copyright 2000 Apple Computer, Inc. All rights reserved.
742     
743     Disclaimer:
744         IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
745         ("Apple") in consideration of your agreement to the following terms, and your
746         use, installation, modification or redistribution of this Apple software
747         constitutes acceptance of these terms.  If you do not agree with these terms,
748         please do not use, install, modify or redistribute this Apple software.
749
750         In consideration of your agreement to abide by the following terms, and subject
751         to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
752         copyrights in this original Apple software (the "Apple Software"), to use,
753         reproduce, modify and redistribute the Apple Software, with or without
754         modifications, in source and/or binary forms; provided that if you redistribute
755         the Apple Software in its entirety and without modifications, you must retain
756         this notice and the following text and disclaimers in all such redistributions of
757         the Apple Software.  Neither the name, trademarks, service marks or logos of
758         Apple Computer, Inc. may be used to endorse or promote products derived from the
759         Apple Software without specific prior written permission from Apple.  Except as
760         expressly stated in this notice, no other rights or licenses, express or implied,
761         are granted by Apple herein, including but not limited to any patent rights that
762         may be infringed by your derivative works or by other works in which the Apple
763         Software may be incorporated.
764
765         The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
766         WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
767         WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
768         PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
769         COMBINATION WITH YOUR PRODUCTS.
770
771         IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
772         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
773         GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
774         ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
775         OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
776         (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
777         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
778
779     Change History (most recent first):
780         Fri, Jan 28, 2000 -- created
781 */
782
783 #include "MacTextEditor.h"
784
785 /* part codes */
786
787 /* kmUPTextPart is the part code we return to indicate the user has clicked
788     in the text area of our control */
789 #define kmUPTextPart 1
790
791 /* kmUPScrollPart is the part code we return to indicate the user has clicked
792     in the scroll bar part of the control. */
793 #define kmUPScrollPart 2
794
795
796 /* routines for using existing user pane controls.
797     These routines are useful for cases where you would like to use an
798     existing user pane control in, say, a dialog window as a scrolling
799     text edit field.*/
800     
801 /* mUPOpenControl initializes a user pane control so it will be drawn
802     and will behave as a scrolling text edit field inside of a window.
803     This routine performs all of the initialization steps necessary,
804     except it does not create the user pane control itself.  theControl
805     should refer to a user pane control that you have either created
806     yourself or extracted from a dialog's control heirarchy using
807     the GetDialogItemAsControl routine.  */
808 OSStatus mUPOpenControl(ControlHandle theControl);
809
810 /* mUPCloseControl deallocates all of the structures allocated
811     by mUPOpenControl.  */
812 OSStatus mUPCloseControl(ControlHandle theControl);
813
814
815
816 /* routines for creating new scrolling text user pane controls.
817     These routines allow you to create new scrolling text
818     user pane controls. */
819
820 /* mUPCreateControl creates a new user pane control and then it passes it
821     to mUPOpenControl to initialize it as a scrolling text user pane control. */
822 OSStatus mUPCreateControl(WindowPtr theWindow, Rect *bounds, ControlHandle *theControl);
823
824 /* mUPDisposeControl calls mUPCloseControl and then it calls DisposeControl. */
825 OSStatus mUPDisposeControl(ControlHandle theControl);
826
827
828 /* Utility Routines */
829
830     /* mUPSetText replaces the contents of the selection with the unicode
831     text described by the text and count parameters:.
832         text = pointer to unicode text buffer
833         count = number of bytes in the buffer.  */
834 OSStatus mUPSetText(ControlHandle theControl, char* text, long count);
835
836 /* mUPGetText returns the current text data being displayed inside of
837     the mUPControl.  When noErr is returned, *theText contain a new
838     handle containing all of the Unicode text copied from the current
839     selection.  It is the caller's responsibiliby to dispose of this handle. */
840 OSStatus mUPGetText(ControlHandle theControl, Handle *theText);
841
842
843 /* mUPSetSelection sets the text selection and autoscrolls the text view
844     so either the cursor or the selction is in the view. */
845 void mUPSetSelection(ControlHandle theControl, long selStart, long selEnd);
846
847
848
849 /* IsmUPControl returns true if theControl is not NULL
850     and theControl refers to a mUP Control.  */
851 Boolean IsmUPControl(ControlHandle theControl);
852
853
854
855 /* Edit commands for mUP Controls. */
856 enum {
857     kmUPCut = 1,
858     kmUPCopy = 2,
859     kmUPPaste = 3,
860     kmUPClear = 4
861 };
862
863
864 /* mUPDoEditCommand performs the editing command specified
865     in the editCommand parameter.  The mUPControl's text
866     and scroll bar are redrawn and updated as necessary. */
867 void mUPDoEditCommand(ControlHandle theControl, short editCommand);
868
869
870
871
872 /* mUPGetContents returns the entire contents of the control including the text
873     and the formatting information. */
874 OSStatus mUPGetContents(ControlHandle theControl, Handle *theContents);
875 /* mUPSetContents replaces the contents of the selection with the data stored in the handle. */
876 OSStatus mUPSetContents(ControlHandle theControl, Handle theContents);
877
878 enum {
879     kShiftKeyCode = 56
880 };
881
882 /* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus
883     routine.  In our focus switching routine this part code is understood
884     as meaning 'the user has clicked in the control and we need to switch
885     the current focus to ourselves before we can continue'. */
886 #define kUserClickedToFocusPart 100
887
888
889 /* kmUPClickScrollDelayTicks is a time measurement in ticks used to
890     slow the speed of 'auto scrolling' inside of our clickloop routine.
891     This value prevents the text from wizzzzzing by while the mouse
892     is being held down inside of the text area. */
893 #define kmUPClickScrollDelayTicks 3
894
895
896 /* STPTextPaneVars is a structure used for storing the the mUP Control's
897     internal variables and state information.  A handle to this record is
898     stored in the pane control's reference value field using the
899     SetControlReference routine. */
900
901 typedef struct {
902         /* OS records referenced */
903     TXNObject fTXNRec; /* the txn record */
904     TXNFrameID fTXNFrame; /* the txn frame ID */
905     ControlHandle fUserPaneRec;  /* handle to the user pane control */
906     WindowPtr fOwner; /* window containing control */
907     GrafPtr fDrawingEnvironment; /* grafport where control is drawn */
908         /* flags */
909     Boolean fInFocus; /* true while the focus rect is drawn around the control */
910     Boolean fIsActive; /* true while the control is drawn in the active state */
911     Boolean fTEActive; /* reflects the activation state of the text edit record */ 
912     Boolean fInDialogWindow; /* true if displayed in a dialog window */ 
913         /* calculated locations */
914     Rect fRTextArea; /* area where the text is drawn */
915     Rect fRFocusOutline;  /* rectangle used to draw the focus box */
916     Rect fRTextOutline; /* rectangle used to draw the border */
917     RgnHandle fTextBackgroundRgn; /* background region for the text, erased before calling TEUpdate */
918         /* our focus advance override routine */
919     EventHandlerUPP handlerUPP;
920     EventHandlerRef handlerRef;
921 } STPTextPaneVars;
922
923
924
925
926 /* Univerals Procedure Pointer variables used by the
927     mUP Control.  These variables are set up
928     the first time that mUPOpenControl is called. */
929 ControlUserPaneDrawUPP gTPDrawProc = NULL;
930 ControlUserPaneHitTestUPP gTPHitProc = NULL;
931 ControlUserPaneTrackingUPP gTPTrackProc = NULL;
932 ControlUserPaneIdleUPP gTPIdleProc = NULL;
933 ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
934 ControlUserPaneActivateUPP gTPActivateProc = NULL;
935 ControlUserPaneFocusUPP gTPFocusProc = NULL;
936
937     /* events handled by our focus advance override routine */
938 #if TARGET_CARBON
939 static const EventTypeSpec gMLTEEvents[] = { { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } };
940 #define kMLTEEventCount (sizeof( gMLTEEvents ) / sizeof( EventTypeSpec ))
941 #endif
942
943
944 /* TPActivatePaneText activates or deactivates the text edit record
945     according to the value of setActive.  The primary purpose of this
946     routine is to ensure each call is only made once. */
947 static void TPActivatePaneText(STPTextPaneVars **tpvars, Boolean setActive) {
948     STPTextPaneVars *varsp;
949     varsp = *tpvars;
950     if (varsp->fTEActive != setActive) {
951     
952         varsp->fTEActive = setActive;
953         
954         TXNActivate(varsp->fTXNRec, varsp->fTXNFrame, varsp->fTEActive);
955         
956         if (varsp->fInFocus)
957             TXNFocus( varsp->fTXNRec, varsp->fTEActive);
958     }
959 }
960
961
962 /* TPFocusPaneText set the focus state for the text record. */
963 static void TPFocusPaneText(STPTextPaneVars **tpvars, Boolean setFocus) {
964     STPTextPaneVars *varsp;
965     varsp = *tpvars;
966     if (varsp->fInFocus != setFocus) {
967         varsp->fInFocus = setFocus;
968         TXNFocus( varsp->fTXNRec, varsp->fInFocus);
969     }
970 }
971
972
973 /* TPPaneDrawProc is called to redraw the control and for update events
974     referring to the control.  This routine erases the text area's background,
975     and redraws the text.  This routine assumes the scroll bar has been
976     redrawn by a call to DrawControls. */
977 static pascal void TPPaneDrawProc(ControlRef theControl, ControlPartCode thePart) {
978     STPTextPaneVars **tpvars, *varsp;
979     char state;
980     Rect bounds;
981         /* set up our globals */
982     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
983     if (tpvars != NULL) {
984         state = HGetState((Handle) tpvars);
985         HLock((Handle) tpvars);
986         varsp = *tpvars;
987             
988             /* save the drawing state */
989         SetPort((**tpvars).fDrawingEnvironment);
990             /* verify our boundary */
991         GetControlBounds(theControl, &bounds);
992         if ( ! EqualRect(&bounds, &varsp->fRTextArea) ) {
993             SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
994             SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
995             SetRect(&varsp->fRTextArea, bounds.left, bounds.top, bounds.right, bounds.bottom);
996             RectRgn(varsp->fTextBackgroundRgn, &varsp->fRTextOutline);
997             TXNSetFrameBounds(  varsp->fTXNRec, bounds.top, bounds.left, bounds.bottom, bounds.right, varsp->fTXNFrame);
998         }
999
1000             /* update the text region */
1001         EraseRgn(varsp->fTextBackgroundRgn);
1002         TXNDraw(varsp->fTXNRec, NULL);
1003             /* restore the drawing environment */
1004             /* draw the text frame and focus frame (if necessary) */
1005         DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
1006         if ((**tpvars).fIsActive && varsp->fInFocus) DrawThemeFocusRect(&varsp->fRFocusOutline, true);
1007             /* release our globals */
1008         HSetState((Handle) tpvars, state);
1009     }
1010 }
1011
1012
1013 /* TPPaneHitTestProc is called when the control manager would
1014     like to determine what part of the control the mouse resides over.
1015     We also call this routine from our tracking proc to determine how
1016     to handle mouse clicks. */
1017 static pascal ControlPartCode TPPaneHitTestProc(ControlHandle theControl, Point where) {
1018     STPTextPaneVars **tpvars;
1019     ControlPartCode result;
1020     char state;
1021         /* set up our locals and lock down our globals*/
1022     result = 0;
1023     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1024     if (tpvars != NULL) {
1025         state = HGetState((Handle) tpvars);
1026         HLock((Handle) tpvars);
1027             /* find the region where we clicked */
1028         if (PtInRect(where, &(**tpvars).fRTextArea)) {
1029             result = kmUPTextPart;
1030         } else result = 0;
1031             /* release oure globals */
1032         HSetState((Handle) tpvars, state);
1033     }
1034     return result;
1035 }
1036
1037
1038
1039
1040
1041 /* TPPaneTrackingProc is called when the mouse is being held down
1042     over our control.  This routine handles clicks in the text area
1043     and in the scroll bar. */
1044 static pascal ControlPartCode TPPaneTrackingProc(ControlHandle theControl, Point startPt, ControlActionUPP actionProc) {
1045     STPTextPaneVars **tpvars, *varsp;
1046     char state;
1047     ControlPartCode partCodeResult;
1048         /* make sure we have some variables... */
1049     partCodeResult = 0;
1050     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1051     if (tpvars != NULL) {
1052             /* lock 'em down */
1053         state = HGetState((Handle) tpvars);
1054         HLock((Handle) tpvars);
1055         varsp = *tpvars;
1056             /* we don't do any of these functions unless we're in focus */
1057         if ( ! varsp->fInFocus) {
1058             WindowPtr owner;
1059             owner = GetControlOwner(theControl);
1060             ClearKeyboardFocus(owner);
1061             SetKeyboardFocus(owner, theControl, kUserClickedToFocusPart);
1062         }
1063             /* find the location for the click */
1064         switch (TPPaneHitTestProc(theControl, startPt)) {
1065                 
1066                 /* handle clicks in the text part */
1067             case kmUPTextPart:
1068                 {   SetPort((**tpvars).fDrawingEnvironment);
1069                     TXNClick( varsp->fTXNRec, GetCurrentEventRecord());
1070                 }
1071                 break;
1072             
1073         }
1074         
1075         HSetState((Handle) tpvars, state);
1076     }
1077     return partCodeResult;
1078 }
1079
1080
1081 /* TPPaneIdleProc is our user pane idle routine.  When our text field
1082     is active and in focus, we use this routine to set the cursor. */
1083 static pascal void TPPaneIdleProc(ControlHandle theControl) {
1084     STPTextPaneVars **tpvars, *varsp;
1085         /* set up locals */
1086     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1087     if (tpvars != NULL) {
1088             /* if we're not active, then we have nothing to say about the cursor */
1089         if ((**tpvars).fIsActive) {
1090             char state;
1091             Rect bounds;
1092             Point mousep;
1093                 /* lock down the globals */
1094             state = HGetState((Handle) tpvars);
1095             HLock((Handle) tpvars);
1096             varsp = *tpvars;
1097                 /* get the current mouse coordinates (in our window) */
1098 #if TARGET_CARBON
1099             SetPort(GetWindowPort(GetControlOwner(theControl)));
1100 #else
1101             SetPort((GrafPtr) GetWindowPort(GetControlOwner(theControl)));
1102 #endif
1103             GetMouse(&mousep);
1104                 /* there's a 'focus thing' and an 'unfocused thing' */
1105             if (varsp->fInFocus) {
1106                     /* flash the cursor */
1107                 SetPort((**tpvars).fDrawingEnvironment);
1108                 TXNIdle(varsp->fTXNRec);
1109                 /* set the cursor */
1110                 if (PtInRect(mousep, &varsp->fRTextArea)) {
1111                     RgnHandle theRgn;
1112                     RectRgn((theRgn = NewRgn()), &varsp->fRTextArea);
1113                     TXNAdjustCursor(varsp->fTXNRec, theRgn);
1114                     DisposeRgn(theRgn);
1115                  } else SetThemeCursor(kThemeArrowCursor);
1116             } else {
1117                 /* if it's in our bounds, set the cursor */
1118                 GetControlBounds(theControl, &bounds);
1119                 if (PtInRect(mousep, &bounds))
1120                     SetThemeCursor(kThemeArrowCursor);
1121             }
1122             
1123             HSetState((Handle) tpvars, state);
1124         }
1125     }
1126 }
1127
1128
1129 /* TPPaneKeyDownProc is called whenever a keydown event is directed
1130     at our control.  Here, we direct the keydown event to the text
1131     edit record and redraw the scroll bar and text field as appropriate. */
1132 static pascal ControlPartCode TPPaneKeyDownProc(ControlHandle theControl,
1133                             SInt16 keyCode, SInt16 charCode, SInt16 modifiers) {
1134     STPTextPaneVars **tpvars;
1135     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1136     if (tpvars != NULL) {
1137         if ((**tpvars).fInFocus) {
1138                 /* turn autoscrolling on and send the key event to text edit */
1139             SetPort((**tpvars).fDrawingEnvironment);
1140             TXNKeyDown( (**tpvars).fTXNRec, GetCurrentEventRecord());
1141         }
1142     }
1143     return kControlEntireControl;
1144 }
1145
1146
1147 /* TPPaneActivateProc is called when the window containing
1148     the user pane control receives activate events. Here, we redraw
1149     the control and it's text as necessary for the activation state. */
1150 static pascal void TPPaneActivateProc(ControlHandle theControl, Boolean activating) {
1151     Rect bounds;
1152     STPTextPaneVars **tpvars, *varsp;
1153     char state;
1154         /* set up locals */
1155     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1156     if (tpvars != NULL) {
1157         state = HGetState((Handle) tpvars);
1158         HLock((Handle) tpvars);
1159         varsp = *tpvars;
1160             /* de/activate the text edit record */
1161         SetPort((**tpvars).fDrawingEnvironment);
1162             GetControlBounds(theControl, &bounds);
1163             varsp->fIsActive = activating;
1164             TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
1165             /* redraw the frame */
1166         DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
1167         if (varsp->fInFocus) DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fIsActive);
1168         HSetState((Handle) tpvars, state);
1169     }
1170 }
1171
1172
1173 /* TPPaneFocusProc is called when every the focus changes to or
1174     from our control.  Herein, switch the focus appropriately
1175     according to the parameters and redraw the control as
1176     necessary.  */
1177 static pascal ControlPartCode TPPaneFocusProc(ControlHandle theControl, ControlFocusPart action) {
1178     ControlPartCode focusResult;
1179     STPTextPaneVars **tpvars, *varsp;
1180     char state;
1181         /* set up locals */
1182     focusResult = kControlFocusNoPart;
1183     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1184     if (tpvars != NULL) {
1185         state = HGetState((Handle) tpvars);
1186         HLock((Handle) tpvars);
1187         varsp = *tpvars;
1188             /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is
1189             tabbing forwards (or shift tabbing backwards) through the items in the dialog,
1190             and kControlFocusNextPart will be received.  When the user clicks in our field
1191             and it is not the current focus, then the constant kUserClickedToFocusPart will
1192             be received.  The constant kControlFocusNoPart will be received when our control
1193             is the current focus and the user clicks in another control.  In your focus routine,
1194             you should respond to these codes as follows:
1195
1196             kControlFocusNoPart - turn off focus and return kControlFocusNoPart.  redraw
1197                 the control and the focus rectangle as necessary.
1198
1199             kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off
1200                 depending on its current state.  redraw the control and the focus rectangle
1201                 as appropriate for the new focus state.  If the focus state is 'off', return the constant
1202                 kControlFocusNoPart, otherwise return a non-zero part code.
1203             kUserClickedToFocusPart - is a constant defined for this example.  You should
1204                 define your own value for handling click-to-focus type events. */
1205             /* save the drawing state */
1206         SetPort((**tpvars).fDrawingEnvironment);
1207             /* calculate the next highlight state */
1208         switch (action) {
1209             default:
1210             case kControlFocusNoPart:
1211                 TPFocusPaneText(tpvars, false);
1212                 focusResult = kControlFocusNoPart;
1213                 break;
1214             case kUserClickedToFocusPart:
1215                 TPFocusPaneText(tpvars, true);
1216                 focusResult = 1;
1217                 break;
1218             case kControlFocusPrevPart:
1219             case kControlFocusNextPart:
1220                 TPFocusPaneText(tpvars, ( ! varsp->fInFocus));
1221                 focusResult = varsp->fInFocus ? 1 : kControlFocusNoPart;
1222                 break;
1223         }
1224             TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
1225             /* redraw the text fram and focus rectangle to indicate the
1226             new focus state */
1227         DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
1228         DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fIsActive && varsp->fInFocus);
1229             /* done */
1230         HSetState((Handle) tpvars, state);
1231     }
1232     return focusResult;
1233 }
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 //This our carbon event handler for unicode key downs
1246 #if TARGET_CARBON
1247 static pascal OSStatus FocusAdvanceOverride(EventHandlerCallRef myHandler, EventRef event, void* userData) {
1248     WindowRef window;
1249     STPTextPaneVars **tpvars;
1250     OSStatus err;
1251     unsigned short mUnicodeText;
1252     ByteCount charCounts=0;
1253         /* get our window pointer */
1254     tpvars = (STPTextPaneVars **) userData;
1255     window = (**tpvars).fOwner;
1256         //find out how many bytes are needed
1257     err = GetEventParameter(event, kEventParamTextInputSendText,
1258                 typeUnicodeText, NULL, 0, &charCounts, NULL);
1259     if (err != noErr) goto bail;
1260         /* we're only looking at single characters */
1261     if (charCounts != 2) { err = eventNotHandledErr; goto bail; }
1262         /* get the character */
1263     err = GetEventParameter(event, kEventParamTextInputSendText, 
1264                 typeUnicodeText, NULL, sizeof(mUnicodeText),
1265                 &charCounts, (char*) &mUnicodeText);
1266     if (err != noErr) goto bail;
1267         /* if it's not the tab key, forget it... */
1268     if ((mUnicodeText != '\t')) { err = eventNotHandledErr; goto bail; }
1269         /* advance the keyboard focus */
1270     AdvanceKeyboardFocus(window);
1271         /* noErr lets the CEM know we handled the event */
1272     return noErr;
1273 bail:
1274     return eventNotHandledErr;
1275 }
1276 #endif
1277
1278
1279 /* mUPOpenControl initializes a user pane control so it will be drawn
1280         and will behave as a scrolling text edit field inside of a window.
1281         This routine performs all of the initialization steps necessary,
1282         except it does not create the user pane control itself.  theControl
1283         should refer to a user pane control that you have either created
1284         yourself or extracted from a dialog's control heirarchy using
1285         the GetDialogItemAsControl routine.  */
1286 OSStatus mUPOpenControl(ControlHandle theControl, bool multiline) {
1287         Rect bounds;
1288         WindowPtr theWindow;
1289         STPTextPaneVars **tpvars, *varsp;
1290         OSStatus err;
1291         RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF};
1292         TXNBackground tback;
1293         
1294                 /* set up our globals */
1295         if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(TPPaneDrawProc);
1296         if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(TPPaneHitTestProc);
1297         if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(TPPaneTrackingProc);
1298         if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(TPPaneIdleProc);
1299         if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc);
1300         if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(TPPaneActivateProc);
1301         if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(TPPaneFocusProc);
1302                 
1303                 /* allocate our private storage */
1304         tpvars = (STPTextPaneVars **) NewHandleClear(sizeof(STPTextPaneVars));
1305         SetControlReference(theControl, (long) tpvars);
1306         HLock((Handle) tpvars);
1307         varsp = *tpvars;
1308                 /* set the initial settings for our private data */
1309         varsp->fInFocus = false;
1310         varsp->fIsActive = true;
1311         varsp->fTEActive = false;
1312         varsp->fUserPaneRec = theControl;
1313         theWindow = varsp->fOwner = GetControlOwner(theControl);
1314 #if TARGET_CARBON
1315     varsp->fDrawingEnvironment = GetWindowPort(varsp->fOwner);
1316 #else
1317     varsp->fDrawingEnvironment = (GrafPtr) GetWindowPort(varsp->fOwner);
1318 #endif
1319     varsp->fInDialogWindow = ( GetWindowKind(varsp->fOwner) == kDialogWindowKind );
1320         /* set up the user pane procedures */
1321     SetControlData(theControl, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
1322     SetControlData(theControl, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
1323     SetControlData(theControl, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
1324     SetControlData(theControl, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
1325     SetControlData(theControl, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
1326     SetControlData(theControl, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
1327     SetControlData(theControl, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
1328         /* calculate the rectangles used by the control */
1329     GetControlBounds(theControl, &bounds);
1330     SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
1331     SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
1332     SetRect(&varsp->fRTextArea, bounds.left, bounds.top, bounds.right, bounds.bottom);
1333         /* calculate the background region for the text.  In this case, it's kindof
1334         and irregular region because we're setting the scroll bar a little ways inside
1335         of the text area. */
1336     RectRgn((varsp->fTextBackgroundRgn = NewRgn()), &varsp->fRTextOutline);
1337
1338         /* set up the drawing environment */
1339     SetPort(varsp->fDrawingEnvironment);
1340
1341         /* create the new edit field */
1342     TXNNewObject(NULL, varsp->fOwner, &varsp->fRTextArea,
1343         kTXNWantVScrollBarMask | kTXNAlwaysWrapAtViewEdgeMask,
1344         kTXNTextEditStyleFrameType,
1345         kTXNTextensionFile,
1346         kTXNSystemDefaultEncoding, 
1347         &varsp->fTXNRec, &varsp->fTXNFrame, (TXNObjectRefcon) tpvars);
1348         
1349         /* set the field's background */
1350     tback.bgType = kTXNBackgroundTypeRGB;
1351     tback.bg.color = rgbWhite;
1352     TXNSetBackground( varsp->fTXNRec, &tback);
1353     
1354         /* install our focus advance override routine */
1355 #if TARGET_CARBON
1356     varsp->handlerUPP = NewEventHandlerUPP(FocusAdvanceOverride);
1357     err = InstallWindowEventHandler( varsp->fOwner, varsp->handlerUPP,
1358         kMLTEEventCount, gMLTEEvents, tpvars, &varsp->handlerRef );
1359 #endif
1360         /* unlock our storage */
1361     HUnlock((Handle) tpvars);
1362         /* perform final activations and setup for our text field.  Here,
1363         we assume that the window is going to be the 'active' window. */
1364     TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
1365         /* all done */
1366     return noErr;
1367 }
1368
1369
1370
1371 /* mUPCloseControl deallocates all of the structures allocated
1372     by mUPOpenControl.  */
1373 OSStatus mUPCloseControl(ControlHandle theControl) {
1374     STPTextPaneVars **tpvars;
1375         /* set up locals */
1376     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1377         /* release our sub records */
1378     TXNDeleteObject((**tpvars).fTXNRec);
1379         /* remove our focus advance override */
1380     RemoveEventHandler((**tpvars).handlerRef);
1381     DisposeEventHandlerUPP((**tpvars).handlerUPP);
1382         /* delete our private storage */
1383     DisposeHandle((Handle) tpvars);
1384         /* zero the control reference */
1385     SetControlReference(theControl, 0);
1386     return noErr;
1387 }
1388
1389
1390
1391
1392     /* mUPSetText replaces the contents of the selection with the unicode
1393     text described by the text and count parameters:.
1394         text = pointer to unicode text buffer
1395         count = number of bytes in the buffer.  */
1396 OSStatus mUPSetText(ControlHandle theControl, char* text, long count) {
1397     STPTextPaneVars **tpvars;
1398         /* set up locals */
1399     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1400         /* set the text in the record */
1401     return TXNSetData( (**tpvars).fTXNRec, kTXNUnicodeTextData, text, count,
1402         kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1403
1404     return noErr;
1405 }
1406
1407
1408 /* mUPSetSelection sets the text selection and autoscrolls the text view
1409     so either the cursor or the selction is in the view. */
1410 void mUPSetSelection(ControlHandle theControl, long selStart, long selEnd) {
1411     STPTextPaneVars **tpvars;
1412         /* set up our locals */
1413     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1414         /* and our drawing environment as the operation
1415         may force a redraw in the text area. */
1416     SetPort((**tpvars).fDrawingEnvironment);
1417         /* change the selection */
1418     TXNSetSelection( (**tpvars).fTXNRec, selStart, selEnd);
1419 }
1420
1421
1422
1423
1424
1425 /* mUPGetText returns the current text data being displayed inside of
1426     the mUPControl.  When noErr is returned, *theText contain a new
1427     handle containing all of the Unicode text copied from the current
1428     selection.  It is the caller's responsibiliby to dispose of this handle. */
1429 OSStatus mUPGetText(ControlHandle theControl, Handle *theText) {
1430     STPTextPaneVars **tpvars;
1431     OSStatus err;
1432         /* set up locals */
1433     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1434         /* extract the text from the record */
1435     err = TXNGetData( (**tpvars).fTXNRec, kTXNUseCurrentSelection, kTXNUseCurrentSelection, theText);
1436         /* all done */
1437     return err;
1438 }
1439
1440
1441
1442 /* mUPCreateControl creates a new user pane control and then it passes it
1443     to mUPOpenControl to initialize it as a scrolling text user pane control. */
1444 OSStatus mUPCreateControl(WindowPtr theWindow, Rect *bounds, ControlHandle *theControl) {
1445     short featurSet;
1446         /* the following feature set can be specified in CNTL resources by using
1447         the value 1214.  When creating a user pane control, we pass this value
1448         in the 'value' parameter. */
1449     featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
1450             | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground
1451             | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
1452         /* create the control */
1453     *theControl = NewControl(theWindow, bounds, "\p", true, featurSet, 0, featurSet, kControlUserPaneProc, 0);
1454         /* set up the mUP specific features and data */
1455     mUPOpenControl(*theControl);
1456         /* all done.... */
1457     return noErr;
1458 }
1459
1460
1461 /* mUPDisposeControl calls mUPCloseControl and then it calls DisposeControl. */
1462 OSStatus mUPDisposeControl(ControlHandle theControl) {
1463         /* deallocate the mUP specific data */
1464     mUPCloseControl(theControl);
1465         /* deallocate the user pane control itself */
1466     DisposeControl(theControl);
1467     return noErr;
1468 }
1469
1470
1471
1472
1473 /* IsmUPControl returns true if theControl is not NULL
1474     and theControl refers to a mUP Control.  */
1475 Boolean IsmUPControl(ControlHandle theControl) {
1476     Size theSize;
1477     ControlUserPaneFocusUPP localFocusProc;
1478         /* a NULL control is not a mUP control */
1479     if (theControl == NULL) return false;
1480         /* check if the control is using our focus procedure */
1481     theSize = sizeof(localFocusProc);
1482     if (GetControlData(theControl, kControlEntireControl, kControlUserPaneFocusProcTag,
1483         sizeof(localFocusProc), &localFocusProc, &theSize) != noErr) return false;
1484     if (localFocusProc != gTPFocusProc) return false;
1485         /* all tests passed, it's a mUP control */
1486     return true;
1487 }
1488
1489
1490 /* mUPDoEditCommand performs the editing command specified
1491     in the editCommand parameter.  The mUPControl's text
1492     and scroll bar are redrawn and updated as necessary. */
1493 void mUPDoEditCommand(ControlHandle theControl, short editCommand) {
1494     STPTextPaneVars **tpvars;
1495         /* set up our locals */
1496     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1497         /* and our drawing environment as the operation
1498         may force a redraw in the text area. */
1499     SetPort((**tpvars).fDrawingEnvironment);
1500         /* perform the editing command */
1501     switch (editCommand) {
1502         case kmUPCut:
1503             ClearCurrentScrap();
1504             TXNCut((**tpvars).fTXNRec); 
1505             TXNConvertToPublicScrap();
1506             break;
1507         case kmUPCopy:
1508             ClearCurrentScrap();
1509             TXNCopy((**tpvars).fTXNRec);
1510             TXNConvertToPublicScrap();
1511             break;
1512         case kmUPPaste:
1513             TXNConvertFromPublicScrap();
1514             TXNPaste((**tpvars).fTXNRec);
1515             break;
1516         case kmUPClear:
1517             TXNClear((**tpvars).fTXNRec);
1518             break;
1519     }
1520 }
1521
1522
1523
1524
1525 /* mUPGetContents returns the entire contents of the control including the text
1526     and the formatting information. */
1527 OSStatus mUPGetContents(ControlHandle theControl, Handle *theContents) {
1528     STPTextPaneVars **tpvars;
1529     OSStatus err;
1530     short vRefNum;
1531     long dirID;
1532     FSSpec tspec;
1533     short trefnum;
1534     Boolean texists;
1535     long bytecount;
1536     Handle localdata;
1537         /* set up locals */
1538     trefnum = 0;
1539     texists = false;
1540     localdata = NULL;
1541     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1542     if (theContents == NULL) return paramErr;
1543         /* create a temporary file */
1544     err = FindFolder(kOnSystemDisk, kTemporaryFolderType, true, &vRefNum, &dirID);
1545     if (err != noErr) goto bail;
1546     FSMakeFSSpec(vRefNum, dirID, "\pmUPGetContents", &tspec);
1547     err = FSpCreate(&tspec, 'trsh', 'trsh', smSystemScript);
1548     if (err != noErr) goto bail;
1549     texists = true;
1550         /* open the file */
1551     err = FSpOpenDF(&tspec, fsRdWrPerm, &trefnum);
1552     if (err != noErr) goto bail;
1553         /* save the data */
1554     err = TXNSave( (**tpvars).fTXNRec, kTXNTextensionFile, 0, kTXNSystemDefaultEncoding, &tspec, trefnum, 0);
1555     if (err != noErr) goto bail;
1556         /* get the file length and set the position */
1557     err = GetEOF(trefnum, &bytecount);
1558     if (err != noErr) goto bail;
1559     err = SetFPos(trefnum, fsFromStart, 0);
1560     if (err != noErr) goto bail;
1561         /* copy the data fork to a handle */
1562     localdata = NewHandle(bytecount);
1563     if (localdata == NULL) { err = memFullErr; goto bail; }
1564     HLock(localdata);
1565     err = FSRead(trefnum, &bytecount, *localdata);
1566     HUnlock(localdata);
1567     if (err != noErr) goto bail;
1568         /* store result */
1569     *theContents = localdata;
1570         /* clean up */
1571     FSClose(trefnum);
1572     FSpDelete(&tspec);
1573         /* all done */
1574     return noErr;
1575 bail:
1576     if (trefnum != 0) FSClose(trefnum);
1577     if (texists) FSpDelete(&tspec);
1578     if (localdata != NULL) DisposeHandle(localdata);
1579     return err;
1580 }
1581
1582
1583
1584
1585 /* mUPSetContents replaces the contents of the selection with the data stored in the handle. */
1586 OSStatus mUPSetContents(ControlHandle theControl, Handle theContents) {
1587     STPTextPaneVars **tpvars;
1588     OSStatus err;
1589     short vRefNum;
1590     long dirID;
1591     FSSpec tspec;
1592     short trefnum;
1593     Boolean texists;
1594     long bytecount;
1595     char state;
1596         /* set up locals */
1597     trefnum = 0;
1598     texists = false;
1599     tpvars = (STPTextPaneVars **) GetControlReference(theControl);
1600     if (theContents == NULL) return paramErr;
1601         /* create a temporary file */
1602     err = FindFolder(kOnSystemDisk,  kTemporaryFolderType, true, &vRefNum, &dirID);
1603     if (err != noErr) goto bail;
1604     FSMakeFSSpec(vRefNum, dirID, "\pmUPSetContents", &tspec);
1605     err = FSpCreate(&tspec, 'trsh', 'trsh', smSystemScript);
1606     if (err != noErr) goto bail;
1607     texists = true;
1608         /* open the file */
1609     err = FSpOpenDF(&tspec, fsRdWrPerm, &trefnum);
1610     if (err != noErr) goto bail;
1611         /* save the data to the temporary file */
1612     state = HGetState(theContents);
1613     HLock(theContents);
1614     bytecount = GetHandleSize(theContents);
1615     err = FSWrite(trefnum, &bytecount, *theContents);
1616     HSetState(theContents, state);
1617     if (err != noErr) goto bail;
1618         /* reset the file position */
1619     err = SetFPos(trefnum, fsFromStart, 0);
1620     if (err != noErr) goto bail;
1621         /* load the data */
1622     err = TXNSetDataFromFile((**tpvars).fTXNRec, trefnum, kTXNTextensionFile, bytecount, kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1623     if (err != noErr) goto bail;
1624         /* clean up */
1625     FSClose(trefnum);
1626     FSpDelete(&tspec);
1627         /* all done */
1628     return noErr;
1629 bail:
1630     if (trefnum != 0) FSClose(trefnum);
1631     if (texists) FSpDelete(&tspec);
1632     return err;
1633 }
1634
1635 #if !USE_SHARED_LIBRARY
1636 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
1637
1638 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
1639     EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
1640     EVT_CHAR(wxTextCtrl::OnChar)
1641     EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
1642     EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
1643     EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
1644     EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
1645     EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
1646
1647     EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
1648     EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
1649     EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
1650     EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
1651     EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
1652 END_EVENT_TABLE()
1653 #endif
1654
1655 // Text item
1656 wxTextCtrl::wxTextCtrl()
1657 {
1658 }
1659
1660 const short kVerticalMargin = 2 ;
1661 const short kHorizontalMargin = 2 ;
1662
1663 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
1664            const wxString& st,
1665            const wxPoint& pos,
1666            const wxSize& size, long style,
1667            const wxValidator& validator,
1668            const wxString& name)
1669 {
1670     // base initialization
1671     if ( !CreateBase(parent, id, pos, size, style, validator, name) )
1672         return FALSE;
1673
1674     wxSize mySize = size ;
1675     if ( UMAHasAppearance() )
1676     {
1677         m_macHorizontalBorder = 5 ; // additional pixels around the real control
1678         m_macVerticalBorder = 5 ;
1679     }
1680     else
1681     {
1682         m_macHorizontalBorder = 0 ; // additional pixels around the real control
1683         m_macVerticalBorder = 0 ;
1684     }
1685
1686
1687     Rect bounds ;
1688     Str255 title ;
1689
1690     if ( mySize.y == -1 )
1691     {
1692         if ( UMAHasAppearance() )
1693             mySize.y = 13 ;
1694         else
1695             mySize.y = 24 ;
1696         
1697         mySize.y += 2 * m_macVerticalBorder ;
1698     }
1699
1700     MacPreControlCreate( parent , id ,  "" , pos , mySize ,style, validator , name , &bounds , title ) ;
1701
1702     if ( m_windowStyle & wxTE_MULTILINE )
1703     {
1704         wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
1705                       wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
1706
1707         m_windowStyle |= wxTE_PROCESS_ENTER;
1708     }
1709
1710
1711     if ( style & wxTE_PASSWORD )
1712     {
1713       m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , "\p" , true , 0 , 0 , 1, 
1714         kControlEditTextPasswordProc , (long) this ) ;
1715     }
1716     else
1717     {
1718     if ( mUPCreateControl(parent->MacGetRootWindow(), &bounds, &m_macControl) != noErr ) 
1719       return FALSE ;
1720     }
1721     MacPostControlCreate() ;
1722
1723     wxString value ;
1724         
1725     if( wxApp::s_macDefaultEncodingIsPC )
1726         value = wxMacMakeMacStringFromPC( st ) ;
1727     else
1728         value = st ;
1729         
1730     if ( style & wxTE_PASSWORD )
1731     {
1732       ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , value.Length() , (char*) ((const char*)value) ) ;
1733   }
1734   else
1735   {
1736     STPTextPaneVars **tpvars;
1737         /* set up locals */
1738     tpvars = (STPTextPaneVars **) GetControlReference( (ControlHandle) m_macControl);
1739         /* set the text in the record */
1740     TXNSetData( (**tpvars).fTXNRec, kTXNTextData,  (const char*)value, value.Length(),
1741       kTXNStartOffset, kTXNEndOffset);
1742   }
1743   
1744   return TRUE;
1745 }
1746
1747 wxString wxTextCtrl::GetValue() const
1748 {
1749     Size actualsize;
1750   if ( m_windowStyle & wxTE_PASSWORD )
1751   {
1752       ::GetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 32767 , wxBuffer , &actualsize) ;
1753   }
1754   else
1755   {
1756     STPTextPaneVars **tpvars;
1757     OSStatus err;
1758         /* set up locals */
1759     tpvars = (STPTextPaneVars **) GetControlReference( (ControlHandle) m_macControl);
1760         /* extract the text from the record */
1761     Handle theText ;
1762     err = TXNGetDataEncoded( (**tpvars).fTXNRec, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1763         /* all done */
1764     if ( err )
1765     {
1766       actualsize = 0 ;
1767     }
1768     else
1769     {
1770       actualsize = GetHandleSize( theText ) ;
1771       strncpy( wxBuffer , *theText , actualsize ) ;
1772       DisposeHandle( theText ) ;
1773     }
1774   }
1775     wxBuffer[actualsize] = 0 ;
1776     if( wxApp::s_macDefaultEncodingIsPC )
1777         return wxMacMakePCStringFromMac( wxBuffer ) ;
1778     else
1779         return wxString(wxBuffer);
1780 }
1781
1782 void wxTextCtrl::GetSelection(long* from, long* to) const
1783 {
1784   if ( m_windowStyle & wxTE_PASSWORD )
1785   {
1786    ControlEditTextSelectionRec selection ;
1787    TEHandle teH ;
1788    long size ;
1789    
1790    ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
1791
1792     *from = (**teH).selStart;
1793     *to = (**teH).selEnd;
1794    }
1795    else
1796    {
1797         STPTextPaneVars **tpvars;
1798
1799             /* set up locals */
1800         tpvars = (STPTextPaneVars **) GetControlReference( (ControlHandle) m_macControl);
1801
1802         TXNGetSelection(  (**tpvars).fTXNRec , (TXNOffset*) from , (TXNOffset*) to ) ;
1803
1804    }
1805 }
1806
1807 void wxTextCtrl::SetValue(const wxString& st)
1808 {
1809     wxString value ;
1810     
1811     if( wxApp::s_macDefaultEncodingIsPC )
1812         value = wxMacMakeMacStringFromPC( st ) ;
1813     else
1814         value = st ;
1815   if ( m_windowStyle & wxTE_PASSWORD )
1816   {
1817       ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , value.Length() , (char*) ((const char*)value) ) ;
1818   }
1819   else
1820   {
1821     STPTextPaneVars **tpvars;
1822         /* set up locals */
1823     tpvars = (STPTextPaneVars **) GetControlReference( (ControlHandle) m_macControl);
1824         /* set the text in the record */
1825     TXNSetData( (**tpvars).fTXNRec, kTXNTextData,  (const char*)value, value.Length(),
1826       kTXNStartOffset, kTXNEndOffset);
1827   }
1828   MacRedrawControl() ;
1829 }
1830
1831 // Clipboard operations
1832 void wxTextCtrl::Copy()
1833 {
1834     if (CanCopy())
1835     {
1836       if ( m_windowStyle & wxTE_PASSWORD )
1837       {
1838             TEHandle teH ;
1839             long size ;
1840        
1841                  ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
1842                 TECopy( teH ) ;
1843                 ClearCurrentScrap();
1844                 TEToScrap() ;
1845         }
1846         else
1847         {
1848           mUPDoEditCommand( (ControlHandle) m_macControl , kmUPCopy ) ;
1849         }
1850         }
1851 }
1852
1853 void wxTextCtrl::Cut()
1854 {
1855     if (CanCut())
1856     {
1857       if ( m_windowStyle & wxTE_PASSWORD )
1858       {
1859             TEHandle teH ;
1860             long size ;
1861        
1862                 ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
1863                 TECut( teH ) ;
1864                 ClearCurrentScrap();
1865                 TEToScrap() ;
1866                 //      MacInvalidateControl() ;
1867     }
1868         else
1869         {
1870           mUPDoEditCommand( (ControlHandle) m_macControl , kmUPCut ) ;
1871         }
1872         }
1873 }
1874
1875 void wxTextCtrl::Paste()
1876 {
1877     if (CanPaste())
1878     {
1879     if ( m_windowStyle & wxTE_PASSWORD )
1880     {
1881             TEHandle teH ;
1882             long size ;
1883      
1884                 ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
1885                 TEFromScrap() ;
1886                 TEPaste( teH ) ;
1887       MacRedrawControl() ;
1888         }
1889         else
1890         {
1891           mUPDoEditCommand( (ControlHandle) m_macControl , kmUPPaste ) ;
1892         }
1893         }
1894 }
1895
1896 bool wxTextCtrl::CanCopy() const
1897 {
1898     // Can copy if there's a selection
1899     long from, to;
1900     GetSelection(& from, & to);
1901     return (from != to);
1902 }
1903
1904 bool wxTextCtrl::CanCut() const
1905 {
1906     // Can cut if there's a selection
1907     long from, to;
1908     GetSelection(& from, & to);
1909     return (from != to);
1910 }
1911
1912 bool wxTextCtrl::CanPaste() const
1913 {
1914     if (!IsEditable())
1915         return FALSE;
1916
1917     long offset ;
1918 #if TARGET_CARBON
1919     OSStatus err = noErr;
1920     ScrapRef scrapRef;
1921     
1922     err = GetCurrentScrap( &scrapRef );
1923     if ( err != noTypeErr && err != memFullErr )    
1924     {
1925         ScrapFlavorFlags    flavorFlags;
1926         Size                byteCount;
1927         
1928         if (( err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags )) == noErr)
1929         {
1930             if (( err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount )) == noErr)
1931             {
1932                 return TRUE ;
1933             }
1934         }
1935     }
1936     return FALSE;
1937     
1938 #else
1939     if ( GetScrap( NULL , 'TEXT' , &offset ) > 0 )
1940     {
1941         return TRUE ;
1942     }
1943 #endif
1944     return FALSE ;
1945 }
1946
1947 void wxTextCtrl::SetEditable(bool editable)
1948 {
1949     if ( editable )
1950         UMAActivateControl( (ControlHandle) m_macControl ) ;
1951     else
1952         UMADeactivateControl( (ControlHandle) m_macControl ) ;
1953 }
1954
1955 void wxTextCtrl::SetInsertionPoint(long pos)
1956 {
1957     SetSelection( pos , pos ) ;
1958 }
1959
1960 void wxTextCtrl::SetInsertionPointEnd()
1961 {
1962     long pos = GetLastPosition();
1963     SetInsertionPoint(pos);
1964 }
1965
1966 long wxTextCtrl::GetInsertionPoint() const
1967 {
1968   long begin,end ;
1969   GetSelection( &begin , &end ) ;
1970   return begin ;
1971 }
1972
1973 long wxTextCtrl::GetLastPosition() const
1974 {
1975     if ( m_windowStyle & wxTE_PASSWORD )
1976   {
1977
1978    ControlEditTextSelectionRec selection ;
1979    TEHandle teH ;
1980    long size ;
1981    
1982    ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
1983    
1984 //   ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection , &size ) ;
1985     return (**teH).teLength ;
1986   }
1987   else
1988   {
1989      STPTextPaneVars**  tpvars = (STPTextPaneVars **) GetControlReference( (ControlHandle) m_macControl);
1990
1991     int actualsize = 0 ;
1992         Handle theText ;
1993         OSErr err = TXNGetDataEncoded( (**tpvars).fTXNRec, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1994                 /* all done */
1995         if ( err )
1996         {
1997           actualsize = 0 ;
1998         }
1999         else
2000         {
2001           actualsize = GetHandleSize( theText ) ;
2002           DisposeHandle( theText ) ;
2003         }
2004         return actualsize ;
2005   }
2006 }
2007
2008 void wxTextCtrl::Replace(long from, long to, const wxString& value)
2009 {
2010   if ( m_windowStyle & wxTE_PASSWORD )
2011   {
2012     TEHandle teH ;
2013     long size ;
2014    
2015     ControlEditTextSelectionRec selection ;
2016    
2017         selection.selStart = from ;
2018         selection.selEnd = to ;
2019         ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
2020                 ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
2021         TESetSelect( from , to  , teH ) ;
2022         TEDelete( teH ) ;
2023                 TEInsert( value , value.Length() , teH ) ;
2024         }
2025         else
2026         {
2027           // TODO
2028         }
2029         Refresh() ;
2030 }
2031
2032 void wxTextCtrl::Remove(long from, long to)
2033 {
2034   if ( m_windowStyle & wxTE_PASSWORD )
2035   {
2036     TEHandle teH ;
2037     long size ;
2038    
2039     ControlEditTextSelectionRec selection ;
2040    
2041         selection.selStart = from ;
2042         selection.selEnd = to ;
2043         ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
2044         ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
2045         TEDelete( teH ) ;
2046   }
2047   else
2048   {
2049     //TODO
2050   }
2051     Refresh() ;
2052 }
2053
2054 void wxTextCtrl::SetSelection(long from, long to)
2055 {
2056   if ( m_windowStyle & wxTE_PASSWORD )
2057   {
2058    ControlEditTextSelectionRec selection ;
2059    TEHandle teH ;
2060    long size ;
2061    
2062    ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
2063    
2064    selection.selStart = from ;
2065    selection.selEnd = to ;
2066    
2067    ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
2068    TESetSelect( selection.selStart , selection.selEnd , teH ) ;
2069   }
2070   else
2071   {
2072     STPTextPaneVars **tpvars;
2073         /* set up our locals */
2074     tpvars = (STPTextPaneVars **) GetControlReference( (ControlHandle) m_macControl);
2075         /* and our drawing environment as the operation
2076         may force a redraw in the text area. */
2077     SetPort((**tpvars).fDrawingEnvironment);
2078         /* change the selection */
2079     TXNSetSelection( (**tpvars).fTXNRec, from, to);
2080   }
2081 }
2082
2083 bool wxTextCtrl::LoadFile(const wxString& file)
2084 {
2085     if ( wxTextCtrlBase::LoadFile(file) )
2086     {
2087         return TRUE;
2088     }
2089
2090     return FALSE;
2091 }
2092
2093 void wxTextCtrl::WriteText(const wxString& text)
2094 {
2095     wxString value ;
2096     if( wxApp::s_macDefaultEncodingIsPC )
2097         value = wxMacMakeMacStringFromPC( text ) ;
2098     else
2099         value = text ;
2100     if ( m_windowStyle & wxTE_PASSWORD )
2101     {
2102       TEHandle teH ;
2103       long size ;
2104           
2105       ::GetControlData( (ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*) &teH , &size ) ;
2106         TEInsert( value , value.Length() , teH ) ;
2107         }
2108         else
2109         {
2110         STPTextPaneVars **tpvars;
2111             /* set up locals */
2112         tpvars = (STPTextPaneVars **) GetControlReference( (ControlHandle) m_macControl);
2113             /* set the text in the record */
2114         TXNSetData( (**tpvars).fTXNRec, kTXNTextData,  (const char*)value, value.Length(),
2115           kTXNUseCurrentSelection, kTXNUseCurrentSelection);
2116         }
2117         Refresh() ;
2118 }
2119
2120 void wxTextCtrl::AppendText(const wxString& text)
2121 {
2122     SetInsertionPointEnd();
2123     WriteText(text);
2124 }
2125
2126 void wxTextCtrl::Clear()
2127 {
2128   if ( m_windowStyle & wxTE_PASSWORD )
2129   {
2130
2131     ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 0 , (char*) ((const char*)NULL) ) ;
2132   }
2133   else
2134   {
2135     mUPDoEditCommand( (ControlHandle) m_macControl , kmUPClear) ;
2136   }
2137         Refresh() ;
2138 }
2139
2140 bool wxTextCtrl::IsModified() const
2141 {
2142     return TRUE;
2143 }
2144
2145 bool wxTextCtrl::IsEditable() const
2146 {
2147     return IsEnabled();
2148 }
2149
2150 bool wxTextCtrl::AcceptsFocus() const
2151 {
2152     // we don't want focus if we can't be edited
2153     return IsEditable() && wxControl::AcceptsFocus();
2154 }
2155
2156 wxSize wxTextCtrl::DoGetBestSize() const
2157 {
2158     int wText = 100 ;
2159     
2160     int hText ;
2161         if ( UMAHasAppearance() )
2162             hText = 13 ;
2163         else
2164             hText = 24 ;
2165     hText += 2 * m_macHorizontalBorder ;
2166 /*
2167     int cx, cy;
2168     wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
2169
2170     int wText = DEFAULT_ITEM_WIDTH;
2171
2172     int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
2173
2174     return wxSize(wText, hText);
2175 */
2176     if ( m_windowStyle & wxTE_MULTILINE )
2177     {
2178         hText *= wxMin(GetNumberOfLines(), 5);
2179     }
2180     //else: for single line control everything is ok
2181     return wxSize(wText, hText);
2182 }
2183
2184 // ----------------------------------------------------------------------------
2185 // Undo/redo
2186 // ----------------------------------------------------------------------------
2187
2188 void wxTextCtrl::Undo()
2189 {
2190     if (CanUndo())
2191     {
2192     }
2193 }
2194
2195 void wxTextCtrl::Redo()
2196 {
2197     if (CanRedo())
2198     {
2199     }
2200 }
2201
2202 bool wxTextCtrl::CanUndo() const
2203 {
2204     return FALSE ;
2205 }
2206
2207 bool wxTextCtrl::CanRedo() const
2208 {
2209     return FALSE ;
2210 }
2211
2212 // Makes 'unmodified'
2213 void wxTextCtrl::DiscardEdits()
2214 {
2215     // TODO
2216 }
2217
2218 int wxTextCtrl::GetNumberOfLines() const
2219 {
2220   // TODO change this if possible to reflect real lines
2221   wxString content = GetValue() ;
2222         
2223         int count = 1;
2224         for (int i = 0; i < content.Length() ; i++)
2225         {
2226             if (content[i] == '\r') count++;
2227         }
2228         
2229   return count;
2230 }
2231
2232 long wxTextCtrl::XYToPosition(long x, long y) const
2233 {
2234     // TODO
2235     return 0;
2236 }
2237
2238 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
2239 {
2240     return FALSE ;
2241 }
2242
2243 void wxTextCtrl::ShowPosition(long pos)
2244 {
2245     // TODO
2246 }
2247
2248 int wxTextCtrl::GetLineLength(long lineNo) const
2249 {
2250   // TODO change this if possible to reflect real lines
2251   wxString content = GetValue() ;
2252         
2253         // Find line first
2254         int count = 0;
2255         for (int i = 0; i < content.Length() ; i++)
2256         {
2257             if (count == lineNo)
2258             {
2259                 // Count chars in line then
2260                 count = 0;
2261                 for (int j = i; j < content.Length(); j++)
2262                 {
2263                     count++;
2264                     if (content[j] == '\r') return count;
2265                 }
2266                 
2267                 return count;
2268             }
2269             if (content[i] == '\r') count++;
2270         }
2271     return 0;
2272 }
2273
2274 wxString wxTextCtrl::GetLineText(long lineNo) const
2275 {
2276   // TODO change this if possible to reflect real lines
2277   wxString content = GetValue() ;
2278
2279         // Find line first
2280         int count = 0;
2281         for (int i = 0; i < content.Length() ; i++)
2282         {
2283             if (count == lineNo)
2284             {
2285                 // Add chars in line then
2286                 wxString tmp("");
2287                 
2288                 for (int j = i; j < content.Length(); j++)
2289                 {
2290                     if (content[j] == '\r')
2291                         return tmp;
2292                         
2293                     tmp += content[j];
2294                 }
2295                 
2296                 return tmp;
2297             }
2298             if (content[i] == '\r') count++;
2299         }
2300     return wxString("");
2301 }
2302
2303 /*
2304  * Text item
2305  */
2306  
2307 void wxTextCtrl::Command(wxCommandEvent & event)
2308 {
2309     SetValue (event.GetString());
2310     ProcessCommand (event);
2311 }
2312
2313 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
2314 {
2315     // By default, load the first file into the text window.
2316     if (event.GetNumberOfFiles() > 0)
2317     {
2318         LoadFile(event.GetFiles()[0]);
2319     }
2320 }
2321
2322 void wxTextCtrl::OnChar(wxKeyEvent& event)
2323 {
2324     switch ( event.KeyCode() )
2325     {
2326         case WXK_RETURN:
2327             if (m_windowStyle & wxPROCESS_ENTER)
2328             {
2329                 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
2330                 event.SetEventObject( this );
2331                 if ( GetEventHandler()->ProcessEvent(event) )
2332                     return;
2333             } 
2334             if ( !(m_windowStyle & wxTE_MULTILINE) )
2335             {
2336                 wxWindow *parent = GetParent();
2337                 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
2338                   parent = parent->GetParent() ;
2339                 }
2340                 if ( parent && parent->GetDefaultItem() )
2341                 {
2342                     wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
2343                                                           wxButton);
2344                     if ( def && def->IsEnabled() )
2345                     {
2346                         wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
2347                         event.SetEventObject(def);
2348                         def->Command(event);
2349                         return ;
2350                    }
2351                 }
2352             }
2353             //else: multiline controls need Enter for themselves
2354
2355             break;
2356
2357         case WXK_TAB:
2358             // always produce navigation event - even if we process TAB
2359             // ourselves the fact that we got here means that the user code
2360             // decided to skip processing of this TAB - probably to let it
2361             // do its default job.
2362             {
2363                 wxNavigationKeyEvent eventNav;
2364                 eventNav.SetDirection(!event.ShiftDown());
2365                 eventNav.SetWindowChange(event.ControlDown());
2366                 eventNav.SetEventObject(this);
2367
2368                 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
2369                     return;
2370                 event.Skip() ;
2371                 return ;
2372             }
2373             break;
2374     }
2375
2376     EventRecord *ev = wxTheApp->MacGetCurrentEvent() ;
2377     short keycode ;
2378     short keychar ;
2379     keychar = short(ev->message & charCodeMask);
2380     keycode = short(ev->message & keyCodeMask) >> 8 ;
2381     UMAHandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ;
2382     if ( keychar >= 0x20 || event.KeyCode() == WXK_RETURN || event.KeyCode() == WXK_DELETE || event.KeyCode() == WXK_BACK)
2383     {
2384         wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
2385         event.SetString( GetValue() ) ;
2386         event.SetEventObject( this );
2387         GetEventHandler()->ProcessEvent(event);
2388     }
2389
2390 }
2391
2392 // ----------------------------------------------------------------------------
2393 // standard handlers for standard edit menu events
2394 // ----------------------------------------------------------------------------
2395
2396 void wxTextCtrl::OnCut(wxCommandEvent& event)
2397 {
2398     Cut();
2399 }
2400
2401 void wxTextCtrl::OnCopy(wxCommandEvent& event)
2402 {
2403     Copy();
2404 }
2405
2406 void wxTextCtrl::OnPaste(wxCommandEvent& event)
2407 {
2408     Paste();
2409 }
2410
2411 void wxTextCtrl::OnUndo(wxCommandEvent& event)
2412 {
2413     Undo();
2414 }
2415
2416 void wxTextCtrl::OnRedo(wxCommandEvent& event)
2417 {
2418     Redo();
2419 }
2420
2421 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
2422 {
2423     event.Enable( CanCut() );
2424 }
2425
2426 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
2427 {
2428     event.Enable( CanCopy() );
2429 }
2430
2431 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
2432 {
2433     event.Enable( CanPaste() );
2434 }
2435
2436 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
2437 {
2438     event.Enable( CanUndo() );
2439 }
2440
2441 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
2442 {
2443     event.Enable( CanRedo() );
2444 }
2445
2446 #endif
2447
2448 #endif
2449     // wxUSE_TEXTCTRL