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