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