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