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