]> git.saurik.com Git - wxWidgets.git/blob - src/mac/textctrl.cpp
added condition for DARWIN (thanks to Steve Hartwell)
[wxWidgets.git] / src / mac / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "textctrl.h"
14 #endif
15
16 #include "wx/defs.h"
17
18 #if wxUSE_TEXTCTRL
19
20 #ifdef __DARWIN__
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #else
24 #include <stat.h>
25 #endif
26
27 #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 static void SetTXNData( TXNObject txn , const wxString& st , TXNOffset start , TXNOffset end )
663 {
664 #if wxUSE_UNICODE
665 size_t len = st.Len() ;
666 #if SIZEOF_WCHAR_T == 2
667 TXNSetData( txn , kTXNUnicodeTextData, (void*)st.wc_str(), len * 2,
668 start, end);
669 #else
670 ByteCount byteBufferLen = len * sizeof( UniChar ) ;
671 UniChar *unibuf = (UniChar*) malloc(byteBufferLen) ;
672 wxMBConvUTF16BE converter ;
673 converter.WC2MB( (char*) unibuf , st.wc_str() , byteBufferLen ) ;
674 TXNSetData( txn , kTXNUnicodeTextData, (void*)unibuf, len * 2,
675 start, end);
676 free( unibuf ) ;
677 #endif
678 #else
679 wxCharBuffer text = st.mb_str(wxConvLocal) ;
680 TXNSetData( txn , kTXNTextData, (void*)text.data(), strlen( text ) ,
681 start, end);
682 #endif
683 }
684
685 // Text item
686 void wxTextCtrl::Init()
687 {
688 m_macTE = NULL ;
689 m_macTXN = NULL ;
690 m_macTXNvars = NULL ;
691 m_macUsesTXN = false ;
692
693 m_editable = true ;
694 m_dirty = false;
695
696 m_maxLength = TE_UNLIMITED_LENGTH ;
697 }
698
699 wxTextCtrl::~wxTextCtrl()
700 {
701 if ( m_macUsesTXN )
702 {
703 SetControlReference((ControlHandle)m_macControl, 0) ;
704 TXNDeleteObject((TXNObject)m_macTXN);
705 /* delete our private storage */
706 DisposeHandle((Handle) m_macTXNvars);
707 /* zero the control reference */
708 }
709 }
710
711 const short kVerticalMargin = 2 ;
712 const short kHorizontalMargin = 2 ;
713
714 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
715 const wxString& str,
716 const wxPoint& pos,
717 const wxSize& size, long style,
718 const wxValidator& validator,
719 const wxString& name)
720 {
721 m_macTE = NULL ;
722 m_macTXN = NULL ;
723 m_macTXNvars = NULL ;
724 m_macUsesTXN = false ;
725 m_editable = true ;
726
727 m_macUsesTXN = ! (style & wxTE_PASSWORD ) ;
728
729 m_macUsesTXN &= (TXNInitTextension != (void*) kUnresolvedCFragSymbolAddress) ;
730
731 // base initialization
732 if ( !wxTextCtrlBase::Create(parent, id, pos, size, style & ~(wxHSCROLL|wxVSCROLL), validator, name) )
733 return FALSE;
734
735 wxSize mySize = size ;
736 if ( m_macUsesTXN )
737 {
738 m_macHorizontalBorder = 5 ; // additional pixels around the real control
739 m_macVerticalBorder = 3 ;
740 }
741 else
742 {
743 m_macHorizontalBorder = 5 ; // additional pixels around the real control
744 m_macVerticalBorder = 5 ;
745 }
746
747
748 Rect bounds ;
749 Str255 title ;
750 /*
751 if ( mySize.y == -1 )
752 {
753 mySize.y = 13 ;
754 if ( m_windowStyle & wxTE_MULTILINE )
755 mySize.y *= 5 ;
756
757 mySize.y += 2 * m_macVerticalBorder ;
758 }
759 */
760 MacPreControlCreate( parent , id , wxEmptyString , pos , mySize ,style, validator , name , &bounds , title ) ;
761
762 if ( m_windowStyle & wxTE_MULTILINE )
763 {
764 wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
765 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
766
767 m_windowStyle |= wxTE_PROCESS_ENTER;
768 }
769
770 if ( m_windowStyle & wxTE_READONLY)
771 {
772 m_editable = FALSE ;
773 }
774
775 wxString st = str ;
776 wxMacConvertNewlines13To10( &st ) ;
777 if ( !m_macUsesTXN )
778 {
779 m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()) , &bounds , "\p" , false , 0 , 0 , 1,
780 (style & wxTE_PASSWORD) ? kControlEditTextPasswordProc : kControlEditTextProc , (long) this ) ;
781 long size ;
782 ::GetControlData((ControlHandle) m_macControl , 0, kControlEditTextTEHandleTag , sizeof( TEHandle ) , (char*)((TEHandle *)&m_macTE) , &size ) ;
783
784 }
785 else
786 {
787 short featurSet;
788
789 featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
790 | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground
791 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
792 /* create the control */
793 m_macControl = NewControl(MAC_WXHWND(parent->MacGetRootWindow()), &bounds, "\p", false , featurSet, 0, featurSet, kControlUserPaneProc, 0);
794 /* set up the mUP specific features and data */
795 mUPOpenControl((ControlHandle) m_macControl, m_windowStyle );
796 }
797 MacPostControlCreate() ;
798
799 if ( !m_macUsesTXN )
800 {
801 wxCharBuffer text = st.mb_str(wxConvLocal) ;
802 ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ;
803 }
804 else
805 {
806 STPTextPaneVars **tpvars;
807 /* set up locals */
808 tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl);
809 /* set the text in the record */
810 m_macTXN = (**tpvars).fTXNRec ;
811 SetTXNData( (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
812 m_macTXNvars = tpvars ;
813 m_macUsesTXN = true ;
814 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
815 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
816 }
817
818 return TRUE;
819 }
820
821 wxString wxTextCtrl::GetValue() const
822 {
823 Size actualSize = 0;
824 wxString result ;
825 OSStatus err ;
826 if ( !m_macUsesTXN )
827 {
828 err = ::GetControlDataSize((ControlHandle) m_macControl, 0,
829 ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag, &actualSize ) ;
830
831 if ( err )
832 return wxEmptyString ;
833
834 if ( actualSize > 0 )
835 {
836 wxCharBuffer buf(actualSize) ;
837 ::GetControlData( (ControlHandle) m_macControl, 0,
838 ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag,
839 actualSize , buf.data() , &actualSize ) ;
840 result = wxString( buf , wxConvLocal) ;
841 }
842 }
843 else
844 {
845 #if wxUSE_UNICODE
846 Handle theText ;
847 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
848 // all done
849 if ( err )
850 {
851 actualSize = 0 ;
852 }
853 else
854 {
855 actualSize = GetHandleSize( theText ) ;
856 if ( actualSize > 0 )
857 {
858 wxChar *ptr = result.GetWriteBuf(actualSize*sizeof(wxChar)) ;
859 #if SIZEOF_WCHAR_T == 2
860 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
861 #else
862 wxMBConvUTF16BE converter ;
863 HLock( theText ) ;
864 converter.MB2WC( ptr , (const char*)*theText , actualSize*sizeof(wxChar) ) ;
865 HUnlock( theText ) ;
866 #endif
867 ptr[actualSize] = 0 ;
868 result.UngetWriteBuf( actualSize ) ;
869 }
870 DisposeHandle( theText ) ;
871 }
872 #else
873 Handle theText ;
874 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
875 // all done
876 if ( err )
877 {
878 actualSize = 0 ;
879 }
880 else
881 {
882 actualSize = GetHandleSize( theText ) ;
883 if ( actualSize > 0 )
884 {
885 HLock( theText ) ;
886 result = wxString( *theText , wxConvLocal , actualSize ) ;
887 HUnlock( theText ) ;
888 }
889 DisposeHandle( theText ) ;
890 }
891 #endif
892 }
893 wxMacConvertNewlines10To13( &result ) ;
894 return result ;
895 }
896
897 void wxTextCtrl::GetSelection(long* from, long* to) const
898 {
899 if ( !m_macUsesTXN )
900 {
901 *from = (**((TEHandle) m_macTE)).selStart;
902 *to = (**((TEHandle) m_macTE)).selEnd;
903 }
904 else
905 {
906 TXNGetSelection( (TXNObject) m_macTXN , (TXNOffset*) from , (TXNOffset*) to ) ;
907 }
908 }
909
910 void wxTextCtrl::SetValue(const wxString& str)
911 {
912 wxString st = str ;
913 wxMacConvertNewlines13To10( &st ) ;
914 if ( !m_macUsesTXN )
915 {
916 wxCharBuffer text = st.mb_str(wxConvLocal) ;
917 ::SetControlData( (ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , strlen(text) , text ) ;
918 }
919 else
920 {
921 bool formerEditable = m_editable ;
922 if ( !formerEditable )
923 SetEditable(true) ;
924 SetTXNData( (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
925 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
926 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
927 if ( !formerEditable )
928 SetEditable(formerEditable) ;
929 }
930 MacRedrawControl() ;
931 }
932
933 void wxTextCtrl::SetMaxLength(unsigned long len)
934 {
935 m_maxLength = len ;
936 }
937
938 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
939 {
940 if ( m_macUsesTXN )
941 {
942 bool formerEditable = m_editable ;
943 if ( !formerEditable )
944 SetEditable(true) ;
945 TXNTypeAttributes typeAttr[4] ;
946 Str255 fontName = "\pMonaco" ;
947 SInt16 fontSize = 12 ;
948 Style fontStyle = normal ;
949 RGBColor color ;
950 int attrCounter = 0 ;
951 if ( style.HasFont() )
952 {
953 const wxFont &font = style.GetFont() ;
954 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
955 fontSize = font.GetPointSize() ;
956 if ( font.GetUnderlined() )
957 fontStyle |= underline ;
958 if ( font.GetWeight() == wxBOLD )
959 fontStyle |= bold ;
960 if ( font.GetStyle() == wxITALIC )
961 fontStyle |= italic ;
962
963 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
964 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
965 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
966 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
967 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
968 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
969 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
970 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
971 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
972 attrCounter += 3 ;
973
974 }
975 if ( style.HasTextColour() )
976 {
977 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
978 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
979 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
980 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
981 attrCounter += 1 ;
982 }
983
984 if ( attrCounter > 0 )
985 {
986 #ifdef __WXDEBUG__
987 OSStatus status =
988 #endif // __WXDEBUG__
989 TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, start,end);
990 wxASSERT_MSG( status == noErr , wxT("Couldn't set text attributes") ) ;
991 }
992 if ( !formerEditable )
993 SetEditable(formerEditable) ;
994 }
995 return TRUE ;
996 }
997
998 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
999 {
1000 wxTextCtrlBase::SetDefaultStyle( style ) ;
1001 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1002 return TRUE ;
1003 }
1004
1005 // Clipboard operations
1006 void wxTextCtrl::Copy()
1007 {
1008 if (CanCopy())
1009 {
1010 if ( !m_macUsesTXN )
1011 {
1012 TECopy( ((TEHandle) m_macTE) ) ;
1013 ClearCurrentScrap();
1014 TEToScrap() ;
1015 MacRedrawControl() ;
1016 }
1017 else
1018 {
1019 ClearCurrentScrap();
1020 TXNCopy((TXNObject)m_macTXN);
1021 TXNConvertToPublicScrap();
1022 }
1023 }
1024 }
1025
1026 void wxTextCtrl::Cut()
1027 {
1028 if (CanCut())
1029 {
1030 if ( !m_macUsesTXN )
1031 {
1032 TECut( ((TEHandle) m_macTE) ) ;
1033 ClearCurrentScrap();
1034 TEToScrap() ;
1035 MacRedrawControl() ;
1036 }
1037 else
1038 {
1039 ClearCurrentScrap();
1040 TXNCut((TXNObject)m_macTXN);
1041 TXNConvertToPublicScrap();
1042 }
1043 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1044 event.SetString( GetValue() ) ;
1045 event.SetEventObject( this );
1046 GetEventHandler()->ProcessEvent(event);
1047 }
1048 }
1049
1050 void wxTextCtrl::Paste()
1051 {
1052 if (CanPaste())
1053 {
1054 if ( !m_macUsesTXN )
1055 {
1056 TEFromScrap() ;
1057 TEPaste( (TEHandle) m_macTE ) ;
1058 MacRedrawControl() ;
1059 }
1060 else
1061 {
1062 TXNConvertFromPublicScrap();
1063 TXNPaste((TXNObject)m_macTXN);
1064 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1065 }
1066 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1067 event.SetString( GetValue() ) ;
1068 event.SetEventObject( this );
1069 GetEventHandler()->ProcessEvent(event);
1070 }
1071 }
1072
1073 bool wxTextCtrl::CanCopy() const
1074 {
1075 // Can copy if there's a selection
1076 long from, to;
1077 GetSelection(& from, & to);
1078 return (from != to);
1079 }
1080
1081 bool wxTextCtrl::CanCut() const
1082 {
1083 if ( !IsEditable() )
1084 {
1085 return false ;
1086 }
1087 // Can cut if there's a selection
1088 long from, to;
1089 GetSelection(& from, & to);
1090 return (from != to);
1091 }
1092
1093 bool wxTextCtrl::CanPaste() const
1094 {
1095 if (!IsEditable())
1096 return FALSE;
1097
1098 #if TARGET_CARBON
1099 OSStatus err = noErr;
1100 ScrapRef scrapRef;
1101
1102 err = GetCurrentScrap( &scrapRef );
1103 if ( err != noTypeErr && err != memFullErr )
1104 {
1105 ScrapFlavorFlags flavorFlags;
1106 Size byteCount;
1107
1108 if (( err = GetScrapFlavorFlags( scrapRef, 'TEXT', &flavorFlags )) == noErr)
1109 {
1110 if (( err = GetScrapFlavorSize( scrapRef, 'TEXT', &byteCount )) == noErr)
1111 {
1112 return TRUE ;
1113 }
1114 }
1115 }
1116 return FALSE;
1117
1118 #else
1119 long offset ;
1120 if ( GetScrap( NULL , 'TEXT' , &offset ) > 0 )
1121 {
1122 return TRUE ;
1123 }
1124 #endif
1125 return FALSE ;
1126 }
1127
1128 void wxTextCtrl::SetEditable(bool editable)
1129 {
1130 if ( editable != m_editable )
1131 {
1132 m_editable = editable ;
1133 if ( !m_macUsesTXN )
1134 {
1135 if ( editable )
1136 UMAActivateControl( (ControlHandle) m_macControl ) ;
1137 else
1138 UMADeactivateControl((ControlHandle) m_macControl ) ;
1139 }
1140 else
1141 {
1142 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1143 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1144 TXNSetTXNObjectControls( (TXNObject) m_macTXN , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ;
1145 }
1146 }
1147 }
1148
1149 void wxTextCtrl::SetInsertionPoint(long pos)
1150 {
1151 SetSelection( pos , pos ) ;
1152 }
1153
1154 void wxTextCtrl::SetInsertionPointEnd()
1155 {
1156 long pos = GetLastPosition();
1157 SetInsertionPoint(pos);
1158 }
1159
1160 long wxTextCtrl::GetInsertionPoint() const
1161 {
1162 long begin,end ;
1163 GetSelection( &begin , &end ) ;
1164 return begin ;
1165 }
1166
1167 long wxTextCtrl::GetLastPosition() const
1168 {
1169 if ( !m_macUsesTXN )
1170 {
1171 return (**((TEHandle) m_macTE)).teLength ;
1172 }
1173 else
1174 {
1175 Handle theText ;
1176 long actualsize ;
1177 OSErr err = TXNGetDataEncoded( (TXNObject) m_macTXN, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1178 /* all done */
1179 if ( err )
1180 {
1181 actualsize = 0 ;
1182 }
1183 else
1184 {
1185 actualsize = GetHandleSize( theText ) ;
1186 DisposeHandle( theText ) ;
1187 }
1188 return actualsize ;
1189 }
1190 }
1191
1192 void wxTextCtrl::Replace(long from, long to, const wxString& str)
1193 {
1194 wxString value = str ;
1195 wxMacConvertNewlines13To10( &value ) ;
1196 if ( !m_macUsesTXN )
1197 {
1198 ControlEditTextSelectionRec selection ;
1199
1200 selection.selStart = from ;
1201 selection.selEnd = to ;
1202 ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1203 TESetSelect( from , to , ((TEHandle) m_macTE) ) ;
1204 TEDelete( ((TEHandle) m_macTE) ) ;
1205 TEInsert( value , value.Length() , ((TEHandle) m_macTE) ) ;
1206 }
1207 else
1208 {
1209 bool formerEditable = m_editable ;
1210 if ( !formerEditable )
1211 SetEditable(true) ;
1212 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1213 TXNClear( ((TXNObject) m_macTXN) ) ;
1214 SetTXNData( (TXNObject) m_macTXN , str , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1215 if ( !formerEditable )
1216 SetEditable( formerEditable ) ;
1217 }
1218 Refresh() ;
1219 }
1220
1221 void wxTextCtrl::Remove(long from, long to)
1222 {
1223 if ( !m_macUsesTXN )
1224 {
1225 ControlEditTextSelectionRec selection ;
1226
1227 selection.selStart = from ;
1228 selection.selEnd = to ;
1229 ::SetControlData( (ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1230 TEDelete( ((TEHandle) m_macTE) ) ;
1231 }
1232 else
1233 {
1234 bool formerEditable = m_editable ;
1235 if ( !formerEditable )
1236 SetEditable(true) ;
1237 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1238 TXNClear( ((TXNObject) m_macTXN) ) ;
1239 if ( !formerEditable )
1240 SetEditable( formerEditable ) ;
1241 }
1242 Refresh() ;
1243 }
1244
1245 void wxTextCtrl::SetSelection(long from, long to)
1246 {
1247 if ( !m_macUsesTXN )
1248 {
1249 ControlEditTextSelectionRec selection ;
1250 if ((from == -1) && (to == -1))
1251 {
1252 selection.selStart = 0 ;
1253 selection.selEnd = 32767 ;
1254 }
1255 else
1256 {
1257 selection.selStart = from ;
1258 selection.selEnd = to ;
1259 }
1260
1261 TESetSelect( selection.selStart , selection.selEnd , ((TEHandle) m_macTE) ) ;
1262 ::SetControlData((ControlHandle) m_macControl , 0, kControlEditTextSelectionTag , sizeof( selection ) , (char*) &selection ) ;
1263 }
1264 else
1265 {
1266 STPTextPaneVars **tpvars;
1267 /* set up our locals */
1268 tpvars = (STPTextPaneVars **) GetControlReference((ControlHandle) m_macControl);
1269 /* and our drawing environment as the operation
1270 may force a redraw in the text area. */
1271 SetPort((**tpvars).fDrawingEnvironment);
1272 /* change the selection */
1273 if ((from == -1) && (to == -1))
1274 TXNSelectAll((TXNObject) m_macTXN);
1275 else
1276 TXNSetSelection( (**tpvars).fTXNRec, from, to);
1277 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1278 }
1279 }
1280
1281 bool wxTextCtrl::LoadFile(const wxString& file)
1282 {
1283 if ( wxTextCtrlBase::LoadFile(file) )
1284 {
1285 return TRUE;
1286 }
1287
1288 return FALSE;
1289 }
1290
1291 void wxTextCtrl::WriteText(const wxString& str)
1292 {
1293 wxString st = str ;
1294 wxMacConvertNewlines13To10( &st ) ;
1295 if ( !m_macUsesTXN )
1296 {
1297 wxCharBuffer text = st.mb_str(wxConvLocal) ;
1298 TEInsert( text , strlen(text) , ((TEHandle) m_macTE) ) ;
1299 }
1300 else
1301 {
1302 bool formerEditable = m_editable ;
1303 if ( !formerEditable )
1304 SetEditable(true) ;
1305 long start , end , dummy ;
1306 GetSelection( &start , &dummy ) ;
1307 SetTXNData( (TXNObject) m_macTXN , st , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1308 GetSelection( &dummy , &end ) ;
1309 SetStyle( start , end , GetDefaultStyle() ) ;
1310 if ( !formerEditable )
1311 SetEditable( formerEditable ) ;
1312 }
1313 MacRedrawControl() ;
1314 }
1315
1316 void wxTextCtrl::AppendText(const wxString& text)
1317 {
1318 SetInsertionPointEnd();
1319 WriteText(text);
1320 }
1321
1322 void wxTextCtrl::Clear()
1323 {
1324 if ( !m_macUsesTXN )
1325 {
1326 ::SetControlData((ControlHandle) m_macControl, 0, ( m_windowStyle & wxTE_PASSWORD ) ? kControlEditTextPasswordTag : kControlEditTextTextTag , 0 , (char*) ((const char*)NULL) ) ;
1327 }
1328 else
1329 {
1330 TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ;
1331 TXNClear((TXNObject)m_macTXN);
1332 }
1333 Refresh() ;
1334 }
1335
1336 bool wxTextCtrl::IsModified() const
1337 {
1338 return m_dirty;
1339 }
1340
1341 bool wxTextCtrl::IsEditable() const
1342 {
1343 return IsEnabled() && m_editable ;
1344 }
1345
1346 bool wxTextCtrl::AcceptsFocus() const
1347 {
1348 // we don't want focus if we can't be edited
1349 return /*IsEditable() && */ wxControl::AcceptsFocus();
1350 }
1351
1352 wxSize wxTextCtrl::DoGetBestSize() const
1353 {
1354 int wText = 100 ;
1355
1356 int hText;
1357 if ( m_macUsesTXN )
1358 {
1359 hText = 17 ;
1360 }
1361 else
1362 {
1363 hText = 13 ;
1364 }
1365 /*
1366 int cx, cy;
1367 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
1368
1369 int wText = DEFAULT_ITEM_WIDTH;
1370
1371 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
1372
1373 return wxSize(wText, hText);
1374 */
1375 if ( m_windowStyle & wxTE_MULTILINE )
1376 {
1377 hText *= 5 ;
1378 }
1379 hText += 2 * m_macVerticalBorder ;
1380 wText += 2 * m_macHorizontalBorder ;
1381 //else: for single line control everything is ok
1382 return wxSize(wText, hText);
1383 }
1384
1385 // ----------------------------------------------------------------------------
1386 // Undo/redo
1387 // ----------------------------------------------------------------------------
1388
1389 void wxTextCtrl::Undo()
1390 {
1391 if (CanUndo())
1392 {
1393 if ( m_macUsesTXN )
1394 {
1395 TXNUndo((TXNObject)m_macTXN);
1396 }
1397 }
1398 }
1399
1400 void wxTextCtrl::Redo()
1401 {
1402 if (CanRedo())
1403 {
1404 if ( m_macUsesTXN )
1405 {
1406 TXNRedo((TXNObject)m_macTXN);
1407 }
1408 }
1409 }
1410
1411 bool wxTextCtrl::CanUndo() const
1412 {
1413 if ( !IsEditable() )
1414 {
1415 return false ;
1416 }
1417 if ( m_macUsesTXN )
1418 {
1419 return TXNCanUndo((TXNObject)m_macTXN,NULL);
1420 }
1421 return FALSE ;
1422 }
1423
1424 bool wxTextCtrl::CanRedo() const
1425 {
1426 if ( !IsEditable() )
1427 {
1428 return false ;
1429 }
1430 if ( m_macUsesTXN )
1431 {
1432 return TXNCanRedo((TXNObject)m_macTXN,NULL);
1433 }
1434 return FALSE ;
1435 }
1436
1437 // Makes modifie or unmodified
1438 void wxTextCtrl::MarkDirty()
1439 {
1440 m_dirty = true;
1441 }
1442
1443 void wxTextCtrl::DiscardEdits()
1444 {
1445 m_dirty = false;
1446 }
1447
1448 int wxTextCtrl::GetNumberOfLines() const
1449 {
1450 if ( m_macUsesTXN )
1451 {
1452 ItemCount lines ;
1453 TXNGetLineCount((TXNObject)m_macTXN, &lines ) ;
1454 return lines ;
1455 }
1456 else
1457 {
1458 wxString content = GetValue() ;
1459
1460 int count = 1;
1461 for (size_t i = 0; i < content.Length() ; i++)
1462 {
1463 if (content[i] == '\r') count++;
1464 }
1465 return count;
1466 }
1467 }
1468
1469 long wxTextCtrl::XYToPosition(long x, long y) const
1470 {
1471 // TODO
1472 return 0;
1473 }
1474
1475 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
1476 {
1477 return FALSE ;
1478 }
1479
1480 void wxTextCtrl::ShowPosition(long pos)
1481 {
1482 #if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER)
1483 if ( m_macUsesTXN )
1484 {
1485 Point current ;
1486 Point desired ;
1487 TXNOffset selstart , selend ;
1488 TXNGetSelection( (TXNObject) m_macTXN , &selstart , &selend) ;
1489 TXNOffsetToPoint( (TXNObject) m_macTXN, selstart , &current);
1490 TXNOffsetToPoint( (TXNObject) m_macTXN, pos , &desired);
1491 //TODO use HIPoints for 10.3 and above
1492 if ( (UInt32) TXNScroll != (UInt32) kUnresolvedCFragSymbolAddress )
1493 {
1494 OSErr theErr = noErr;
1495 SInt32 dv = desired.v - current.v ;
1496 SInt32 dh = desired.h - current.h ;
1497 TXNShowSelection( (TXNObject) m_macTXN , true ) ;
1498 theErr = TXNScroll( (TXNObject) m_macTXN, kTXNScrollUnitsInPixels , kTXNScrollUnitsInPixels , &dv , &dh );
1499 wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
1500 }
1501 }
1502 #endif
1503 }
1504
1505 int wxTextCtrl::GetLineLength(long lineNo) const
1506 {
1507 // TODO change this if possible to reflect real lines
1508 wxString content = GetValue() ;
1509
1510 // Find line first
1511 int count = 0;
1512 for (size_t i = 0; i < content.Length() ; i++)
1513 {
1514 if (count == lineNo)
1515 {
1516 // Count chars in line then
1517 count = 0;
1518 for (size_t j = i; j < content.Length(); j++)
1519 {
1520 count++;
1521 if (content[j] == '\n') return count;
1522 }
1523
1524 return count;
1525 }
1526 if (content[i] == '\n') count++;
1527 }
1528 return 0;
1529 }
1530
1531 wxString wxTextCtrl::GetLineText(long lineNo) const
1532 {
1533 // TODO change this if possible to reflect real lines
1534 wxString content = GetValue() ;
1535
1536 // Find line first
1537 int count = 0;
1538 for (size_t i = 0; i < content.Length() ; i++)
1539 {
1540 if (count == lineNo)
1541 {
1542 // Add chars in line then
1543 wxString tmp;
1544
1545 for (size_t j = i; j < content.Length(); j++)
1546 {
1547 if (content[j] == '\n')
1548 return tmp;
1549
1550 tmp += content[j];
1551 }
1552
1553 return tmp;
1554 }
1555 if (content[i] == '\n') count++;
1556 }
1557 return wxEmptyString ;
1558 }
1559
1560 /*
1561 * Text item
1562 */
1563
1564 void wxTextCtrl::Command(wxCommandEvent & event)
1565 {
1566 SetValue (event.GetString());
1567 ProcessCommand (event);
1568 }
1569
1570 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
1571 {
1572 // By default, load the first file into the text window.
1573 if (event.GetNumberOfFiles() > 0)
1574 {
1575 LoadFile(event.GetFiles()[0]);
1576 }
1577 }
1578
1579 void wxTextCtrl::OnChar(wxKeyEvent& event)
1580 {
1581 int key = event.GetKeyCode() ;
1582 bool eat_key = false ;
1583
1584 if ( key == 'c' && event.MetaDown() )
1585 {
1586 if ( CanCopy() )
1587 Copy() ;
1588 return ;
1589 }
1590
1591 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
1592 !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1593 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1594 )
1595 {
1596 // eat it
1597 return ;
1598 }
1599
1600 // assume that any key not processed yet is going to modify the control
1601 m_dirty = true;
1602
1603 if ( key == 'v' && event.MetaDown() )
1604 {
1605 if ( CanPaste() )
1606 Paste() ;
1607 return ;
1608 }
1609 if ( key == 'x' && event.MetaDown() )
1610 {
1611 if ( CanCut() )
1612 Cut() ;
1613 return ;
1614 }
1615 switch ( key )
1616 {
1617 case WXK_RETURN:
1618 if (m_windowStyle & wxPROCESS_ENTER)
1619 {
1620 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1621 event.SetEventObject( this );
1622 event.SetString( GetValue() );
1623 if ( GetEventHandler()->ProcessEvent(event) )
1624 return;
1625 }
1626 if ( !(m_windowStyle & wxTE_MULTILINE) )
1627 {
1628 wxWindow *parent = GetParent();
1629 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
1630 parent = parent->GetParent() ;
1631 }
1632 if ( parent && parent->GetDefaultItem() )
1633 {
1634 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
1635 wxButton);
1636 if ( def && def->IsEnabled() )
1637 {
1638 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
1639 event.SetEventObject(def);
1640 def->Command(event);
1641 return ;
1642 }
1643 }
1644
1645 // this will make wxWindows eat the ENTER key so that
1646 // we actually prevent line wrapping in a single line
1647 // text control
1648 eat_key = TRUE;
1649 }
1650
1651 break;
1652
1653 case WXK_TAB:
1654 // always produce navigation event - even if we process TAB
1655 // ourselves the fact that we got here means that the user code
1656 // decided to skip processing of this TAB - probably to let it
1657 // do its default job.
1658 {
1659 wxNavigationKeyEvent eventNav;
1660 eventNav.SetDirection(!event.ShiftDown());
1661 eventNav.SetWindowChange(event.ControlDown());
1662 eventNav.SetEventObject(this);
1663
1664 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
1665 return;
1666
1667 event.Skip() ;
1668 return;
1669 }
1670 break;
1671 }
1672
1673 if (!eat_key)
1674 {
1675 // perform keystroke handling
1676 #if TARGET_CARBON
1677 if ( m_macUsesTXN && wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
1678 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
1679 else
1680 {
1681 EventRecord rec ;
1682 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
1683 {
1684 EventRecord *ev = &rec ;
1685 short keycode ;
1686 short keychar ;
1687 keychar = short(ev->message & charCodeMask);
1688 keycode = short(ev->message & keyCodeMask) >> 8 ;
1689
1690 ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ;
1691 }
1692 }
1693 #else
1694 EventRecord *ev = (EventRecord*) wxTheApp->MacGetCurrentEvent() ;
1695 short keycode ;
1696 short keychar ;
1697 keychar = short(ev->message & charCodeMask);
1698 keycode = short(ev->message & keyCodeMask) >> 8 ;
1699
1700 ::HandleControlKey( (ControlHandle) m_macControl , keycode , keychar , ev->modifiers ) ;
1701 #endif
1702 }
1703 if ( ( key >= 0x20 && key < WXK_START ) ||
1704 key == WXK_RETURN ||
1705 key == WXK_DELETE ||
1706 key == WXK_BACK)
1707 {
1708 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1709 event1.SetString( GetValue() ) ;
1710 event1.SetEventObject( this );
1711 wxPostEvent(GetEventHandler(),event1);
1712 }
1713 }
1714
1715 void wxTextCtrl::MacSuperShown( bool show )
1716 {
1717 bool former = m_macControlIsShown ;
1718 wxControl::MacSuperShown( show ) ;
1719 if ( (former != m_macControlIsShown) && m_macUsesTXN )
1720 {
1721 if ( m_macControlIsShown )
1722 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1723 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1724 else
1725 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1726 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1727 }
1728 }
1729
1730 bool wxTextCtrl::Show(bool show)
1731 {
1732 bool former = m_macControlIsShown ;
1733
1734 bool retval = wxControl::Show( show ) ;
1735
1736 if ( former != m_macControlIsShown && m_macUsesTXN )
1737 {
1738 if ( m_macControlIsShown )
1739 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1740 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom,(**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1741 else
1742 TXNSetFrameBounds( (TXNObject) m_macTXN, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.top + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.left,
1743 (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.bottom + 30000, (**(STPTextPaneVars **)m_macTXNvars).fRTextArea.right, (**(STPTextPaneVars **)m_macTXNvars).fTXNFrame);
1744 }
1745
1746 return retval ;
1747 }
1748
1749 // ----------------------------------------------------------------------------
1750 // standard handlers for standard edit menu events
1751 // ----------------------------------------------------------------------------
1752
1753 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1754 {
1755 Cut();
1756 }
1757
1758 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1759 {
1760 Copy();
1761 }
1762
1763 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1764 {
1765 Paste();
1766 }
1767
1768 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1769 {
1770 Undo();
1771 }
1772
1773 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1774 {
1775 Redo();
1776 }
1777
1778 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1779 {
1780 event.Enable( CanCut() );
1781 }
1782
1783 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1784 {
1785 event.Enable( CanCopy() );
1786 }
1787
1788 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1789 {
1790 event.Enable( CanPaste() );
1791 }
1792
1793 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1794 {
1795 event.Enable( CanUndo() );
1796 }
1797
1798 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1799 {
1800 event.Enable( CanRedo() );
1801 }
1802
1803 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1804 {
1805 if ( m_macUsesTXN )
1806 return true ;
1807 else
1808 return wxWindow::MacSetupCursor( pt ) ;
1809 }
1810
1811 #endif
1812 // wxUSE_TEXTCTRL