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