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