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