Include wx/settings.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 #endif
29
30 #ifdef __DARWIN__
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #else
34 #include <stat.h>
35 #endif
36
37 #include "wx/msgdlg.h"
38
39 #if wxUSE_STD_IOSTREAM
40 #if wxUSE_IOSTREAMH
41 #include <fstream.h>
42 #else
43 #include <fstream>
44 #endif
45 #endif
46
47 #include "wx/toplevel.h"
48 #include "wx/notebook.h"
49 #include "wx/tabctrl.h"
50 #include "wx/filefn.h"
51
52 #if defined(__BORLANDC__) && !defined(__WIN32__)
53 #include <alloc.h>
54 #elif !defined(__MWERKS__) && !defined(__GNUWIN32) && !defined(__DARWIN__)
55 #include <malloc.h>
56 #endif
57
58 #ifndef __DARWIN__
59 #include <Scrap.h>
60 #endif
61 #include <MacTextEditor.h>
62 #include <ATSUnicode.h>
63 #include <TextCommon.h>
64 #include <TextEncodingConverter.h>
65 #include "wx/mac/uma.h"
66
67 #define TE_UNLIMITED_LENGTH 0xFFFFFFFFUL
68
69 extern wxControl *wxFindControlFromMacControl(ControlHandle inControl ) ;
70
71 // CS:TODO we still have a problem getting properly at the text events of a control because under Carbon
72 // the MLTE engine registers itself for the key events thus the normal flow never occurs, the only measure for the
73 // moment is to avoid setting the true focus on the control, the proper solution at the end would be to have
74 // an alternate path for carbon key events that routes automatically into the same wx flow of events
75
76 /* part codes */
77
78 /* kmUPTextPart is the part code we return to indicate the user has clicked
79 in the text area of our control */
80 #define kmUPTextPart 1
81
82 /* kmUPScrollPart is the part code we return to indicate the user has clicked
83 in the scroll bar part of the control. */
84 #define kmUPScrollPart 2
85
86
87 /* routines for using existing user pane controls.
88 These routines are useful for cases where you would like to use an
89 existing user pane control in, say, a dialog window as a scrolling
90 text edit field.*/
91
92 /* mUPOpenControl initializes a user pane control so it will be drawn
93 and will behave as a scrolling text edit field inside of a window.
94 This routine performs all of the initialization steps necessary,
95 except it does not create the user pane control itself. theControl
96 should refer to a user pane control that you have either created
97 yourself or extracted from a dialog's control heirarchy using
98 the GetDialogItemAsControl routine. */
99 OSStatus mUPOpenControl(ControlHandle theControl, long wxStyle);
100
101 /* Utility Routines */
102
103 enum {
104 kShiftKeyCode = 56
105 };
106
107 /* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus
108 routine. In our focus switching routine this part code is understood
109 as meaning 'the user has clicked in the control and we need to switch
110 the current focus to ourselves before we can continue'. */
111 #define kUserClickedToFocusPart 100
112
113
114 /* kmUPClickScrollDelayTicks is a time measurement in ticks used to
115 slow the speed of 'auto scrolling' inside of our clickloop routine.
116 This value prevents the text from wizzzzzing by while the mouse
117 is being held down inside of the text area. */
118 #define kmUPClickScrollDelayTicks 3
119
120
121 /* STPTextPaneVars is a structure used for storing the the mUP Control's
122 internal variables and state information. A handle to this record is
123 stored in the pane control's reference value field using the
124 SetControlReference routine. */
125
126 typedef struct {
127 /* OS records referenced */
128 TXNObject fTXNRec; /* the txn record */
129 TXNFrameID fTXNFrame; /* the txn frame ID */
130 ControlHandle fUserPaneRec; /* handle to the user pane control */
131 WindowPtr fOwner; /* window containing control */
132 GrafPtr fDrawingEnvironment; /* grafport where control is drawn */
133 /* flags */
134 Boolean fInFocus; /* true while the focus rect is drawn around the control */
135 Boolean fIsActive; /* true while the control is drawn in the active state */
136 Boolean fTEActive; /* reflects the activation state of the text edit record */
137 Boolean fInDialogWindow; /* true if displayed in a dialog window */
138 /* calculated locations */
139 Rect fRTextArea; /* area where the text is drawn */
140 Rect fRFocusOutline; /* rectangle used to draw the focus box */
141 Rect fRTextOutline; /* rectangle used to draw the border */
142 RgnHandle fTextBackgroundRgn; /* background region for the text, erased before calling TEUpdate */
143 /* our focus advance override routine */
144 EventHandlerUPP handlerUPP;
145 EventHandlerRef handlerRef;
146 bool fMultiline ;
147 } STPTextPaneVars;
148
149
150
151
152 /* Univerals Procedure Pointer variables used by the
153 mUP Control. These variables are set up
154 the first time that mUPOpenControl is called. */
155 ControlUserPaneDrawUPP gTPDrawProc = NULL;
156 ControlUserPaneHitTestUPP gTPHitProc = NULL;
157 ControlUserPaneTrackingUPP gTPTrackProc = NULL;
158 ControlUserPaneIdleUPP gTPIdleProc = NULL;
159 ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
160 ControlUserPaneActivateUPP gTPActivateProc = NULL;
161 ControlUserPaneFocusUPP gTPFocusProc = NULL;
162
163 /* TPActivatePaneText activates or deactivates the text edit record
164 according to the value of setActive. The primary purpose of this
165 routine is to ensure each call is only made once. */
166 static void TPActivatePaneText(STPTextPaneVars **tpvars, Boolean setActive) {
167 STPTextPaneVars *varsp;
168 varsp = *tpvars;
169 if (varsp->fTEActive != setActive) {
170
171 varsp->fTEActive = setActive;
172
173 TXNActivate(varsp->fTXNRec, varsp->fTXNFrame, varsp->fTEActive);
174
175 if (varsp->fInFocus)
176 TXNFocus( varsp->fTXNRec, varsp->fTEActive);
177 }
178 }
179
180
181 /* TPFocusPaneText set the focus state for the text record. */
182 static void TPFocusPaneText(STPTextPaneVars **tpvars, Boolean setFocus) {
183 STPTextPaneVars *varsp;
184 varsp = *tpvars;
185 if (varsp->fInFocus != setFocus) {
186 varsp->fInFocus = setFocus;
187 TXNFocus( varsp->fTXNRec, varsp->fInFocus);
188 }
189 }
190
191
192 /* TPPaneDrawProc is called to redraw the control and for update events
193 referring to the control. This routine erases the text area's background,
194 and redraws the text. This routine assumes the scroll bar has been
195 redrawn by a call to DrawControls. */
196 static pascal void TPPaneDrawProc(ControlRef theControl, ControlPartCode thePart) {
197 STPTextPaneVars **tpvars, *varsp;
198 char state;
199 Rect bounds;
200 /* set up our globals */
201
202 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
203 if (tpvars != NULL) {
204 state = HGetState((Handle) tpvars);
205 HLock((Handle) tpvars);
206 varsp = *tpvars;
207
208 /* save the drawing state */
209 SetPort((**tpvars).fDrawingEnvironment);
210 /* verify our boundary */
211 GetControlBounds(theControl, &bounds);
212
213 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
214 if ( ! EqualRect(&bounds, &varsp->fRFocusOutline) ) {
215 // scrollbar is on the border, we add one
216 Rect oldbounds = varsp->fRFocusOutline ;
217 InsetRect( &oldbounds , -1 , -1 ) ;
218
219 if ( IsControlVisible( theControl ) )
220 InvalWindowRect( GetControlOwner( theControl ) , &oldbounds ) ;
221 SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
222 SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
223 SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) ,
224 bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2));
225 RectRgn(varsp->fTextBackgroundRgn, &varsp->fRTextOutline);
226 if ( IsControlVisible( theControl ) )
227 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left,
228 varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame);
229 else
230 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top + 30000 , varsp->fRTextArea.left + 30000 ,
231 varsp->fRTextArea.bottom + 30000 , varsp->fRTextArea.right + 30000 , varsp->fTXNFrame);
232
233 }
234
235 if ( IsControlVisible( theControl ) )
236 {
237 /* update the text region */
238 RGBColor white = { 65535 , 65535 , 65535 } ;
239 RGBBackColor( &white ) ;
240 EraseRgn(varsp->fTextBackgroundRgn);
241 TXNDraw(varsp->fTXNRec, NULL);
242 /* restore the drawing environment */
243 /* draw the text frame and focus frame (if necessary) */
244 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
245 if ((**tpvars).fIsActive && varsp->fInFocus)
246 DrawThemeFocusRect(&varsp->fRFocusOutline, true);
247 /* release our globals */
248 HSetState((Handle) tpvars, state);
249 }
250 }
251 }
252
253
254 /* TPPaneHitTestProc is called when the control manager would
255 like to determine what part of the control the mouse resides over.
256 We also call this routine from our tracking proc to determine how
257 to handle mouse clicks. */
258 static pascal ControlPartCode TPPaneHitTestProc(ControlHandle theControl, Point where) {
259 STPTextPaneVars **tpvars;
260 ControlPartCode result;
261 char state;
262 /* set up our locals and lock down our globals*/
263 result = 0;
264 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
265 if (tpvars != NULL && IsControlVisible( theControl) ) {
266 state = HGetState((Handle) tpvars);
267 HLock((Handle) tpvars);
268 /* find the region where we clicked */
269 if (PtInRect(where, &(**tpvars).fRTextArea)) {
270 result = kmUPTextPart;
271 } else result = 0;
272 /* release oure globals */
273 HSetState((Handle) tpvars, state);
274 }
275 return result;
276 }
277
278
279
280
281
282 /* TPPaneTrackingProc is called when the mouse is being held down
283 over our control. This routine handles clicks in the text area
284 and in the scroll bar. */
285 static pascal ControlPartCode TPPaneTrackingProc(ControlHandle theControl, Point startPt, ControlActionUPP actionProc) {
286 STPTextPaneVars **tpvars, *varsp;
287 char state;
288 ControlPartCode partCodeResult;
289 /* make sure we have some variables... */
290 partCodeResult = 0;
291 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
292 if (tpvars != NULL && IsControlVisible( theControl ) ) {
293 /* lock 'em down */
294 state = HGetState((Handle) tpvars);
295 HLock((Handle) tpvars);
296 varsp = *tpvars;
297 /* we don't do any of these functions unless we're in focus */
298 if ( ! varsp->fInFocus) {
299 WindowPtr owner;
300 owner = GetControlOwner(theControl);
301 ClearKeyboardFocus(owner);
302 SetKeyboardFocus(owner, theControl, kUserClickedToFocusPart);
303 }
304 /* find the location for the click */
305 switch (TPPaneHitTestProc(theControl, startPt)) {
306
307 /* handle clicks in the text part */
308 case kmUPTextPart:
309 { SetPort((**tpvars).fDrawingEnvironment);
310 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
311 #if !TARGET_CARBON
312 TXNClick( varsp->fTXNRec, (const EventRecord*) wxTheApp->MacGetCurrentEvent());
313 #else
314 EventRecord rec ;
315 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
316 TXNClick( varsp->fTXNRec, &rec );
317 #endif
318 }
319 break;
320
321 }
322
323 HSetState((Handle) tpvars, state);
324 }
325 return partCodeResult;
326 }
327
328
329 /* TPPaneIdleProc is our user pane idle routine. When our text field
330 is active and in focus, we use this routine to set the cursor. */
331 static pascal void TPPaneIdleProc(ControlHandle theControl) {
332 STPTextPaneVars **tpvars, *varsp;
333 /* set up locals */
334 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
335 if (tpvars != NULL && IsControlVisible( theControl ) ) {
336 /* if we're not active, then we have nothing to say about the cursor */
337 if ((**tpvars).fIsActive) {
338 char state;
339 Rect bounds;
340 Point mousep;
341 /* lock down the globals */
342 state = HGetState((Handle) tpvars);
343 HLock((Handle) tpvars);
344 varsp = *tpvars;
345 /* get the current mouse coordinates (in our window) */
346 SetPortWindowPort(GetControlOwner(theControl));
347 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
348 GetMouse(&mousep);
349 /* there's a 'focus thing' and an 'unfocused thing' */
350 if (varsp->fInFocus) {
351 /* flash the cursor */
352 SetPort((**tpvars).fDrawingEnvironment);
353 TXNIdle(varsp->fTXNRec);
354 /* set the cursor */
355 if (PtInRect(mousep, &varsp->fRTextArea)) {
356 RgnHandle theRgn;
357 RectRgn((theRgn = NewRgn()), &varsp->fRTextArea);
358 TXNAdjustCursor(varsp->fTXNRec, theRgn);
359 DisposeRgn(theRgn);
360 }
361 else
362 {
363 // SetThemeCursor(kThemeArrowCursor);
364 }
365 } else {
366 /* if it's in our bounds, set the cursor */
367 GetControlBounds(theControl, &bounds);
368 if (PtInRect(mousep, &bounds))
369 {
370 // SetThemeCursor(kThemeArrowCursor);
371 }
372 }
373
374 HSetState((Handle) tpvars, state);
375 }
376 }
377 }
378
379
380 /* TPPaneKeyDownProc is called whenever a keydown event is directed
381 at our control. Here, we direct the keydown event to the text
382 edit record and redraw the scroll bar and text field as appropriate. */
383 static pascal ControlPartCode TPPaneKeyDownProc(ControlHandle theControl,
384 SInt16 keyCode, SInt16 charCode, SInt16 modifiers) {
385 STPTextPaneVars **tpvars;
386 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
387 if (tpvars != NULL) {
388 if ((**tpvars).fInFocus) {
389 /* turn autoscrolling on and send the key event to text edit */
390 SetPort((**tpvars).fDrawingEnvironment);
391 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
392 EventRecord ev ;
393 memset( &ev , 0 , sizeof( ev ) ) ;
394 ev.what = keyDown ;
395 ev.modifiers = modifiers ;
396 ev.message = (( keyCode << 8 ) & keyCodeMask ) + ( charCode & charCodeMask ) ;
397 TXNKeyDown( (**tpvars).fTXNRec, &ev);
398 }
399 }
400 return kControlEntireControl;
401 }
402
403
404 /* TPPaneActivateProc is called when the window containing
405 the user pane control receives activate events. Here, we redraw
406 the control and it's text as necessary for the activation state. */
407 static pascal void TPPaneActivateProc(ControlHandle theControl, Boolean activating) {
408 Rect bounds;
409 STPTextPaneVars **tpvars, *varsp;
410 char state;
411 /* set up locals */
412 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
413 if (tpvars != NULL) {
414 state = HGetState((Handle) tpvars);
415 HLock((Handle) tpvars);
416 varsp = *tpvars;
417 /* de/activate the text edit record */
418 SetPort((**tpvars).fDrawingEnvironment);
419 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
420 GetControlBounds(theControl, &bounds);
421 varsp->fIsActive = activating;
422 TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
423 /* redraw the frame */
424 if ( IsControlVisible( theControl ) )
425 {
426 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
427 if (varsp->fInFocus)
428 DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fIsActive);
429 }
430 HSetState((Handle) tpvars, state);
431 }
432 }
433
434
435 /* TPPaneFocusProc is called when every the focus changes to or
436 from our control. Herein, switch the focus appropriately
437 according to the parameters and redraw the control as
438 necessary. */
439 static pascal ControlPartCode TPPaneFocusProc(ControlHandle theControl, ControlFocusPart action) {
440 ControlPartCode focusResult;
441 STPTextPaneVars **tpvars, *varsp;
442 char state;
443 /* set up locals */
444 focusResult = kControlFocusNoPart;
445 tpvars = (STPTextPaneVars **) GetControlReference(theControl);
446 if (tpvars != NULL ) {
447 state = HGetState((Handle) tpvars);
448 HLock((Handle) tpvars);
449 varsp = *tpvars;
450 /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is
451 tabbing forwards (or shift tabbing backwards) through the items in the dialog,
452 and kControlFocusNextPart will be received. When the user clicks in our field
453 and it is not the current focus, then the constant kUserClickedToFocusPart will
454 be received. The constant kControlFocusNoPart will be received when our control
455 is the current focus and the user clicks in another control. In your focus routine,
456 you should respond to these codes as follows:
457
458 kControlFocusNoPart - turn off focus and return kControlFocusNoPart. redraw
459 the control and the focus rectangle as necessary.
460
461 kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off
462 depending on its current state. redraw the control and the focus rectangle
463 as appropriate for the new focus state. If the focus state is 'off', return the constant
464 kControlFocusNoPart, otherwise return a non-zero part code.
465 kUserClickedToFocusPart - is a constant defined for this example. You should
466 define your own value for handling click-to-focus type events. */
467 /* calculate the next highlight state */
468 switch (action) {
469 default:
470 case kControlFocusNoPart:
471 TPFocusPaneText(tpvars, false);
472 focusResult = kControlFocusNoPart;
473 break;
474 case kUserClickedToFocusPart:
475 TPFocusPaneText(tpvars, true);
476 focusResult = 1;
477 break;
478 case kControlFocusPrevPart:
479 case kControlFocusNextPart:
480 TPFocusPaneText(tpvars, ( ! varsp->fInFocus));
481 focusResult = varsp->fInFocus ? 1 : kControlFocusNoPart;
482 break;
483 }
484 TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
485 /* redraw the text fram and focus rectangle to indicate the
486 new focus state */
487 if ( IsControlVisible( theControl ) )
488 {
489 /* save the drawing state */
490 SetPort((**tpvars).fDrawingEnvironment);
491 wxMacWindowClipper clipper( wxFindControlFromMacControl(theControl ) ) ;
492 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
493 DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fIsActive && varsp->fInFocus);
494 }
495 /* done */
496 HSetState((Handle) tpvars, state);
497 }
498 return focusResult;
499 }
500
501
502 /* mUPOpenControl initializes a user pane control so it will be drawn
503 and will behave as a scrolling text edit field inside of a window.
504 This routine performs all of the initialization steps necessary,
505 except it does not create the user pane control itself. theControl
506 should refer to a user pane control that you have either created
507 yourself or extracted from a dialog's control heirarchy using
508 the GetDialogItemAsControl routine. */
509 OSStatus mUPOpenControl(ControlHandle theControl, long wxStyle )
510 {
511 Rect bounds;
512 WindowRef theWindow;
513 STPTextPaneVars **tpvars, *varsp;
514 OSStatus err = noErr ;
515 RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF};
516 TXNBackground tback;
517
518 /* set up our globals */
519 if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(TPPaneDrawProc);
520 if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(TPPaneHitTestProc);
521 if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(TPPaneTrackingProc);
522 if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(TPPaneIdleProc);
523 if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc);
524 if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(TPPaneActivateProc);
525 if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(TPPaneFocusProc);
526
527 /* allocate our private storage */
528 tpvars = (STPTextPaneVars **) NewHandleClear(sizeof(STPTextPaneVars));
529 SetControlReference(theControl, (long) tpvars);
530 HLock((Handle) tpvars);
531 varsp = *tpvars;
532 /* set the initial settings for our private data */
533 varsp->fMultiline = wxStyle & wxTE_MULTILINE ;
534 varsp->fInFocus = false;
535 varsp->fIsActive = true;
536 varsp->fTEActive = true; // in order to get a deactivate
537 varsp->fUserPaneRec = theControl;
538 theWindow = varsp->fOwner = GetControlOwner(theControl);
539
540 varsp->fDrawingEnvironment = (GrafPtr) GetWindowPort(theWindow);
541
542 varsp->fInDialogWindow = ( GetWindowKind(varsp->fOwner) == kDialogWindowKind );
543 /* set up the user pane procedures */
544 SetControlData(theControl, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
545 SetControlData(theControl, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
546 SetControlData(theControl, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
547 SetControlData(theControl, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
548 SetControlData(theControl, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
549 SetControlData(theControl, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
550 SetControlData(theControl, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
551 /* calculate the rectangles used by the control */
552 GetControlBounds(theControl, &bounds);
553 SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
554 SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
555 SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) ,
556 bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2));
557 /* calculate the background region for the text. In this case, it's kindof
558 and irregular region because we're setting the scroll bar a little ways inside
559 of the text area. */
560 RectRgn((varsp->fTextBackgroundRgn = NewRgn()), &varsp->fRTextOutline);
561
562 /* set up the drawing environment */
563 SetPort(varsp->fDrawingEnvironment);
564
565 /* create the new edit field */
566
567 TXNFrameOptions frameOptions =
568 kTXNDontDrawCaretWhenInactiveMask ;
569 if ( ! ( wxStyle & wxTE_NOHIDESEL ) )
570 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
571
572 if ( wxStyle & wxTE_MULTILINE )
573 {
574 if ( ! ( wxStyle & wxTE_DONTWRAP ) )
575 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
576 else
577 {
578 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
579 frameOptions |= kTXNWantHScrollBarMask ;
580 }
581
582 if ( !(wxStyle & wxTE_NO_VSCROLL ) )
583 frameOptions |= kTXNWantVScrollBarMask ;
584 }
585 else
586 frameOptions |= kTXNSingleLineOnlyMask ;
587
588 if ( wxStyle & wxTE_READONLY )
589 frameOptions |= kTXNReadOnlyMask ;
590
591 TXNNewObject(NULL, varsp->fOwner, &varsp->fRTextArea,
592 frameOptions ,
593 kTXNTextEditStyleFrameType,
594 kTXNTextensionFile,
595 kTXNSystemDefaultEncoding,
596 &varsp->fTXNRec, &varsp->fTXNFrame, (TXNObjectRefcon) tpvars);
597
598 if ( !IsControlVisible( theControl ) )
599 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top + 30000 , varsp->fRTextArea.left + 30000 ,
600 varsp->fRTextArea.bottom + 30000 , varsp->fRTextArea.right + 30000 , varsp->fTXNFrame);
601
602
603 if ( (wxStyle & wxTE_MULTILINE) && (wxStyle & wxTE_DONTWRAP) )
604 {
605 TXNControlTag tag = kTXNWordWrapStateTag ;
606 TXNControlData dat ;
607 dat.uValue = kTXNNoAutoWrap ;
608 TXNSetTXNObjectControls( varsp->fTXNRec , false , 1 , &tag , &dat ) ;
609 }
610 Str255 fontName ;
611 SInt16 fontSize ;
612 Style fontStyle ;
613
614 GetThemeFont(kThemeSmallSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
615
616 TXNTypeAttributes typeAttr[] =
617 {
618 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
619 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
620 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
621 } ;
622
623 err = TXNSetTypeAttributes (varsp->fTXNRec, sizeof( typeAttr ) / sizeof(TXNTypeAttributes) , typeAttr,
624 kTXNStartOffset,
625 kTXNEndOffset);
626 /* set the field's background */
627
628 tback.bgType = kTXNBackgroundTypeRGB;
629 tback.bg.color = rgbWhite;
630 TXNSetBackground( varsp->fTXNRec, &tback);
631
632 /* unlock our storage */
633 HUnlock((Handle) tpvars);
634 /* perform final activations and setup for our text field. Here,
635 we assume that the window is going to be the 'active' window. */
636 TPActivatePaneText(tpvars, varsp->fIsActive && varsp->fInFocus);
637 /* all done */
638 return err;
639 }
640
641
642
643
644 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
645
646 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
647 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
648 EVT_CHAR(wxTextCtrl::OnChar)
649 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
650 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
651 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
652 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
653 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
654
655 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
656 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
657 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
658 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
659 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
660 END_EVENT_TABLE()
661
662 static void SetTXNData( TXNObject txn , const wxString& st , TXNOffset start , TXNOffset end )
663 {
664 #if wxUSE_UNICODE
665 #if SIZEOF_WCHAR_T == 2
666 size_t len = st.Len() ;
667 TXNSetData( txn , kTXNUnicodeTextData, (void*)st.wc_str(), len * 2,
668 start, end);
669 #else
670 wxMBConvUTF16BE converter ;
671 ByteCount byteBufferLen = converter.WC2MB( NULL , st.wc_str() , 0 ) ;
672 UniChar *unibuf = (UniChar*) malloc(byteBufferLen) ;
673 converter.WC2MB( (char*) unibuf , st.wc_str() , byteBufferLen ) ;
674 TXNSetData( txn , kTXNUnicodeTextData, (void*)unibuf, byteBufferLen ,
675 start, end);
676 free( unibuf ) ;
677 #endif
678 #else
679 wxCharBuffer text = st.mb_str(wxConvLocal) ;
680 TXNSetData( txn , kTXNTextData, (void*)text.data(), strlen( text ) ,
681 start, end);
682 #endif
683 }
684
685 // Text item
686 void wxTextCtrl::Init()
687 {
688 m_macTE = NULL ;
689 m_macTXN = NULL ;
690 m_macTXNvars = NULL ;
691 m_macUsesTXN = false ;
692
693 m_editable = true ;
694 m_dirty = false;
695
696 m_maxLength = TE_UNLIMITED_LENGTH ;
697 }
698
699 wxTextCtrl::~wxTextCtrl()
700 {
701 if ( m_macUsesTXN )
702 {
703 SetControlReference((ControlHandle)m_macControl, 0) ;
704 TXNDeleteObject((TXNObject)m_macTXN);
705 /* delete our private storage */
706 DisposeHandle((Handle) m_macTXNvars);
707 /* zero the control reference */
708 }
709 }
710
711 const short kVerticalMargin = 2 ;
712 const short kHorizontalMargin = 2 ;
713
714 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
715 const wxString& str,
716 const wxPoint& pos,
717 const wxSize& size, long style,
718 const wxValidator& validator,
719 const wxString& name)
720 {
721 m_macTE = NULL ;
722 m_macTXN = NULL ;
723 m_macTXNvars = NULL ;
724 m_macUsesTXN = false ;
725 m_editable = true ;
726
727 m_macUsesTXN = ! (style & wxTE_PASSWORD ) ;
728
729 m_macUsesTXN &= (TXNInitTextension != (void*) kUnresolvedCFragSymbolAddress) ;
730
731 // base initialization
732 if ( !wxTextCtrlBase::Create(parent, id, pos, size, style & ~(wxHSCROLL|wxVSCROLL), validator, name) )
733 return false;
734
735 wxSize mySize = size ;
736 if ( m_macUsesTXN )
737 {
738 m_macHorizontalBorder = 5 ; // additional pixels around the real control
739 m_macVerticalBorder = 3 ;
740 }
741 else
742 {
743 m_macHorizontalBorder = 5 ; // additional pixels around the real control
744 m_macVerticalBorder = 5 ;
745 }
746
747
748 Rect bounds ;
749 Str255 title ;
750 /*
751 if ( mySize.y == -1 )
752 {
753 mySize.y = 13 ;
754 if ( m_windowStyle & wxTE_MULTILINE )
755 mySize.y *= 5 ;
756
757 mySize.y += 2 * m_macVerticalBorder ;
758 }
759 */
760 MacPreControlCreate( parent , id , wxEmptyString , pos , mySize ,style, validator , name , &bounds , title ) ;
761
762 if ( m_windowStyle & wxTE_MULTILINE )
763 {
764 wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
765 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
766
767 m_windowStyle |= wxTE_PROCESS_ENTER;
768 }
769
770 if ( m_windowStyle & wxTE_READONLY)
771 {
772 m_editable = false ;
773 }
774
775 wxString st = str ;
776 wxMacConvertNewlines13To10( &st ) ;
777 if ( !m_macUsesTXN )
778 {
779 m_macControl = (WXWidget) ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , "\p" , false , 0 , 0 , 1,
780 (style & wxTE_PASSWORD) ? kControlEditTextPasswordProc : kControlEditTextProc , (long) this ) ;
781 long size ;
782 ::GetControlData((ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*)((TEHandle *)&m_macTE) , &size ) ;
783
784 }
785 else
786 {
787 short featurSet;
788
789 featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
790 | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground
791 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
792 /* create the control */
793 m_macControl = (WXWidget) ::NewControl(MAC_WXHWND(parent->MacGetRootWindow()), &bounds, "\p", false , featurSet, 0, featurSet, kControlUserPaneProc, 0);
794 /* set up the mUP specific features and data */
795 mUPOpenControl((ControlHandle) m_macControl, m_windowStyle );
796 }
797 MacPostControlCreate() ;
798
799 if ( !m_macUsesTXN )
800 {
801 wxCharBuffer text = st.mb_str(wxConvLocal) ;
802 ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ;
803 }
804 else
805 {
806 STPTextPaneVars **tpvars;
807 /* set up locals */
808 tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl);
809 /* set the text in the record */
810 m_macTXN = (**tpvars).fTXNRec ;
811 SetTXNData( (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
812 m_macTXNvars = tpvars ;
813 m_macUsesTXN = true ;
814 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
815 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
816 }
817
818 return true;
819 }
820
821 wxString wxTextCtrl::GetValue() const
822 {
823 Size actualSize = 0;
824 wxString result ;
825 OSStatus err ;
826 if ( !m_macUsesTXN )
827 {
828 err = ::GetControlDataSize((ControlHandle) m_macControl, 0,
829 ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag, &actualSize ) ;
830
831 if ( err )
832 return wxEmptyString ;
833
834 if ( actualSize > 0 )
835 {
836 wxCharBuffer buf(actualSize) ;
837 ::GetControlData( (ControlHandle) m_macControl, 0,
838 ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag,
839 actualSize , buf.data() , &actualSize ) ;
840 result = wxString( buf , wxConvLocal) ;
841 }
842 }
843 else
844 {
845 #if wxUSE_UNICODE
846 Handle theText ;
847 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
848 // all done
849 if ( err )
850 {
851 actualSize = 0 ;
852 }
853 else
854 {
855 actualSize = GetHandleSize( theText ) / sizeof( UniChar) ;
856 if ( actualSize > 0 )
857 {
858 wxChar *ptr = result.GetWriteBuf(actualSize*sizeof(wxChar)) ;
859 #if SIZEOF_WCHAR_T == 2
860 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
861 #else
862 wxMBConvUTF16BE converter ;
863 HLock( theText ) ;
864 converter.MB2WC( ptr , (const char*)*theText , actualSize ) ;
865 HUnlock( theText ) ;
866 #endif
867 ptr[actualSize] = 0 ;
868 result.UngetWriteBuf( actualSize *sizeof(wxChar) ) ;
869 }
870 DisposeHandle( theText ) ;
871 }
872 #else
873 Handle theText ;
874 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
875 // all done
876 if ( err )
877 {
878 actualSize = 0 ;
879 }
880 else
881 {
882 actualSize = GetHandleSize( theText ) ;
883 if ( actualSize > 0 )
884 {
885 HLock( theText ) ;
886 result = wxString( *theText , wxConvLocal , actualSize ) ;
887 HUnlock( theText ) ;
888 }
889 DisposeHandle( theText ) ;
890 }
891 #endif
892 }
893 wxMacConvertNewlines10To13( &result ) ;
894 return result ;
895 }
896
897 void wxTextCtrl::GetSelection(long* from, long* to) const
898 {
899 if ( !m_macUsesTXN )
900 {
901 *from = (**((TEHandle) m_macTE)).selStart;
902 *to = (**((TEHandle) m_macTE)).selEnd;
903 }
904 else
905 {
906 TXNGetSelection( (TXNObject) m_macTXN , (TXNOffset*) from , (TXNOffset*) to ) ;
907 }
908 }
909
910 void wxTextCtrl::SetValue(const wxString& str)
911 {
912 wxString st = str ;
913 wxMacConvertNewlines13To10( &st ) ;
914 if ( !m_macUsesTXN )
915 {
916 wxCharBuffer text = st.mb_str(wxConvLocal) ;
917 ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ;
918 }
919 else
920 {
921 bool formerEditable = m_editable ;
922 if ( !formerEditable )
923 SetEditable(true) ;
924 SetTXNData( (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
925 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
926 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
927 if ( !formerEditable )
928 SetEditable(formerEditable) ;
929 }
930 MacRedrawControl() ;
931 }
932
933 void wxTextCtrl::SetMaxLength(unsigned long len)
934 {
935 m_maxLength = len ;
936 }
937
938 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
939 {
940 if ( m_macUsesTXN )
941 {
942 bool formerEditable = m_editable ;
943 if ( !formerEditable )
944 SetEditable(true) ;
945 TXNTypeAttributes typeAttr[4] ;
946 Str255 fontName = "\pMonaco" ;
947 SInt16 fontSize = 12 ;
948 Style fontStyle = normal ;
949 RGBColor color ;
950 int attrCounter = 0 ;
951 if ( style.HasFont() )
952 {
953 const wxFont &font = style.GetFont() ;
954 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
955 fontSize = font.GetPointSize() ;
956 if ( font.GetUnderlined() )
957 fontStyle |= underline ;
958 if ( font.GetWeight() == wxBOLD )
959 fontStyle |= bold ;
960 if ( font.GetStyle() == wxITALIC )
961 fontStyle |= italic ;
962
963 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
964 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
965 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
966 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
967 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
968 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
969 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
970 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
971 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
972 attrCounter += 3 ;
973
974 }
975 if ( style.HasTextColour() )
976 {
977 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
978 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
979 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
980 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
981 attrCounter += 1 ;
982 }
983
984 if ( attrCounter > 0 )
985 {
986 #ifdef __WXDEBUG__
987 OSStatus status =
988 #endif // __WXDEBUG__
989 TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, start,end);
990 wxASSERT_MSG( status == noErr , wxT("Couldn't set text attributes") ) ;
991 }
992 if ( !formerEditable )
993 SetEditable(formerEditable) ;
994 }
995 return true ;
996 }
997
998 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
999 {
1000 wxTextCtrlBase::SetDefaultStyle( style ) ;
1001 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1002 return true ;
1003 }
1004
1005 // Clipboard operations
1006 void wxTextCtrl::Copy()
1007 {
1008 if (CanCopy())
1009 {
1010 if ( !m_macUsesTXN )
1011 {
1012 TECopy( ((TEHandle) m_macTE) ) ;
1013 ClearCurrentScrap();
1014 TEToScrap() ;
1015 MacRedrawControl() ;
1016 }
1017 else
1018 {
1019 ClearCurrentScrap();
1020 TXNCopy((TXNObject)m_macTXN);
1021 TXNConvertToPublicScrap();
1022 }
1023 }
1024 }
1025
1026 void wxTextCtrl::Cut()
1027 {
1028 if (CanCut())
1029 {
1030 if ( !m_macUsesTXN )
1031 {
1032 TECut( ((TEHandle) m_macTE) ) ;
1033 ClearCurrentScrap();
1034 TEToScrap() ;
1035 MacRedrawControl() ;
1036 }
1037 else
1038 {
1039 ClearCurrentScrap();
1040 TXNCut((TXNObject)m_macTXN);
1041 TXNConvertToPublicScrap();
1042 }
1043 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1044 event.SetEventObject( this );
1045 GetEventHandler()->ProcessEvent(event);
1046 }
1047 }
1048
1049 void wxTextCtrl::Paste()
1050 {
1051 if (CanPaste())
1052 {
1053 if ( !m_macUsesTXN )
1054 {
1055 TEFromScrap() ;
1056 TEPaste( (TEHandle) m_macTE ) ;
1057 MacRedrawControl() ;
1058 }
1059 else
1060 {
1061 TXNConvertFromPublicScrap();
1062 TXNPaste((TXNObject)m_macTXN);
1063 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1064 }
1065 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
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 wxTextPos 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 wxTextPos 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 & wxTE_PROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1591 /* && key != WXK_PAGEUP && key != WXK_PAGEDOWN && 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 & wxTE_PROCESS_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 if ( !(m_windowStyle & wxTE_PROCESS_TAB))
1653 {
1654 int flags = 0;
1655 if (!event.ShiftDown())
1656 flags |= wxNavigationKeyEvent::IsForward ;
1657 if (event.ControlDown())
1658 flags |= wxNavigationKeyEvent::WinChange ;
1659 Navigate(flags);
1660 return;
1661 }
1662 else
1663 {
1664 // This is necessary (don't know why) or the tab will not
1665 // be inserted.
1666 WriteText(wxT("\t"));
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.SetEventObject( this );
1708 wxPostEvent(GetEventHandler(),event1);
1709 }
1710 }
1711
1712 void wxTextCtrl::MacSuperShown( bool show )
1713 {
1714 bool former = m_macControlIsShown ;
1715 wxControl::MacSuperShown( show ) ;
1716 if ( (former != m_macControlIsShown) && m_macUsesTXN )
1717 {
1718 if ( m_macControlIsShown )
1719 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1720 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1721 else
1722 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1723 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1724 }
1725 }
1726
1727 bool wxTextCtrl::Show(bool show)
1728 {
1729 bool former = m_macControlIsShown ;
1730
1731 bool retval = wxControl::Show( show ) ;
1732
1733 if ( former != m_macControlIsShown && m_macUsesTXN )
1734 {
1735 if ( m_macControlIsShown )
1736 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1737 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1738 else
1739 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1740 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1741 }
1742
1743 return retval ;
1744 }
1745
1746 // ----------------------------------------------------------------------------
1747 // standard handlers for standard edit menu events
1748 // ----------------------------------------------------------------------------
1749
1750 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1751 {
1752 Cut();
1753 }
1754
1755 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1756 {
1757 Copy();
1758 }
1759
1760 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1761 {
1762 Paste();
1763 }
1764
1765 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1766 {
1767 Undo();
1768 }
1769
1770 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1771 {
1772 Redo();
1773 }
1774
1775 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1776 {
1777 event.Enable( CanCut() );
1778 }
1779
1780 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1781 {
1782 event.Enable( CanCopy() );
1783 }
1784
1785 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1786 {
1787 event.Enable( CanPaste() );
1788 }
1789
1790 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1791 {
1792 event.Enable( CanUndo() );
1793 }
1794
1795 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1796 {
1797 event.Enable( CanRedo() );
1798 }
1799
1800 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1801 {
1802 if ( m_macUsesTXN )
1803 return true ;
1804 else
1805 return wxWindow::MacSetupCursor( pt ) ;
1806 }
1807
1808 #endif
1809 // wxUSE_TEXTCTRL