]> git.saurik.com Git - wxWidgets.git/blob - src/mac/textctrl.cpp
d84050093d63d00f8fc174f5adb38bfc6db9dbd0
[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 wxTextCtrl::wxTextCtrl()
641 {
642 m_macTE = NULL ;
643 m_macTXN = NULL ;
644 m_macTXNvars = NULL ;
645 m_macUsesTXN = false ;
646 m_editable = true ;
647 m_maxLength = TE_UNLIMITED_LENGTH ;
648 }
649
650 wxTextCtrl::~wxTextCtrl()
651 {
652 if ( m_macUsesTXN )
653 {
654 SetControlReference((ControlHandle)m_macControl, 0) ;
655 TXNDeleteObject((TXNObject)m_macTXN);
656 /* delete our private storage */
657 DisposeHandle((Handle) m_macTXNvars);
658 /* zero the control reference */
659 }
660 }
661
662 const short kVerticalMargin = 2 ;
663 const short kHorizontalMargin = 2 ;
664
665 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
666 const wxString& st,
667 const wxPoint& pos,
668 const wxSize& size, long style,
669 const wxValidator& validator,
670 const wxString& name)
671 {
672 m_macTE = NULL ;
673 m_macTXN = NULL ;
674 m_macTXNvars = NULL ;
675 m_macUsesTXN = false ;
676 m_editable = true ;
677
678 m_macUsesTXN = ! (style & wxTE_PASSWORD ) ;
679
680 m_macUsesTXN &= (TXNInitTextension != (void*) kUnresolvedCFragSymbolAddress) ;
681
682 // base initialization
683 if ( !wxTextCtrlBase::Create(parent, id, pos, size, style, validator, name) )
684 return FALSE;
685
686 wxSize mySize = size ;
687 if ( m_macUsesTXN )
688 {
689 m_macHorizontalBorder = 5 ; // additional pixels around the real control
690 m_macVerticalBorder = 3 ;
691 }
692 else
693 {
694 m_macHorizontalBorder = 5 ; // additional pixels around the real control
695 m_macVerticalBorder = 5 ;
696 }
697
698
699 Rect bounds ;
700 Str255 title ;
701 /*
702 if ( mySize.y == -1 )
703 {
704 mySize.y = 13 ;
705 if ( m_windowStyle & wxTE_MULTILINE )
706 mySize.y *= 5 ;
707
708 mySize.y += 2 * m_macVerticalBorder ;
709 }
710 */
711 MacPreControlCreate( parent , id , wxEmptyString , pos , mySize ,style, validator , name , &bounds , title ) ;
712
713 if ( m_windowStyle & wxTE_MULTILINE )
714 {
715 wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
716 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
717
718 m_windowStyle |= wxTE_PROCESS_ENTER;
719 }
720
721 if ( m_windowStyle & wxTE_READONLY)
722 {
723 m_editable = FALSE ;
724 }
725
726 if ( !m_macUsesTXN )
727 {
728 m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , "\p" , true , 0 , 0 , 1,
729 (style & wxTE_PASSWORD) ? kControlEditTextPasswordProc : kControlEditTextProc , (long) this ) ;
730 long size ;
731 ::GetControlData((ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*)((TEHandle *)&m_macTE) , &size ) ;
732
733 }
734 else
735 {
736 short featurSet;
737
738 featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
739 | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground
740 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
741 /* create the control */
742 m_macControl = NewControl(MAC_WXHWND(parent->MacGetRootWindow()), &bounds, "\p", true, featurSet, 0, featurSet, kControlUserPaneProc, 0);
743 /* set up the mUP specific features and data */
744 mUPOpenControl((ControlHandle) m_macControl, m_windowStyle );
745 }
746 MacPostControlCreate() ;
747
748 if ( !m_macUsesTXN )
749 {
750 wxCharBuffer text = wxMacStringToCString( st ) ;
751 ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ;
752 }
753 else
754 {
755 STPTextPaneVars **tpvars;
756 /* set up locals */
757 tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl);
758 /* set the text in the record */
759 m_macTXN = (**tpvars).fTXNRec ;
760 #if wxUSE_UNICODE
761 TXNSetData( ((TXNObject) m_macTXN) , kTXNUnicodeTextData, (void*)st.wc_str(), st.Length() * 2,
762 kTXNStartOffset, kTXNEndOffset);
763 #else
764 wxCharBuffer text = wxMacStringToCString( st ) ;
765 TXNSetData( ((TXNObject) m_macTXN) , kTXNTextData, (void*)text.data(), strlen( text ) ,
766 kTXNStartOffset, kTXNEndOffset);
767 #endif
768 m_macTXNvars = tpvars ;
769 m_macUsesTXN = true ;
770 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
771 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
772 }
773
774 return TRUE;
775 }
776
777 wxString wxTextCtrl::GetValue() const
778 {
779 Size actualSize = 0;
780 wxString result ;
781 OSStatus err ;
782 if ( !m_macUsesTXN )
783 {
784 err = ::GetControlDataSize((ControlHandle) m_macControl, 0,
785 ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag, &actualSize ) ;
786
787 if ( err )
788 return wxEmptyString ;
789
790 if ( actualSize > 0 )
791 {
792 wxCharBuffer buf(actualSize) ;
793 ::GetControlData( (ControlHandle) m_macControl, 0,
794 ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag,
795 actualSize , buf.data() , &actualSize ) ;
796 result = wxMacMakeStringFromCString( buf ) ;
797 }
798 }
799 else
800 {
801 #if wxUSE_UNICODE
802 Handle theText ;
803 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
804 // all done
805 if ( err )
806 {
807 actualSize = 0 ;
808 }
809 else
810 {
811 actualSize = GetHandleSize( theText ) ;
812 if ( actualSize > 0 )
813 {
814 wxChar *ptr = result.GetWriteBuf(actualSize*sizeof(wxChar)) ;
815 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
816 ptr[actualSize] = 0 ;
817 result.UngetWriteBuf( actualSize ) ;
818 }
819 DisposeHandle( theText ) ;
820 }
821 #else
822 Handle theText ;
823 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
824 // all done
825 if ( err )
826 {
827 actualSize = 0 ;
828 }
829 else
830 {
831 actualSize = GetHandleSize( theText ) ;
832 if ( actualSize > 0 )
833 {
834 HLock( theText ) ;
835 result = wxMacMakeStringFromCString( *theText , actualSize ) ;
836 HUnlock( theText ) ;
837 }
838 DisposeHandle( theText ) ;
839 }
840 #endif
841 }
842
843 return result ;
844 }
845
846 void wxTextCtrl::GetSelection(long* from, long* to) const
847 {
848 if ( !m_macUsesTXN )
849 {
850 *from = (**((TEHandle) m_macTE)).selStart;
851 *to = (**((TEHandle) m_macTE)).selEnd;
852 }
853 else
854 {
855 TXNGetSelection( ((TXNObject) m_macTXN) , (TXNOffset*) from , (TXNOffset*) to ) ;
856 }
857 }
858
859 void wxTextCtrl::SetValue(const wxString& st)
860 {
861 if ( !m_macUsesTXN )
862 {
863 wxCharBuffer text = wxMacStringToCString( st ) ;
864 ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ;
865 }
866 else
867 {
868 bool formerEditable = m_editable ;
869 if ( !formerEditable )
870 SetEditable(true) ;
871 #if wxUSE_UNICODE
872 TXNSetData( ((TXNObject) m_macTXN), kTXNUnicodeTextData, (void*)st.wc_str(), st.Length() * 2 ,
873 kTXNStartOffset, kTXNEndOffset);
874 #else
875 wxCharBuffer text = wxMacStringToCString( st ) ;
876 TXNSetData( ((TXNObject) m_macTXN), kTXNTextData, (void*)text.data(), strlen( text ) ,
877 kTXNStartOffset, kTXNEndOffset);
878 #endif
879 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
880 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
881 if ( !formerEditable )
882 SetEditable(formerEditable) ;
883 }
884 MacRedrawControl() ;
885 }
886
887 void wxTextCtrl::SetMaxLength(unsigned long len)
888 {
889 m_maxLength = len ;
890 }
891
892 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
893 {
894 if ( m_macUsesTXN )
895 {
896 bool formerEditable = m_editable ;
897 if ( !formerEditable )
898 SetEditable(true) ;
899 TXNTypeAttributes typeAttr[4] ;
900 Str255 fontName = "\pMonaco" ;
901 SInt16 fontSize = 12 ;
902 Style fontStyle = normal ;
903 RGBColor color ;
904 int attrCounter = 0 ;
905 if ( style.HasFont() )
906 {
907 const wxFont &font = style.GetFont() ;
908 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
909 fontSize = font.GetPointSize() ;
910 if ( font.GetUnderlined() )
911 fontStyle |= underline ;
912 if ( font.GetWeight() == wxBOLD )
913 fontStyle |= bold ;
914 if ( font.GetStyle() == wxITALIC )
915 fontStyle |= italic ;
916
917 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
918 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
919 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
920 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
921 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
922 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
923 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
924 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
925 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
926 attrCounter += 3 ;
927
928 }
929 if ( style.HasTextColour() )
930 {
931 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
932 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
933 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
934 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
935 attrCounter += 1 ;
936 }
937
938 if ( attrCounter > 0 )
939 {
940 #ifdef __WXDEBUG__
941 OSStatus status =
942 #endif // __WXDEBUG__
943 TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, start,end);
944 wxASSERT_MSG( status == noErr , wxT("Couldn't set text attributes") ) ;
945 }
946 if ( !formerEditable )
947 SetEditable(formerEditable) ;
948 }
949 return TRUE ;
950 }
951
952 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
953 {
954 wxTextCtrlBase::SetDefaultStyle( style ) ;
955 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
956 return TRUE ;
957 }
958
959 // Clipboard operations
960 void wxTextCtrl::Copy()
961 {
962 if (CanCopy())
963 {
964 if ( !m_macUsesTXN )
965 {
966 TECopy( ((TEHandle) m_macTE) ) ;
967 ClearCurrentScrap();
968 TEToScrap() ;
969 MacRedrawControl() ;
970 }
971 else
972 {
973 ClearCurrentScrap();
974 TXNCopy((TXNObject)m_macTXN);
975 TXNConvertToPublicScrap();
976 }
977 }
978 }
979
980 void wxTextCtrl::Cut()
981 {
982 if (CanCut())
983 {
984 if ( !m_macUsesTXN )
985 {
986 TECut( ((TEHandle) m_macTE) ) ;
987 ClearCurrentScrap();
988 TEToScrap() ;
989 MacRedrawControl() ;
990 }
991 else
992 {
993 ClearCurrentScrap();
994 TXNCut((TXNObject)m_macTXN);
995 TXNConvertToPublicScrap();
996 }
997 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
998 event.SetString( GetValue() ) ;
999 event.SetEventObject( this );
1000 GetEventHandler()->ProcessEvent(event);
1001 }
1002 }
1003
1004 void wxTextCtrl::Paste()
1005 {
1006 if (CanPaste())
1007 {
1008 if ( !m_macUsesTXN )
1009 {
1010 TEFromScrap() ;
1011 TEPaste( (TEHandle) m_macTE ) ;
1012 MacRedrawControl() ;
1013 }
1014 else
1015 {
1016 TXNConvertFromPublicScrap();
1017 TXNPaste((TXNObject)m_macTXN);
1018 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1019 }
1020 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1021 event.SetString( GetValue() ) ;
1022 event.SetEventObject( this );
1023 GetEventHandler()->ProcessEvent(event);
1024 }
1025 }
1026
1027 bool wxTextCtrl::CanCopy() const
1028 {
1029 // Can copy if there's a selection
1030 long from, to;
1031 GetSelection(& from, & to);
1032 return (from != to);
1033 }
1034
1035 bool wxTextCtrl::CanCut() const
1036 {
1037 if ( !IsEditable() )
1038 {
1039 return false ;
1040 }
1041 // Can cut if there's a selection
1042 long from, to;
1043 GetSelection(& from, & to);
1044 return (from != to);
1045 }
1046
1047 bool wxTextCtrl::CanPaste() const
1048 {
1049 if (!IsEditable())
1050 return FALSE;
1051
1052 #if TARGET_CARBON
1053 OSStatus err = noErr;
1054 ScrapRef scrapRef;
1055
1056 err = GetCurrentScrap( &scrapRef );
1057 if ( err != noTypeErr && err != memFullErr )
1058 {
1059 ScrapFlavorFlags flavorFlags;
1060 Size byteCount;
1061
1062 if (( err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags )) == noErr)
1063 {
1064 if (( err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount )) == noErr)
1065 {
1066 return TRUE ;
1067 }
1068 }
1069 }
1070 return FALSE;
1071
1072 #else
1073 long offset ;
1074 if ( GetScrap( NULL , 'TEXT' , &offset ) > 0 )
1075 {
1076 return TRUE ;
1077 }
1078 #endif
1079 return FALSE ;
1080 }
1081
1082 void wxTextCtrl::SetEditable(bool editable)
1083 {
1084 if ( editable != m_editable )
1085 {
1086 m_editable = editable ;
1087 if ( !m_macUsesTXN )
1088 {
1089 if ( editable )
1090 UMAActivateControl( (ControlHandle) m_macControl ) ;
1091 else
1092 UMADeactivateControl((ControlHandle) m_macControl ) ;
1093 }
1094 else
1095 {
1096 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1097 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1098 TXNSetTXNObjectControls( (TXNObject) m_macTXN , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ;
1099 }
1100 }
1101 }
1102
1103 void wxTextCtrl::SetInsertionPoint(long pos)
1104 {
1105 SetSelection( pos , pos ) ;
1106 }
1107
1108 void wxTextCtrl::SetInsertionPointEnd()
1109 {
1110 long pos = GetLastPosition();
1111 SetInsertionPoint(pos);
1112 }
1113
1114 long wxTextCtrl::GetInsertionPoint() const
1115 {
1116 long begin,end ;
1117 GetSelection( &begin , &end ) ;
1118 return begin ;
1119 }
1120
1121 long wxTextCtrl::GetLastPosition() const
1122 {
1123 if ( !m_macUsesTXN )
1124 {
1125 return (**((TEHandle) m_macTE)).teLength ;
1126 }
1127 else
1128 {
1129 Handle theText ;
1130 long actualsize ;
1131 OSErr err = TXNGetDataEncoded( (TXNObject) m_macTXN, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1132 /* all done */
1133 if ( err )
1134 {
1135 actualsize = 0 ;
1136 }
1137 else
1138 {
1139 actualsize = GetHandleSize( theText ) ;
1140 DisposeHandle( theText ) ;
1141 }
1142 return actualsize ;
1143 }
1144 }
1145
1146 void wxTextCtrl::Replace(long from, long to, const wxString& value)
1147 {
1148 if ( !m_macUsesTXN )
1149 {
1150 ControlEditTextSelectionRec selection ;
1151
1152 selection.selStart = from ;
1153 selection.selEnd = to ;
1154 ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1155 TESetSelect( from , to , ((TEHandle) m_macTE) ) ;
1156 TEDelete( ((TEHandle) m_macTE) ) ;
1157 TEInsert( value , value.Length() , ((TEHandle) m_macTE) ) ;
1158 }
1159 else
1160 {
1161 bool formerEditable = m_editable ;
1162 if ( !formerEditable )
1163 SetEditable(true) ;
1164 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1165 TXNClear( ((TXNObject) m_macTXN) ) ;
1166 #if wxUSE_UNICODE
1167 TXNSetData( ((TXNObject) m_macTXN), kTXNUnicodeTextData, (void*)value.wc_str(), value.Length() * 2 ,
1168 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1169 #else
1170 TXNSetData( ((TXNObject) m_macTXN), kTXNTextData, (void*)value.c_str(), value.Length(),
1171 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1172 #endif
1173 if ( !formerEditable )
1174 SetEditable( formerEditable ) ;
1175 }
1176 Refresh() ;
1177 }
1178
1179 void wxTextCtrl::Remove(long from, long to)
1180 {
1181 if ( !m_macUsesTXN )
1182 {
1183 ControlEditTextSelectionRec selection ;
1184
1185 selection.selStart = from ;
1186 selection.selEnd = to ;
1187 ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1188 TEDelete( ((TEHandle) m_macTE) ) ;
1189 }
1190 else
1191 {
1192 bool formerEditable = m_editable ;
1193 if ( !formerEditable )
1194 SetEditable(true) ;
1195 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1196 TXNClear( ((TXNObject) m_macTXN) ) ;
1197 if ( !formerEditable )
1198 SetEditable( formerEditable ) ;
1199 }
1200 Refresh() ;
1201 }
1202
1203 void wxTextCtrl::SetSelection(long from, long to)
1204 {
1205 if ( !m_macUsesTXN )
1206 {
1207 ControlEditTextSelectionRec selection ;
1208 if ((from == -1) && (to == -1))
1209 {
1210 selection.selStart = 0 ;
1211 selection.selEnd = 32767 ;
1212 }
1213 else
1214 {
1215 selection.selStart = from ;
1216 selection.selEnd = to ;
1217 }
1218
1219 TESetSelect( selection.selStart , selection.selEnd , ((TEHandle) m_macTE) ) ;
1220 ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1221 }
1222 else
1223 {
1224 STPTextPaneVars **tpvars;
1225 /* set up our locals */
1226 tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl);
1227 /* and our drawing environment as the operation
1228 may force a redraw in the text area. */
1229 SetPort((**tpvars).fDrawingEnvironment);
1230 /* change the selection */
1231 if ((from == -1) && (to == -1))
1232 TXNSelectAll((TXNObject) m_macTXN);
1233 else
1234 TXNSetSelection( (**tpvars).fTXNRec, from, to);
1235 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1236 }
1237 }
1238
1239 bool wxTextCtrl::LoadFile(const wxString& file)
1240 {
1241 if ( wxTextCtrlBase::LoadFile(file) )
1242 {
1243 return TRUE;
1244 }
1245
1246 return FALSE;
1247 }
1248
1249 void wxTextCtrl::WriteText(const wxString& st)
1250 {
1251 if ( !m_macUsesTXN )
1252 {
1253 wxCharBuffer text = wxMacStringToCString( st ) ;
1254 TEInsert( text , strlen(text) , ((TEHandle) m_macTE) ) ;
1255 }
1256 else
1257 {
1258 bool formerEditable = m_editable ;
1259 if ( !formerEditable )
1260 SetEditable(true) ;
1261 long start , end , dummy ;
1262 GetSelection( &start , &dummy ) ;
1263 #if wxUSE_UNICODE
1264 TXNSetData( ((TXNObject) m_macTXN), kTXNUnicodeTextData, (void*)st.wc_str(), st.Length() * 2 ,
1265 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1266 #else
1267 wxCharBuffer text = wxMacStringToCString( st ) ;
1268 TXNSetData( ((TXNObject) m_macTXN), kTXNTextData, (void*)text.data(), strlen( text ) ,
1269 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1270 #endif
1271 GetSelection( &dummy , &end ) ;
1272 SetStyle( start , end , GetDefaultStyle() ) ;
1273 if ( !formerEditable )
1274 SetEditable( formerEditable ) ;
1275 }
1276 MacRedrawControl() ;
1277 }
1278
1279 void wxTextCtrl::AppendText(const wxString& text)
1280 {
1281 SetInsertionPointEnd();
1282 WriteText(text);
1283 }
1284
1285 void wxTextCtrl::Clear()
1286 {
1287 if ( !IsEditable() )
1288 {
1289 return ;
1290 }
1291 if ( !m_macUsesTXN )
1292 {
1293 ::SetControlData((ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 0 , (char*) ((const char*)NULL) ) ;
1294 }
1295 else
1296 {
1297 TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ;
1298 TXNClear((TXNObject)m_macTXN);
1299 }
1300 Refresh() ;
1301 }
1302
1303 bool wxTextCtrl::IsModified() const
1304 {
1305 return TRUE;
1306 }
1307
1308 bool wxTextCtrl::IsEditable() const
1309 {
1310 return IsEnabled() && m_editable ;
1311 }
1312
1313 bool wxTextCtrl::AcceptsFocus() const
1314 {
1315 // we don't want focus if we can't be edited
1316 return /*IsEditable() && */ wxControl::AcceptsFocus();
1317 }
1318
1319 wxSize wxTextCtrl::DoGetBestSize() const
1320 {
1321 int wText = 100 ;
1322
1323 int hText;
1324 if ( m_macUsesTXN )
1325 {
1326 hText = 17 ;
1327 }
1328 else
1329 {
1330 hText = 13 ;
1331 }
1332 /*
1333 int cx, cy;
1334 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
1335
1336 int wText = DEFAULT_ITEM_WIDTH;
1337
1338 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
1339
1340 return wxSize(wText, hText);
1341 */
1342 if ( m_windowStyle & wxTE_MULTILINE )
1343 {
1344 hText *= 5 ;
1345 }
1346 hText += 2 * m_macVerticalBorder ;
1347 wText += 2 * m_macHorizontalBorder ;
1348 //else: for single line control everything is ok
1349 return wxSize(wText, hText);
1350 }
1351
1352 // ----------------------------------------------------------------------------
1353 // Undo/redo
1354 // ----------------------------------------------------------------------------
1355
1356 void wxTextCtrl::Undo()
1357 {
1358 if (CanUndo())
1359 {
1360 if ( m_macUsesTXN )
1361 {
1362 TXNUndo((TXNObject)m_macTXN);
1363 }
1364 }
1365 }
1366
1367 void wxTextCtrl::Redo()
1368 {
1369 if (CanRedo())
1370 {
1371 if ( m_macUsesTXN )
1372 {
1373 TXNRedo((TXNObject)m_macTXN);
1374 }
1375 }
1376 }
1377
1378 bool wxTextCtrl::CanUndo() const
1379 {
1380 if ( !IsEditable() )
1381 {
1382 return false ;
1383 }
1384 if ( m_macUsesTXN )
1385 {
1386 return TXNCanUndo((TXNObject)m_macTXN,NULL);
1387 }
1388 return FALSE ;
1389 }
1390
1391 bool wxTextCtrl::CanRedo() const
1392 {
1393 if ( !IsEditable() )
1394 {
1395 return false ;
1396 }
1397 if ( m_macUsesTXN )
1398 {
1399 return TXNCanRedo((TXNObject)m_macTXN,NULL);
1400 }
1401 return FALSE ;
1402 }
1403
1404 // Makes 'unmodified'
1405 void wxTextCtrl::DiscardEdits()
1406 {
1407 // TODO
1408 }
1409
1410 int wxTextCtrl::GetNumberOfLines() const
1411 {
1412 // TODO change this if possible to reflect real lines
1413 wxString content = GetValue() ;
1414
1415 int count = 1;
1416 for (size_t i = 0; i < content.Length() ; i++)
1417 {
1418 if (content[i] == '\r') count++;
1419 }
1420
1421 return count;
1422 }
1423
1424 long wxTextCtrl::XYToPosition(long x, long y) const
1425 {
1426 // TODO
1427 return 0;
1428 }
1429
1430 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
1431 {
1432 return FALSE ;
1433 }
1434
1435 void wxTextCtrl::ShowPosition(long pos)
1436 {
1437 // TODO
1438 }
1439
1440 int wxTextCtrl::GetLineLength(long lineNo) const
1441 {
1442 // TODO change this if possible to reflect real lines
1443 wxString content = GetValue() ;
1444
1445 // Find line first
1446 int count = 0;
1447 for (size_t i = 0; i < content.Length() ; i++)
1448 {
1449 if (count == lineNo)
1450 {
1451 // Count chars in line then
1452 count = 0;
1453 for (size_t j = i; j < content.Length(); j++)
1454 {
1455 count++;
1456 if (content[j] == '\r') return count;
1457 }
1458
1459 return count;
1460 }
1461 if (content[i] == '\r') count++;
1462 }
1463 return 0;
1464 }
1465
1466 wxString wxTextCtrl::GetLineText(long lineNo) const
1467 {
1468 // TODO change this if possible to reflect real lines
1469 wxString content = GetValue() ;
1470
1471 // Find line first
1472 int count = 0;
1473 for (size_t i = 0; i < content.Length() ; i++)
1474 {
1475 if (count == lineNo)
1476 {
1477 // Add chars in line then
1478 wxString tmp;
1479
1480 for (size_t j = i; j < content.Length(); j++)
1481 {
1482 if (content[j] == '\r')
1483 return tmp;
1484
1485 tmp += content[j];
1486 }
1487
1488 return tmp;
1489 }
1490 if (content[i] == '\r') count++;
1491 }
1492 return wxEmptyString ;
1493 }
1494
1495 /*
1496 * Text item
1497 */
1498
1499 void wxTextCtrl::Command(wxCommandEvent & event)
1500 {
1501 SetValue (event.GetString());
1502 ProcessCommand (event);
1503 }
1504
1505 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
1506 {
1507 // By default, load the first file into the text window.
1508 if (event.GetNumberOfFiles() > 0)
1509 {
1510 LoadFile(event.GetFiles()[0]);
1511 }
1512 }
1513
1514 void wxTextCtrl::OnChar(wxKeyEvent& event)
1515 {
1516 int key = event.GetKeyCode() ;
1517 bool eat_key = false ;
1518
1519 if ( key == 'c' && event.MetaDown() )
1520 {
1521 if ( CanCopy() )
1522 Copy() ;
1523 return ;
1524 }
1525
1526 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
1527 !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1528 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1529 )
1530 {
1531 // eat it
1532 return ;
1533 }
1534 if ( key == 'v' && event.MetaDown() )
1535 {
1536 if ( CanPaste() )
1537 Paste() ;
1538 return ;
1539 }
1540 if ( key == 'x' && event.MetaDown() )
1541 {
1542 if ( CanCut() )
1543 Cut() ;
1544 return ;
1545 }
1546 switch ( key )
1547 {
1548 case WXK_RETURN:
1549 if (m_windowStyle & wxPROCESS_ENTER)
1550 {
1551 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1552 event.SetEventObject( this );
1553 event.SetString( GetValue() );
1554 if ( GetEventHandler()->ProcessEvent(event) )
1555 return;
1556 }
1557 if ( !(m_windowStyle & wxTE_MULTILINE) )
1558 {
1559 wxWindow *parent = GetParent();
1560 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
1561 parent = parent->GetParent() ;
1562 }
1563 if ( parent && parent->GetDefaultItem() )
1564 {
1565 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
1566 wxButton);
1567 if ( def && def->IsEnabled() )
1568 {
1569 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
1570 event.SetEventObject(def);
1571 def->Command(event);
1572 return ;
1573 }
1574 }
1575
1576 // this will make wxWindows eat the ENTER key so that
1577 // we actually prevent line wrapping in a single line
1578 // text control
1579 eat_key = TRUE;
1580 }
1581
1582 break;
1583
1584 case WXK_TAB:
1585 // always produce navigation event - even if we process TAB
1586 // ourselves the fact that we got here means that the user code
1587 // decided to skip processing of this TAB - probably to let it
1588 // do its default job.
1589 {
1590 wxNavigationKeyEvent eventNav;
1591 eventNav.SetDirection(!event.ShiftDown());
1592 eventNav.SetWindowChange(event.ControlDown());
1593 eventNav.SetEventObject(this);
1594
1595 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
1596 return;
1597
1598 event.Skip() ;
1599 return;
1600 }
1601 break;
1602 }
1603
1604 if (!eat_key)
1605 {
1606 // perform keystroke handling
1607 #if TARGET_CARBON
1608 if ( m_macUsesTXN && wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
1609 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
1610 else
1611 #endif
1612 {
1613 EventRecord rec ;
1614 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
1615 {
1616 EventRecord *ev = &rec ;
1617 short keycode ;
1618 short keychar ;
1619 keychar = short(ev->message & charCodeMask);
1620 keycode = short(ev->message & keyCodeMask) >> 8 ;
1621
1622 ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ;
1623 }
1624 }
1625 }
1626 if ( ( key >= 0x20 && key < WXK_START ) ||
1627 key == WXK_RETURN ||
1628 key == WXK_DELETE ||
1629 key == WXK_BACK)
1630 {
1631 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1632 event1.SetString( GetValue() ) ;
1633 event1.SetEventObject( this );
1634 wxPostEvent(GetEventHandler(),event1);
1635 }
1636 }
1637
1638 void wxTextCtrl::MacSuperShown( bool show )
1639 {
1640 bool former = m_macControlIsShown ;
1641 wxControl::MacSuperShown( show ) ;
1642 if ( (former != m_macControlIsShown) && m_macUsesTXN )
1643 {
1644 if ( m_macControlIsShown )
1645 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1646 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1647 else
1648 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1649 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1650 }
1651 }
1652
1653 bool wxTextCtrl::Show(bool show)
1654 {
1655 bool former = m_macControlIsShown ;
1656
1657 bool retval = wxControl::Show( show ) ;
1658
1659 if ( former != m_macControlIsShown && m_macUsesTXN )
1660 {
1661 if ( m_macControlIsShown )
1662 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1663 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1664 else
1665 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1666 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1667 }
1668
1669 return retval ;
1670 }
1671
1672 // ----------------------------------------------------------------------------
1673 // standard handlers for standard edit menu events
1674 // ----------------------------------------------------------------------------
1675
1676 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1677 {
1678 Cut();
1679 }
1680
1681 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1682 {
1683 Copy();
1684 }
1685
1686 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1687 {
1688 Paste();
1689 }
1690
1691 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1692 {
1693 Undo();
1694 }
1695
1696 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1697 {
1698 Redo();
1699 }
1700
1701 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1702 {
1703 event.Enable( CanCut() );
1704 }
1705
1706 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1707 {
1708 event.Enable( CanCopy() );
1709 }
1710
1711 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1712 {
1713 event.Enable( CanPaste() );
1714 }
1715
1716 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1717 {
1718 event.Enable( CanUndo() );
1719 }
1720
1721 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1722 {
1723 event.Enable( CanRedo() );
1724 }
1725
1726 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1727 {
1728 if ( m_macUsesTXN )
1729 return true ;
1730 else
1731 return wxWindow::MacSetupCursor( pt ) ;
1732 }
1733
1734 #endif
1735 // wxUSE_TEXTCTRL