]> git.saurik.com Git - wxWidgets.git/blob - src/mac/textctrl.cpp
Modified CaptureMouse to call DoReleaseMouse if necessary before
[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