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