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 #define wxMAC_USE_CARBON_EVENTS 0
56 extern wxApp
*wxTheApp
;
58 // CS:TODO we still have a problem getting properly at the text events of a control because under Carbon
59 // the MLTE engine registers itself for the key events thus the normal flow never occurs, the only measure for the
60 // moment is to avoid setting the true focus on the control, the proper solution at the end would be to have
61 // an alternate path for carbon key events that routes automatically into the same wx flow of events
63 #include "MacTextEditor.h"
67 /* kmUPTextPart is the part code we return to indicate the user has clicked
68 in the text area of our control */
69 #define kmUPTextPart 1
71 /* kmUPScrollPart is the part code we return to indicate the user has clicked
72 in the scroll bar part of the control. */
73 #define kmUPScrollPart 2
76 /* routines for using existing user pane controls.
77 These routines are useful for cases where you would like to use an
78 existing user pane control in, say, a dialog window as a scrolling
81 /* mUPOpenControl initializes a user pane control so it will be drawn
82 and will behave as a scrolling text edit field inside of a window.
83 This routine performs all of the initialization steps necessary,
84 except it does not create the user pane control itself. theControl
85 should refer to a user pane control that you have either created
86 yourself or extracted from a dialog's control heirarchy using
87 the GetDialogItemAsControl routine. */
88 OSStatus
mUPOpenControl(ControlHandle theControl
, bool multiline
);
90 /* Utility Routines */
96 /* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus
97 routine. In our focus switching routine this part code is understood
98 as meaning 'the user has clicked in the control and we need to switch
99 the current focus to ourselves before we can continue'. */
100 #define kUserClickedToFocusPart 100
103 /* kmUPClickScrollDelayTicks is a time measurement in ticks used to
104 slow the speed of 'auto scrolling' inside of our clickloop routine.
105 This value prevents the text from wizzzzzing by while the mouse
106 is being held down inside of the text area. */
107 #define kmUPClickScrollDelayTicks 3
110 /* STPTextPaneVars is a structure used for storing the the mUP Control's
111 internal variables and state information. A handle to this record is
112 stored in the pane control's reference value field using the
113 SetControlReference routine. */
116 /* OS records referenced */
117 TXNObject fTXNRec
; /* the txn record */
118 TXNFrameID fTXNFrame
; /* the txn frame ID */
119 ControlHandle fUserPaneRec
; /* handle to the user pane control */
120 WindowPtr fOwner
; /* window containing control */
121 GrafPtr fDrawingEnvironment
; /* grafport where control is drawn */
123 Boolean fInFocus
; /* true while the focus rect is drawn around the control */
124 Boolean fIsActive
; /* true while the control is drawn in the active state */
125 Boolean fTEActive
; /* reflects the activation state of the text edit record */
126 Boolean fInDialogWindow
; /* true if displayed in a dialog window */
127 /* calculated locations */
128 Rect fRTextArea
; /* area where the text is drawn */
129 Rect fRFocusOutline
; /* rectangle used to draw the focus box */
130 Rect fRTextOutline
; /* rectangle used to draw the border */
131 RgnHandle fTextBackgroundRgn
; /* background region for the text, erased before calling TEUpdate */
132 /* our focus advance override routine */
133 EventHandlerUPP handlerUPP
;
134 EventHandlerRef handlerRef
;
141 /* Univerals Procedure Pointer variables used by the
142 mUP Control. These variables are set up
143 the first time that mUPOpenControl is called. */
144 ControlUserPaneDrawUPP gTPDrawProc
= NULL
;
145 ControlUserPaneHitTestUPP gTPHitProc
= NULL
;
146 ControlUserPaneTrackingUPP gTPTrackProc
= NULL
;
147 ControlUserPaneIdleUPP gTPIdleProc
= NULL
;
148 ControlUserPaneKeyDownUPP gTPKeyProc
= NULL
;
149 ControlUserPaneActivateUPP gTPActivateProc
= NULL
;
150 ControlUserPaneFocusUPP gTPFocusProc
= NULL
;
152 /* events handled by our focus advance override routine */
154 #if wxMAC_USE_CARBON_EVENTS
155 static const EventTypeSpec gMLTEEvents
[] = { { kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
} };
156 #define kMLTEEventCount (sizeof( gMLTEEvents ) / sizeof( EventTypeSpec ))
161 /* TPActivatePaneText activates or deactivates the text edit record
162 according to the value of setActive. The primary purpose of this
163 routine is to ensure each call is only made once. */
164 static void TPActivatePaneText(STPTextPaneVars
**tpvars
, Boolean setActive
) {
165 STPTextPaneVars
*varsp
;
167 if (varsp
->fTEActive
!= setActive
) {
169 varsp
->fTEActive
= setActive
;
171 TXNActivate(varsp
->fTXNRec
, varsp
->fTXNFrame
, varsp
->fTEActive
);
175 TXNFocus( varsp
->fTXNRec
, varsp
->fTEActive
);
181 /* TPFocusPaneText set the focus state for the text record. */
182 static void TPFocusPaneText(STPTextPaneVars
**tpvars
, Boolean setFocus
) {
183 STPTextPaneVars
*varsp
;
185 if (varsp
->fInFocus
!= setFocus
) {
186 varsp
->fInFocus
= setFocus
;
188 TXNFocus( varsp
->fTXNRec
, varsp
->fInFocus
);
194 /* TPPaneDrawProc is called to redraw the control and for update events
195 referring to the control. This routine erases the text area's background,
196 and redraws the text. This routine assumes the scroll bar has been
197 redrawn by a call to DrawControls. */
198 static pascal void TPPaneDrawProc(ControlRef theControl
, ControlPartCode thePart
) {
199 STPTextPaneVars
**tpvars
, *varsp
;
202 /* set up our globals */
203 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
204 if (tpvars
!= NULL
) {
205 state
= HGetState((Handle
) tpvars
);
206 HLock((Handle
) tpvars
);
209 /* save the drawing state */
210 SetPort((**tpvars
).fDrawingEnvironment
);
211 /* verify our boundary */
212 GetControlBounds(theControl
, &bounds
);
213 if ( ! EqualRect(&bounds
, &varsp
->fRFocusOutline
) ) {
214 // scrollbar is on the border, we add one
215 Rect oldbounds
= varsp
->fRFocusOutline
;
216 InsetRect( &oldbounds
, -1 , -1 ) ;
218 // InvalWindowRect( GetControlOwner( theControl ) , &oldbounds ) ;
219 SetRect(&varsp
->fRFocusOutline
, bounds
.left
, bounds
.top
, bounds
.right
, bounds
.bottom
);
220 SetRect(&varsp
->fRTextOutline
, bounds
.left
, bounds
.top
, bounds
.right
, bounds
.bottom
);
221 SetRect(&varsp
->fRTextArea
, bounds
.left
+ 2 , bounds
.top
+ (varsp
->fMultiline
? 0 : 2) ,
222 bounds
.right
- (varsp
->fMultiline
? 0 : 2), bounds
.bottom
- (varsp
->fMultiline
? 0 : 2));
223 RectRgn(varsp
->fTextBackgroundRgn
, &varsp
->fRTextOutline
);
224 TXNSetFrameBounds( varsp
->fTXNRec
, varsp
->fRTextArea
.top
, varsp
->fRTextArea
.left
,
225 varsp
->fRTextArea
.bottom
, varsp
->fRTextArea
.right
, varsp
->fTXNFrame
);
228 /* update the text region */
229 RGBColor white
= { 65535 , 65535 , 65535 } ;
230 RGBBackColor( &white
) ;
231 EraseRgn(varsp
->fTextBackgroundRgn
);
232 TXNDraw(varsp
->fTXNRec
, NULL
);
233 /* restore the drawing environment */
234 /* draw the text frame and focus frame (if necessary) */
235 DrawThemeEditTextFrame(&varsp
->fRTextOutline
, varsp
->fIsActive
? kThemeStateActive
: kThemeStateInactive
);
236 if ((**tpvars
).fIsActive
&& varsp
->fInFocus
) DrawThemeFocusRect(&varsp
->fRFocusOutline
, true);
237 /* release our globals */
238 HSetState((Handle
) tpvars
, state
);
243 /* TPPaneHitTestProc is called when the control manager would
244 like to determine what part of the control the mouse resides over.
245 We also call this routine from our tracking proc to determine how
246 to handle mouse clicks. */
247 static pascal ControlPartCode
TPPaneHitTestProc(ControlHandle theControl
, Point where
) {
248 STPTextPaneVars
**tpvars
;
249 ControlPartCode result
;
251 /* set up our locals and lock down our globals*/
253 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
254 if (tpvars
!= NULL
) {
255 state
= HGetState((Handle
) tpvars
);
256 HLock((Handle
) tpvars
);
257 /* find the region where we clicked */
258 if (PtInRect(where
, &(**tpvars
).fRTextArea
)) {
259 result
= kmUPTextPart
;
261 /* release oure globals */
262 HSetState((Handle
) tpvars
, state
);
271 /* TPPaneTrackingProc is called when the mouse is being held down
272 over our control. This routine handles clicks in the text area
273 and in the scroll bar. */
274 static pascal ControlPartCode
TPPaneTrackingProc(ControlHandle theControl
, Point startPt
, ControlActionUPP actionProc
) {
275 STPTextPaneVars
**tpvars
, *varsp
;
277 ControlPartCode partCodeResult
;
278 /* make sure we have some variables... */
280 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
281 if (tpvars
!= NULL
) {
283 state
= HGetState((Handle
) tpvars
);
284 HLock((Handle
) tpvars
);
286 /* we don't do any of these functions unless we're in focus */
287 if ( ! varsp
->fInFocus
) {
289 owner
= GetControlOwner(theControl
);
290 ClearKeyboardFocus(owner
);
291 SetKeyboardFocus(owner
, theControl
, kUserClickedToFocusPart
);
293 /* find the location for the click */
294 switch (TPPaneHitTestProc(theControl
, startPt
)) {
296 /* handle clicks in the text part */
298 { SetPort((**tpvars
).fDrawingEnvironment
);
299 TXNClick( varsp
->fTXNRec
, (const EventRecord
*) wxTheApp
->MacGetCurrentEvent());
305 HSetState((Handle
) tpvars
, state
);
307 return partCodeResult
;
311 /* TPPaneIdleProc is our user pane idle routine. When our text field
312 is active and in focus, we use this routine to set the cursor. */
313 static pascal void TPPaneIdleProc(ControlHandle theControl
) {
314 STPTextPaneVars
**tpvars
, *varsp
;
316 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
317 if (tpvars
!= NULL
) {
318 /* if we're not active, then we have nothing to say about the cursor */
319 if ((**tpvars
).fIsActive
) {
323 /* lock down the globals */
324 state
= HGetState((Handle
) tpvars
);
325 HLock((Handle
) tpvars
);
327 /* get the current mouse coordinates (in our window) */
328 SetPortWindowPort(GetControlOwner(theControl
));
330 /* there's a 'focus thing' and an 'unfocused thing' */
331 if (varsp
->fInFocus
) {
332 /* flash the cursor */
333 SetPort((**tpvars
).fDrawingEnvironment
);
334 TXNIdle(varsp
->fTXNRec
);
336 if (PtInRect(mousep
, &varsp
->fRTextArea
)) {
338 RectRgn((theRgn
= NewRgn()), &varsp
->fRTextArea
);
339 TXNAdjustCursor(varsp
->fTXNRec
, theRgn
);
341 } else SetThemeCursor(kThemeArrowCursor
);
343 /* if it's in our bounds, set the cursor */
344 GetControlBounds(theControl
, &bounds
);
345 if (PtInRect(mousep
, &bounds
))
346 SetThemeCursor(kThemeArrowCursor
);
349 HSetState((Handle
) tpvars
, state
);
355 /* TPPaneKeyDownProc is called whenever a keydown event is directed
356 at our control. Here, we direct the keydown event to the text
357 edit record and redraw the scroll bar and text field as appropriate. */
358 static pascal ControlPartCode
TPPaneKeyDownProc(ControlHandle theControl
,
359 SInt16 keyCode
, SInt16 charCode
, SInt16 modifiers
) {
360 STPTextPaneVars
**tpvars
;
361 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
362 if (tpvars
!= NULL
) {
363 if ((**tpvars
).fInFocus
) {
364 /* turn autoscrolling on and send the key event to text edit */
365 SetPort((**tpvars
).fDrawingEnvironment
);
366 TXNKeyDown( (**tpvars
).fTXNRec
, (const EventRecord
*) wxTheApp
->MacGetCurrentEvent());
369 return kControlEntireControl
;
373 /* TPPaneActivateProc is called when the window containing
374 the user pane control receives activate events. Here, we redraw
375 the control and it's text as necessary for the activation state. */
376 static pascal void TPPaneActivateProc(ControlHandle theControl
, Boolean activating
) {
378 STPTextPaneVars
**tpvars
, *varsp
;
381 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
382 if (tpvars
!= NULL
) {
383 state
= HGetState((Handle
) tpvars
);
384 HLock((Handle
) tpvars
);
386 /* de/activate the text edit record */
387 SetPort((**tpvars
).fDrawingEnvironment
);
388 GetControlBounds(theControl
, &bounds
);
389 varsp
->fIsActive
= activating
;
390 TPActivatePaneText(tpvars
, varsp
->fIsActive
&& varsp
->fInFocus
);
391 /* redraw the frame */
392 DrawThemeEditTextFrame(&varsp
->fRTextOutline
, varsp
->fIsActive
? kThemeStateActive
: kThemeStateInactive
);
393 if (varsp
->fInFocus
) DrawThemeFocusRect(&varsp
->fRFocusOutline
, varsp
->fIsActive
);
394 HSetState((Handle
) tpvars
, state
);
399 /* TPPaneFocusProc is called when every the focus changes to or
400 from our control. Herein, switch the focus appropriately
401 according to the parameters and redraw the control as
403 static pascal ControlPartCode
TPPaneFocusProc(ControlHandle theControl
, ControlFocusPart action
) {
404 ControlPartCode focusResult
;
405 STPTextPaneVars
**tpvars
, *varsp
;
408 focusResult
= kControlFocusNoPart
;
409 tpvars
= (STPTextPaneVars
**) GetControlReference(theControl
);
410 if (tpvars
!= NULL
) {
411 state
= HGetState((Handle
) tpvars
);
412 HLock((Handle
) tpvars
);
414 /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is
415 tabbing forwards (or shift tabbing backwards) through the items in the dialog,
416 and kControlFocusNextPart will be received. When the user clicks in our field
417 and it is not the current focus, then the constant kUserClickedToFocusPart will
418 be received. The constant kControlFocusNoPart will be received when our control
419 is the current focus and the user clicks in another control. In your focus routine,
420 you should respond to these codes as follows:
422 kControlFocusNoPart - turn off focus and return kControlFocusNoPart. redraw
423 the control and the focus rectangle as necessary.
425 kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off
426 depending on its current state. redraw the control and the focus rectangle
427 as appropriate for the new focus state. If the focus state is 'off', return the constant
428 kControlFocusNoPart, otherwise return a non-zero part code.
429 kUserClickedToFocusPart - is a constant defined for this example. You should
430 define your own value for handling click-to-focus type events. */
431 /* save the drawing state */
432 SetPort((**tpvars
).fDrawingEnvironment
);
433 /* calculate the next highlight state */
436 case kControlFocusNoPart
:
437 TPFocusPaneText(tpvars
, false);
438 focusResult
= kControlFocusNoPart
;
440 case kUserClickedToFocusPart
:
441 TPFocusPaneText(tpvars
, true);
444 case kControlFocusPrevPart
:
445 case kControlFocusNextPart
:
446 TPFocusPaneText(tpvars
, ( ! varsp
->fInFocus
));
447 focusResult
= varsp
->fInFocus
? 1 : kControlFocusNoPart
;
450 TPActivatePaneText(tpvars
, varsp
->fIsActive
&& varsp
->fInFocus
);
451 /* redraw the text fram and focus rectangle to indicate the
453 DrawThemeEditTextFrame(&varsp
->fRTextOutline
, varsp
->fIsActive
? kThemeStateActive
: kThemeStateInactive
);
454 DrawThemeFocusRect(&varsp
->fRFocusOutline
, varsp
->fIsActive
&& varsp
->fInFocus
);
456 HSetState((Handle
) tpvars
, state
);
461 //This our carbon event handler for unicode key downs
463 #if wxMAC_USE_CARBON_EVENTS
464 static pascal OSStatus
FocusAdvanceOverride(EventHandlerCallRef myHandler
, EventRef event
, void* userData
) {
466 STPTextPaneVars
**tpvars
;
468 unsigned short mUnicodeText
;
469 ByteCount charCounts
=0;
470 /* get our window pointer */
471 tpvars
= (STPTextPaneVars
**) userData
;
472 window
= (**tpvars
).fOwner
;
473 //find out how many bytes are needed
474 err
= GetEventParameter(event
, kEventParamTextInputSendText
,
475 typeUnicodeText
, NULL
, 0, &charCounts
, NULL
);
476 if (err
!= noErr
) goto bail
;
477 /* we're only looking at single characters */
478 if (charCounts
!= 2) { err
= eventNotHandledErr
; goto bail
; }
479 /* get the character */
480 err
= GetEventParameter(event
, kEventParamTextInputSendText
,
481 typeUnicodeText
, NULL
, sizeof(mUnicodeText
),
482 &charCounts
, (char*) &mUnicodeText
);
483 if (err
!= noErr
) goto bail
;
484 /* if it's not the tab key, forget it... */
485 if ((mUnicodeText
!= '\t')) { err
= eventNotHandledErr
; goto bail
; }
486 /* advance the keyboard focus */
487 AdvanceKeyboardFocus(window
);
488 /* noErr lets the CEM know we handled the event */
491 return eventNotHandledErr
;
497 /* mUPOpenControl initializes a user pane control so it will be drawn
498 and will behave as a scrolling text edit field inside of a window.
499 This routine performs all of the initialization steps necessary,
500 except it does not create the user pane control itself. theControl
501 should refer to a user pane control that you have either created
502 yourself or extracted from a dialog's control heirarchy using
503 the GetDialogItemAsControl routine. */
504 OSStatus
mUPOpenControl(ControlHandle theControl
, bool multiline
)
508 STPTextPaneVars
**tpvars
, *varsp
;
510 RGBColor rgbWhite
= {0xFFFF, 0xFFFF, 0xFFFF};
513 /* set up our globals */
514 if (gTPDrawProc
== NULL
) gTPDrawProc
= NewControlUserPaneDrawUPP(TPPaneDrawProc
);
515 if (gTPHitProc
== NULL
) gTPHitProc
= NewControlUserPaneHitTestUPP(TPPaneHitTestProc
);
516 if (gTPTrackProc
== NULL
) gTPTrackProc
= NewControlUserPaneTrackingUPP(TPPaneTrackingProc
);
517 if (gTPIdleProc
== NULL
) gTPIdleProc
= NewControlUserPaneIdleUPP(TPPaneIdleProc
);
518 if (gTPKeyProc
== NULL
) gTPKeyProc
= NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc
);
519 if (gTPActivateProc
== NULL
) gTPActivateProc
= NewControlUserPaneActivateUPP(TPPaneActivateProc
);
520 if (gTPFocusProc
== NULL
) gTPFocusProc
= NewControlUserPaneFocusUPP(TPPaneFocusProc
);
522 /* allocate our private storage */
523 tpvars
= (STPTextPaneVars
**) NewHandleClear(sizeof(STPTextPaneVars
));
524 SetControlReference(theControl
, (long) tpvars
);
525 HLock((Handle
) tpvars
);
527 /* set the initial settings for our private data */
528 varsp
->fMultiline
= multiline
;
529 varsp
->fInFocus
= false;
530 varsp
->fIsActive
= true;
531 varsp
->fTEActive
= true; // in order to get a deactivate
532 varsp
->fUserPaneRec
= theControl
;
533 theWindow
= varsp
->fOwner
= GetControlOwner(theControl
);
535 varsp
->fDrawingEnvironment
= (GrafPtr
) GetWindowPort(theWindow
);
537 varsp
->fInDialogWindow
= ( GetWindowKind(varsp
->fOwner
) == kDialogWindowKind
);
538 /* set up the user pane procedures */
539 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneDrawProcTag
, sizeof(gTPDrawProc
), &gTPDrawProc
);
540 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneHitTestProcTag
, sizeof(gTPHitProc
), &gTPHitProc
);
541 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneTrackingProcTag
, sizeof(gTPTrackProc
), &gTPTrackProc
);
542 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneIdleProcTag
, sizeof(gTPIdleProc
), &gTPIdleProc
);
543 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneKeyDownProcTag
, sizeof(gTPKeyProc
), &gTPKeyProc
);
544 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneActivateProcTag
, sizeof(gTPActivateProc
), &gTPActivateProc
);
545 SetControlData(theControl
, kControlEntireControl
, kControlUserPaneFocusProcTag
, sizeof(gTPFocusProc
), &gTPFocusProc
);
546 /* calculate the rectangles used by the control */
547 GetControlBounds(theControl
, &bounds
);
548 SetRect(&varsp
->fRFocusOutline
, bounds
.left
, bounds
.top
, bounds
.right
, bounds
.bottom
);
549 SetRect(&varsp
->fRTextOutline
, bounds
.left
, bounds
.top
, bounds
.right
, bounds
.bottom
);
550 SetRect(&varsp
->fRTextArea
, bounds
.left
+ 2 , bounds
.top
+ (varsp
->fMultiline
? 0 : 2) ,
551 bounds
.right
- (varsp
->fMultiline
? 0 : 2), bounds
.bottom
- (varsp
->fMultiline
? 0 : 2));
552 /* calculate the background region for the text. In this case, it's kindof
553 and irregular region because we're setting the scroll bar a little ways inside
555 RectRgn((varsp
->fTextBackgroundRgn
= NewRgn()), &varsp
->fRTextOutline
);
557 /* set up the drawing environment */
558 SetPort(varsp
->fDrawingEnvironment
);
560 /* create the new edit field */
561 TXNNewObject(NULL
, varsp
->fOwner
, &varsp
->fRTextArea
,
562 ( multiline
? kTXNWantVScrollBarMask
: 0 ) |
564 kTXNDontDrawCaretWhenInactiveMask
|
565 kTXNDontDrawSelectionWhenInactiveMask
|
567 kTXNAlwaysWrapAtViewEdgeMask
,
568 kTXNTextEditStyleFrameType
,
570 kTXNSystemDefaultEncoding
,
571 &varsp
->fTXNRec
, &varsp
->fTXNFrame
, (TXNObjectRefcon
) tpvars
);
577 GetThemeFont(kThemeSmallSystemFont
, GetApplicationScript() , fontName
, &fontSize
, &fontStyle
) ;
579 TXNTypeAttributes typeAttr
[] =
581 { kTXNQDFontNameAttribute
, kTXNQDFontNameAttributeSize
, { (void*) fontName
} } ,
582 { kTXNQDFontSizeAttribute
, kTXNFontSizeAttributeSize
, { (void*) (fontSize
<< 16) } } ,
583 { kTXNQDFontStyleAttribute
, kTXNQDFontStyleAttributeSize
, { (void*) normal
} } ,
586 OSStatus status
= TXNSetTypeAttributes (varsp
->fTXNRec
, sizeof( typeAttr
) / sizeof(TXNTypeAttributes
) , typeAttr
,
589 /* set the field's background */
590 tback
.bgType
= kTXNBackgroundTypeRGB
;
591 tback
.bg
.color
= rgbWhite
;
592 TXNSetBackground( varsp
->fTXNRec
, &tback
);
594 /* install our focus advance override routine */
596 #if wxMAC_USE_CARBON_EVENTS
597 varsp
->handlerUPP
= NewEventHandlerUPP(FocusAdvanceOverride
);
598 err
= InstallWindowEventHandler( varsp
->fOwner
, varsp
->handlerUPP
,
599 kMLTEEventCount
, gMLTEEvents
, tpvars
, &varsp
->handlerRef
);
603 /* unlock our storage */
604 HUnlock((Handle
) tpvars
);
605 /* perform final activations and setup for our text field. Here,
606 we assume that the window is going to be the 'active' window. */
607 TPActivatePaneText(tpvars
, varsp
->fIsActive
&& varsp
->fInFocus
);
615 #if !USE_SHARED_LIBRARY
616 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
, wxControl
)
618 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
)
619 EVT_DROP_FILES(wxTextCtrl::OnDropFiles
)
620 EVT_CHAR(wxTextCtrl::OnChar
)
621 EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
)
622 EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
)
623 EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
)
624 EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
)
625 EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
)
627 EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
)
628 EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
)
629 EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
)
630 EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
)
631 EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
)
636 wxTextCtrl::wxTextCtrl()
640 m_macTXNvars
= NULL
;
641 m_macUsesTXN
= false ;
645 wxTextCtrl::~wxTextCtrl()
649 SetControlReference((ControlHandle
)m_macControl
, 0) ;
650 TXNDeleteObject((TXNObject
)m_macTXN
);
652 #if wxMAC_USE_CARBON_EVENTS
653 /* remove our focus advance override */
654 ::RemoveEventHandler((**(STPTextPaneVars
**) m_macTXNvars
).handlerRef
);
655 ::DisposeEventHandlerUPP((**(STPTextPaneVars
**) m_macTXNvars
).handlerUPP
);
658 /* delete our private storage */
659 DisposeHandle((Handle
) m_macTXNvars
);
660 /* zero the control reference */
664 const short kVerticalMargin
= 2 ;
665 const short kHorizontalMargin
= 2 ;
667 bool wxTextCtrl::Create(wxWindow
*parent
, wxWindowID id
,
670 const wxSize
& size
, long style
,
671 const wxValidator
& validator
,
672 const wxString
& name
)
676 m_macTXNvars
= NULL
;
677 m_macUsesTXN
= false ;
680 m_macUsesTXN
= ! (style
& wxTE_PASSWORD
) ;
682 m_macUsesTXN
&= (TXNInitTextension
!= (void*) kUnresolvedCFragSymbolAddress
) ;
684 // base initialization
685 if ( !CreateBase(parent
, id
, pos
, size
, style
, validator
, name
) )
688 wxSize mySize
= size
;
691 m_macHorizontalBorder
= 5 ; // additional pixels around the real control
692 m_macVerticalBorder
= 3 ;
696 m_macHorizontalBorder
= 5 ; // additional pixels around the real control
697 m_macVerticalBorder
= 5 ;
704 if ( mySize.y == -1 )
707 if ( m_windowStyle & wxTE_MULTILINE )
710 mySize.y += 2 * m_macVerticalBorder ;
713 MacPreControlCreate( parent
, id
, "" , pos
, mySize
,style
, validator
, name
, &bounds
, title
) ;
715 if ( m_windowStyle
& wxTE_MULTILINE
)
717 wxASSERT_MSG( !(m_windowStyle
& wxTE_PROCESS_ENTER
),
718 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
720 m_windowStyle
|= wxTE_PROCESS_ENTER
;
726 m_macControl
= ::NewControl( MAC_WXHWND(parent
->MacGetRootWindow()) , &bounds
, "\p" , true , 0 , 0 , 1,
727 (style
& wxTE_PASSWORD
) ? kControlEditTextPasswordProc
: kControlEditTextProc
, (long) this ) ;
729 ::GetControlData((ControlHandle
) m_macControl
, 0, kControlEditTextTEHandleTag
, sizeof( TEHandle
) , (char*) &((TEHandle
) m_macTE
) , &size
) ;
736 featurSet
= kControlSupportsEmbedding
| kControlSupportsFocus
// | kControlWantsIdle
737 | kControlWantsActivate
| kControlHandlesTracking
| kControlHasSpecialBackground
738 | kControlGetsFocusOnClick
| kControlSupportsLiveFeedback
;
739 /* create the control */
740 m_macControl
= NewControl(MAC_WXHWND(parent
->MacGetRootWindow()), &bounds
, "\p", true, featurSet
, 0, featurSet
, kControlUserPaneProc
, 0);
741 /* set up the mUP specific features and data */
742 mUPOpenControl((ControlHandle
) m_macControl
, m_windowStyle
& wxTE_MULTILINE
);
744 MacPostControlCreate() ;
748 if( wxApp::s_macDefaultEncodingIsPC
)
749 value
= wxMacMakeMacStringFromPC( st
) ;
755 ::SetControlData( (ControlHandle
) m_macControl
, 0, ( m_windowStyle
& wxTE_PASSWORD
) ? kControlEditTextPasswordTag
: kControlEditTextTextTag
, value
.Length() , (char*) ((const char*)value
) ) ;
759 STPTextPaneVars
**tpvars
;
761 tpvars
= (STPTextPaneVars
**) GetControlReference((ControlHandle
) m_macControl
);
762 /* set the text in the record */
763 TXNSetData( (**tpvars
).fTXNRec
, kTXNTextData
, (void*)value
.c_str(), value
.Length(),
764 kTXNStartOffset
, kTXNEndOffset
);
765 m_macTXN
= (**tpvars
).fTXNRec
;
766 m_macTXNvars
= tpvars
;
767 m_macUsesTXN
= true ;
773 wxString
wxTextCtrl::GetValue() const
778 ::GetControlData( (ControlHandle
) m_macControl
, 0, ( m_windowStyle
& wxTE_PASSWORD
) ? kControlEditTextPasswordTag
: kControlEditTextTextTag
, 32767 , wxBuffer
, &actualsize
) ;
783 OSStatus err
= TXNGetDataEncoded( ((TXNObject
) m_macTXN
), kTXNStartOffset
, kTXNEndOffset
, &theText
, kTXNTextData
);
791 actualsize
= GetHandleSize( theText
) ;
793 strncpy( wxBuffer
, *theText
, actualsize
) ;
794 DisposeHandle( theText
) ;
797 wxBuffer
[actualsize
] = 0 ;
798 if( wxApp::s_macDefaultEncodingIsPC
)
799 return wxMacMakePCStringFromMac( wxBuffer
) ;
801 return wxString(wxBuffer
);
804 void wxTextCtrl::GetSelection(long* from
, long* to
) const
808 *from
= (**((TEHandle
) m_macTE
)).selStart
;
809 *to
= (**((TEHandle
) m_macTE
)).selEnd
;
813 TXNGetSelection( ((TXNObject
) m_macTXN
) , (TXNOffset
*) from
, (TXNOffset
*) to
) ;
817 void wxTextCtrl::SetValue(const wxString
& st
)
821 if( wxApp::s_macDefaultEncodingIsPC
)
822 value
= wxMacMakeMacStringFromPC( st
) ;
827 ::SetControlData((ControlHandle
) m_macControl
, 0, ( m_windowStyle
& wxTE_PASSWORD
) ? kControlEditTextPasswordTag
: kControlEditTextTextTag
, value
.Length() , (char*) ((const char*)value
) ) ;
831 TXNSetData( ((TXNObject
) m_macTXN
), kTXNTextData
, (void*)value
.c_str(), value
.Length(),
832 kTXNStartOffset
, kTXNEndOffset
);
837 // Clipboard operations
838 void wxTextCtrl::Copy()
844 TECopy( ((TEHandle
) m_macTE
) ) ;
852 TXNCopy((TXNObject
)m_macTXN
);
853 TXNConvertToPublicScrap();
858 void wxTextCtrl::Cut()
864 TECut( ((TEHandle
) m_macTE
) ) ;
872 TXNCut((TXNObject
)m_macTXN
);
873 TXNConvertToPublicScrap();
875 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, m_windowId
);
876 event
.SetString( GetValue() ) ;
877 event
.SetEventObject( this );
878 GetEventHandler()->ProcessEvent(event
);
882 void wxTextCtrl::Paste()
889 TEPaste( (TEHandle
) m_macTE
) ;
894 TXNConvertFromPublicScrap();
895 TXNPaste((TXNObject
)m_macTXN
);
897 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, m_windowId
);
898 event
.SetString( GetValue() ) ;
899 event
.SetEventObject( this );
900 GetEventHandler()->ProcessEvent(event
);
904 bool wxTextCtrl::CanCopy() const
906 // Can copy if there's a selection
908 GetSelection(& from
, & to
);
912 bool wxTextCtrl::CanCut() const
918 // Can cut if there's a selection
920 GetSelection(& from
, & to
);
924 bool wxTextCtrl::CanPaste() const
931 OSStatus err
= noErr
;
934 err
= GetCurrentScrap( &scrapRef
);
935 if ( err
!= noTypeErr
&& err
!= memFullErr
)
937 ScrapFlavorFlags flavorFlags
;
940 if (( err
= GetScrapFlavorFlags( scrapRef
, 'TEXT', &flavorFlags
)) == noErr
)
942 if (( err
= GetScrapFlavorSize( scrapRef
, 'TEXT', &byteCount
)) == noErr
)
951 if ( GetScrap( NULL
, 'TEXT' , &offset
) > 0 )
959 void wxTextCtrl::SetEditable(bool editable
)
961 if ( editable
!= m_editable
)
963 m_editable
= editable
;
965 UMAActivateControl( (ControlHandle
) m_macControl
) ;
967 UMADeactivateControl((ControlHandle
) m_macControl
) ;
971 void wxTextCtrl::SetInsertionPoint(long pos
)
973 SetSelection( pos
, pos
) ;
976 void wxTextCtrl::SetInsertionPointEnd()
978 long pos
= GetLastPosition();
979 SetInsertionPoint(pos
);
982 long wxTextCtrl::GetInsertionPoint() const
985 GetSelection( &begin
, &end
) ;
989 long wxTextCtrl::GetLastPosition() const
993 return (**((TEHandle
) m_macTE
)).teLength
;
999 OSErr err
= TXNGetDataEncoded( (TXNObject
) m_macTXN
, kTXNStartOffset
, kTXNEndOffset
, &theText
, kTXNTextData
);
1007 actualsize
= GetHandleSize( theText
) ;
1008 DisposeHandle( theText
) ;
1014 void wxTextCtrl::Replace(long from
, long to
, const wxString
& value
)
1016 if ( !m_macUsesTXN
)
1018 ControlEditTextSelectionRec selection
;
1020 selection
.selStart
= from
;
1021 selection
.selEnd
= to
;
1022 ::SetControlData((ControlHandle
) m_macControl
, 0, kControlEditTextSelectionTag
, sizeof( selection
) , (char*) &selection
) ;
1023 TESetSelect( from
, to
, ((TEHandle
) m_macTE
) ) ;
1024 TEDelete( ((TEHandle
) m_macTE
) ) ;
1025 TEInsert( value
, value
.Length() , ((TEHandle
) m_macTE
) ) ;
1029 TXNSetSelection( ((TXNObject
) m_macTXN
) , from
, to
) ;
1030 TXNClear( ((TXNObject
) m_macTXN
) ) ;
1031 TXNSetData( ((TXNObject
) m_macTXN
), kTXNTextData
, (void*)value
.c_str(), value
.Length(),
1032 kTXNUseCurrentSelection
, kTXNUseCurrentSelection
);
1037 void wxTextCtrl::Remove(long from
, long to
)
1039 if ( !m_macUsesTXN
)
1041 ControlEditTextSelectionRec selection
;
1043 selection
.selStart
= from
;
1044 selection
.selEnd
= to
;
1045 ::SetControlData( (ControlHandle
) m_macControl
, 0, kControlEditTextSelectionTag
, sizeof( selection
) , (char*) &selection
) ;
1046 TEDelete( ((TEHandle
) m_macTE
) ) ;
1050 TXNSetSelection( ((TXNObject
) m_macTXN
) , from
, to
) ;
1051 TXNClear( ((TXNObject
) m_macTXN
) ) ;
1056 void wxTextCtrl::SetSelection(long from
, long to
)
1059 if ( !m_macUsesTXN
)
1061 ControlEditTextSelectionRec selection
;
1062 selection
.selStart
= from
;
1063 selection
.selEnd
= to
;
1065 TESetSelect( selection
.selStart
, selection
.selEnd
, ((TEHandle
) m_macTE
) ) ;
1066 ::SetControlData((ControlHandle
) m_macControl
, 0, kControlEditTextSelectionTag
, sizeof( selection
) , (char*) &selection
) ;
1070 STPTextPaneVars
**tpvars
;
1071 /* set up our locals */
1072 tpvars
= (STPTextPaneVars
**) GetControlReference((ControlHandle
) m_macControl
);
1073 /* and our drawing environment as the operation
1074 may force a redraw in the text area. */
1075 SetPort((**tpvars
).fDrawingEnvironment
);
1076 /* change the selection */
1077 TXNSetSelection( (**tpvars
).fTXNRec
, from
, to
);
1081 bool wxTextCtrl::LoadFile(const wxString
& file
)
1083 if ( wxTextCtrlBase::LoadFile(file
) )
1091 void wxTextCtrl::WriteText(const wxString
& text
)
1094 if( wxApp::s_macDefaultEncodingIsPC
)
1095 value
= wxMacMakeMacStringFromPC( text
) ;
1098 if ( !m_macUsesTXN
)
1100 TEInsert( value
, value
.Length() , ((TEHandle
) m_macTE
) ) ;
1104 TXNSetData( ((TXNObject
) m_macTXN
), kTXNTextData
, (void*) (const char*)value
, value
.Length(),
1105 kTXNUseCurrentSelection
, kTXNUseCurrentSelection
);
1107 MacRedrawControl() ;
1110 void wxTextCtrl::AppendText(const wxString
& text
)
1112 SetInsertionPointEnd();
1116 void wxTextCtrl::Clear()
1118 if ( !IsEditable() )
1122 if ( !m_macUsesTXN
)
1124 ::SetControlData((ControlHandle
) m_macControl
, 0, ( m_windowStyle
& wxTE_PASSWORD
) ? kControlEditTextPasswordTag
: kControlEditTextTextTag
, 0 , (char*) ((const char*)NULL
) ) ;
1128 ClearCurrentScrap();
1129 TXNClear((TXNObject
)m_macTXN
);
1134 bool wxTextCtrl::IsModified() const
1139 bool wxTextCtrl::IsEditable() const
1141 return IsEnabled() && m_editable
;
1144 bool wxTextCtrl::AcceptsFocus() const
1146 // we don't want focus if we can't be edited
1147 return /*IsEditable() && */ wxControl::AcceptsFocus();
1150 wxSize
wxTextCtrl::DoGetBestSize() const
1165 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
1167 int wText = DEFAULT_ITEM_WIDTH;
1169 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
1171 return wxSize(wText, hText);
1173 if ( m_windowStyle
& wxTE_MULTILINE
)
1177 hText
+= 2 * m_macVerticalBorder
;
1178 wText
+= 2 * m_macHorizontalBorder
;
1179 //else: for single line control everything is ok
1180 return wxSize(wText
, hText
);
1183 // ----------------------------------------------------------------------------
1185 // ----------------------------------------------------------------------------
1187 void wxTextCtrl::Undo()
1194 void wxTextCtrl::Redo()
1201 bool wxTextCtrl::CanUndo() const
1206 bool wxTextCtrl::CanRedo() const
1211 // Makes 'unmodified'
1212 void wxTextCtrl::DiscardEdits()
1217 int wxTextCtrl::GetNumberOfLines() const
1219 // TODO change this if possible to reflect real lines
1220 wxString content
= GetValue() ;
1223 for (int i
= 0; i
< content
.Length() ; i
++)
1225 if (content
[i
] == '\r') count
++;
1231 long wxTextCtrl::XYToPosition(long x
, long y
) const
1237 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const
1242 void wxTextCtrl::ShowPosition(long pos
)
1247 int wxTextCtrl::GetLineLength(long lineNo
) const
1249 // TODO change this if possible to reflect real lines
1250 wxString content
= GetValue() ;
1254 for (int i
= 0; i
< content
.Length() ; i
++)
1256 if (count
== lineNo
)
1258 // Count chars in line then
1260 for (int j
= i
; j
< content
.Length(); j
++)
1263 if (content
[j
] == '\r') return count
;
1268 if (content
[i
] == '\r') count
++;
1273 wxString
wxTextCtrl::GetLineText(long lineNo
) const
1275 // TODO change this if possible to reflect real lines
1276 wxString content
= GetValue() ;
1280 for (int i
= 0; i
< content
.Length() ; i
++)
1282 if (count
== lineNo
)
1284 // Add chars in line then
1287 for (int j
= i
; j
< content
.Length(); j
++)
1289 if (content
[j
] == '\r')
1297 if (content
[i
] == '\r') count
++;
1306 void wxTextCtrl::Command(wxCommandEvent
& event
)
1308 SetValue (event
.GetString());
1309 ProcessCommand (event
);
1312 void wxTextCtrl::OnDropFiles(wxDropFilesEvent
& event
)
1314 // By default, load the first file into the text window.
1315 if (event
.GetNumberOfFiles() > 0)
1317 LoadFile(event
.GetFiles()[0]);
1321 void wxTextCtrl::OnChar(wxKeyEvent
& event
)
1323 int key
= event
.GetKeyCode() ;
1324 bool eat_key
= false ;
1326 if ( !IsEditable() && key
!= WXK_LEFT
&& key
!= WXK_RIGHT
&& key
!= WXK_DOWN
&& key
!= WXK_UP
&& key
!= WXK_TAB
&&
1327 !( key
== WXK_RETURN
&& ( (m_windowStyle
& wxPROCESS_ENTER
) || (m_windowStyle
& wxTE_MULTILINE
) ) )
1328 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1337 if (m_windowStyle
& wxPROCESS_ENTER
)
1339 wxCommandEvent
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
);
1340 event
.SetEventObject( this );
1341 event
.SetString( GetValue() );
1342 if ( GetEventHandler()->ProcessEvent(event
) )
1345 if ( !(m_windowStyle
& wxTE_MULTILINE
) )
1347 wxWindow
*parent
= GetParent();
1348 while( parent
&& !parent
->IsTopLevel() && parent
->GetDefaultItem() == NULL
) {
1349 parent
= parent
->GetParent() ;
1351 if ( parent
&& parent
->GetDefaultItem() )
1353 wxButton
*def
= wxDynamicCast(parent
->GetDefaultItem(),
1355 if ( def
&& def
->IsEnabled() )
1357 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, def
->GetId() );
1358 event
.SetEventObject(def
);
1359 def
->Command(event
);
1364 // this will make wxWindows eat the ENTER key so that
1365 // we actually prevent line wrapping in a single line
1373 // always produce navigation event - even if we process TAB
1374 // ourselves the fact that we got here means that the user code
1375 // decided to skip processing of this TAB - probably to let it
1376 // do its default job.
1378 wxNavigationKeyEvent eventNav
;
1379 eventNav
.SetDirection(!event
.ShiftDown());
1380 eventNav
.SetWindowChange(event
.ControlDown());
1381 eventNav
.SetEventObject(this);
1383 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav
) )
1392 EventRecord
*ev
= (EventRecord
*) wxTheApp
->MacGetCurrentEvent();
1393 short keychar
= short(ev
->message
& charCodeMask
);
1396 short keycode
= short(ev
->message
& keyCodeMask
) >> 8 ;
1397 ::HandleControlKey( (ControlHandle
) m_macControl
, keycode
, keychar
, ev
->modifiers
);
1399 if ( keychar
>= 0x20 ||
1400 event
.KeyCode() == WXK_RETURN
||
1401 event
.KeyCode() == WXK_DELETE
||
1402 event
.KeyCode() == WXK_BACK
)
1404 wxCommandEvent
event1(wxEVT_COMMAND_TEXT_UPDATED
, m_windowId
);
1405 event1
.SetString( GetValue() ) ;
1406 event1
.SetEventObject( this );
1407 GetEventHandler()->ProcessEvent(event1
);
1411 // ----------------------------------------------------------------------------
1412 // standard handlers for standard edit menu events
1413 // ----------------------------------------------------------------------------
1415 void wxTextCtrl::OnCut(wxCommandEvent
& event
)
1420 void wxTextCtrl::OnCopy(wxCommandEvent
& event
)
1425 void wxTextCtrl::OnPaste(wxCommandEvent
& event
)
1430 void wxTextCtrl::OnUndo(wxCommandEvent
& event
)
1435 void wxTextCtrl::OnRedo(wxCommandEvent
& event
)
1440 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
)
1442 event
.Enable( CanCut() );
1445 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
)
1447 event
.Enable( CanCopy() );
1450 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
)
1452 event
.Enable( CanPaste() );
1455 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
)
1457 event
.Enable( CanUndo() );
1460 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
)
1462 event
.Enable( CanRedo() );