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