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