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