]> git.saurik.com Git - wxWidgets.git/blob - src/mac/textctrl.cpp
implemented IsModified() and DiscardEdits()
[wxWidgets.git] / src / mac / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
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
27 #if wxUSE_STD_IOSTREAM
28 #if wxUSE_IOSTREAMH
29 #include <fstream.h>
30 #else
31 #include <fstream>
32 #endif
33 #endif
34
35 #include "wx/app.h"
36 #include "wx/dc.h"
37 #include "wx/button.h"
38 #include "wx/toplevel.h"
39 #include "wx/textctrl.h"
40 #include "wx/notebook.h"
41 #include "wx/tabctrl.h"
42 #include "wx/settings.h"
43 #include "wx/filefn.h"
44 #include "wx/utils.h"
45
46 #if defined(__BORLANDC__) && !defined(__WIN32__)
47 #include <alloc.h>
48 #elif !defined(__MWERKS__) && !defined(__GNUWIN32) && !defined(__DARWIN__)
49 #include <malloc.h>
50 #endif
51
52 #ifndef __DARWIN__
53 #include <Scrap.h>
54 #endif
55 #include <MacTextEditor.h>
56 #include "ATSUnicode.h"
57 #include "TextCommon.h"
58 #include "TextEncodingConverter.h"
59 #include "wx/mac/uma.h"
60
61 #define TE_UNLIMITED_LENGTH 0xFFFFFFFFUL
62
63 extern wxControl *wxFindControlFromMacControl(ControlHandle inControl ) ;
64
65 // CS:TODO we still have a problem getting properly at the text events of a control because under Carbon
66 // the MLTE engine registers itself for the key events thus the normal flow never occurs, the only measure for the
67 // moment is to avoid setting the true focus on the control, the proper solution at the end would be to have
68 // an alternate path for carbon key events that routes automatically into the same wx flow of events
69
70 #include "MacTextEditor.h"
71
72 /* part codes */
73
74 /* kmUPTextPart is the part code we return to indicate the user has clicked
75 in the text area of our control */
76 #define kmUPTextPart 1
77
78 /* kmUPScrollPart is the part code we return to indicate the user has clicked
79 in the scroll bar part of the control. */
80 #define kmUPScrollPart 2
81
82
83 /* routines for using existing user pane controls.
84 These routines are useful for cases where you would like to use an
85 existing user pane control in, say, a dialog window as a scrolling
86 text edit field.*/
87
88 /* mUPOpenControl initializes a user pane control so it will be drawn
89 and will behave as a scrolling text edit field inside of a window.
90 This routine performs all of the initialization steps necessary,
91 except it does not create the user pane control itself. theControl
92 should refer to a user pane control that you have either created
93 yourself or extracted from a dialog's control heirarchy using
94 the GetDialogItemAsControl routine. */
95 OSStatus mUPOpenControl(ControlHandle theControl, long wxStyle);
96
97 /* Utility Routines */
98
99 enum {
100 kShiftKeyCode = 56
101 };
102
103 /* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus
104 routine. In our focus switching routine this part code is understood
105 as meaning 'the user has clicked in the control and we need to switch
106 the current focus to ourselves before we can continue'. */
107 #define kUserClickedToFocusPart 100
108
109
110 /* kmUPClickScrollDelayTicks is a time measurement in ticks used to
111 slow the speed of 'auto scrolling' inside of our clickloop routine.
112 This value prevents the text from wizzzzzing by while the mouse
113 is being held down inside of the text area. */
114 #define kmUPClickScrollDelayTicks 3
115
116
117 /* STPTextPaneVars is a structure used for storing the the mUP Control's
118 internal variables and state information. A handle to this record is
119 stored in the pane control's reference value field using the
120 SetControlReference routine. */
121
122 typedef struct {
123 /* OS records referenced */
124 TXNObject fTXNRec; /* the txn record */
125 TXNFrameID fTXNFrame; /* the txn frame ID */
126 ControlHandle fUserPaneRec; /* handle to the user pane control */
127 WindowPtr fOwner; /* window containing control */
128 GrafPtr fDrawingEnvironment; /* grafport where control is drawn */
129 /* flags */
130 Boolean fInFocus; /* true while the focus rect is drawn around the control */
131 Boolean fIsActive; /* true while the control is drawn in the active state */
132 Boolean fTEActive; /* reflects the activation state of the text edit record */
133 Boolean fInDialogWindow; /* true if displayed in a dialog window */
134 /* calculated locations */
135 Rect fRTextArea; /* area where the text is drawn */
136 Rect fRFocusOutline; /* rectangle used to draw the focus box */
137 Rect fRTextOutline; /* rectangle used to draw the border */
138 RgnHandle fTextBackgroundRgn; /* background region for the text, erased before calling TEUpdate */
139 /* our focus advance override routine */
140 EventHandlerUPP handlerUPP;
141 EventHandlerRef handlerRef;
142 bool fMultiline ;
143 } STPTextPaneVars;
144
145
146
147
148 /* Univerals Procedure Pointer variables used by the
149 mUP Control. These variables are set up
150 the first time that mUPOpenControl is called. */
151 ControlUserPaneDrawUPP gTPDrawProc = NULL;
152 ControlUserPaneHitTestUPP gTPHitProc = NULL;
153 ControlUserPaneTrackingUPP gTPTrackProc = NULL;
154 ControlUserPaneIdleUPP gTPIdleProc = NULL;
155 ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
156 ControlUserPaneActivateUPP gTPActivateProc = NULL;
157 ControlUserPaneFocusUPP gTPFocusProc = NULL;
158
159 /* TPActivatePaneText activates or deactivates the text edit record
160 according to the value of setActive. The primary purpose of this
161 routine is to ensure each call is only made once. */
162 static void TPActivatePaneText(STPTextPaneVars **tpvars, Boolean setActive) {
163 STPTextPaneVars *varsp;
164 varsp = *tpvars;
165 if (varsp->fTEActive != setActive) {
166
167 varsp->fTEActive = setActive;
168
169 TXNActivate(varsp->fTXNRec, varsp->fTXNFrame, varsp->fTEActive);
170
171 if (varsp->fInFocus)
172 TXNFocus( varsp->fTXNRec, varsp->fTEActive);
173 }
174 }
175
176
177 /* TPFocusPaneText set the focus state for the text record. */
178 static void TPFocusPaneText(STPTextPaneVars **tpvars, Boolean setFocus) {
179 STPTextPaneVars *varsp;
180 varsp = *tpvars;
181 if (varsp->fInFocus != setFocus) {
182 varsp->fInFocus = setFocus;
183 TXNFocus( varsp->fTXNRec, varsp->fInFocus);
184 }
185 }
186
187
188 /* TPPaneDrawProc is called to redraw the control and for update events
189 referring to the control. This routine erases the text area's background,
190 and redraws the text. This routine assumes the scroll bar has been
191 redrawn by a call to DrawControls. */
192 static pascal void TPPaneDrawProc(ControlRef theControl, ControlPartCode thePart) {
193 STPTextPaneVars **tpvars, *varsp;
194 char state;
195 Rect bounds;
196 /* set up our globals */
197
198 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
199 if (tpvars != NULL) {
200 state = HGetState((Handle) tpvars);
201 HLock((Handle) tpvars);
202 varsp = *tpvars;
203
204 /* save the drawing state */
205 SetPort((**tpvars).fDrawingEnvironment);
206 /* verify our boundary */
207 GetControlBounds(theControl, &bounds);
208
209 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
210 if ( ! EqualRect(&bounds, &varsp->fRFocusOutline) ) {
211 // scrollbar is on the border, we add one
212 Rect oldbounds = varsp->fRFocusOutline ;
213 InsetRect( &oldbounds , -1 , -1 ) ;
214
215 InvalWindowRect( GetControlOwner( theControl ) , &oldbounds ) ;
216 SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
217 SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
218 SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) ,
219 bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2));
220 RectRgn(varsp->fTextBackgroundRgn, &varsp->fRTextOutline);
221 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left,
222 varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame);
223 }
224
225 /* update the text region */
226 RGBColor white = { 65535 , 65535 , 65535 } ;
227 RGBBackColor( &white ) ;
228 EraseRgn(varsp->fTextBackgroundRgn);
229 TXNDraw(varsp->fTXNRec, NULL);
230 /* restore the drawing environment */
231 /* draw the text frame and focus frame (if necessary) */
232 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
233 if ((**tpvars).fIsActive && varsp->fInFocus) DrawThemeFocusRect(&varsp->fRFocusOutline, true);
234 /* release our globals */
235 HSetState((Handle) tpvars, state);
236
237 }
238 }
239
240
241 /* TPPaneHitTestProc is called when the control manager would
242 like to determine what part of the control the mouse resides over.
243 We also call this routine from our tracking proc to determine how
244 to handle mouse clicks. */
245 static pascal ControlPartCode TPPaneHitTestProc(ControlHandle theControl, Point where) {
246 STPTextPaneVars **tpvars;
247 ControlPartCode result;
248 char state;
249 /* set up our locals and lock down our globals*/
250 result = 0;
251 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
252 if (tpvars != NULL) {
253 state = HGetState((Handle) tpvars);
254 HLock((Handle) tpvars);
255 /* find the region where we clicked */
256 if (PtInRect(where, &(**tpvars).fRTextArea)) {
257 result = kmUPTextPart;
258 } else result = 0;
259 /* release oure globals */
260 HSetState((Handle) tpvars, state);
261 }
262 return result;
263 }
264
265
266
267
268
269 /* TPPaneTrackingProc is called when the mouse is being held down
270 over our control. This routine handles clicks in the text area
271 and in the scroll bar. */
272 static pascal ControlPartCode TPPaneTrackingProc(ControlHandle theControl, Point startPt, ControlActionUPP actionProc) {
273 STPTextPaneVars **tpvars, *varsp;
274 char state;
275 ControlPartCode partCodeResult;
276 /* make sure we have some variables... */
277 partCodeResult = 0;
278 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
279 if (tpvars != NULL) {
280 /* lock 'em down */
281 state = HGetState((Handle) tpvars);
282 HLock((Handle) tpvars);
283 varsp = *tpvars;
284 /* we don't do any of these functions unless we're in focus */
285 if ( ! varsp->fInFocus) {
286 WindowPtr owner;
287 owner = GetControlOwner(theControl);
288 ClearKeyboardFocus(owner);
289 SetKeyboardFocus(owner, theControl, kUserClickedToFocusPart);
290 }
291 /* find the location for the click */
292 switch (TPPaneHitTestProc(theControl, startPt)) {
293
294 /* handle clicks in the text part */
295 case kmUPTextPart:
296 { SetPort((**tpvars).fDrawingEnvironment);
297 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
298 #if !TARGET_CARBON
299 TXNClick( varsp->fTXNRec, (const EventRecord*) wxTheApp->MacGetCurrentEvent());
300 #else
301 EventRecord rec ;
302 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
303 TXNClick( varsp->fTXNRec, &rec );
304 #endif
305 }
306 break;
307
308 }
309
310 HSetState((Handle) tpvars, state);
311 }
312 return partCodeResult;
313 }
314
315
316 /* TPPaneIdleProc is our user pane idle routine. When our text field
317 is active and in focus, we use this routine to set the cursor. */
318 static pascal void TPPaneIdleProc(ControlHandle theControl) {
319 STPTextPaneVars **tpvars, *varsp;
320 /* set up locals */
321 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
322 if (tpvars != NULL) {
323 /* if we're not active, then we have nothing to say about the cursor */
324 if ((**tpvars).fIsActive) {
325 char state;
326 Rect bounds;
327 Point mousep;
328 /* lock down the globals */
329 state = HGetState((Handle) tpvars);
330 HLock((Handle) tpvars);
331 varsp = *tpvars;
332 /* get the current mouse coordinates (in our window) */
333 SetPortWindowPort(GetControlOwner(theControl));
334 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
335 GetMouse(&mousep);
336 /* there's a 'focus thing' and an 'unfocused thing' */
337 if (varsp->fInFocus) {
338 /* flash the cursor */
339 SetPort((**tpvars).fDrawingEnvironment);
340 TXNIdle(varsp->fTXNRec);
341 /* set the cursor */
342 if (PtInRect(mousep, &varsp->fRTextArea)) {
343 RgnHandle theRgn;
344 RectRgn((theRgn = NewRgn()), &varsp->fRTextArea);
345 TXNAdjustCursor(varsp->fTXNRec, theRgn);
346 DisposeRgn(theRgn);
347 }
348 else
349 {
350 // SetThemeCursor(kThemeArrowCursor);
351 }
352 } else {
353 /* if it's in our bounds, set the cursor */
354 GetControlBounds(theControl, &bounds);
355 if (PtInRect(mousep, &bounds))
356 {
357 // SetThemeCursor(kThemeArrowCursor);
358 }
359 }
360
361 HSetState((Handle) tpvars, state);
362 }
363 }
364 }
365
366
367 /* TPPaneKeyDownProc is called whenever a keydown event is directed
368 at our control. Here, we direct the keydown event to the text
369 edit record and redraw the scroll bar and text field as appropriate. */
370 static pascal ControlPartCode TPPaneKeyDownProc(ControlHandle theControl,
371 SInt16 keyCode, SInt16 charCode, SInt16 modifiers) {
372 STPTextPaneVars **tpvars;
373 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
374 if (tpvars != NULL) {
375 if ((**tpvars).fInFocus) {
376 /* turn autoscrolling on and send the key event to text edit */
377 SetPort((**tpvars).fDrawingEnvironment);
378 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
379 EventRecord ev ;
380 memset( &ev , 0 , sizeof( ev ) ) ;
381 ev.what = keyDown ;
382 ev.modifiers = modifiers ;
383 ev.message = (( keyCode << 8 ) & keyCodeMask ) + ( charCode & charCodeMask ) ;
384 TXNKeyDown( (**tpvars).fTXNRec, &ev);
385 }
386 }
387 return kControlEntireControl;
388 }
389
390
391 /* TPPaneActivateProc is called when the window containing
392 the user pane control receives activate events. Here, we redraw
393 the control and it's text as necessary for the activation state. */
394 static pascal void TPPaneActivateProc(ControlHandle theControl, Boolean activating) {
395 Rect bounds;
396 STPTextPaneVars **tpvars, *varsp;
397 char state;
398 /* set up locals */
399 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
400 if (tpvars != NULL) {
401 state = HGetState((Handle) tpvars);
402 HLock((Handle) tpvars);
403 varsp = *tpvars;
404 /* de/activate the text edit record */
405 SetPort((**tpvars).fDrawingEnvironment);
406 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
407 GetControlBounds(theControl, &bounds);
408 varsp->fIsActive = activating;
409 TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
410 /* redraw the frame */
411 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
412 if (varsp->fInFocus) DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fIsActive);
413 HSetState((Handle) tpvars, state);
414 }
415 }
416
417
418 /* TPPaneFocusProc is called when every the focus changes to or
419 from our control. Herein, switch the focus appropriately
420 according to the parameters and redraw the control as
421 necessary. */
422 static pascal ControlPartCode TPPaneFocusProc(ControlHandle theControl, ControlFocusPart action) {
423 ControlPartCode focusResult;
424 STPTextPaneVars **tpvars, *varsp;
425 char state;
426 /* set up locals */
427 focusResult = kControlFocusNoPart;
428 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
429 if (tpvars != NULL) {
430 state = HGetState((Handle) tpvars);
431 HLock((Handle) tpvars);
432 varsp = *tpvars;
433 /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is
434 tabbing forwards (or shift tabbing backwards) through the items in the dialog,
435 and kControlFocusNextPart will be received. When the user clicks in our field
436 and it is not the current focus, then the constant kUserClickedToFocusPart will
437 be received. The constant kControlFocusNoPart will be received when our control
438 is the current focus and the user clicks in another control. In your focus routine,
439 you should respond to these codes as follows:
440
441 kControlFocusNoPart - turn off focus and return kControlFocusNoPart. redraw
442 the control and the focus rectangle as necessary.
443
444 kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off
445 depending on its current state. redraw the control and the focus rectangle
446 as appropriate for the new focus state. If the focus state is 'off', return the constant
447 kControlFocusNoPart, otherwise return a non-zero part code.
448 kUserClickedToFocusPart - is a constant defined for this example. You should
449 define your own value for handling click-to-focus type events. */
450 /* save the drawing state */
451 SetPort((**tpvars).fDrawingEnvironment);
452 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
453 /* calculate the next highlight state */
454 switch (action) {
455 default:
456 case kControlFocusNoPart:
457 TPFocusPaneText(tpvars, false);
458 focusResult = kControlFocusNoPart;
459 break;
460 case kUserClickedToFocusPart:
461 TPFocusPaneText(tpvars, true);
462 focusResult = 1;
463 break;
464 case kControlFocusPrevPart:
465 case kControlFocusNextPart:
466 TPFocusPaneText(tpvars, ( ! varsp->fInFocus));
467 focusResult = varsp->fInFocus ? 1 : kControlFocusNoPart;
468 break;
469 }
470 TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
471 /* redraw the text fram and focus rectangle to indicate the
472 new focus state */
473 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
474 DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fIsActive && varsp->fInFocus);
475 /* done */
476 HSetState((Handle) tpvars, state);
477 }
478 return focusResult;
479 }
480
481
482 /* mUPOpenControl initializes a user pane control so it will be drawn
483 and will behave as a scrolling text edit field inside of a window.
484 This routine performs all of the initialization steps necessary,
485 except it does not create the user pane control itself. theControl
486 should refer to a user pane control that you have either created
487 yourself or extracted from a dialog's control heirarchy using
488 the GetDialogItemAsControl routine. */
489 OSStatus mUPOpenControl(ControlHandle theControl, long wxStyle )
490 {
491 Rect bounds;
492 WindowRef theWindow;
493 STPTextPaneVars **tpvars, *varsp;
494 OSStatus err = noErr ;
495 RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF};
496 TXNBackground tback;
497
498 /* set up our globals */
499 if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(TPPaneDrawProc);
500 if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(TPPaneHitTestProc);
501 if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(TPPaneTrackingProc);
502 if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(TPPaneIdleProc);
503 if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc);
504 if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(TPPaneActivateProc);
505 if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(TPPaneFocusProc);
506
507 /* allocate our private storage */
508 tpvars = (STPTextPaneVars **) NewHandleClear(sizeof(STPTextPaneVars));
509 SetControlReference(theControl, (long) tpvars);
510 HLock((Handle) tpvars);
511 varsp = *tpvars;
512 /* set the initial settings for our private data */
513 varsp->fMultiline = wxStyle & wxTE_MULTILINE ;
514 varsp->fInFocus = false;
515 varsp->fIsActive = true;
516 varsp->fTEActive = true; // in order to get a deactivate
517 varsp->fUserPaneRec = theControl;
518 theWindow = varsp->fOwner = GetControlOwner(theControl);
519
520 varsp->fDrawingEnvironment = (GrafPtr) GetWindowPort(theWindow);
521
522 varsp->fInDialogWindow = ( GetWindowKind(varsp->fOwner) == kDialogWindowKind );
523 /* set up the user pane procedures */
524 SetControlData(theControl, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
525 SetControlData(theControl, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
526 SetControlData(theControl, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
527 SetControlData(theControl, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
528 SetControlData(theControl, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
529 SetControlData(theControl, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
530 SetControlData(theControl, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
531 /* calculate the rectangles used by the control */
532 GetControlBounds(theControl, &bounds);
533 SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
534 SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
535 SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) ,
536 bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2));
537 /* calculate the background region for the text. In this case, it's kindof
538 and irregular region because we're setting the scroll bar a little ways inside
539 of the text area. */
540 RectRgn((varsp->fTextBackgroundRgn = NewRgn()), &varsp->fRTextOutline);
541
542 /* set up the drawing environment */
543 SetPort(varsp->fDrawingEnvironment);
544
545 /* create the new edit field */
546
547 TXNFrameOptions frameOptions =
548 kTXNDontDrawCaretWhenInactiveMask ;
549 if ( ! ( wxStyle & wxTE_NOHIDESEL ) )
550 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
551
552 if ( wxStyle & wxTE_MULTILINE )
553 {
554 if ( ! ( wxStyle & wxTE_DONTWRAP ) )
555 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
556 else
557 {
558 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
559 frameOptions |= kTXNWantHScrollBarMask ;
560 }
561
562 if ( !(wxStyle & wxTE_NO_VSCROLL ) )
563 frameOptions |= kTXNWantVScrollBarMask ;
564 }
565 else
566 frameOptions |= kTXNSingleLineOnlyMask ;
567
568 if ( wxStyle & wxTE_READONLY )
569 frameOptions |= kTXNReadOnlyMask ;
570
571 TXNNewObject(NULL, varsp->fOwner, &varsp->fRTextArea,
572 frameOptions ,
573 kTXNTextEditStyleFrameType,
574 kTXNTextensionFile,
575 kTXNSystemDefaultEncoding,
576 &varsp->fTXNRec, &varsp->fTXNFrame, (TXNObjectRefcon) tpvars);
577
578 if ( (wxStyle & wxTE_MULTILINE) && (wxStyle & wxTE_DONTWRAP) )
579 {
580 TXNControlTag tag = kTXNWordWrapStateTag ;
581 TXNControlData dat ;
582 dat.uValue = kTXNNoAutoWrap ;
583 TXNSetTXNObjectControls( varsp->fTXNRec , false , 1 , &tag , &dat ) ;
584 }
585 Str255 fontName ;
586 SInt16 fontSize ;
587 Style fontStyle ;
588
589 GetThemeFont(kThemeSmallSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
590
591 TXNTypeAttributes typeAttr[] =
592 {
593 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
594 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
595 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
596 } ;
597
598 err = TXNSetTypeAttributes (varsp->fTXNRec, sizeof( typeAttr ) / sizeof(TXNTypeAttributes) , typeAttr,
599 kTXNStartOffset,
600 kTXNEndOffset);
601 /* set the field's background */
602
603 tback.bgType = kTXNBackgroundTypeRGB;
604 tback.bg.color = rgbWhite;
605 TXNSetBackground( varsp->fTXNRec, &tback);
606
607 /* unlock our storage */
608 HUnlock((Handle) tpvars);
609 /* perform final activations and setup for our text field. Here,
610 we assume that the window is going to be the 'active' window. */
611 TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
612 /* all done */
613 return err;
614 }
615
616
617
618
619 #if !USE_SHARED_LIBRARY
620 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
621
622 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
623 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
624 EVT_CHAR(wxTextCtrl::OnChar)
625 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
626 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
627 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
628 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
629 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
630
631 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
632 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
633 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
634 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
635 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
636 END_EVENT_TABLE()
637 #endif
638
639 // Text item
640 void wxTextCtrl::Init()
641 {
642 m_macTE = NULL ;
643 m_macTXN = NULL ;
644 m_macTXNvars = NULL ;
645 m_macUsesTXN = false ;
646
647 m_editable = true ;
648 m_dirty = false;
649
650 m_maxLength = TE_UNLIMITED_LENGTH ;
651 }
652
653 wxTextCtrl::~wxTextCtrl()
654 {
655 if ( m_macUsesTXN )
656 {
657 SetControlReference((ControlHandle)m_macControl, 0) ;
658 TXNDeleteObject((TXNObject)m_macTXN);
659 /* delete our private storage */
660 DisposeHandle((Handle) m_macTXNvars);
661 /* zero the control reference */
662 }
663 }
664
665 const short kVerticalMargin = 2 ;
666 const short kHorizontalMargin = 2 ;
667
668 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
669 const wxString& st,
670 const wxPoint& pos,
671 const wxSize& size, long style,
672 const wxValidator& validator,
673 const wxString& name)
674 {
675 m_macTE = NULL ;
676 m_macTXN = NULL ;
677 m_macTXNvars = NULL ;
678 m_macUsesTXN = false ;
679 m_editable = true ;
680
681 m_macUsesTXN = ! (style & wxTE_PASSWORD ) ;
682
683 m_macUsesTXN &= (TXNInitTextension != (void*) kUnresolvedCFragSymbolAddress) ;
684
685 // base initialization
686 if ( !wxTextCtrlBase::Create(parent, id, pos, size, style, validator, name) )
687 return FALSE;
688
689 wxSize mySize = size ;
690 if ( m_macUsesTXN )
691 {
692 m_macHorizontalBorder = 5 ; // additional pixels around the real control
693 m_macVerticalBorder = 3 ;
694 }
695 else
696 {
697 m_macHorizontalBorder = 5 ; // additional pixels around the real control
698 m_macVerticalBorder = 5 ;
699 }
700
701
702 Rect bounds ;
703 Str255 title ;
704 /*
705 if ( mySize.y == -1 )
706 {
707 mySize.y = 13 ;
708 if ( m_windowStyle & wxTE_MULTILINE )
709 mySize.y *= 5 ;
710
711 mySize.y += 2 * m_macVerticalBorder ;
712 }
713 */
714 MacPreControlCreate( parent , id , wxEmptyString , pos , mySize ,style, validator , name , &bounds , title ) ;
715
716 if ( m_windowStyle & wxTE_MULTILINE )
717 {
718 wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
719 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
720
721 m_windowStyle |= wxTE_PROCESS_ENTER;
722 }
723
724 if ( m_windowStyle & wxTE_READONLY)
725 {
726 m_editable = FALSE ;
727 }
728
729 if ( !m_macUsesTXN )
730 {
731 m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , "\p" , true , 0 , 0 , 1,
732 (style & wxTE_PASSWORD) ? kControlEditTextPasswordProc : kControlEditTextProc , (long) this ) ;
733 long size ;
734 ::GetControlData((ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*)((TEHandle *)&m_macTE) , &size ) ;
735
736 }
737 else
738 {
739 short featurSet;
740
741 featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
742 | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground
743 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
744 /* create the control */
745 m_macControl = NewControl(MAC_WXHWND(parent->MacGetRootWindow()), &bounds, "\p", true, featurSet, 0, featurSet, kControlUserPaneProc, 0);
746 /* set up the mUP specific features and data */
747 mUPOpenControl((ControlHandle) m_macControl, m_windowStyle );
748 }
749 MacPostControlCreate() ;
750
751 if ( !m_macUsesTXN )
752 {
753 wxCharBuffer text = wxMacStringToCString( st ) ;
754 ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ;
755 }
756 else
757 {
758 STPTextPaneVars **tpvars;
759 /* set up locals */
760 tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl);
761 /* set the text in the record */
762 m_macTXN = (**tpvars).fTXNRec ;
763 #if wxUSE_UNICODE
764 TXNSetData( ((TXNObject) m_macTXN) , kTXNUnicodeTextData, (void*)st.wc_str(), st.Length() * 2,
765 kTXNStartOffset, kTXNEndOffset);
766 #else
767 wxCharBuffer text = wxMacStringToCString( st ) ;
768 TXNSetData( ((TXNObject) m_macTXN) , kTXNTextData, (void*)text.data(), strlen( text ) ,
769 kTXNStartOffset, kTXNEndOffset);
770 #endif
771 m_macTXNvars = tpvars ;
772 m_macUsesTXN = true ;
773 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
774 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
775 }
776
777 return TRUE;
778 }
779
780 wxString wxTextCtrl::GetValue() const
781 {
782 Size actualSize = 0;
783 wxString result ;
784 OSStatus err ;
785 if ( !m_macUsesTXN )
786 {
787 err = ::GetControlDataSize((ControlHandle) m_macControl, 0,
788 ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag, &actualSize ) ;
789
790 if ( err )
791 return wxEmptyString ;
792
793 if ( actualSize > 0 )
794 {
795 wxCharBuffer buf(actualSize) ;
796 ::GetControlData( (ControlHandle) m_macControl, 0,
797 ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag,
798 actualSize , buf.data() , &actualSize ) ;
799 result = wxMacMakeStringFromCString( buf ) ;
800 }
801 }
802 else
803 {
804 #if wxUSE_UNICODE
805 Handle theText ;
806 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
807 // all done
808 if ( err )
809 {
810 actualSize = 0 ;
811 }
812 else
813 {
814 actualSize = GetHandleSize( theText ) ;
815 if ( actualSize > 0 )
816 {
817 wxChar *ptr = result.GetWriteBuf(actualSize*sizeof(wxChar)) ;
818 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
819 ptr[actualSize] = 0 ;
820 result.UngetWriteBuf( actualSize ) ;
821 }
822 DisposeHandle( theText ) ;
823 }
824 #else
825 Handle theText ;
826 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
827 // all done
828 if ( err )
829 {
830 actualSize = 0 ;
831 }
832 else
833 {
834 actualSize = GetHandleSize( theText ) ;
835 if ( actualSize > 0 )
836 {
837 HLock( theText ) ;
838 result = wxMacMakeStringFromCString( *theText , actualSize ) ;
839 HUnlock( theText ) ;
840 }
841 DisposeHandle( theText ) ;
842 }
843 #endif
844 }
845
846 return result ;
847 }
848
849 void wxTextCtrl::GetSelection(long* from, long* to) const
850 {
851 if ( !m_macUsesTXN )
852 {
853 *from = (**((TEHandle) m_macTE)).selStart;
854 *to = (**((TEHandle) m_macTE)).selEnd;
855 }
856 else
857 {
858 TXNGetSelection( ((TXNObject) m_macTXN) , (TXNOffset*) from , (TXNOffset*) to ) ;
859 }
860 }
861
862 void wxTextCtrl::SetValue(const wxString& st)
863 {
864 if ( !m_macUsesTXN )
865 {
866 wxCharBuffer text = wxMacStringToCString( st ) ;
867 ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ;
868 }
869 else
870 {
871 bool formerEditable = m_editable ;
872 if ( !formerEditable )
873 SetEditable(true) ;
874 #if wxUSE_UNICODE
875 TXNSetData( ((TXNObject) m_macTXN), kTXNUnicodeTextData, (void*)st.wc_str(), st.Length() * 2 ,
876 kTXNStartOffset, kTXNEndOffset);
877 #else
878 wxCharBuffer text = wxMacStringToCString( st ) ;
879 TXNSetData( ((TXNObject) m_macTXN), kTXNTextData, (void*)text.data(), strlen( text ) ,
880 kTXNStartOffset, kTXNEndOffset);
881 #endif
882 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
883 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
884 if ( !formerEditable )
885 SetEditable(formerEditable) ;
886 }
887 MacRedrawControl() ;
888 }
889
890 void wxTextCtrl::SetMaxLength(unsigned long len)
891 {
892 m_maxLength = len ;
893 }
894
895 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
896 {
897 if ( m_macUsesTXN )
898 {
899 bool formerEditable = m_editable ;
900 if ( !formerEditable )
901 SetEditable(true) ;
902 TXNTypeAttributes typeAttr[4] ;
903 Str255 fontName = "\pMonaco" ;
904 SInt16 fontSize = 12 ;
905 Style fontStyle = normal ;
906 RGBColor color ;
907 int attrCounter = 0 ;
908 if ( style.HasFont() )
909 {
910 const wxFont &font = style.GetFont() ;
911 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
912 fontSize = font.GetPointSize() ;
913 if ( font.GetUnderlined() )
914 fontStyle |= underline ;
915 if ( font.GetWeight() == wxBOLD )
916 fontStyle |= bold ;
917 if ( font.GetStyle() == wxITALIC )
918 fontStyle |= italic ;
919
920 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
921 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
922 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
923 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
924 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
925 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
926 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
927 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
928 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
929 attrCounter += 3 ;
930
931 }
932 if ( style.HasTextColour() )
933 {
934 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
935 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
936 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
937 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
938 attrCounter += 1 ;
939 }
940
941 if ( attrCounter > 0 )
942 {
943 #ifdef __WXDEBUG__
944 OSStatus status =
945 #endif // __WXDEBUG__
946 TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, start,end);
947 wxASSERT_MSG( status == noErr , wxT("Couldn't set text attributes") ) ;
948 }
949 if ( !formerEditable )
950 SetEditable(formerEditable) ;
951 }
952 return TRUE ;
953 }
954
955 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
956 {
957 wxTextCtrlBase::SetDefaultStyle( style ) ;
958 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
959 return TRUE ;
960 }
961
962 // Clipboard operations
963 void wxTextCtrl::Copy()
964 {
965 if (CanCopy())
966 {
967 if ( !m_macUsesTXN )
968 {
969 TECopy( ((TEHandle) m_macTE) ) ;
970 ClearCurrentScrap();
971 TEToScrap() ;
972 MacRedrawControl() ;
973 }
974 else
975 {
976 ClearCurrentScrap();
977 TXNCopy((TXNObject)m_macTXN);
978 TXNConvertToPublicScrap();
979 }
980 }
981 }
982
983 void wxTextCtrl::Cut()
984 {
985 if (CanCut())
986 {
987 if ( !m_macUsesTXN )
988 {
989 TECut( ((TEHandle) m_macTE) ) ;
990 ClearCurrentScrap();
991 TEToScrap() ;
992 MacRedrawControl() ;
993 }
994 else
995 {
996 ClearCurrentScrap();
997 TXNCut((TXNObject)m_macTXN);
998 TXNConvertToPublicScrap();
999 }
1000 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1001 event.SetString( GetValue() ) ;
1002 event.SetEventObject( this );
1003 GetEventHandler()->ProcessEvent(event);
1004 }
1005 }
1006
1007 void wxTextCtrl::Paste()
1008 {
1009 if (CanPaste())
1010 {
1011 if ( !m_macUsesTXN )
1012 {
1013 TEFromScrap() ;
1014 TEPaste( (TEHandle) m_macTE ) ;
1015 MacRedrawControl() ;
1016 }
1017 else
1018 {
1019 TXNConvertFromPublicScrap();
1020 TXNPaste((TXNObject)m_macTXN);
1021 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1022 }
1023 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1024 event.SetString( GetValue() ) ;
1025 event.SetEventObject( this );
1026 GetEventHandler()->ProcessEvent(event);
1027 }
1028 }
1029
1030 bool wxTextCtrl::CanCopy() const
1031 {
1032 // Can copy if there's a selection
1033 long from, to;
1034 GetSelection(& from, & to);
1035 return (from != to);
1036 }
1037
1038 bool wxTextCtrl::CanCut() const
1039 {
1040 if ( !IsEditable() )
1041 {
1042 return false ;
1043 }
1044 // Can cut if there's a selection
1045 long from, to;
1046 GetSelection(& from, & to);
1047 return (from != to);
1048 }
1049
1050 bool wxTextCtrl::CanPaste() const
1051 {
1052 if (!IsEditable())
1053 return FALSE;
1054
1055 #if TARGET_CARBON
1056 OSStatus err = noErr;
1057 ScrapRef scrapRef;
1058
1059 err = GetCurrentScrap( &scrapRef );
1060 if ( err != noTypeErr && err != memFullErr )
1061 {
1062 ScrapFlavorFlags flavorFlags;
1063 Size byteCount;
1064
1065 if (( err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags )) == noErr)
1066 {
1067 if (( err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount )) == noErr)
1068 {
1069 return TRUE ;
1070 }
1071 }
1072 }
1073 return FALSE;
1074
1075 #else
1076 long offset ;
1077 if ( GetScrap( NULL , 'TEXT' , &offset ) > 0 )
1078 {
1079 return TRUE ;
1080 }
1081 #endif
1082 return FALSE ;
1083 }
1084
1085 void wxTextCtrl::SetEditable(bool editable)
1086 {
1087 if ( editable != m_editable )
1088 {
1089 m_editable = editable ;
1090 if ( !m_macUsesTXN )
1091 {
1092 if ( editable )
1093 UMAActivateControl( (ControlHandle) m_macControl ) ;
1094 else
1095 UMADeactivateControl((ControlHandle) m_macControl ) ;
1096 }
1097 else
1098 {
1099 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1100 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1101 TXNSetTXNObjectControls( (TXNObject) m_macTXN , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ;
1102 }
1103 }
1104 }
1105
1106 void wxTextCtrl::SetInsertionPoint(long pos)
1107 {
1108 SetSelection( pos , pos ) ;
1109 }
1110
1111 void wxTextCtrl::SetInsertionPointEnd()
1112 {
1113 long pos = GetLastPosition();
1114 SetInsertionPoint(pos);
1115 }
1116
1117 long wxTextCtrl::GetInsertionPoint() const
1118 {
1119 long begin,end ;
1120 GetSelection( &begin , &end ) ;
1121 return begin ;
1122 }
1123
1124 long wxTextCtrl::GetLastPosition() const
1125 {
1126 if ( !m_macUsesTXN )
1127 {
1128 return (**((TEHandle) m_macTE)).teLength ;
1129 }
1130 else
1131 {
1132 Handle theText ;
1133 long actualsize ;
1134 OSErr err = TXNGetDataEncoded( (TXNObject) m_macTXN, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1135 /* all done */
1136 if ( err )
1137 {
1138 actualsize = 0 ;
1139 }
1140 else
1141 {
1142 actualsize = GetHandleSize( theText ) ;
1143 DisposeHandle( theText ) ;
1144 }
1145 return actualsize ;
1146 }
1147 }
1148
1149 void wxTextCtrl::Replace(long from, long to, const wxString& value)
1150 {
1151 if ( !m_macUsesTXN )
1152 {
1153 ControlEditTextSelectionRec selection ;
1154
1155 selection.selStart = from ;
1156 selection.selEnd = to ;
1157 ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1158 TESetSelect( from , to , ((TEHandle) m_macTE) ) ;
1159 TEDelete( ((TEHandle) m_macTE) ) ;
1160 TEInsert( value , value.Length() , ((TEHandle) m_macTE) ) ;
1161 }
1162 else
1163 {
1164 bool formerEditable = m_editable ;
1165 if ( !formerEditable )
1166 SetEditable(true) ;
1167 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1168 TXNClear( ((TXNObject) m_macTXN) ) ;
1169 #if wxUSE_UNICODE
1170 TXNSetData( ((TXNObject) m_macTXN), kTXNUnicodeTextData, (void*)value.wc_str(), value.Length() * 2 ,
1171 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1172 #else
1173 TXNSetData( ((TXNObject) m_macTXN), kTXNTextData, (void*)value.c_str(), value.Length(),
1174 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1175 #endif
1176 if ( !formerEditable )
1177 SetEditable( formerEditable ) ;
1178 }
1179 Refresh() ;
1180 }
1181
1182 void wxTextCtrl::Remove(long from, long to)
1183 {
1184 if ( !m_macUsesTXN )
1185 {
1186 ControlEditTextSelectionRec selection ;
1187
1188 selection.selStart = from ;
1189 selection.selEnd = to ;
1190 ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1191 TEDelete( ((TEHandle) m_macTE) ) ;
1192 }
1193 else
1194 {
1195 bool formerEditable = m_editable ;
1196 if ( !formerEditable )
1197 SetEditable(true) ;
1198 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1199 TXNClear( ((TXNObject) m_macTXN) ) ;
1200 if ( !formerEditable )
1201 SetEditable( formerEditable ) ;
1202 }
1203 Refresh() ;
1204 }
1205
1206 void wxTextCtrl::SetSelection(long from, long to)
1207 {
1208 if ( !m_macUsesTXN )
1209 {
1210 ControlEditTextSelectionRec selection ;
1211 if ((from == -1) && (to == -1))
1212 {
1213 selection.selStart = 0 ;
1214 selection.selEnd = 32767 ;
1215 }
1216 else
1217 {
1218 selection.selStart = from ;
1219 selection.selEnd = to ;
1220 }
1221
1222 TESetSelect( selection.selStart , selection.selEnd , ((TEHandle) m_macTE) ) ;
1223 ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1224 }
1225 else
1226 {
1227 STPTextPaneVars **tpvars;
1228 /* set up our locals */
1229 tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl);
1230 /* and our drawing environment as the operation
1231 may force a redraw in the text area. */
1232 SetPort((**tpvars).fDrawingEnvironment);
1233 /* change the selection */
1234 if ((from == -1) && (to == -1))
1235 TXNSelectAll((TXNObject) m_macTXN);
1236 else
1237 TXNSetSelection( (**tpvars).fTXNRec, from, to);
1238 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1239 }
1240 }
1241
1242 bool wxTextCtrl::LoadFile(const wxString& file)
1243 {
1244 if ( wxTextCtrlBase::LoadFile(file) )
1245 {
1246 return TRUE;
1247 }
1248
1249 return FALSE;
1250 }
1251
1252 void wxTextCtrl::WriteText(const wxString& st)
1253 {
1254 if ( !m_macUsesTXN )
1255 {
1256 wxCharBuffer text = wxMacStringToCString( st ) ;
1257 TEInsert( text , strlen(text) , ((TEHandle) m_macTE) ) ;
1258 }
1259 else
1260 {
1261 bool formerEditable = m_editable ;
1262 if ( !formerEditable )
1263 SetEditable(true) ;
1264 long start , end , dummy ;
1265 GetSelection( &start , &dummy ) ;
1266 #if wxUSE_UNICODE
1267 TXNSetData( ((TXNObject) m_macTXN), kTXNUnicodeTextData, (void*)st.wc_str(), st.Length() * 2 ,
1268 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1269 #else
1270 wxCharBuffer text = wxMacStringToCString( st ) ;
1271 TXNSetData( ((TXNObject) m_macTXN), kTXNTextData, (void*)text.data(), strlen( text ) ,
1272 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1273 #endif
1274 GetSelection( &dummy , &end ) ;
1275 SetStyle( start , end , GetDefaultStyle() ) ;
1276 if ( !formerEditable )
1277 SetEditable( formerEditable ) ;
1278 }
1279 MacRedrawControl() ;
1280 }
1281
1282 void wxTextCtrl::AppendText(const wxString& text)
1283 {
1284 SetInsertionPointEnd();
1285 WriteText(text);
1286 }
1287
1288 void wxTextCtrl::Clear()
1289 {
1290 if ( !IsEditable() )
1291 {
1292 return ;
1293 }
1294 if ( !m_macUsesTXN )
1295 {
1296 ::SetControlData((ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 0 , (char*) ((const char*)NULL) ) ;
1297 }
1298 else
1299 {
1300 TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ;
1301 TXNClear((TXNObject)m_macTXN);
1302 }
1303 Refresh() ;
1304 }
1305
1306 bool wxTextCtrl::IsModified() const
1307 {
1308 return m_dirty;
1309 }
1310
1311 bool wxTextCtrl::IsEditable() const
1312 {
1313 return IsEnabled() && m_editable ;
1314 }
1315
1316 bool wxTextCtrl::AcceptsFocus() const
1317 {
1318 // we don't want focus if we can't be edited
1319 return /*IsEditable() && */ wxControl::AcceptsFocus();
1320 }
1321
1322 wxSize wxTextCtrl::DoGetBestSize() const
1323 {
1324 int wText = 100 ;
1325
1326 int hText;
1327 if ( m_macUsesTXN )
1328 {
1329 hText = 17 ;
1330 }
1331 else
1332 {
1333 hText = 13 ;
1334 }
1335 /*
1336 int cx, cy;
1337 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
1338
1339 int wText = DEFAULT_ITEM_WIDTH;
1340
1341 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
1342
1343 return wxSize(wText, hText);
1344 */
1345 if ( m_windowStyle & wxTE_MULTILINE )
1346 {
1347 hText *= 5 ;
1348 }
1349 hText += 2 * m_macVerticalBorder ;
1350 wText += 2 * m_macHorizontalBorder ;
1351 //else: for single line control everything is ok
1352 return wxSize(wText, hText);
1353 }
1354
1355 // ----------------------------------------------------------------------------
1356 // Undo/redo
1357 // ----------------------------------------------------------------------------
1358
1359 void wxTextCtrl::Undo()
1360 {
1361 if (CanUndo())
1362 {
1363 if ( m_macUsesTXN )
1364 {
1365 TXNUndo((TXNObject)m_macTXN);
1366 }
1367 }
1368 }
1369
1370 void wxTextCtrl::Redo()
1371 {
1372 if (CanRedo())
1373 {
1374 if ( m_macUsesTXN )
1375 {
1376 TXNRedo((TXNObject)m_macTXN);
1377 }
1378 }
1379 }
1380
1381 bool wxTextCtrl::CanUndo() const
1382 {
1383 if ( !IsEditable() )
1384 {
1385 return false ;
1386 }
1387 if ( m_macUsesTXN )
1388 {
1389 return TXNCanUndo((TXNObject)m_macTXN,NULL);
1390 }
1391 return FALSE ;
1392 }
1393
1394 bool wxTextCtrl::CanRedo() const
1395 {
1396 if ( !IsEditable() )
1397 {
1398 return false ;
1399 }
1400 if ( m_macUsesTXN )
1401 {
1402 return TXNCanRedo((TXNObject)m_macTXN,NULL);
1403 }
1404 return FALSE ;
1405 }
1406
1407 // Makes 'unmodified'
1408 void wxTextCtrl::DiscardEdits()
1409 {
1410 m_dirty = false;
1411 }
1412
1413 int wxTextCtrl::GetNumberOfLines() const
1414 {
1415 // TODO change this if possible to reflect real lines
1416 wxString content = GetValue() ;
1417
1418 int count = 1;
1419 for (size_t i = 0; i < content.Length() ; i++)
1420 {
1421 if (content[i] == '\r') count++;
1422 }
1423
1424 return count;
1425 }
1426
1427 long wxTextCtrl::XYToPosition(long x, long y) const
1428 {
1429 // TODO
1430 return 0;
1431 }
1432
1433 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
1434 {
1435 return FALSE ;
1436 }
1437
1438 void wxTextCtrl::ShowPosition(long pos)
1439 {
1440 // TODO
1441 }
1442
1443 int wxTextCtrl::GetLineLength(long lineNo) const
1444 {
1445 // TODO change this if possible to reflect real lines
1446 wxString content = GetValue() ;
1447
1448 // Find line first
1449 int count = 0;
1450 for (size_t i = 0; i < content.Length() ; i++)
1451 {
1452 if (count == lineNo)
1453 {
1454 // Count chars in line then
1455 count = 0;
1456 for (size_t j = i; j < content.Length(); j++)
1457 {
1458 count++;
1459 if (content[j] == '\r') return count;
1460 }
1461
1462 return count;
1463 }
1464 if (content[i] == '\r') count++;
1465 }
1466 return 0;
1467 }
1468
1469 wxString wxTextCtrl::GetLineText(long lineNo) const
1470 {
1471 // TODO change this if possible to reflect real lines
1472 wxString content = GetValue() ;
1473
1474 // Find line first
1475 int count = 0;
1476 for (size_t i = 0; i < content.Length() ; i++)
1477 {
1478 if (count == lineNo)
1479 {
1480 // Add chars in line then
1481 wxString tmp;
1482
1483 for (size_t j = i; j < content.Length(); j++)
1484 {
1485 if (content[j] == '\r')
1486 return tmp;
1487
1488 tmp += content[j];
1489 }
1490
1491 return tmp;
1492 }
1493 if (content[i] == '\r') count++;
1494 }
1495 return wxEmptyString ;
1496 }
1497
1498 /*
1499 * Text item
1500 */
1501
1502 void wxTextCtrl::Command(wxCommandEvent & event)
1503 {
1504 SetValue (event.GetString());
1505 ProcessCommand (event);
1506 }
1507
1508 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
1509 {
1510 // By default, load the first file into the text window.
1511 if (event.GetNumberOfFiles() > 0)
1512 {
1513 LoadFile(event.GetFiles()[0]);
1514 }
1515 }
1516
1517 void wxTextCtrl::OnChar(wxKeyEvent& event)
1518 {
1519 int key = event.GetKeyCode() ;
1520 bool eat_key = false ;
1521
1522 if ( key == 'c' && event.MetaDown() )
1523 {
1524 if ( CanCopy() )
1525 Copy() ;
1526 return ;
1527 }
1528
1529 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
1530 !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1531 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1532 )
1533 {
1534 // eat it
1535 return ;
1536 }
1537
1538 // assume that any key not processed yet is going to modify the control
1539 m_dirty = true;
1540
1541 if ( key == 'v' && event.MetaDown() )
1542 {
1543 if ( CanPaste() )
1544 Paste() ;
1545 return ;
1546 }
1547 if ( key == 'x' && event.MetaDown() )
1548 {
1549 if ( CanCut() )
1550 Cut() ;
1551 return ;
1552 }
1553 switch ( key )
1554 {
1555 case WXK_RETURN:
1556 if (m_windowStyle & wxPROCESS_ENTER)
1557 {
1558 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1559 event.SetEventObject( this );
1560 event.SetString( GetValue() );
1561 if ( GetEventHandler()->ProcessEvent(event) )
1562 return;
1563 }
1564 if ( !(m_windowStyle & wxTE_MULTILINE) )
1565 {
1566 wxWindow *parent = GetParent();
1567 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
1568 parent = parent->GetParent() ;
1569 }
1570 if ( parent && parent->GetDefaultItem() )
1571 {
1572 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
1573 wxButton);
1574 if ( def && def->IsEnabled() )
1575 {
1576 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
1577 event.SetEventObject(def);
1578 def->Command(event);
1579 return ;
1580 }
1581 }
1582
1583 // this will make wxWindows eat the ENTER key so that
1584 // we actually prevent line wrapping in a single line
1585 // text control
1586 eat_key = TRUE;
1587 }
1588
1589 break;
1590
1591 case WXK_TAB:
1592 // always produce navigation event - even if we process TAB
1593 // ourselves the fact that we got here means that the user code
1594 // decided to skip processing of this TAB - probably to let it
1595 // do its default job.
1596 {
1597 wxNavigationKeyEvent eventNav;
1598 eventNav.SetDirection(!event.ShiftDown());
1599 eventNav.SetWindowChange(event.ControlDown());
1600 eventNav.SetEventObject(this);
1601
1602 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
1603 return;
1604
1605 event.Skip() ;
1606 return;
1607 }
1608 break;
1609 }
1610
1611 if (!eat_key)
1612 {
1613 // perform keystroke handling
1614 #if TARGET_CARBON
1615 if ( m_macUsesTXN && wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
1616 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
1617 else
1618 #endif
1619 {
1620 EventRecord rec ;
1621 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
1622 {
1623 EventRecord *ev = &rec ;
1624 short keycode ;
1625 short keychar ;
1626 keychar = short(ev->message & charCodeMask);
1627 keycode = short(ev->message & keyCodeMask) >> 8 ;
1628
1629 ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ;
1630 }
1631 }
1632 }
1633 if ( ( key >= 0x20 && key < WXK_START ) ||
1634 key == WXK_RETURN ||
1635 key == WXK_DELETE ||
1636 key == WXK_BACK)
1637 {
1638 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1639 event1.SetString( GetValue() ) ;
1640 event1.SetEventObject( this );
1641 wxPostEvent(GetEventHandler(),event1);
1642 }
1643 }
1644
1645 void wxTextCtrl::MacSuperShown( bool show )
1646 {
1647 bool former = m_macControlIsShown ;
1648 wxControl::MacSuperShown( show ) ;
1649 if ( (former != m_macControlIsShown) && m_macUsesTXN )
1650 {
1651 if ( m_macControlIsShown )
1652 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1653 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1654 else
1655 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1656 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1657 }
1658 }
1659
1660 bool wxTextCtrl::Show(bool show)
1661 {
1662 bool former = m_macControlIsShown ;
1663
1664 bool retval = wxControl::Show( show ) ;
1665
1666 if ( former != m_macControlIsShown && m_macUsesTXN )
1667 {
1668 if ( m_macControlIsShown )
1669 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1670 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1671 else
1672 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1673 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1674 }
1675
1676 return retval ;
1677 }
1678
1679 // ----------------------------------------------------------------------------
1680 // standard handlers for standard edit menu events
1681 // ----------------------------------------------------------------------------
1682
1683 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1684 {
1685 Cut();
1686 }
1687
1688 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1689 {
1690 Copy();
1691 }
1692
1693 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1694 {
1695 Paste();
1696 }
1697
1698 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1699 {
1700 Undo();
1701 }
1702
1703 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1704 {
1705 Redo();
1706 }
1707
1708 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1709 {
1710 event.Enable( CanCut() );
1711 }
1712
1713 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1714 {
1715 event.Enable( CanCopy() );
1716 }
1717
1718 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1719 {
1720 event.Enable( CanPaste() );
1721 }
1722
1723 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1724 {
1725 event.Enable( CanUndo() );
1726 }
1727
1728 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1729 {
1730 event.Enable( CanRedo() );
1731 }
1732
1733 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1734 {
1735 if ( m_macUsesTXN )
1736 return true ;
1737 else
1738 return wxWindow::MacSetupCursor( pt ) ;
1739 }
1740
1741 #endif
1742 // wxUSE_TEXTCTRL