]> git.saurik.com Git - wxWidgets.git/blob - src/mac/textctrl.cpp
Added a notification observer for NSWindow. Observe the become key and
[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 ( from == -1 )
1206 from = 0;
1207
1208 if ( to == -1 )
1209 to = GetLastPosition();
1210
1211 if ( !m_macUsesTXN )
1212 {
1213 ControlEditTextSelectionRec selection ;
1214 selection.selStart = from ;
1215 selection.selEnd = to ;
1216
1217 TESetSelect( selection.selStart , selection.selEnd , ((TEHandle) m_macTE) ) ;
1218 ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1219 }
1220 else
1221 {
1222 STPTextPaneVars **tpvars;
1223 /* set up our locals */
1224 tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl);
1225 /* and our drawing environment as the operation
1226 may force a redraw in the text area. */
1227 SetPort((**tpvars).fDrawingEnvironment);
1228 /* change the selection */
1229 TXNSetSelection( (**tpvars).fTXNRec, from, to);
1230 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1231 }
1232 }
1233
1234 bool wxTextCtrl::LoadFile(const wxString& file)
1235 {
1236 if ( wxTextCtrlBase::LoadFile(file) )
1237 {
1238 return TRUE;
1239 }
1240
1241 return FALSE;
1242 }
1243
1244 void wxTextCtrl::WriteText(const wxString& st)
1245 {
1246 if ( !m_macUsesTXN )
1247 {
1248 wxCharBuffer text = wxMacStringToCString( st ) ;
1249 TEInsert( text , strlen(text) , ((TEHandle) m_macTE) ) ;
1250 }
1251 else
1252 {
1253 bool formerEditable = m_editable ;
1254 if ( !formerEditable )
1255 SetEditable(true) ;
1256 long start , end , dummy ;
1257 GetSelection( &start , &dummy ) ;
1258 #if wxUSE_UNICODE
1259 TXNSetData( ((TXNObject) m_macTXN), kTXNUnicodeTextData, (void*)st.wc_str(), st.Length() * 2 ,
1260 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1261 #else
1262 wxCharBuffer text = wxMacStringToCString( st ) ;
1263 TXNSetData( ((TXNObject) m_macTXN), kTXNTextData, (void*)text.data(), strlen( text ) ,
1264 kTXNUseCurrentSelection, kTXNUseCurrentSelection);
1265 #endif
1266 GetSelection( &dummy , &end ) ;
1267 SetStyle( start , end , GetDefaultStyle() ) ;
1268 if ( !formerEditable )
1269 SetEditable( formerEditable ) ;
1270 }
1271 MacRedrawControl() ;
1272 }
1273
1274 void wxTextCtrl::AppendText(const wxString& text)
1275 {
1276 SetInsertionPointEnd();
1277 WriteText(text);
1278 }
1279
1280 void wxTextCtrl::Clear()
1281 {
1282 if ( !IsEditable() )
1283 {
1284 return ;
1285 }
1286 if ( !m_macUsesTXN )
1287 {
1288 ::SetControlData((ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 0 , (char*) ((const char*)NULL) ) ;
1289 }
1290 else
1291 {
1292 TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ;
1293 TXNClear((TXNObject)m_macTXN);
1294 }
1295 Refresh() ;
1296 }
1297
1298 bool wxTextCtrl::IsModified() const
1299 {
1300 return TRUE;
1301 }
1302
1303 bool wxTextCtrl::IsEditable() const
1304 {
1305 return IsEnabled() && m_editable ;
1306 }
1307
1308 bool wxTextCtrl::AcceptsFocus() const
1309 {
1310 // we don't want focus if we can't be edited
1311 return /*IsEditable() && */ wxControl::AcceptsFocus();
1312 }
1313
1314 wxSize wxTextCtrl::DoGetBestSize() const
1315 {
1316 int wText = 100 ;
1317
1318 int hText;
1319 if ( m_macUsesTXN )
1320 {
1321 hText = 17 ;
1322 }
1323 else
1324 {
1325 hText = 13 ;
1326 }
1327 /*
1328 int cx, cy;
1329 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
1330
1331 int wText = DEFAULT_ITEM_WIDTH;
1332
1333 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
1334
1335 return wxSize(wText, hText);
1336 */
1337 if ( m_windowStyle & wxTE_MULTILINE )
1338 {
1339 hText *= 5 ;
1340 }
1341 hText += 2 * m_macVerticalBorder ;
1342 wText += 2 * m_macHorizontalBorder ;
1343 //else: for single line control everything is ok
1344 return wxSize(wText, hText);
1345 }
1346
1347 // ----------------------------------------------------------------------------
1348 // Undo/redo
1349 // ----------------------------------------------------------------------------
1350
1351 void wxTextCtrl::Undo()
1352 {
1353 if (CanUndo())
1354 {
1355 if ( m_macUsesTXN )
1356 {
1357 TXNUndo((TXNObject)m_macTXN);
1358 }
1359 }
1360 }
1361
1362 void wxTextCtrl::Redo()
1363 {
1364 if (CanRedo())
1365 {
1366 if ( m_macUsesTXN )
1367 {
1368 TXNRedo((TXNObject)m_macTXN);
1369 }
1370 }
1371 }
1372
1373 bool wxTextCtrl::CanUndo() const
1374 {
1375 if ( !IsEditable() )
1376 {
1377 return false ;
1378 }
1379 if ( m_macUsesTXN )
1380 {
1381 return TXNCanUndo((TXNObject)m_macTXN,NULL);
1382 }
1383 return FALSE ;
1384 }
1385
1386 bool wxTextCtrl::CanRedo() const
1387 {
1388 if ( !IsEditable() )
1389 {
1390 return false ;
1391 }
1392 if ( m_macUsesTXN )
1393 {
1394 return TXNCanRedo((TXNObject)m_macTXN,NULL);
1395 }
1396 return FALSE ;
1397 }
1398
1399 // Makes 'unmodified'
1400 void wxTextCtrl::DiscardEdits()
1401 {
1402 // TODO
1403 }
1404
1405 int wxTextCtrl::GetNumberOfLines() const
1406 {
1407 // TODO change this if possible to reflect real lines
1408 wxString content = GetValue() ;
1409
1410 int count = 1;
1411 for (size_t i = 0; i < content.Length() ; i++)
1412 {
1413 if (content[i] == '\r') count++;
1414 }
1415
1416 return count;
1417 }
1418
1419 long wxTextCtrl::XYToPosition(long x, long y) const
1420 {
1421 // TODO
1422 return 0;
1423 }
1424
1425 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
1426 {
1427 return FALSE ;
1428 }
1429
1430 void wxTextCtrl::ShowPosition(long pos)
1431 {
1432 // TODO
1433 }
1434
1435 int wxTextCtrl::GetLineLength(long lineNo) const
1436 {
1437 // TODO change this if possible to reflect real lines
1438 wxString content = GetValue() ;
1439
1440 // Find line first
1441 int count = 0;
1442 for (size_t i = 0; i < content.Length() ; i++)
1443 {
1444 if (count == lineNo)
1445 {
1446 // Count chars in line then
1447 count = 0;
1448 for (size_t j = i; j < content.Length(); j++)
1449 {
1450 count++;
1451 if (content[j] == '\r') return count;
1452 }
1453
1454 return count;
1455 }
1456 if (content[i] == '\r') count++;
1457 }
1458 return 0;
1459 }
1460
1461 wxString wxTextCtrl::GetLineText(long lineNo) const
1462 {
1463 // TODO change this if possible to reflect real lines
1464 wxString content = GetValue() ;
1465
1466 // Find line first
1467 int count = 0;
1468 for (size_t i = 0; i < content.Length() ; i++)
1469 {
1470 if (count == lineNo)
1471 {
1472 // Add chars in line then
1473 wxString tmp;
1474
1475 for (size_t j = i; j < content.Length(); j++)
1476 {
1477 if (content[j] == '\r')
1478 return tmp;
1479
1480 tmp += content[j];
1481 }
1482
1483 return tmp;
1484 }
1485 if (content[i] == '\r') count++;
1486 }
1487 return wxEmptyString ;
1488 }
1489
1490 /*
1491 * Text item
1492 */
1493
1494 void wxTextCtrl::Command(wxCommandEvent & event)
1495 {
1496 SetValue (event.GetString());
1497 ProcessCommand (event);
1498 }
1499
1500 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
1501 {
1502 // By default, load the first file into the text window.
1503 if (event.GetNumberOfFiles() > 0)
1504 {
1505 LoadFile(event.GetFiles()[0]);
1506 }
1507 }
1508
1509 void wxTextCtrl::OnChar(wxKeyEvent& event)
1510 {
1511 int key = event.GetKeyCode() ;
1512 bool eat_key = false ;
1513
1514 if ( key == 'c' && event.MetaDown() )
1515 {
1516 if ( CanCopy() )
1517 Copy() ;
1518 return ;
1519 }
1520
1521 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
1522 !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1523 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1524 )
1525 {
1526 // eat it
1527 return ;
1528 }
1529 if ( key == 'v' && event.MetaDown() )
1530 {
1531 if ( CanPaste() )
1532 Paste() ;
1533 return ;
1534 }
1535 if ( key == 'x' && event.MetaDown() )
1536 {
1537 if ( CanCut() )
1538 Cut() ;
1539 return ;
1540 }
1541 switch ( key )
1542 {
1543 case WXK_RETURN:
1544 if (m_windowStyle & wxPROCESS_ENTER)
1545 {
1546 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1547 event.SetEventObject( this );
1548 event.SetString( GetValue() );
1549 if ( GetEventHandler()->ProcessEvent(event) )
1550 return;
1551 }
1552 if ( !(m_windowStyle & wxTE_MULTILINE) )
1553 {
1554 wxWindow *parent = GetParent();
1555 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
1556 parent = parent->GetParent() ;
1557 }
1558 if ( parent && parent->GetDefaultItem() )
1559 {
1560 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
1561 wxButton);
1562 if ( def && def->IsEnabled() )
1563 {
1564 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
1565 event.SetEventObject(def);
1566 def->Command(event);
1567 return ;
1568 }
1569 }
1570
1571 // this will make wxWindows eat the ENTER key so that
1572 // we actually prevent line wrapping in a single line
1573 // text control
1574 eat_key = TRUE;
1575 }
1576
1577 break;
1578
1579 case WXK_TAB:
1580 // always produce navigation event - even if we process TAB
1581 // ourselves the fact that we got here means that the user code
1582 // decided to skip processing of this TAB - probably to let it
1583 // do its default job.
1584 {
1585 wxNavigationKeyEvent eventNav;
1586 eventNav.SetDirection(!event.ShiftDown());
1587 eventNav.SetWindowChange(event.ControlDown());
1588 eventNav.SetEventObject(this);
1589
1590 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
1591 return;
1592
1593 event.Skip() ;
1594 return;
1595 }
1596 break;
1597 }
1598
1599 if (!eat_key)
1600 {
1601 // perform keystroke handling
1602 #if TARGET_CARBON
1603 if ( m_macUsesTXN && wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
1604 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
1605 else
1606 #endif
1607 {
1608 EventRecord rec ;
1609 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
1610 {
1611 EventRecord *ev = &rec ;
1612 short keycode ;
1613 short keychar ;
1614 keychar = short(ev->message & charCodeMask);
1615 keycode = short(ev->message & keyCodeMask) >> 8 ;
1616
1617 ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ;
1618 }
1619 }
1620 }
1621 if ( ( key >= 0x20 && key < WXK_START ) ||
1622 key == WXK_RETURN ||
1623 key == WXK_DELETE ||
1624 key == WXK_BACK)
1625 {
1626 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1627 event1.SetString( GetValue() ) ;
1628 event1.SetEventObject( this );
1629 wxPostEvent(GetEventHandler(),event1);
1630 }
1631 }
1632
1633 void wxTextCtrl::MacSuperShown( bool show )
1634 {
1635 bool former = m_macControlIsShown ;
1636 wxControl::MacSuperShown( show ) ;
1637 if ( (former != m_macControlIsShown) && m_macUsesTXN )
1638 {
1639 if ( m_macControlIsShown )
1640 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1641 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1642 else
1643 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1644 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1645 }
1646 }
1647
1648 bool wxTextCtrl::Show(bool show)
1649 {
1650 bool former = m_macControlIsShown ;
1651
1652 bool retval = wxControl::Show( show ) ;
1653
1654 if ( former != m_macControlIsShown && m_macUsesTXN )
1655 {
1656 if ( m_macControlIsShown )
1657 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1658 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1659 else
1660 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1661 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1662 }
1663
1664 return retval ;
1665 }
1666
1667 // ----------------------------------------------------------------------------
1668 // standard handlers for standard edit menu events
1669 // ----------------------------------------------------------------------------
1670
1671 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1672 {
1673 Cut();
1674 }
1675
1676 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1677 {
1678 Copy();
1679 }
1680
1681 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1682 {
1683 Paste();
1684 }
1685
1686 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1687 {
1688 Undo();
1689 }
1690
1691 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1692 {
1693 Redo();
1694 }
1695
1696 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1697 {
1698 event.Enable( CanCut() );
1699 }
1700
1701 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1702 {
1703 event.Enable( CanCopy() );
1704 }
1705
1706 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1707 {
1708 event.Enable( CanPaste() );
1709 }
1710
1711 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1712 {
1713 event.Enable( CanUndo() );
1714 }
1715
1716 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1717 {
1718 event.Enable( CanRedo() );
1719 }
1720
1721 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1722 {
1723 if ( m_macUsesTXN )
1724 return true ;
1725 else
1726 return wxWindow::MacSetupCursor( pt ) ;
1727 }
1728
1729 #endif
1730 // wxUSE_TEXTCTRL