1 /////////////////////////////////////////////////////////////////////////////
8 // Copyright: (c) AUTHOR
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "textctrl.h"
21 #include <sys/types.h>
30 #include "wx/button.h"
31 #include "wx/toplevel.h"
32 #include "wx/textctrl.h"
33 #include "wx/notebook.h"
34 #include "wx/tabctrl.h"
35 #include "wx/settings.h"
36 #include "wx/filefn.h"
39 #if defined(__BORLANDC__) && !defined(__WIN32__)
41 #elif !defined(__MWERKS__) && !defined(__GNUWIN32) && !defined(__DARWIN__)
48 #include <MacTextEditor.h>
49 #include "ATSUnicode.h"
50 #include "TextCommon.h"
51 #include "TextEncodingConverter.h"
52 #include "wx/mac/uma.h"
54 extern wxApp
*wxTheApp
;
56 // CS:TODO we still have a problem getting properly at the text events of a control because under Carbon
57 // the MLTE engine registers itself for the key events thus the normal flow never occurs, the only measure for the
58 // moment is to avoid setting the true focus on the control, the proper solution at the end would be to have
59 // an alternate path for carbon key events that routes automatically into the same wx flow of events
61 #include "MacTextEditor.h"
65 /* kmUPTextPart is the part code we return to indicate the user has clicked
66 in the text area of our control */
67 #define kmUPTextPart 1
69 /* kmUPScrollPart is the part code we return to indicate the user has clicked
70 in the scroll bar part of the control. */
71 #define kmUPScrollPart 2
74 /* routines for using existing user pane controls.
75 These routines are useful for cases where you would like to use an
76 existing user pane control in, say, a dialog window as a scrolling
79 /* mUPOpenControl initializes a user pane control so it will be drawn
80 and will behave as a scrolling text edit field inside of a window.
81 This routine performs all of the initialization steps necessary,
82 except it does not create the user pane control itself. theControl
83 should refer to a user pane control that you have either created
84 yourself or extracted from a dialog's control heirarchy using
85 the GetDialogItemAsControl routine. */
86 OSStatus
mUPOpenControl(ControlHandle theControl
, bool multiline
);
88 /* Utility Routines */
94 /* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus
95 routine. In our focus switching routine this part code is understood
96 as meaning 'the user has clicked in the control and we need to switch
97 the current focus to ourselves before we can continue'. */
98 #define kUserClickedToFocusPart 100
101 /* kmUPClickScrollDelayTicks is a time measurement in ticks used to
102 slow the speed of 'auto scrolling' inside of our clickloop routine.
103 This value prevents the text from wizzzzzing by while the mouse
104 is being held down inside of the text area. */
105 #define kmUPClickScrollDelayTicks 3
108 /* STPTextPaneVars is a structure used for storing the the mUP Control's
109 internal variables and state information. A handle to this record is
110 stored in the pane control's reference value field using the
111 SetControlReference routine. */
114 /* OS records referenced */
115 TXNObject fTXNRec
; /* the txn record */
116 TXNFrameID fTXNFrame
; /* the txn frame ID */
117 ControlHandle fUserPaneRec
; /* handle to the user pane control */
118 WindowPtr fOwner
; /* window containing control */
119 GrafPtr fDrawingEnvironment
; /* grafport where control is drawn */
121 Boolean fInFocus
; /* true while the focus rect is drawn around the control */
122 Boolean fIsActive
; /* true while the control is drawn in the active state */
123 Boolean fTEActive
; /* reflects the activation state of the text edit record */
124 Boolean fInDialogWindow
; /* true if displayed in a dialog window */
125 /* calculated locations */
126 Rect fRTextArea
; /* area where the text is drawn */
127 Rect fRFocusOutline
; /* rectangle used to draw the focus box */
128 Rect fRTextOutline
; /* rectangle used to draw the border */
129 RgnHandle fTextBackgroundRgn
; /* background region for the text, erased before calling TEUpdate */
130 /* our focus advance override routine */
131 EventHandlerUPP handlerUPP
;
132 EventHandlerRef handlerRef
;
139 /* Univerals Procedure Pointer variables used by the
140 mUP Control. These variables are set up
141 the first time that mUPOpenControl is called. */
142 ControlUserPaneDrawUPP gTPDrawProc
= NULL
;
143 ControlUserPaneHitTestUPP gTPHitProc
= NULL
;
144 ControlUserPaneTrackingUPP gTPTrackProc
= NULL
;
145 ControlUserPaneIdleUPP gTPIdleProc
= NULL
;
146 ControlUserPaneKeyDownUPP gTPKeyProc
= NULL
;
147 ControlUserPaneActivateUPP gTPActivateProc
= NULL
;
148 ControlUserPaneFocusUPP gTPFocusProc
= NULL
;
150 /* TPActivatePaneText activates or deactivates the text edit record
151 according to the value of setActive. The primary purpose of this
152 routine is to ensure each call is only made once. */
153 static void TPActivatePaneText(STPTextPaneVars
**tpvars
, Boolean setActive
) {
154 STPTextPaneVars
*varsp
;
156 if (varsp
->fTEActive
!= setActive
) {
158 varsp
->fTEActive
= setActive
;
160 TXNActivate(varsp
->fTXNRec
, varsp
->fTXNFrame
, varsp
->fTEActive
);
163 TXNFocus( varsp
->fTXNRec
, varsp
->fTEActive
);
168 /* TPFocusPaneText set the focus state for the text record. */
169 static void TPFocusPaneText(STPTextPaneVars
**tpvars
, Boolean setFocus
) {
170 STPTextPaneVars
*varsp
;
172 if (varsp
->fInFocus
!= setFocus
) {
173 varsp
->fInFocus
= setFocus
;
174 TXNFocus( varsp
->fTXNRec
, varsp
->fInFocus
);
179 /* TPPaneDrawProc is called to redraw the control and for update events
180 referring to the control. This routine erases the text area's background,
181 and redraws the text. This routine assumes the scroll bar has been
182 redrawn by a call to DrawControls. */
183 static pascal void TPPaneDrawProc(ControlRef theControl
, ControlPartCode thePart
) {
184 STPTextPaneVars
**tpvars
, *varsp
;
187 /* set up our globals */
189 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
190 if (tpvars
!= NULL
) {
191 state
= HGetState((Handle
) tpvars
);
192 HLock((Handle
) tpvars
);
195 /* save the drawing state */
196 SetPort((**tpvars
).fDrawingEnvironment
);
197 /* verify our boundary */
198 GetControlBounds(theControl
, &bounds
);
199 if ( ! EqualRect(&bounds
, &varsp
->fRFocusOutline
) ) {
200 // scrollbar is on the border, we add one
201 Rect oldbounds
= varsp
->fRFocusOutline
;
202 InsetRect( &oldbounds
, -1 , -1 ) ;
204 InvalWindowRect( GetControlOwner( theControl
) , &oldbounds
) ;
205 SetRect(&varsp
->fRFocusOutline
, bounds
.left
, bounds
.top
, bounds
.right
, bounds
.bottom
);
206 SetRect(&varsp
->fRTextOutline
, bounds
.left
, bounds
.top
, bounds
.right
, bounds
.bottom
);
207 SetRect(&varsp
->fRTextArea
, bounds
.left
+ 2 , bounds
.top
+ (varsp
->fMultiline
? 0 : 2) ,
208 bounds
.right
- (varsp
->fMultiline
? 0 : 2), bounds
.bottom
- (varsp
->fMultiline
? 0 : 2));
209 RectRgn(varsp
->fTextBackgroundRgn
, &varsp
->fRTextOutline
);
210 TXNSetFrameBounds( varsp
->fTXNRec
, varsp
->fRTextArea
.top
, varsp
->fRTextArea
.left
,
211 varsp
->fRTextArea
.bottom
, varsp
->fRTextArea
.right
, varsp
->fTXNFrame
);
214 /* update the text region */
215 RGBColor white
= { 65535 , 65535 , 65535 } ;
216 RGBBackColor( &white
) ;
217 EraseRgn(varsp
->fTextBackgroundRgn
);
218 TXNDraw(varsp
->fTXNRec
, NULL
);
219 /* restore the drawing environment */
220 /* draw the text frame and focus frame (if necessary) */
221 DrawThemeEditTextFrame(&varsp
->fRTextOutline
, varsp
->fIsActive
? kThemeStateActive
: kThemeStateInactive
);
222 if ((**tpvars
).fIsActive
&& varsp
->fInFocus
) DrawThemeFocusRect(&varsp
->fRFocusOutline
, true);
223 /* release our globals */
224 HSetState((Handle
) tpvars
, state
);
229 /* TPPaneHitTestProc is called when the control manager would
230 like to determine what part of the control the mouse resides over.
231 We also call this routine from our tracking proc to determine how
232 to handle mouse clicks. */
233 static pascal ControlPartCode
TPPaneHitTestProc(ControlHandle theControl
, Point where
) {
234 STPTextPaneVars
**tpvars
;
235 ControlPartCode result
;
237 /* set up our locals and lock down our globals*/
239 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
240 if (tpvars
!= NULL
) {
241 state
= HGetState((Handle
) tpvars
);
242 HLock((Handle
) tpvars
);
243 /* find the region where we clicked */
244 if (PtInRect(where
, &(**tpvars
).fRTextArea
)) {
245 result
= kmUPTextPart
;
247 /* release oure globals */
248 HSetState((Handle
) tpvars
, state
);
257 /* TPPaneTrackingProc is called when the mouse is being held down
258 over our control. This routine handles clicks in the text area
259 and in the scroll bar. */
260 static pascal ControlPartCode
TPPaneTrackingProc(ControlHandle theControl
, Point startPt
, ControlActionUPP actionProc
) {
261 STPTextPaneVars
**tpvars
, *varsp
;
263 ControlPartCode partCodeResult
;
264 /* make sure we have some variables... */
266 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
267 if (tpvars
!= NULL
) {
269 state
= HGetState((Handle
) tpvars
);
270 HLock((Handle
) tpvars
);
272 /* we don't do any of these functions unless we're in focus */
273 if ( ! varsp
->fInFocus
) {
275 owner
= GetControlOwner(theControl
);
276 ClearKeyboardFocus(owner
);
277 SetKeyboardFocus(owner
, theControl
, kUserClickedToFocusPart
);
279 /* find the location for the click */
280 switch (TPPaneHitTestProc(theControl
, startPt
)) {
282 /* handle clicks in the text part */
284 { SetPort((**tpvars
).fDrawingEnvironment
);
285 TXNClick( varsp
->fTXNRec
, (const EventRecord
*) wxTheApp
->MacGetCurrentEvent());
291 HSetState((Handle
) tpvars
, state
);
293 return partCodeResult
;
297 /* TPPaneIdleProc is our user pane idle routine. When our text field
298 is active and in focus, we use this routine to set the cursor. */
299 static pascal void TPPaneIdleProc(ControlHandle theControl
) {
300 STPTextPaneVars
**tpvars
, *varsp
;
302 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
303 if (tpvars
!= NULL
) {
304 /* if we're not active, then we have nothing to say about the cursor */
305 if ((**tpvars
).fIsActive
) {
309 /* lock down the globals */
310 state
= HGetState((Handle
) tpvars
);
311 HLock((Handle
) tpvars
);
313 /* get the current mouse coordinates (in our window) */
314 SetPortWindowPort(GetControlOwner(theControl
));
316 /* there's a 'focus thing' and an 'unfocused thing' */
317 if (varsp
->fInFocus
) {
318 /* flash the cursor */
319 SetPort((**tpvars
).fDrawingEnvironment
);
320 TXNIdle(varsp
->fTXNRec
);
322 if (PtInRect(mousep
, &varsp
->fRTextArea
)) {
324 RectRgn((theRgn
= NewRgn()), &varsp
->fRTextArea
);
325 TXNAdjustCursor(varsp
->fTXNRec
, theRgn
);
327 } else SetThemeCursor(kThemeArrowCursor
);
329 /* if it's in our bounds, set the cursor */
330 GetControlBounds(theControl
, &bounds
);
331 if (PtInRect(mousep
, &bounds
))
332 SetThemeCursor(kThemeArrowCursor
);
335 HSetState((Handle
) tpvars
, state
);
341 /* TPPaneKeyDownProc is called whenever a keydown event is directed
342 at our control. Here, we direct the keydown event to the text
343 edit record and redraw the scroll bar and text field as appropriate. */
344 static pascal ControlPartCode
TPPaneKeyDownProc(ControlHandle theControl
,
345 SInt16 keyCode
, SInt16 charCode
, SInt16 modifiers
) {
346 STPTextPaneVars
**tpvars
;
347 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
348 if (tpvars
!= NULL
) {
349 if ((**tpvars
).fInFocus
) {
350 /* turn autoscrolling on and send the key event to text edit */
351 SetPort((**tpvars
).fDrawingEnvironment
);
353 memset( &ev
, 0 , sizeof( ev
) ) ;
355 ev
.modifiers
= modifiers
;
356 ev
.message
= (( keyCode
<< 8 ) & keyCodeMask
) + ( charCode
& charCodeMask
) ;
357 TXNKeyDown( (**tpvars
).fTXNRec
, &ev
);
360 return kControlEntireControl
;
364 /* TPPaneActivateProc is called when the window containing
365 the user pane control receives activate events. Here, we redraw
366 the control and it's text as necessary for the activation state. */
367 static pascal void TPPaneActivateProc(ControlHandle theControl
, Boolean activating
) {
369 STPTextPaneVars
**tpvars
, *varsp
;
372 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
373 if (tpvars
!= NULL
) {
374 state
= HGetState((Handle
) tpvars
);
375 HLock((Handle
) tpvars
);
377 /* de/activate the text edit record */
378 SetPort((**tpvars
).fDrawingEnvironment
);
379 GetControlBounds(theControl
, &bounds
);
380 varsp
->fIsActive
= activating
;
381 TPActivatePaneText(tpvars
, varsp
->fIsActive
&& varsp
->fInFocus
);
382 /* redraw the frame */
383 DrawThemeEditTextFrame(&varsp
->fRTextOutline
, varsp
->fIsActive
? kThemeStateActive
: kThemeStateInactive
);
384 if (varsp
->fInFocus
) DrawThemeFocusRect(&varsp
->fRFocusOutline
, varsp
->fIsActive
);
385 HSetState((Handle
) tpvars
, state
);
390 /* TPPaneFocusProc is called when every the focus changes to or
391 from our control. Herein, switch the focus appropriately
392 according to the parameters and redraw the control as
394 static pascal ControlPartCode
TPPaneFocusProc(ControlHandle theControl
, ControlFocusPart action
) {
395 ControlPartCode focusResult
;
396 STPTextPaneVars
**tpvars
, *varsp
;
399 focusResult
= kControlFocusNoPart
;
400 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
401 if (tpvars
!= NULL
) {
402 state
= HGetState((Handle
) tpvars
);
403 HLock((Handle
) tpvars
);
405 /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is
406 tabbing forwards (or shift tabbing backwards) through the items in the dialog,
407 and kControlFocusNextPart will be received. When the user clicks in our field
408 and it is not the current focus, then the constant kUserClickedToFocusPart will
409 be received. The constant kControlFocusNoPart will be received when our control
410 is the current focus and the user clicks in another control. In your focus routine,
411 you should respond to these codes as follows:
413 kControlFocusNoPart - turn off focus and return kControlFocusNoPart. redraw
414 the control and the focus rectangle as necessary.
416 kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off
417 depending on its current state. redraw the control and the focus rectangle
418 as appropriate for the new focus state. If the focus state is 'off', return the constant
419 kControlFocusNoPart, otherwise return a non-zero part code.
420 kUserClickedToFocusPart - is a constant defined for this example. You should
421 define your own value for handling click-to-focus type events. */
422 /* save the drawing state */
423 SetPort((**tpvars
).fDrawingEnvironment
);
424 /* calculate the next highlight state */
427 case kControlFocusNoPart
:
428 TPFocusPaneText(tpvars
, false);
429 focusResult
= kControlFocusNoPart
;
431 case kUserClickedToFocusPart
:
432 TPFocusPaneText(tpvars
, true);
435 case kControlFocusPrevPart
:
436 case kControlFocusNextPart
:
437 TPFocusPaneText(tpvars
, ( ! varsp
->fInFocus
));
438 focusResult
= varsp
->fInFocus
? 1 : kControlFocusNoPart
;
441 TPActivatePaneText(tpvars
, varsp
->fIsActive
&& varsp
->fInFocus
);
442 /* redraw the text fram and focus rectangle to indicate the
444 DrawThemeEditTextFrame(&varsp
->fRTextOutline
, varsp
->fIsActive
? kThemeStateActive
: kThemeStateInactive
);
445 DrawThemeFocusRect(&varsp
->fRFocusOutline
, varsp
->fIsActive
&& varsp
->fInFocus
);
447 HSetState((Handle
) tpvars
, state
);
453 /* mUPOpenControl initializes a user pane control so it will be drawn
454 and will behave as a scrolling text edit field inside of a window.
455 This routine performs all of the initialization steps necessary,
456 except it does not create the user pane control itself. theControl
457 should refer to a user pane control that you have either created
458 yourself or extracted from a dialog's control heirarchy using
459 the GetDialogItemAsControl routine. */
460 OSStatus
mUPOpenControl(ControlHandle theControl
, bool multiline
)
464 STPTextPaneVars
**tpvars
, *varsp
;
466 RGBColor rgbWhite
= {0xFFFF, 0xFFFF, 0xFFFF};
469 /* set up our globals */
470 if (gTPDrawProc
== NULL
) gTPDrawProc
= NewControlUserPaneDrawUPP(TPPaneDrawProc
);
471 if (gTPHitProc
== NULL
) gTPHitProc
= NewControlUserPaneHitTestUPP(TPPaneHitTestProc
);
472 if (gTPTrackProc
== NULL
) gTPTrackProc
= NewControlUserPaneTrackingUPP(TPPaneTrackingProc
);
473 if (gTPIdleProc
== NULL
) gTPIdleProc
= NewControlUserPaneIdleUPP(TPPaneIdleProc
);
474 if (gTPKeyProc
== NULL
) gTPKeyProc
= NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc
);
475 if (gTPActivateProc
== NULL
) gTPActivateProc
= NewControlUserPaneActivateUPP(TPPaneActivateProc
);
476 if (gTPFocusProc
== NULL
) gTPFocusProc
= NewControlUserPaneFocusUPP(TPPaneFocusProc
);
478 /* allocate our private storage */
479 tpvars
= (STPTextPaneVars
**) NewHandleClear(sizeof(STPTextPaneVars
));
480 SetControlReference(theControl
, (long) tpvars
);
481 HLock((Handle
) tpvars
);
483 /* set the initial settings for our private data */
484 varsp
->fMultiline
= multiline
;
485 varsp
->fInFocus
= false;
486 varsp
->fIsActive
= true;
487 varsp
->fTEActive
= true; // in order to get a deactivate
488 varsp
->fUserPaneRec
= theControl
;
489 theWindow
= varsp
->fOwner
= GetControlOwner(theControl
);
491 varsp
->fDrawingEnvironment
= (GrafPtr
) GetWindowPort(theWindow
);
493 varsp
->fInDialogWindow
= ( GetWindowKind(varsp
->fOwner
) == kDialogWindowKind
);
494 /* set up the user pane procedures */
495 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneDrawProcTag
, sizeof(gTPDrawProc
), &gTPDrawProc
);
496 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneHitTestProcTag
, sizeof(gTPHitProc
), &gTPHitProc
);
497 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneTrackingProcTag
, sizeof(gTPTrackProc
), &gTPTrackProc
);
498 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneIdleProcTag
, sizeof(gTPIdleProc
), &gTPIdleProc
);
499 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneKeyDownProcTag
, sizeof(gTPKeyProc
), &gTPKeyProc
);
500 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneActivateProcTag
, sizeof(gTPActivateProc
), &gTPActivateProc
);
501 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneFocusProcTag
, sizeof(gTPFocusProc
), &gTPFocusProc
);
502 /* calculate the rectangles used by the control */
503 GetControlBounds(theControl
, &bounds
);
504 SetRect(&varsp
->fRFocusOutline
, bounds
.left
, bounds
.top
, bounds
.right
, bounds
.bottom
);
505 SetRect(&varsp
->fRTextOutline
, bounds
.left
, bounds
.top
, bounds
.right
, bounds
.bottom
);
506 SetRect(&varsp
->fRTextArea
, bounds
.left
+ 2 , bounds
.top
+ (varsp
->fMultiline
? 0 : 2) ,
507 bounds
.right
- (varsp
->fMultiline
? 0 : 2), bounds
.bottom
- (varsp
->fMultiline
? 0 : 2));
508 /* calculate the background region for the text. In this case, it's kindof
509 and irregular region because we're setting the scroll bar a little ways inside
511 RectRgn((varsp
->fTextBackgroundRgn
= NewRgn()), &varsp
->fRTextOutline
);
513 /* set up the drawing environment */
514 SetPort(varsp
->fDrawingEnvironment
);
516 /* create the new edit field */
517 TXNNewObject(NULL
, varsp
->fOwner
, &varsp
->fRTextArea
,
518 ( multiline
? kTXNWantVScrollBarMask
: 0 ) |
519 kTXNDontDrawCaretWhenInactiveMask
|
520 kTXNDontDrawSelectionWhenInactiveMask
|
521 kTXNAlwaysWrapAtViewEdgeMask
,
522 kTXNTextEditStyleFrameType
,
524 kTXNSystemDefaultEncoding
,
525 &varsp
->fTXNRec
, &varsp
->fTXNFrame
, (TXNObjectRefcon
) tpvars
);
531 GetThemeFont(kThemeSmallSystemFont
, GetApplicationScript() , fontName
, &fontSize
, &fontStyle
) ;
533 TXNTypeAttributes typeAttr
[] =
535 { kTXNQDFontNameAttribute
, kTXNQDFontNameAttributeSize
, { (void*) fontName
} } ,
536 { kTXNQDFontSizeAttribute
, kTXNFontSizeAttributeSize
, { (void*) (fontSize
<< 16) } } ,
537 { kTXNQDFontStyleAttribute
, kTXNQDFontStyleAttributeSize
, { (void*) normal
} } ,
540 OSStatus status
= TXNSetTypeAttributes (varsp
->fTXNRec
, sizeof( typeAttr
) / sizeof(TXNTypeAttributes
) , typeAttr
,
543 /* set the field's background */
544 tback
.bgType
= kTXNBackgroundTypeRGB
;
545 tback
.bg
.color
= rgbWhite
;
546 TXNSetBackground( varsp
->fTXNRec
, &tback
);
548 /* unlock our storage */
549 HUnlock((Handle
) tpvars
);
550 /* perform final activations and setup for our text field. Here,
551 we assume that the window is going to be the 'active' window. */
552 TPActivatePaneText(tpvars
, varsp
->fIsActive
&& varsp
->fInFocus
);
560 #if !USE_SHARED_LIBRARY
561 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
, wxControl
)
563 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
)
564 EVT_DROP_FILES(wxTextCtrl::OnDropFiles
)
565 EVT_CHAR(wxTextCtrl::OnChar
)
566 EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
)
567 EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
)
568 EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
)
569 EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
)
570 EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
)
572 EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
)
573 EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
)
574 EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
)
575 EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
)
576 EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
)
581 wxTextCtrl::wxTextCtrl()
585 m_macTXNvars
= NULL
;
586 m_macUsesTXN
= false ;
590 wxTextCtrl::~wxTextCtrl()
594 SetControlReference((ControlHandle
)m_macControl
, 0) ;
595 TXNDeleteObject((TXNObject
)m_macTXN
);
596 /* delete our private storage */
597 DisposeHandle((Handle
) m_macTXNvars
);
598 /* zero the control reference */
602 const short kVerticalMargin
= 2 ;
603 const short kHorizontalMargin
= 2 ;
605 bool wxTextCtrl::Create(wxWindow
*parent
, wxWindowID id
,
608 const wxSize
& size
, long style
,
609 const wxValidator
& validator
,
610 const wxString
& name
)
614 m_macTXNvars
= NULL
;
615 m_macUsesTXN
= false ;
618 m_macUsesTXN
= ! (style
& wxTE_PASSWORD
) ;
620 m_macUsesTXN
&= (TXNInitTextension
!= (void*) kUnresolvedCFragSymbolAddress
) ;
622 // base initialization
623 if ( !CreateBase(parent
, id
, pos
, size
, style
, validator
, name
) )
626 wxSize mySize
= size
;
629 m_macHorizontalBorder
= 5 ; // additional pixels around the real control
630 m_macVerticalBorder
= 3 ;
634 m_macHorizontalBorder
= 5 ; // additional pixels around the real control
635 m_macVerticalBorder
= 5 ;
642 if ( mySize.y == -1 )
645 if ( m_windowStyle & wxTE_MULTILINE )
648 mySize.y += 2 * m_macVerticalBorder ;
651 MacPreControlCreate( parent
, id
, "" , pos
, mySize
,style
, validator
, name
, &bounds
, title
) ;
653 if ( m_windowStyle
& wxTE_MULTILINE
)
655 wxASSERT_MSG( !(m_windowStyle
& wxTE_PROCESS_ENTER
),
656 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
658 m_windowStyle
|= wxTE_PROCESS_ENTER
;
664 m_macControl
= ::NewControl( MAC_WXHWND(parent
->MacGetRootWindow()) , &bounds
, "\p" , true , 0 , 0 , 1,
665 (style
& wxTE_PASSWORD
) ? kControlEditTextPasswordProc
: kControlEditTextProc
, (long) this ) ;
667 ::GetControlData((ControlHandle
) m_macControl
, 0, kControlEditTextTEHandleTag
, sizeof( TEHandle
) , (char*) &((TEHandle
) m_macTE
) , &size
) ;
674 featurSet
= kControlSupportsEmbedding
| kControlSupportsFocus
// | kControlWantsIdle
675 | kControlWantsActivate
| kControlHandlesTracking
| kControlHasSpecialBackground
676 | kControlGetsFocusOnClick
| kControlSupportsLiveFeedback
;
677 /* create the control */
678 m_macControl
= NewControl(MAC_WXHWND(parent
->MacGetRootWindow()), &bounds
, "\p", true, featurSet
, 0, featurSet
, kControlUserPaneProc
, 0);
679 /* set up the mUP specific features and data */
680 mUPOpenControl((ControlHandle
) m_macControl
, m_windowStyle
& wxTE_MULTILINE
);
683 parent
->MacGetTopLevelWindow()->MacInstallEventHandler() ;
686 MacPostControlCreate() ;
690 if( wxApp::s_macDefaultEncodingIsPC
)
691 value
= wxMacMakeMacStringFromPC( st
) ;
697 ::SetControlData( (ControlHandle
) m_macControl
, 0, ( m_windowStyle
& wxTE_PASSWORD
) ? kControlEditTextPasswordTag
: kControlEditTextTextTag
, value
.Length() , (char*) ((const char*)value
) ) ;
701 STPTextPaneVars
**tpvars
;
703 tpvars
= (STPTextPaneVars
**) GetControlReference((ControlHandle
) m_macControl
);
704 /* set the text in the record */
705 TXNSetData( (**tpvars
).fTXNRec
, kTXNTextData
, (void*)value
.c_str(), value
.Length(),
706 kTXNStartOffset
, kTXNEndOffset
);
707 m_macTXN
= (**tpvars
).fTXNRec
;
708 m_macTXNvars
= tpvars
;
709 m_macUsesTXN
= true ;
715 wxString
wxTextCtrl::GetValue() const
721 ::GetControlData( (ControlHandle
) m_macControl
, 0,
722 ( m_windowStyle
& wxTE_PASSWORD
) ? kControlEditTextPasswordTag
: kControlEditTextTextTag
,
723 32767 , wxBuffer
, &actualsize
) ;
728 OSStatus err
= TXNGetDataEncoded( ((TXNObject
) m_macTXN
), kTXNStartOffset
, kTXNEndOffset
, &theText
, kTXNTextData
);
736 actualsize
= GetHandleSize( theText
) ;
738 strncpy( wxBuffer
, *theText
, actualsize
) ;
739 DisposeHandle( theText
) ;
743 wxBuffer
[actualsize
] = 0 ;
747 if( wxApp::s_macDefaultEncodingIsPC
)
748 value
= wxMacMakePCStringFromMac( wxBuffer
) ;
752 value
.Replace( "\r", "\n" );
757 void wxTextCtrl::GetSelection(long* from
, long* to
) const
761 *from
= (**((TEHandle
) m_macTE
)).selStart
;
762 *to
= (**((TEHandle
) m_macTE
)).selEnd
;
766 TXNGetSelection( ((TXNObject
) m_macTXN
) , (TXNOffset
*) from
, (TXNOffset
*) to
) ;
770 void wxTextCtrl::SetValue(const wxString
& st
)
774 if( wxApp::s_macDefaultEncodingIsPC
)
775 value
= wxMacMakeMacStringFromPC( st
) ;
779 value
.Replace( "\n", "\r" );
783 ::SetControlData((ControlHandle
) m_macControl
, 0, ( m_windowStyle
& wxTE_PASSWORD
) ? kControlEditTextPasswordTag
: kControlEditTextTextTag
, value
.Length() , (char*) ((const char*)value
) ) ;
787 TXNSetData( ((TXNObject
) m_macTXN
), kTXNTextData
, (void*)value
.c_str(), value
.Length(),
788 kTXNStartOffset
, kTXNEndOffset
);
794 // Clipboard operations
795 void wxTextCtrl::Copy()
801 TECopy( ((TEHandle
) m_macTE
) ) ;
809 TXNCopy((TXNObject
)m_macTXN
);
810 TXNConvertToPublicScrap();
815 void wxTextCtrl::Cut()
821 TECut( ((TEHandle
) m_macTE
) ) ;
829 TXNCut((TXNObject
)m_macTXN
);
830 TXNConvertToPublicScrap();
832 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, m_windowId
);
833 event
.SetString( GetValue() ) ;
834 event
.SetEventObject( this );
835 GetEventHandler()->ProcessEvent(event
);
839 void wxTextCtrl::Paste()
846 TEPaste( (TEHandle
) m_macTE
) ;
851 TXNConvertFromPublicScrap();
852 TXNPaste((TXNObject
)m_macTXN
);
854 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, m_windowId
);
855 event
.SetString( GetValue() ) ;
856 event
.SetEventObject( this );
857 GetEventHandler()->ProcessEvent(event
);
861 bool wxTextCtrl::CanCopy() const
863 // Can copy if there's a selection
865 GetSelection(& from
, & to
);
869 bool wxTextCtrl::CanCut() const
875 // Can cut if there's a selection
877 GetSelection(& from
, & to
);
881 bool wxTextCtrl::CanPaste() const
888 OSStatus err
= noErr
;
891 err
= GetCurrentScrap( &scrapRef
);
892 if ( err
!= noTypeErr
&& err
!= memFullErr
)
894 ScrapFlavorFlags flavorFlags
;
897 if (( err
= GetScrapFlavorFlags( scrapRef
, 'TEXT', &flavorFlags
)) == noErr
)
899 if (( err
= GetScrapFlavorSize( scrapRef
, 'TEXT', &byteCount
)) == noErr
)
908 if ( GetScrap( NULL
, 'TEXT' , &offset
) > 0 )
916 void wxTextCtrl::SetEditable(bool editable
)
918 if ( editable
!= m_editable
)
920 m_editable
= editable
;
922 UMAActivateControl( (ControlHandle
) m_macControl
) ;
924 UMADeactivateControl((ControlHandle
) m_macControl
) ;
928 void wxTextCtrl::SetInsertionPoint(long pos
)
930 SetSelection( pos
, pos
) ;
933 void wxTextCtrl::SetInsertionPointEnd()
935 long pos
= GetLastPosition();
936 SetInsertionPoint(pos
);
939 long wxTextCtrl::GetInsertionPoint() const
942 GetSelection( &begin
, &end
) ;
946 long wxTextCtrl::GetLastPosition() const
950 return (**((TEHandle
) m_macTE
)).teLength
;
956 OSErr err
= TXNGetDataEncoded( (TXNObject
) m_macTXN
, kTXNStartOffset
, kTXNEndOffset
, &theText
, kTXNTextData
);
964 actualsize
= GetHandleSize( theText
) ;
965 DisposeHandle( theText
) ;
971 void wxTextCtrl::Replace(long from
, long to
, const wxString
& value
)
975 ControlEditTextSelectionRec selection
;
977 selection
.selStart
= from
;
978 selection
.selEnd
= to
;
979 ::SetControlData((ControlHandle
) m_macControl
, 0, kControlEditTextSelectionTag
, sizeof( selection
) , (char*) &selection
) ;
980 TESetSelect( from
, to
, ((TEHandle
) m_macTE
) ) ;
981 TEDelete( ((TEHandle
) m_macTE
) ) ;
982 TEInsert( value
, value
.Length() , ((TEHandle
) m_macTE
) ) ;
986 TXNSetSelection( ((TXNObject
) m_macTXN
) , from
, to
) ;
987 TXNClear( ((TXNObject
) m_macTXN
) ) ;
988 TXNSetData( ((TXNObject
) m_macTXN
), kTXNTextData
, (void*)value
.c_str(), value
.Length(),
989 kTXNUseCurrentSelection
, kTXNUseCurrentSelection
);
994 void wxTextCtrl::Remove(long from
, long to
)
998 ControlEditTextSelectionRec selection
;
1000 selection
.selStart
= from
;
1001 selection
.selEnd
= to
;
1002 ::SetControlData( (ControlHandle
) m_macControl
, 0, kControlEditTextSelectionTag
, sizeof( selection
) , (char*) &selection
) ;
1003 TEDelete( ((TEHandle
) m_macTE
) ) ;
1007 TXNSetSelection( ((TXNObject
) m_macTXN
) , from
, to
) ;
1008 TXNClear( ((TXNObject
) m_macTXN
) ) ;
1013 void wxTextCtrl::SetSelection(long from
, long to
)
1016 if ( !m_macUsesTXN
)
1018 ControlEditTextSelectionRec selection
;
1019 selection
.selStart
= from
;
1020 selection
.selEnd
= to
;
1022 TESetSelect( selection
.selStart
, selection
.selEnd
, ((TEHandle
) m_macTE
) ) ;
1023 ::SetControlData((ControlHandle
) m_macControl
, 0, kControlEditTextSelectionTag
, sizeof( selection
) , (char*) &selection
) ;
1027 STPTextPaneVars
**tpvars
;
1028 /* set up our locals */
1029 tpvars
= (STPTextPaneVars
**) GetControlReference((ControlHandle
) m_macControl
);
1030 /* and our drawing environment as the operation
1031 may force a redraw in the text area. */
1032 SetPort((**tpvars
).fDrawingEnvironment
);
1033 /* change the selection */
1034 TXNSetSelection( (**tpvars
).fTXNRec
, from
, to
);
1038 bool wxTextCtrl::LoadFile(const wxString
& file
)
1040 if ( wxTextCtrlBase::LoadFile(file
) )
1048 void wxTextCtrl::WriteText(const wxString
& text
)
1051 if( wxApp::s_macDefaultEncodingIsPC
)
1052 value
= wxMacMakeMacStringFromPC( text
) ;
1055 if ( !m_macUsesTXN
)
1057 TEInsert( value
, value
.Length() , ((TEHandle
) m_macTE
) ) ;
1061 TXNSetData( ((TXNObject
) m_macTXN
), kTXNTextData
, (void*) (const char*)value
, value
.Length(),
1062 kTXNUseCurrentSelection
, kTXNUseCurrentSelection
);
1064 MacRedrawControl() ;
1067 void wxTextCtrl::AppendText(const wxString
& text
)
1069 SetInsertionPointEnd();
1073 void wxTextCtrl::Clear()
1075 if ( !IsEditable() )
1079 if ( !m_macUsesTXN
)
1081 ::SetControlData((ControlHandle
) m_macControl
, 0, ( m_windowStyle
& wxTE_PASSWORD
) ? kControlEditTextPasswordTag
: kControlEditTextTextTag
, 0 , (char*) ((const char*)NULL
) ) ;
1085 ClearCurrentScrap();
1086 TXNClear((TXNObject
)m_macTXN
);
1091 bool wxTextCtrl::IsModified() const
1096 bool wxTextCtrl::IsEditable() const
1098 return IsEnabled() && m_editable
;
1101 bool wxTextCtrl::AcceptsFocus() const
1103 // we don't want focus if we can't be edited
1104 return /*IsEditable() && */ wxControl::AcceptsFocus();
1107 wxSize
wxTextCtrl::DoGetBestSize() const
1122 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
1124 int wText = DEFAULT_ITEM_WIDTH;
1126 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
1128 return wxSize(wText, hText);
1130 if ( m_windowStyle
& wxTE_MULTILINE
)
1134 hText
+= 2 * m_macVerticalBorder
;
1135 wText
+= 2 * m_macHorizontalBorder
;
1136 //else: for single line control everything is ok
1137 return wxSize(wText
, hText
);
1140 // ----------------------------------------------------------------------------
1142 // ----------------------------------------------------------------------------
1144 void wxTextCtrl::Undo()
1151 void wxTextCtrl::Redo()
1158 bool wxTextCtrl::CanUndo() const
1163 bool wxTextCtrl::CanRedo() const
1168 // Makes 'unmodified'
1169 void wxTextCtrl::DiscardEdits()
1174 int wxTextCtrl::GetNumberOfLines() const
1176 // TODO change this if possible to reflect real lines
1177 wxString content
= GetValue() ;
1180 for (int i
= 0; i
< content
.Length() ; i
++)
1182 if (content
[i
] == '\r') count
++;
1188 long wxTextCtrl::XYToPosition(long x
, long y
) const
1194 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const
1199 void wxTextCtrl::ShowPosition(long pos
)
1204 int wxTextCtrl::GetLineLength(long lineNo
) const
1206 // TODO change this if possible to reflect real lines
1207 wxString content
= GetValue() ;
1211 for (int i
= 0; i
< content
.Length() ; i
++)
1213 if (count
== lineNo
)
1215 // Count chars in line then
1217 for (int j
= i
; j
< content
.Length(); j
++)
1220 if (content
[j
] == '\r') return count
;
1225 if (content
[i
] == '\r') count
++;
1230 wxString
wxTextCtrl::GetLineText(long lineNo
) const
1232 // TODO change this if possible to reflect real lines
1233 wxString content
= GetValue() ;
1237 for (int i
= 0; i
< content
.Length() ; i
++)
1239 if (count
== lineNo
)
1241 // Add chars in line then
1244 for (int j
= i
; j
< content
.Length(); j
++)
1246 if (content
[j
] == '\r')
1254 if (content
[i
] == '\r') count
++;
1263 void wxTextCtrl::Command(wxCommandEvent
& event
)
1265 SetValue (event
.GetString());
1266 ProcessCommand (event
);
1269 void wxTextCtrl::OnDropFiles(wxDropFilesEvent
& event
)
1271 // By default, load the first file into the text window.
1272 if (event
.GetNumberOfFiles() > 0)
1274 LoadFile(event
.GetFiles()[0]);
1278 void wxTextCtrl::OnChar(wxKeyEvent
& event
)
1280 int key
= event
.GetKeyCode() ;
1281 bool eat_key
= false ;
1283 if ( !IsEditable() && key
!= WXK_LEFT
&& key
!= WXK_RIGHT
&& key
!= WXK_DOWN
&& key
!= WXK_UP
&& key
!= WXK_TAB
&&
1284 !( key
== WXK_RETURN
&& ( (m_windowStyle
& wxPROCESS_ENTER
) || (m_windowStyle
& wxTE_MULTILINE
) ) )
1285 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1294 if (m_windowStyle
& wxPROCESS_ENTER
)
1296 wxCommandEvent
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
);
1297 event
.SetEventObject( this );
1298 event
.SetString( GetValue() );
1299 if ( GetEventHandler()->ProcessEvent(event
) )
1302 if ( !(m_windowStyle
& wxTE_MULTILINE
) )
1304 wxWindow
*parent
= GetParent();
1305 while( parent
&& !parent
->IsTopLevel() && parent
->GetDefaultItem() == NULL
) {
1306 parent
= parent
->GetParent() ;
1308 if ( parent
&& parent
->GetDefaultItem() )
1310 wxButton
*def
= wxDynamicCast(parent
->GetDefaultItem(),
1312 if ( def
&& def
->IsEnabled() )
1314 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, def
->GetId() );
1315 event
.SetEventObject(def
);
1316 def
->Command(event
);
1321 // this will make wxWindows eat the ENTER key so that
1322 // we actually prevent line wrapping in a single line
1330 // always produce navigation event - even if we process TAB
1331 // ourselves the fact that we got here means that the user code
1332 // decided to skip processing of this TAB - probably to let it
1333 // do its default job.
1335 wxNavigationKeyEvent eventNav
;
1336 eventNav
.SetDirection(!event
.ShiftDown());
1337 eventNav
.SetWindowChange(event
.ControlDown());
1338 eventNav
.SetEventObject(this);
1340 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav
) )
1355 key
== WXK_RETURN
||
1356 key
== WXK_DELETE
||
1359 wxCommandEvent
event1(wxEVT_COMMAND_TEXT_UPDATED
, m_windowId
);
1360 event1
.SetString( GetValue() ) ;
1361 event1
.SetEventObject( this );
1362 wxPostEvent(GetEventHandler(),event1
);
1366 void wxTextCtrl::MacSuperShown( bool show
)
1368 bool former
= m_macControlIsShown
;
1369 wxControl::MacSuperShown( show
) ;
1370 if ( (former
!= m_macControlIsShown
) && m_macUsesTXN
)
1372 if ( m_macControlIsShown
)
1373 TXNSetFrameBounds( (TXNObject
) m_macTXN
, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.top
, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.left
,
1374 (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.bottom
,(**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.right
, (**(STPTextPaneVars
**)m_macTXNvars
).fTXNFrame
);
1376 TXNSetFrameBounds( (TXNObject
) m_macTXN
, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.top
+ 30000, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.left
,
1377 (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.bottom
+ 30000, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.right
, (**(STPTextPaneVars
**)m_macTXNvars
).fTXNFrame
);
1381 bool wxTextCtrl::Show(bool show
)
1383 bool former
= m_macControlIsShown
;
1385 bool retval
= wxControl::Show( show
) ;
1387 if ( former
!= m_macControlIsShown
)
1389 if ( m_macControlIsShown
)
1390 TXNSetFrameBounds( (TXNObject
) m_macTXN
, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.top
, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.left
,
1391 (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.bottom
,(**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.right
, (**(STPTextPaneVars
**)m_macTXNvars
).fTXNFrame
);
1393 TXNSetFrameBounds( (TXNObject
) m_macTXN
, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.top
+ 30000, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.left
,
1394 (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.bottom
+ 30000, (**(STPTextPaneVars
**)m_macTXNvars
).fRTextArea
.right
, (**(STPTextPaneVars
**)m_macTXNvars
).fTXNFrame
);
1400 // ----------------------------------------------------------------------------
1401 // standard handlers for standard edit menu events
1402 // ----------------------------------------------------------------------------
1404 void wxTextCtrl::OnCut(wxCommandEvent
& event
)
1409 void wxTextCtrl::OnCopy(wxCommandEvent
& event
)
1414 void wxTextCtrl::OnPaste(wxCommandEvent
& event
)
1419 void wxTextCtrl::OnUndo(wxCommandEvent
& event
)
1424 void wxTextCtrl::OnRedo(wxCommandEvent
& event
)
1429 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
)
1431 event
.Enable( CanCut() );
1434 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
)
1436 event
.Enable( CanCopy() );
1439 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
)
1441 event
.Enable( CanPaste() );
1444 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
)
1446 event
.Enable( CanUndo() );
1449 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
)
1451 event
.Enable( CanRedo() );