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