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