Include wx/msgdlg.h according to precompiled headers of wx/wx.h (with other minor...
[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 #endif
30
31 #ifdef __DARWIN__
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #else
35 #include <stat.h>
36 #endif
37
38 #if wxUSE_STD_IOSTREAM
39 #if wxUSE_IOSTREAMH
40 #include <fstream.h>
41 #else
42 #include <fstream>
43 #endif
44 #endif
45
46 #include "wx/toplevel.h"
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, wxControl)
644
645 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
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.Len() ;
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 bool wxTextCtrl::LoadFile(const wxString& file)
1279 {
1280 if ( wxTextCtrlBase::LoadFile(file) )
1281 {
1282 return true;
1283 }
1284
1285 return false;
1286 }
1287
1288 void wxTextCtrl::WriteText(const wxString& str)
1289 {
1290 wxString st = str ;
1291 wxMacConvertNewlines13To10( &st ) ;
1292 if ( !m_macUsesTXN )
1293 {
1294 wxCharBuffer text = st.mb_str(wxConvLocal) ;
1295 TEInsert( text , strlen(text) , ((TEHandle) m_macTE) ) ;
1296 }
1297 else
1298 {
1299 bool formerEditable = m_editable ;
1300 if ( !formerEditable )
1301 SetEditable(true) ;
1302 long start , end , dummy ;
1303 GetSelection( &start , &dummy ) ;
1304 SetTXNData( (TXNObject) m_macTXN , st , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1305 GetSelection( &dummy , &end ) ;
1306 SetStyle( start , end , GetDefaultStyle() ) ;
1307 if ( !formerEditable )
1308 SetEditable( formerEditable ) ;
1309 }
1310 MacRedrawControl() ;
1311 }
1312
1313 void wxTextCtrl::AppendText(const wxString& text)
1314 {
1315 SetInsertionPointEnd();
1316 WriteText(text);
1317 }
1318
1319 void wxTextCtrl::Clear()
1320 {
1321 if ( !m_macUsesTXN )
1322 {
1323 ::SetControlData((ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 0 , (char*) ((const char*)NULL) ) ;
1324 }
1325 else
1326 {
1327 TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ;
1328 TXNClear((TXNObject)m_macTXN);
1329 }
1330 Refresh() ;
1331 }
1332
1333 bool wxTextCtrl::IsModified() const
1334 {
1335 return m_dirty;
1336 }
1337
1338 bool wxTextCtrl::IsEditable() const
1339 {
1340 return IsEnabled() && m_editable ;
1341 }
1342
1343 bool wxTextCtrl::AcceptsFocus() const
1344 {
1345 // we don't want focus if we can't be edited
1346 return /*IsEditable() && */ wxControl::AcceptsFocus();
1347 }
1348
1349 wxSize wxTextCtrl::DoGetBestSize() const
1350 {
1351 int wText = 100 ;
1352
1353 int hText;
1354 if ( m_macUsesTXN )
1355 {
1356 hText = 17 ;
1357 }
1358 else
1359 {
1360 hText = 13 ;
1361 }
1362 /*
1363 int cx, cy;
1364 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
1365
1366 int wText = DEFAULT_ITEM_WIDTH;
1367
1368 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
1369
1370 return wxSize(wText, hText);
1371 */
1372 if ( m_windowStyle & wxTE_MULTILINE )
1373 {
1374 hText *= 5 ;
1375 }
1376 hText += 2 * m_macVerticalBorder ;
1377 wText += 2 * m_macHorizontalBorder ;
1378 //else: for single line control everything is ok
1379 return wxSize(wText, hText);
1380 }
1381
1382 // ----------------------------------------------------------------------------
1383 // Undo/redo
1384 // ----------------------------------------------------------------------------
1385
1386 void wxTextCtrl::Undo()
1387 {
1388 if (CanUndo())
1389 {
1390 if ( m_macUsesTXN )
1391 {
1392 TXNUndo((TXNObject)m_macTXN);
1393 }
1394 }
1395 }
1396
1397 void wxTextCtrl::Redo()
1398 {
1399 if (CanRedo())
1400 {
1401 if ( m_macUsesTXN )
1402 {
1403 TXNRedo((TXNObject)m_macTXN);
1404 }
1405 }
1406 }
1407
1408 bool wxTextCtrl::CanUndo() const
1409 {
1410 if ( !IsEditable() )
1411 {
1412 return false ;
1413 }
1414 if ( m_macUsesTXN )
1415 {
1416 return TXNCanUndo((TXNObject)m_macTXN,NULL);
1417 }
1418 return false ;
1419 }
1420
1421 bool wxTextCtrl::CanRedo() const
1422 {
1423 if ( !IsEditable() )
1424 {
1425 return false ;
1426 }
1427 if ( m_macUsesTXN )
1428 {
1429 return TXNCanRedo((TXNObject)m_macTXN,NULL);
1430 }
1431 return false ;
1432 }
1433
1434 // Makes modifie or unmodified
1435 void wxTextCtrl::MarkDirty()
1436 {
1437 m_dirty = true;
1438 }
1439
1440 void wxTextCtrl::DiscardEdits()
1441 {
1442 m_dirty = false;
1443 }
1444
1445 int wxTextCtrl::GetNumberOfLines() const
1446 {
1447 if ( m_macUsesTXN )
1448 {
1449 ItemCount lines ;
1450 TXNGetLineCount((TXNObject)m_macTXN, &lines ) ;
1451 return lines ;
1452 }
1453 else
1454 {
1455 wxString content = GetValue() ;
1456
1457 int count = 1;
1458 for (size_t i = 0; i < content.length() ; i++)
1459 {
1460 if (content[i] == '\r') count++;
1461 }
1462 return count;
1463 }
1464 }
1465
1466 long wxTextCtrl::XYToPosition(long x, long y) const
1467 {
1468 // TODO
1469 return 0;
1470 }
1471
1472 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
1473 {
1474 return false ;
1475 }
1476
1477 void wxTextCtrl::ShowPosition(long pos)
1478 {
1479 #if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER)
1480 if ( m_macUsesTXN )
1481 {
1482 Point current ;
1483 Point desired ;
1484 TXNOffset selstart , selend ;
1485 TXNGetSelection( (TXNObject) m_macTXN , &selstart , &selend) ;
1486 TXNOffsetToPoint( (TXNObject) m_macTXN, selstart , &current);
1487 TXNOffsetToPoint( (TXNObject) m_macTXN, pos , &desired);
1488 //TODO use HIPoints for 10.3 and above
1489 if ( (UInt32) TXNScroll != (UInt32) kUnresolvedCFragSymbolAddress )
1490 {
1491 OSErr theErr = noErr;
1492 SInt32 dv = desired.v - current.v ;
1493 SInt32 dh = desired.h - current.h ;
1494 TXNShowSelection( (TXNObject) m_macTXN , true ) ;
1495 theErr = TXNScroll( (TXNObject) m_macTXN, kTXNScrollUnitsInPixels , kTXNScrollUnitsInPixels , &dv , &dh );
1496 wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
1497 }
1498 }
1499 #endif
1500 }
1501
1502 int wxTextCtrl::GetLineLength(long lineNo) const
1503 {
1504 // TODO change this if possible to reflect real lines
1505 wxString content = GetValue() ;
1506
1507 // Find line first
1508 int count = 0;
1509 for (size_t i = 0; i < content.length() ; i++)
1510 {
1511 if (count == lineNo)
1512 {
1513 // Count chars in line then
1514 count = 0;
1515 for (size_t j = i; j < content.length(); j++)
1516 {
1517 count++;
1518 if (content[j] == '\n') return count;
1519 }
1520
1521 return count;
1522 }
1523 if (content[i] == '\n') count++;
1524 }
1525 return 0;
1526 }
1527
1528 wxString wxTextCtrl::GetLineText(long lineNo) const
1529 {
1530 // TODO change this if possible to reflect real lines
1531 wxString content = GetValue() ;
1532
1533 // Find line first
1534 int count = 0;
1535 for (size_t i = 0; i < content.length() ; i++)
1536 {
1537 if (count == lineNo)
1538 {
1539 // Add chars in line then
1540 wxString tmp;
1541
1542 for (size_t j = i; j < content.length(); j++)
1543 {
1544 if (content[j] == '\n')
1545 return tmp;
1546
1547 tmp += content[j];
1548 }
1549
1550 return tmp;
1551 }
1552 if (content[i] == '\n') count++;
1553 }
1554 return wxEmptyString ;
1555 }
1556
1557 /*
1558 * Text item
1559 */
1560
1561 void wxTextCtrl::Command(wxCommandEvent & event)
1562 {
1563 SetValue (event.GetString());
1564 ProcessCommand (event);
1565 }
1566
1567 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
1568 {
1569 // By default, load the first file into the text window.
1570 if (event.GetNumberOfFiles() > 0)
1571 {
1572 LoadFile(event.GetFiles()[0]);
1573 }
1574 }
1575
1576 void wxTextCtrl::OnChar(wxKeyEvent& event)
1577 {
1578 int key = event.GetKeyCode() ;
1579 bool eat_key = false ;
1580
1581 if ( key == 'c' && event.MetaDown() )
1582 {
1583 if ( CanCopy() )
1584 Copy() ;
1585 return ;
1586 }
1587
1588 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
1589 !( key == WXK_RETURN && ( (m_windowStyle & wxTE_PROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1590 /* && key != WXK_PAGEUP && key != WXK_PAGEDOWN && key != WXK_HOME && key != WXK_END */
1591 )
1592 {
1593 // eat it
1594 return ;
1595 }
1596
1597 // assume that any key not processed yet is going to modify the control
1598 m_dirty = true;
1599
1600 if ( key == 'v' && event.MetaDown() )
1601 {
1602 if ( CanPaste() )
1603 Paste() ;
1604 return ;
1605 }
1606 if ( key == 'x' && event.MetaDown() )
1607 {
1608 if ( CanCut() )
1609 Cut() ;
1610 return ;
1611 }
1612 switch ( key )
1613 {
1614 case WXK_RETURN:
1615 if (m_windowStyle & wxTE_PROCESS_ENTER)
1616 {
1617 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1618 event.SetEventObject( this );
1619 event.SetString( GetValue() );
1620 if ( GetEventHandler()->ProcessEvent(event) )
1621 return;
1622 }
1623 if ( !(m_windowStyle & wxTE_MULTILINE) )
1624 {
1625 wxWindow *parent = GetParent();
1626 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
1627 parent = parent->GetParent() ;
1628 }
1629 if ( parent && parent->GetDefaultItem() )
1630 {
1631 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
1632 wxButton);
1633 if ( def && def->IsEnabled() )
1634 {
1635 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
1636 event.SetEventObject(def);
1637 def->Command(event);
1638 return ;
1639 }
1640 }
1641
1642 // this will make wxWidgets eat the ENTER key so that
1643 // we actually prevent line wrapping in a single line
1644 // text control
1645 eat_key = true;
1646 }
1647
1648 break;
1649
1650 case WXK_TAB:
1651 if ( !(m_windowStyle & wxTE_PROCESS_TAB))
1652 {
1653 int flags = 0;
1654 if (!event.ShiftDown())
1655 flags |= wxNavigationKeyEvent::IsForward ;
1656 if (event.ControlDown())
1657 flags |= wxNavigationKeyEvent::WinChange ;
1658 Navigate(flags);
1659 return;
1660 }
1661 else
1662 {
1663 // This is necessary (don't know why) or the tab will not
1664 // be inserted.
1665 WriteText(wxT("\t"));
1666 }
1667 break;
1668 }
1669
1670 if (!eat_key)
1671 {
1672 // perform keystroke handling
1673 #if TARGET_CARBON
1674 if ( m_macUsesTXN && wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
1675 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
1676 else
1677 {
1678 EventRecord rec ;
1679 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
1680 {
1681 EventRecord *ev = &rec ;
1682 short keycode ;
1683 short keychar ;
1684 keychar = short(ev->message & charCodeMask);
1685 keycode = short(ev->message & keyCodeMask) >> 8 ;
1686
1687 ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ;
1688 }
1689 }
1690 #else
1691 EventRecord *ev = (EventRecord*) wxTheApp->MacGetCurrentEvent() ;
1692 short keycode ;
1693 short keychar ;
1694 keychar = short(ev->message & charCodeMask);
1695 keycode = short(ev->message & keyCodeMask) >> 8 ;
1696
1697 ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ;
1698 #endif
1699 }
1700 if ( ( key >= 0x20 && key < WXK_START ) ||
1701 key == WXK_RETURN ||
1702 key == WXK_DELETE ||
1703 key == WXK_BACK)
1704 {
1705 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1706 event1.SetEventObject( this );
1707 wxPostEvent(GetEventHandler(),event1);
1708 }
1709 }
1710
1711 void wxTextCtrl::MacSuperShown( bool show )
1712 {
1713 bool former = m_macControlIsShown ;
1714 wxControl::MacSuperShown( show ) ;
1715 if ( (former != m_macControlIsShown) && m_macUsesTXN )
1716 {
1717 if ( m_macControlIsShown )
1718 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1719 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1720 else
1721 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1722 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1723 }
1724 }
1725
1726 bool wxTextCtrl::Show(bool show)
1727 {
1728 bool former = m_macControlIsShown ;
1729
1730 bool retval = wxControl::Show( show ) ;
1731
1732 if ( former != m_macControlIsShown && m_macUsesTXN )
1733 {
1734 if ( m_macControlIsShown )
1735 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1736 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1737 else
1738 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1739 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1740 }
1741
1742 return retval ;
1743 }
1744
1745 // ----------------------------------------------------------------------------
1746 // standard handlers for standard edit menu events
1747 // ----------------------------------------------------------------------------
1748
1749 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1750 {
1751 Cut();
1752 }
1753
1754 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1755 {
1756 Copy();
1757 }
1758
1759 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1760 {
1761 Paste();
1762 }
1763
1764 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1765 {
1766 Undo();
1767 }
1768
1769 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1770 {
1771 Redo();
1772 }
1773
1774 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1775 {
1776 event.Enable( CanCut() );
1777 }
1778
1779 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1780 {
1781 event.Enable( CanCopy() );
1782 }
1783
1784 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1785 {
1786 event.Enable( CanPaste() );
1787 }
1788
1789 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1790 {
1791 event.Enable( CanUndo() );
1792 }
1793
1794 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1795 {
1796 event.Enable( CanRedo() );
1797 }
1798
1799 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1800 {
1801 if ( m_macUsesTXN )
1802 return true ;
1803 else
1804 return wxWindow::MacSetupCursor( pt ) ;
1805 }
1806
1807 #endif
1808 // wxUSE_TEXTCTRL