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