Consistent tab behaviour
[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 #if TARGET_API_MAC_OSX
65 #define wxMAC_USE_MLTE 0
66 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
67 #define wxMAC_USE_MLTE_HIVIEW 1
68 #else
69 #define wxMAC_USE_MLTE_HIVIEW 0
70 #endif
71 #else
72 // there is no unicodetextctrl on classic, and hopefully MLTE works better there
73 #define wxMAC_USE_MLTE 1
74 #define wxMAC_USE_MLTE_HIVIEW 0
75 #endif
76
77 #if wxMAC_USE_MLTE
78
79 TXNFrameOptions FrameOptionsFromWXStyle( long wxStyle )
80 {
81 TXNFrameOptions frameOptions =
82 kTXNDontDrawCaretWhenInactiveMask ;
83 if ( ! ( wxStyle & wxTE_NOHIDESEL ) )
84 frameOptions |= kTXNDontDrawSelectionWhenInactiveMask ;
85
86 if ( wxStyle & wxTE_MULTILINE )
87 {
88 if ( ! ( wxStyle & wxTE_DONTWRAP ) )
89 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
90 else
91 {
92 frameOptions |= kTXNAlwaysWrapAtViewEdgeMask ;
93 frameOptions |= kTXNWantHScrollBarMask ;
94 }
95
96 if ( !(wxStyle & wxTE_NO_VSCROLL ) )
97 frameOptions |= kTXNWantVScrollBarMask ;
98 }
99 else
100 frameOptions |= kTXNSingleLineOnlyMask ;
101 return frameOptions ;
102 }
103
104 void AdjustAttributesFromWXStyle( TXNObject txn , long wxStyle , bool visible )
105 {
106 TXNControlTag iControlTags[3] = { kTXNDoFontSubstitution, kTXNWordWrapStateTag };
107 TXNControlData iControlData[3] = { {false}, {kTXNNoAutoWrap} };
108 int toptag = 2 ;
109 #if TARGET_API_MAC_OSX
110 iControlTags[2] = kTXNVisibilityTag ;
111 iControlData[2].uValue = visible ;
112 toptag++ ;
113 #endif
114
115 if ( wxStyle & wxTE_MULTILINE )
116 {
117 if (wxStyle & wxTE_DONTWRAP)
118 iControlData[1].uValue = kTXNNoAutoWrap ;
119 else
120 iControlData[1].uValue = kTXNAutoWrap ;
121
122 }
123 verify_noerr( TXNSetTXNObjectControls( txn, false, toptag,
124 iControlTags, iControlData )) ;
125
126 Str255 fontName ;
127 SInt16 fontSize ;
128 Style fontStyle ;
129
130 GetThemeFont(kThemeSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
131
132 TXNTypeAttributes typeAttr[] =
133 {
134 { kTXNQDFontNameAttribute , kTXNQDFontNameAttributeSize , { (void*) fontName } } ,
135 { kTXNQDFontSizeAttribute , kTXNFontSizeAttributeSize , { (void*) (fontSize << 16) } } ,
136 { kTXNQDFontStyleAttribute , kTXNQDFontStyleAttributeSize , { (void*) normal } } ,
137 } ;
138
139 verify_noerr( TXNSetTypeAttributes (txn, sizeof( typeAttr ) / sizeof(TXNTypeAttributes) , typeAttr,
140 kTXNStartOffset,
141 kTXNEndOffset) );
142
143 }
144
145 #if !wxMAC_USE_MLTE_HIVIEW
146
147 // CS:TODO we still have a problem getting properly at the text events of a control because under Carbon
148 // the MLTE engine registers itself for the key events thus the normal flow never occurs, the only measure for the
149 // moment is to avoid setting the true focus on the control, the proper solution at the end would be to have
150 // an alternate path for carbon key events that routes automatically into the same wx flow of events
151
152 /* part codes */
153
154 /* kmUPTextPart is the part code we return to indicate the user has clicked
155 in the text area of our control */
156 #define kmUPTextPart 1
157
158
159 /* routines for using existing user pane controls.
160 These routines are useful for cases where you would like to use an
161 existing user pane control in, say, a dialog window as a scrolling
162 text edit field.*/
163
164 /* Utility Routines */
165
166 /* kUserClickedToFocusPart is a part code we pass to the SetKeyboardFocus
167 routine. In our focus switching routine this part code is understood
168 as meaning 'the user has clicked in the control and we need to switch
169 the current focus to ourselves before we can continue'. */
170 #define kUserClickedToFocusPart 100
171
172 /* STPTextPaneVars is a structure used for storing the the mUP Control's
173 internal variables and state information. A handle to this record is
174 stored in the pane control's reference value field using the
175 SetControlReference routine. */
176
177 typedef struct {
178 /* OS records referenced */
179 TXNObject fTXNRec; /* the txn record */
180 TXNFrameID fTXNFrame; /* the txn frame ID */
181 ControlRef fUserPaneRec; /* handle to the user pane control */
182 WindowPtr fOwner; /* window containing control */
183 GrafPtr fDrawingEnvironment; /* grafport where control is drawn */
184 /* flags */
185 Boolean fInFocus; /* true while the focus rect is drawn around the control */
186 Boolean fIsActive; /* true while the control is drawn in the active state */
187 Boolean fTXNObjectActive; /* reflects the activation state of the text edit record */
188 Boolean fFocusDrawState; /* true if focus is drawn (default: true) */
189 /* calculated locations */
190 Rect fRBounds; /* control bounds */
191 Rect fRTextArea; /* area where the text is drawn */
192 Rect fRFocusOutline; /* rectangle used to draw the focus box */
193 Rect fRTextOutline; /* rectangle used to draw the border */
194 RgnHandle fRTextOutlineRegion; /* background region for the text, erased before calling TEUpdate */
195 /* our focus advance override routine */
196 EventHandlerUPP handlerUPP;
197 EventHandlerRef handlerRef;
198 bool fNoBorders ;
199 bool fMultiline ;
200 bool fVisible ;
201 } STPTextPaneVars;
202
203 /* mUPOpenControl initializes a user pane control so it will be drawn
204 and will behave as a scrolling text edit field inside of a window.
205 This routine performs all of the initialization steps necessary,
206 except it does not create the user pane control itself. theControl
207 should refer to a user pane control that you have either created
208 yourself or extracted from a dialog's control heirarchy using
209 the GetDialogItemAsControl routine. */
210 OSStatus mUPOpenControl(STPTextPaneVars* &handle, ControlRef theControl, long wxStyle);
211
212
213
214
215 /* Univerals Procedure Pointer variables used by the
216 mUP Control. These variables are set up
217 the first time that mUPOpenControl is called. */
218 ControlUserPaneDrawUPP gTPDrawProc = NULL;
219 ControlUserPaneHitTestUPP gTPHitProc = NULL;
220 ControlUserPaneTrackingUPP gTPTrackProc = NULL;
221 ControlUserPaneIdleUPP gTPIdleProc = NULL;
222 ControlUserPaneKeyDownUPP gTPKeyProc = NULL;
223 ControlUserPaneActivateUPP gTPActivateProc = NULL;
224 ControlUserPaneFocusUPP gTPFocusProc = NULL;
225
226 // one place for calculating all
227 static void TPCalculateBounds(STPTextPaneVars *varsp, const Rect& bounds)
228 {
229 SetRect(&varsp->fRBounds, bounds.left, bounds.top, bounds.right, bounds.bottom);
230 SetRect(&varsp->fRFocusOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
231 // eventually make TextOutline inset 1,1
232 SetRect(&varsp->fRTextOutline, bounds.left, bounds.top, bounds.right, bounds.bottom);
233 if ( !varsp->fNoBorders )
234 {
235 SetRect(&varsp->fRTextArea, bounds.left + 2 , bounds.top + (varsp->fMultiline ? 0 : 2) ,
236 bounds.right - (varsp->fMultiline ? 0 : 2), bounds.bottom - (varsp->fMultiline ? 0 : 2));
237 }
238 else
239 {
240 SetRect(&varsp->fRTextArea, bounds.left , bounds.top ,
241 bounds.right, bounds.bottom);
242 }
243 }
244
245 OSStatus MLTESetObjectVisibility( STPTextPaneVars *varsp, Boolean vis , long wxStyle)
246 {
247 OSStatus err = noErr ;
248 #if TARGET_API_MAC_OSX
249 TXNControlTag iControlTags[1] = { kTXNVisibilityTag };
250 TXNControlData iControlData[1] = {{ vis }};
251 err = ::TXNSetTXNObjectControls( varsp->fTXNRec, false, 1, iControlTags, iControlData );
252 #endif
253 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
254 if ( vis && textctrl )
255 {
256 Rect bounds ;
257 UMAGetControlBoundsInWindowCoords( varsp->fUserPaneRec, &bounds);
258 TPCalculateBounds( varsp , bounds ) ;
259 wxMacWindowClipper cl(textctrl) ;
260 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left,
261 varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame);
262 TXNShowSelection( varsp->fTXNRec, kTXNShowStart);
263 }
264 return err ;
265 }
266
267 // make sure we don't miss changes as carbon events are not available for these under classic
268 static void TPUpdateVisibility(ControlRef theControl) {
269 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
270 if ( textctrl == NULL )
271 return ;
272
273 STPTextPaneVars *varsp = (STPTextPaneVars *) textctrl->m_macTXNvars ;
274
275 Rect bounds ;
276 UMAGetControlBoundsInWindowCoords(theControl, &bounds);
277 if ( textctrl->MacIsReallyShown() != varsp->fVisible )
278 {
279 // invalidate old position
280 // InvalWindowRect( GetControlOwner( theControl ) , &varsp->fRBounds ) ;
281 varsp->fVisible = textctrl->MacIsReallyShown() ;
282 }
283 if ( !EqualRect( &bounds , &varsp->fRBounds ) )
284 {
285 // old position
286 Rect oldBounds = varsp->fRBounds ;
287 TPCalculateBounds( varsp , bounds ) ;
288 // we only recalculate when visible, otherwise scrollbars get drawn at incorrect places
289 if ( varsp->fVisible )
290 {
291 wxMacWindowClipper cl(textctrl) ;
292 TXNSetFrameBounds( varsp->fTXNRec, varsp->fRTextArea.top, varsp->fRTextArea.left,
293 varsp->fRTextArea.bottom, varsp->fRTextArea.right, varsp->fTXNFrame);
294 }
295 InvalWindowRect( GetControlOwner( theControl ) , &oldBounds ) ;
296 InvalWindowRect( GetControlOwner( theControl ) , &varsp->fRBounds ) ;
297 }
298 }
299
300 // make correct activations
301 static void TPActivatePaneText(STPTextPaneVars *varsp, Boolean setActive) {
302
303 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
304 if (varsp->fTXNObjectActive != setActive && textctrl->MacIsReallyShown() )
305 {
306 varsp->fTXNObjectActive = setActive;
307 TXNActivate(varsp->fTXNRec, varsp->fTXNFrame, varsp->fTXNObjectActive);
308 if (varsp->fInFocus)
309 TXNFocus( varsp->fTXNRec, varsp->fTXNObjectActive);
310 }
311 }
312
313 // update focus outlines
314 static void TPRedrawFocusOutline(STPTextPaneVars *varsp) {
315
316 /* state changed */
317 if (varsp->fFocusDrawState != (varsp->fIsActive && varsp->fInFocus))
318 {
319 varsp->fFocusDrawState = (varsp->fIsActive && varsp->fInFocus);
320 DrawThemeFocusRect(&varsp->fRFocusOutline, varsp->fFocusDrawState);
321 }
322 }
323
324 // update TXN focus state
325 static void TPFocusPaneText(STPTextPaneVars *varsp, Boolean setFocus) {
326 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(varsp->fUserPaneRec);
327
328 if (varsp->fInFocus != setFocus && textctrl->MacIsReallyShown()) {
329 varsp->fInFocus = setFocus;
330 TXNFocus( varsp->fTXNRec, varsp->fInFocus);
331 }
332 }
333
334 // draw the control
335 static pascal void TPPaneDrawProc(ControlRef theControl, ControlPartCode thePart) {
336 /* set up our globals */
337
338 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
339 if ( textctrl == NULL )
340 return ;
341 TPUpdateVisibility( theControl ) ;
342
343 STPTextPaneVars *varsp = (STPTextPaneVars *) textctrl->m_macTXNvars ;
344 if ( textctrl->MacIsReallyShown() )
345 {
346 wxMacWindowClipper clipper( textctrl ) ;
347 TXNDraw(varsp->fTXNRec, NULL);
348 if ( !varsp->fNoBorders )
349 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
350 TPRedrawFocusOutline( varsp ) ;
351 }
352
353 }
354
355
356 /* TPPaneHitTestProc is called when the control manager would
357 like to determine what part of the control the mouse resides over.
358 We also call this routine from our tracking proc to determine how
359 to handle mouse clicks. */
360 static pascal ControlPartCode TPPaneHitTestProc(ControlRef theControl, Point where) {
361 ControlPartCode result;
362 /* set up our locals and lock down our globals*/
363 result = 0;
364 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
365 if ( textctrl == NULL )
366 return 0 ;
367 TPUpdateVisibility( theControl ) ;
368 STPTextPaneVars *varsp = (STPTextPaneVars *) textctrl->m_macTXNvars ;
369 if (textctrl->MacIsReallyShown() )
370 {
371 if (PtInRect(where, &varsp->fRBounds))
372 result = kmUPTextPart;
373 else
374 result = 0;
375 }
376 return result;
377 }
378
379
380
381
382
383 /* TPPaneTrackingProc is called when the mouse is being held down
384 over our control. This routine handles clicks in the text area
385 and in the scroll bar. */
386 static pascal ControlPartCode TPPaneTrackingProc(ControlRef theControl, Point startPt, ControlActionUPP actionProc) {
387
388 ControlPartCode partCodeResult;
389 /* make sure we have some variables... */
390 partCodeResult = 0;
391 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
392 if ( textctrl == NULL )
393 return 0;
394 TPUpdateVisibility( theControl ) ;
395 STPTextPaneVars *varsp = (STPTextPaneVars *) textctrl->m_macTXNvars ;
396 if (textctrl->MacIsReallyShown() )
397 {
398 /* we don't do any of these functions unless we're in focus */
399 if ( ! varsp->fInFocus) {
400 WindowPtr owner;
401 owner = GetControlOwner(theControl);
402 ClearKeyboardFocus(owner);
403 SetKeyboardFocus(owner, theControl, kUserClickedToFocusPart);
404 }
405 /* find the location for the click */
406 // for compositing, we must convert these into toplevel window coordinates, because hittesting expects them
407 if ( textctrl->MacGetTopLevelWindow()->MacUsesCompositing() )
408 {
409 int x = 0 , y = 0 ;
410 textctrl->MacClientToRootWindow( &x , &y ) ;
411 startPt.h += x ;
412 startPt.v += y ;
413 }
414
415 switch (TPPaneHitTestProc(theControl, startPt))
416 {
417
418 /* handle clicks in the text part */
419 case kmUPTextPart:
420 {
421 wxMacWindowClipper clipper( textctrl ) ;
422
423 EventRecord rec ;
424 ConvertEventRefToEventRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) ;
425 TXNClick( varsp->fTXNRec, &rec );
426
427 }
428 break;
429
430 }
431 }
432 return partCodeResult;
433 }
434
435
436 /* TPPaneIdleProc is our user pane idle routine. When our text field
437 is active and in focus, we use this routine to set the cursor. */
438 static pascal void TPPaneIdleProc(ControlRef theControl) {
439 /* set up locals */
440 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
441 if ( textctrl == NULL )
442 return ;
443 TPUpdateVisibility( theControl ) ;
444 STPTextPaneVars *varsp = (STPTextPaneVars *) textctrl->m_macTXNvars ;
445 if (textctrl->MacIsReallyShown()) {
446 /* if we're not active, then we have nothing to say about the cursor */
447 if (varsp->fIsActive) {
448 Rect bounds;
449 Point mousep;
450
451 wxMacWindowClipper clipper( textctrl ) ;
452 GetMouse(&mousep);
453 /* there's a 'focus thing' and an 'unfocused thing' */
454 if (varsp->fInFocus) {
455 /* flash the cursor */
456 SetPort(varsp->fDrawingEnvironment);
457 TXNIdle(varsp->fTXNRec);
458 /* set the cursor */
459 if (PtInRect(mousep, &varsp->fRTextArea)) {
460 RgnHandle theRgn;
461 RectRgn((theRgn = NewRgn()), &varsp->fRTextArea);
462 TXNAdjustCursor(varsp->fTXNRec, theRgn);
463 DisposeRgn(theRgn);
464 }
465 else
466 {
467 // SetThemeCursor(kThemeArrowCursor);
468 }
469 } else {
470 /* if it's in our bounds, set the cursor */
471 UMAGetControlBoundsInWindowCoords(theControl, &bounds);
472 if (PtInRect(mousep, &bounds))
473 {
474 // SetThemeCursor(kThemeArrowCursor);
475 }
476 }
477 }
478 }
479 }
480
481
482 /* TPPaneKeyDownProc is called whenever a keydown event is directed
483 at our control. Here, we direct the keydown event to the text
484 edit record and redraw the scroll bar and text field as appropriate. */
485 static pascal ControlPartCode TPPaneKeyDownProc(ControlRef theControl,
486 SInt16 keyCode, SInt16 charCode, SInt16 modifiers) {
487
488 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
489 if ( textctrl == NULL )
490 return 0;
491 TPUpdateVisibility( theControl ) ;
492
493 STPTextPaneVars *varsp = (STPTextPaneVars *) textctrl->m_macTXNvars ;
494 if (varsp->fInFocus)
495 {
496 /* turn autoscrolling on and send the key event to text edit */
497 wxMacWindowClipper clipper( textctrl ) ;
498 EventRecord ev ;
499 memset( &ev , 0 , sizeof( ev ) ) ;
500 ev.what = keyDown ;
501 ev.modifiers = modifiers ;
502 ev.message = (( keyCode << 8 ) & keyCodeMask ) + ( charCode & charCodeMask ) ;
503 TXNKeyDown( varsp->fTXNRec, &ev);
504 }
505 return kControlEntireControl;
506 }
507
508
509 /* TPPaneActivateProc is called when the window containing
510 the user pane control receives activate events. Here, we redraw
511 the control and it's text as necessary for the activation state. */
512 static pascal void TPPaneActivateProc(ControlRef theControl, Boolean activating) {
513 /* set up locals */
514 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
515
516 if ( textctrl == NULL )
517 return ;
518 TPUpdateVisibility( theControl ) ;
519
520 STPTextPaneVars *varsp = (STPTextPaneVars *) textctrl->m_macTXNvars ;
521
522 varsp->fIsActive = activating;
523 wxMacWindowClipper clipper( textctrl ) ;
524 TPActivatePaneText(varsp, varsp->fIsActive && varsp->fInFocus);
525 /* redraw the frame */
526 if ( textctrl->MacIsReallyShown() )
527 {
528 if ( !varsp->fNoBorders )
529 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
530 TPRedrawFocusOutline( varsp ) ;
531 }
532 }
533
534
535 /* TPPaneFocusProc is called when every the focus changes to or
536 from our control. Herein, switch the focus appropriately
537 according to the parameters and redraw the control as
538 necessary. */
539 static pascal ControlPartCode TPPaneFocusProc(ControlRef theControl, ControlFocusPart action) {
540 ControlPartCode focusResult;
541
542 focusResult = kControlFocusNoPart;
543 wxTextCtrl* textctrl = (wxTextCtrl*) GetControlReference(theControl);
544 if ( textctrl == NULL )
545 return 0;
546 TPUpdateVisibility( theControl ) ;
547 STPTextPaneVars *varsp = (STPTextPaneVars *) textctrl->m_macTXNvars ;
548 /* if kControlFocusPrevPart and kControlFocusNextPart are received when the user is
549 tabbing forwards (or shift tabbing backwards) through the items in the dialog,
550 and kControlFocusNextPart will be received. When the user clicks in our field
551 and it is not the current focus, then the constant kUserClickedToFocusPart will
552 be received. The constant kControlFocusNoPart will be received when our control
553 is the current focus and the user clicks in another control. In your focus routine,
554 you should respond to these codes as follows:
555
556 kControlFocusNoPart - turn off focus and return kControlFocusNoPart. redraw
557 the control and the focus rectangle as necessary.
558
559 kControlFocusPrevPart or kControlFocusNextPart - toggle focus on or off
560 depending on its current state. redraw the control and the focus rectangle
561 as appropriate for the new focus state. If the focus state is 'off', return the constant
562 kControlFocusNoPart, otherwise return a non-zero part code.
563 kUserClickedToFocusPart - is a constant defined for this example. You should
564 define your own value for handling click-to-focus type events. */
565 /* calculate the next highlight state */
566 switch (action) {
567 default:
568 case kControlFocusNoPart:
569 TPFocusPaneText(varsp, false);
570 focusResult = kControlFocusNoPart;
571 break;
572 case kUserClickedToFocusPart:
573 TPFocusPaneText(varsp, true);
574 focusResult = 1;
575 break;
576 case kControlFocusPrevPart:
577 case kControlFocusNextPart:
578 TPFocusPaneText(varsp, ( ! varsp->fInFocus));
579 focusResult = varsp->fInFocus ? 1 : kControlFocusNoPart;
580 break;
581 }
582 TPActivatePaneText(varsp, varsp->fIsActive && varsp->fInFocus);
583 /* redraw the text fram and focus rectangle to indicate the
584 new focus state */
585 if ( textctrl->MacIsReallyShown() )
586 {
587 wxMacWindowClipper c( textctrl ) ;
588 if ( !varsp->fNoBorders )
589 DrawThemeEditTextFrame(&varsp->fRTextOutline, varsp->fIsActive ? kThemeStateActive: kThemeStateInactive);
590 TPRedrawFocusOutline( varsp ) ;
591 }
592 return focusResult;
593 }
594
595
596 /* mUPOpenControl initializes a user pane control so it will be drawn
597 and will behave as a scrolling text edit field inside of a window.
598 This routine performs all of the initialization steps necessary,
599 except it does not create the user pane control itself. theControl
600 should refer to a user pane control that you have either created
601 yourself or extracted from a dialog's control heirarchy using
602 the GetDialogItemAsControl routine. */
603 OSStatus mUPOpenControl(STPTextPaneVars* &handle, ControlRef theControl, long wxStyle )
604 {
605 Rect bounds;
606 WindowRef theWindow;
607 STPTextPaneVars *varsp;
608 OSStatus err = noErr ;
609
610 /* set up our globals */
611 if (gTPDrawProc == NULL) gTPDrawProc = NewControlUserPaneDrawUPP(TPPaneDrawProc);
612 if (gTPHitProc == NULL) gTPHitProc = NewControlUserPaneHitTestUPP(TPPaneHitTestProc);
613 if (gTPTrackProc == NULL) gTPTrackProc = NewControlUserPaneTrackingUPP(TPPaneTrackingProc);
614 if (gTPIdleProc == NULL) gTPIdleProc = NewControlUserPaneIdleUPP(TPPaneIdleProc);
615 if (gTPKeyProc == NULL) gTPKeyProc = NewControlUserPaneKeyDownUPP(TPPaneKeyDownProc);
616 if (gTPActivateProc == NULL) gTPActivateProc = NewControlUserPaneActivateUPP(TPPaneActivateProc);
617 if (gTPFocusProc == NULL) gTPFocusProc = NewControlUserPaneFocusUPP(TPPaneFocusProc);
618
619 /* allocate our private storage */
620 varsp = (STPTextPaneVars *) malloc(sizeof(STPTextPaneVars));
621 handle = varsp ;
622
623 /* set the initial settings for our private data */
624 varsp->fMultiline = wxStyle & wxTE_MULTILINE ;
625 varsp->fNoBorders = wxStyle & wxNO_BORDER ;
626 varsp->fInFocus = false;
627 varsp->fIsActive = true;
628 varsp->fTXNObjectActive = false;
629 varsp->fFocusDrawState = false ;
630 varsp->fUserPaneRec = theControl;
631 varsp->fVisible = true ;
632
633 theWindow = varsp->fOwner = GetControlOwner(theControl);
634
635 varsp->fDrawingEnvironment = (GrafPtr) GetWindowPort(theWindow);
636
637 /* set up the user pane procedures */
638 SetControlData(theControl, kControlEntireControl, kControlUserPaneDrawProcTag, sizeof(gTPDrawProc), &gTPDrawProc);
639 SetControlData(theControl, kControlEntireControl, kControlUserPaneHitTestProcTag, sizeof(gTPHitProc), &gTPHitProc);
640 SetControlData(theControl, kControlEntireControl, kControlUserPaneTrackingProcTag, sizeof(gTPTrackProc), &gTPTrackProc);
641 SetControlData(theControl, kControlEntireControl, kControlUserPaneIdleProcTag, sizeof(gTPIdleProc), &gTPIdleProc);
642 SetControlData(theControl, kControlEntireControl, kControlUserPaneKeyDownProcTag, sizeof(gTPKeyProc), &gTPKeyProc);
643 SetControlData(theControl, kControlEntireControl, kControlUserPaneActivateProcTag, sizeof(gTPActivateProc), &gTPActivateProc);
644 SetControlData(theControl, kControlEntireControl, kControlUserPaneFocusProcTag, sizeof(gTPFocusProc), &gTPFocusProc);
645
646 /* calculate the rectangles used by the control */
647 UMAGetControlBoundsInWindowCoords(theControl, &bounds);
648 varsp->fRTextOutlineRegion = NewRgn() ;
649 TPCalculateBounds( varsp , bounds ) ;
650
651 /* set up the drawing environment */
652 SetPort(varsp->fDrawingEnvironment);
653
654 /* create the new edit field */
655
656 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( wxStyle ) ;
657
658 verify_noerr(TXNNewObject(NULL, varsp->fOwner, &varsp->fRTextArea,
659 frameOptions ,
660 kTXNTextEditStyleFrameType,
661 kTXNTextensionFile,
662 kTXNSystemDefaultEncoding,
663 &varsp->fTXNRec, &varsp->fTXNFrame, (TXNObjectRefcon) varsp));
664
665 AdjustAttributesFromWXStyle( varsp->fTXNRec , wxStyle , varsp->fVisible ) ;
666 /* perform final activations and setup for our text field. Here,
667 we assume that the window is going to be the 'active' window. */
668 TPActivatePaneText(varsp, varsp->fIsActive && varsp->fInFocus);
669 /* all done */
670 return err;
671 }
672
673 #else
674 struct STPTextPaneVars
675 {
676 } ;
677
678 #endif
679
680 static void SetTXNData( STPTextPaneVars *varsp, TXNObject txn , const wxString& st , TXNOffset start , TXNOffset end )
681 {
682 #if wxUSE_UNICODE
683 #if SIZEOF_WCHAR_T == 2
684 size_t len = st.Len() ;
685 TXNSetData( txn , kTXNUnicodeTextData, (void*)st.wc_str(), len * 2,
686 start, end);
687 #else
688 wxMBConvUTF16BE converter ;
689 ByteCount byteBufferLen = converter.WC2MB( NULL , st.wc_str() , 0 ) ;
690 UniChar *unibuf = (UniChar*) malloc(byteBufferLen) ;
691 converter.WC2MB( (char*) unibuf , st.wc_str() , byteBufferLen ) ;
692 TXNSetData( txn , kTXNUnicodeTextData, (void*)unibuf, byteBufferLen ,
693 start, end);
694 free( unibuf ) ;
695 #endif
696 #else
697 wxCharBuffer text = st.mb_str(wxConvLocal) ;
698 TXNSetData( txn , kTXNTextData, (void*)text.data(), strlen( text ) ,
699 start, end);
700 #endif
701 }
702
703
704 #endif
705
706 #if !USE_SHARED_LIBRARY
707 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
708
709 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
710 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
711 EVT_CHAR(wxTextCtrl::OnChar)
712 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
713 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
714 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
715 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
716 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
717
718 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
719 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
720 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
721 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
722 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
723 END_EVENT_TABLE()
724 #endif
725
726 // Text item
727 void wxTextCtrl::Init()
728 {
729 m_macTXN = NULL ;
730 m_macTXNvars = NULL ;
731
732 m_editable = true ;
733 m_dirty = false;
734
735 m_maxLength = TE_UNLIMITED_LENGTH ;
736 }
737
738 wxTextCtrl::~wxTextCtrl()
739 {
740 #if wxMAC_USE_MLTE
741 SetControlReference(*m_peer, 0) ;
742 #if !wxMAC_USE_MLTE_HIVIEW
743 TXNDeleteObject((TXNObject)m_macTXN);
744 #endif
745 /* delete our private storage */
746 free(m_macTXNvars);
747 /* zero the control reference */
748 #endif
749 }
750
751
752 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
753 const wxString& str,
754 const wxPoint& pos,
755 const wxSize& size, long style,
756 const wxValidator& validator,
757 const wxString& name)
758 {
759 m_macIsUserPane = FALSE ;
760
761 m_macTXN = NULL ;
762 m_macTXNvars = NULL ;
763 m_editable = true ;
764
765 // base initialization
766 if ( !wxTextCtrlBase::Create(parent, id, pos, size, style & ~(wxHSCROLL|wxVSCROLL), validator, name) )
767 return FALSE;
768
769 wxSize mySize = size ;
770
771 Rect bounds = wxMacGetBoundsForControl( this , pos , size ) ;
772
773 if ( m_windowStyle & wxTE_MULTILINE )
774 {
775 wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
776 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
777
778 m_windowStyle |= wxTE_PROCESS_ENTER;
779 }
780
781 wxString st = str ;
782 wxMacConvertNewlines13To10( &st ) ;
783 #if wxMAC_USE_MLTE
784 {
785 #if wxMAC_USE_MLTE_HIVIEW
786 HIRect hr = { bounds.left , bounds.top , bounds.right - bounds.left , bounds.bottom- bounds.top } ;
787 HIViewRef scrollView = NULL ;
788 TXNFrameOptions frameOptions = FrameOptionsFromWXStyle( style ) ;
789
790 if ( frameOptions & (kTXNWantVScrollBarMask|kTXNWantHScrollBarMask) )
791 {
792 HIScrollViewCreate(( frameOptions & kTXNWantHScrollBarMask ? kHIScrollViewOptionsHorizScroll : 0) |
793 ( frameOptions & kTXNWantVScrollBarMask ? kHIScrollViewOptionsVertScroll: 0 ) , &scrollView ) ;
794
795 HIViewSetFrame( scrollView, &hr );
796 HIViewSetVisible( scrollView, true );
797 }
798 HIViewRef textView ;
799 HITextViewCreate( NULL , 0, frameOptions , (ControlRef*) &textView ) ;
800 m_macTXN = HITextViewGetTXNObject( textView) ;
801 AdjustAttributesFromWXStyle( (TXNObject) m_macTXN , style , true ) ;
802 HIViewSetVisible( (ControlRef) textView , true ) ;
803 if ( scrollView )
804 {
805 HIViewAddSubview( scrollView , textView ) ;
806 m_peer = scrollView ;
807 }
808 else
809 {
810 m_peer = textView ;
811 }
812 #else
813 short featurSet;
814
815 featurSet = kControlSupportsEmbedding | kControlSupportsFocus | kControlWantsIdle
816 | kControlWantsActivate | kControlHandlesTracking | kControlHasSpecialBackground
817 | kControlGetsFocusOnClick | kControlSupportsLiveFeedback;
818 /* create the control */
819 m_peer = new wxMacControl() ;
820 verify_noerr( ::CreateUserPaneControl( MAC_WXHWND(GetParent()->MacGetTopLevelWindowRef()), &bounds, featurSet, *m_peer ) );
821
822 wxMacWindowClipper c(this) ;
823 STPTextPaneVars *varsp ;
824 mUPOpenControl( varsp, *m_peer, m_windowStyle );
825 m_macTXNvars = varsp ;
826 m_macTXN = varsp->fTXNRec ;
827 #endif
828
829 if ( style & wxTE_PASSWORD )
830 {
831 UniChar c = 0xA5 ;
832 verify_noerr(TXNEchoMode( (TXNObject) m_macTXN , c , 0 , true )) ;
833 }
834 }
835 MacPostControlCreate(pos,size) ;
836
837 #if !wxMAC_USE_MLTE_HIVIEW
838 if ( MacIsReallyShown() )
839 MLTESetObjectVisibility( (STPTextPaneVars*) m_macTXNvars, true , GetWindowStyle() ) ;
840 #endif
841
842 {
843 wxMacWindowClipper clipper( this ) ;
844 #if !wxMAC_USE_MLTE_HIVIEW
845 TPUpdateVisibility( *m_peer ) ;
846 #endif
847 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
848
849 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
850 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
851 }
852
853 // in case MLTE is catching events before we get the chance to do so, we'd have to reintroduce the tlw-handler in front :
854 // parent->MacGetTopLevelWindow()->MacInstallTopLevelWindowEventHandler() ;
855
856 SetBackgroundColour( *wxWHITE ) ;
857
858 TXNBackground tback;
859 tback.bgType = kTXNBackgroundTypeRGB;
860 tback.bg.color = MAC_WXCOLORREF( GetBackgroundColour().GetPixel() );
861 TXNSetBackground( (TXNObject) m_macTXN , &tback);
862
863 #else
864 wxMacCFStringHolder cf(st , m_font.GetEncoding()) ;
865 CFStringRef cfr = cf ;
866 Boolean isPassword = ( m_windowStyle & wxTE_PASSWORD ) != 0 ;
867 m_peer = new wxMacControl() ;
868 CreateEditUnicodeTextControl( MAC_WXHWND(parent->MacGetTopLevelWindowRef()), &bounds , cfr , isPassword , NULL , *m_peer ) ;
869
870 if ( !(m_windowStyle & wxTE_MULTILINE) )
871 {
872 Boolean singleline = true ;
873 ::SetControlData( *m_peer, kControlEditTextPart , kControlEditTextSingleLineTag , sizeof( singleline ) , &singleline ) ;
874 }
875 MacPostControlCreate(pos,size) ;
876
877 #endif
878 if ( m_windowStyle & wxTE_READONLY)
879 {
880 SetEditable( false ) ;
881 }
882
883
884 return TRUE;
885 }
886
887 void wxTextCtrl::MacVisibilityChanged()
888 {
889 #if wxMAC_USE_MLTE
890 #if !wxMAC_USE_MLTE_HIVIEW
891 MLTESetObjectVisibility((STPTextPaneVars*) m_macTXNvars , MacIsReallyShown() , GetWindowStyle() ) ;
892 if ( !MacIsReallyShown() )
893 InvalWindowRect( GetControlOwner( *m_peer ) , &((STPTextPaneVars *)m_macTXNvars)->fRBounds ) ;
894 #endif
895 #else
896 if ( !(m_windowStyle & wxTE_MULTILINE) && MacIsReallyShown() )
897 {
898 // work around a refresh issue insofar as not always the entire content is shown even if this would be possible
899 ControlEditTextSelectionRec sel ;
900 CFStringRef value = NULL ;
901 Size actualSize = 0 ;
902 ResType datatag = GetWindowStyle() & wxTE_PASSWORD ?
903 kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag ;
904
905 verify_noerr( GetControlData( *m_peer , 0, kControlEditTextSelectionTag,
906 sizeof(ControlEditTextSelectionRec), &sel, &actualSize ) );
907 verify_noerr( GetControlData( *m_peer , 0, datatag , sizeof(CFStringRef), &value, &actualSize ) );
908
909 verify_noerr( SetControlData( *m_peer , 0, datatag, sizeof(CFStringRef), &value ) );
910 verify_noerr( SetControlData( *m_peer , 0, kControlEditTextSelectionTag, sizeof(ControlEditTextSelectionRec), &sel ) );
911
912 CFRelease( value ) ;
913 }
914 #endif
915 }
916
917 void wxTextCtrl::MacEnabledStateChanged()
918 {
919 }
920
921
922 wxString wxTextCtrl::GetValue() const
923 {
924 wxString result ;
925 #if wxMAC_USE_MLTE
926 OSStatus err ;
927 Size actualSize = 0;
928 {
929 #if wxUSE_UNICODE
930 Handle theText ;
931 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
932 // all done
933 if ( err )
934 {
935 actualSize = 0 ;
936 }
937 else
938 {
939 actualSize = GetHandleSize( theText ) / sizeof( UniChar) ;
940 if ( actualSize > 0 )
941 {
942 wxChar *ptr = NULL ;
943 #if SIZEOF_WCHAR_T == 2
944 ptr = new wxChar[actualSize + 1 ] ;
945 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
946
947 #else
948 SetHandleSize( theText , ( actualSize + 1 ) * sizeof( UniChar ) ) ;
949 HLock( theText ) ;
950 (((UniChar*)*theText)[actualSize]) = 0 ;
951 wxMBConvUTF16BE converter ;
952 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
953 ptr = new wxChar[noChars + 1] ;
954
955 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars ) ;
956 ptr[noChars] = 0 ;
957 HUnlock( theText ) ;
958 #endif
959 ptr[actualSize] = 0 ;
960 result = wxString( ptr ) ;
961 delete[] ptr ;
962 }
963 DisposeHandle( theText ) ;
964 }
965 #else
966 Handle theText ;
967 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
968 // all done
969 if ( err )
970 {
971 actualSize = 0 ;
972 }
973 else
974 {
975 actualSize = GetHandleSize( theText ) ;
976 if ( actualSize > 0 )
977 {
978 HLock( theText ) ;
979 result = wxString( *theText , wxConvLocal , actualSize ) ;
980 HUnlock( theText ) ;
981 }
982 DisposeHandle( theText ) ;
983 }
984 #endif
985 }
986 #else
987 CFStringRef value = NULL ;
988 Size actualSize = 0 ;
989
990 verify_noerr( GetControlData( *m_peer , 0, GetWindowStyle() & wxTE_PASSWORD ?
991 kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag,
992 sizeof(CFStringRef), &value, &actualSize ) );
993 if ( value )
994 {
995 wxMacCFStringHolder cf(value) ;
996 result = cf.AsString() ;
997 }
998 #endif
999 wxMacConvertNewlines10To13( &result ) ;
1000 return result ;
1001 }
1002
1003 void wxTextCtrl::GetSelection(long* from, long* to) const
1004 {
1005 #if wxMAC_USE_MLTE
1006 TXNGetSelection( (TXNObject) m_macTXN , (TXNOffset*) from , (TXNOffset*) to ) ;
1007 #else
1008 ControlEditTextSelectionRec sel ;
1009 Size actualSize ;
1010 verify_noerr( GetControlData( *m_peer , 0, kControlEditTextSelectionTag,
1011 sizeof(ControlEditTextSelectionRec), &sel, &actualSize ) );
1012 if ( from ) *from = sel.selStart ;
1013 if ( to ) *to = sel.selEnd ;
1014 #endif
1015 }
1016
1017 void wxTextCtrl::SetValue(const wxString& str)
1018 {
1019 // optimize redraws
1020 if ( GetValue() == str )
1021 return ;
1022
1023 wxString st = str ;
1024 wxMacConvertNewlines13To10( &st ) ;
1025 #if wxMAC_USE_MLTE
1026 {
1027 wxMacWindowClipper c( this ) ;
1028 bool formerEditable = m_editable ;
1029 if ( !formerEditable )
1030 SetEditable(true) ;
1031
1032 #if !wxMAC_USE_MLTE_HIVIEW
1033 // otherwise scrolling might have problems ?
1034 TPUpdateVisibility( ( (STPTextPaneVars *)m_macTXNvars)->fUserPaneRec ) ;
1035 #endif
1036 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
1037 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
1038 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1039 if ( !formerEditable )
1040 SetEditable(formerEditable) ;
1041 }
1042 #else
1043 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1044 CFStringRef value = cf ;
1045 verify_noerr( SetControlData( *m_peer , 0, GetWindowStyle() & wxTE_PASSWORD ?
1046 kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag,
1047 sizeof(CFStringRef), &value ) );
1048 #endif
1049 }
1050
1051 void wxTextCtrl::SetMaxLength(unsigned long len)
1052 {
1053 m_maxLength = len ;
1054 }
1055
1056 bool wxTextCtrl::SetFont( const wxFont& font )
1057 {
1058 if ( !wxTextCtrlBase::SetFont( font ) )
1059 return FALSE ;
1060
1061 #if wxMAC_USE_MLTE
1062 wxMacWindowClipper c( this ) ;
1063 bool formerEditable = m_editable ;
1064 if ( !formerEditable )
1065 SetEditable(true) ;
1066
1067 TXNTypeAttributes typeAttr[4] ;
1068 Str255 fontName = "\pMonaco" ;
1069 SInt16 fontSize = 12 ;
1070 Style fontStyle = normal ;
1071 int attrCounter = 0 ;
1072
1073 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
1074 fontSize = font.MacGetFontSize() ;
1075 fontStyle = font.MacGetFontStyle() ;
1076
1077 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
1078 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
1079 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
1080 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
1081 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
1082 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
1083 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
1084 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
1085 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
1086 attrCounter += 3 ;
1087 /*
1088 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
1089 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
1090 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
1091 color = MAC_WXCOLORREF(GetForegroundColour().GetPixel()) ;
1092 attrCounter += 1 ;
1093 */
1094 verify_noerr( TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, kTXNStartOffset,kTXNEndOffset) );
1095
1096 if ( !formerEditable )
1097 SetEditable(formerEditable) ;
1098 #endif
1099 return true ;
1100 }
1101
1102 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
1103 {
1104 #if wxMAC_USE_MLTE
1105 bool formerEditable = m_editable ;
1106 if ( !formerEditable )
1107 SetEditable(true) ;
1108 TXNTypeAttributes typeAttr[4] ;
1109 Str255 fontName = "\pMonaco" ;
1110 SInt16 fontSize = 12 ;
1111 Style fontStyle = normal ;
1112 RGBColor color ;
1113 int attrCounter = 0 ;
1114 if ( style.HasFont() )
1115 {
1116 const wxFont &font = style.GetFont() ;
1117 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
1118 fontSize = font.GetPointSize() ;
1119 if ( font.GetUnderlined() )
1120 fontStyle |= underline ;
1121 if ( font.GetWeight() == wxBOLD )
1122 fontStyle |= bold ;
1123 if ( font.GetStyle() == wxITALIC )
1124 fontStyle |= italic ;
1125
1126 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
1127 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
1128 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
1129 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
1130 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
1131 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
1132 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
1133 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
1134 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
1135 attrCounter += 3 ;
1136
1137 }
1138 if ( style.HasTextColour() )
1139 {
1140 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
1141 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
1142 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
1143 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
1144 attrCounter += 1 ;
1145 }
1146
1147 if ( attrCounter > 0 )
1148 {
1149 verify_noerr( TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, start,end) );
1150 }
1151 if ( !formerEditable )
1152 SetEditable(formerEditable) ;
1153 #endif
1154 return TRUE ;
1155 }
1156
1157 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
1158 {
1159 wxTextCtrlBase::SetDefaultStyle( style ) ;
1160 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1161 return TRUE ;
1162 }
1163
1164 // Clipboard operations
1165 void wxTextCtrl::Copy()
1166 {
1167 if (CanCopy())
1168 {
1169 #if wxMAC_USE_MLTE
1170 ClearCurrentScrap();
1171 TXNCopy((TXNObject)m_macTXN);
1172 TXNConvertToPublicScrap();
1173 #else
1174 m_peer->SendHICommand( kHICommandCopy ) ;
1175 #endif
1176 }
1177 }
1178
1179 void wxTextCtrl::Cut()
1180 {
1181 if (CanCut())
1182 {
1183 #if wxMAC_USE_MLTE
1184 ClearCurrentScrap();
1185 TXNCut((TXNObject)m_macTXN);
1186 TXNConvertToPublicScrap();
1187 #else
1188 m_peer->SendHICommand( kHICommandCut ) ;
1189 #endif
1190 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1191 event.SetString( GetValue() ) ;
1192 event.SetEventObject( this );
1193 GetEventHandler()->ProcessEvent(event);
1194 }
1195 }
1196
1197 void wxTextCtrl::Paste()
1198 {
1199 if (CanPaste())
1200 {
1201 #if wxMAC_USE_MLTE
1202 TXNConvertFromPublicScrap();
1203 TXNPaste((TXNObject)m_macTXN);
1204 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1205 #else
1206 m_peer->SendHICommand( kHICommandPaste ) ;
1207 #endif
1208 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1209 event.SetString( GetValue() ) ;
1210 event.SetEventObject( this );
1211 GetEventHandler()->ProcessEvent(event);
1212 }
1213 }
1214
1215 bool wxTextCtrl::CanCopy() const
1216 {
1217 // Can copy if there's a selection
1218 long from, to;
1219 GetSelection(& from, & to);
1220 return (from != to);
1221 }
1222
1223 bool wxTextCtrl::CanCut() const
1224 {
1225 if ( !IsEditable() )
1226 {
1227 return false ;
1228 }
1229 // Can cut if there's a selection
1230 long from, to;
1231 GetSelection(& from, & to);
1232 return (from != to);
1233 }
1234
1235 bool wxTextCtrl::CanPaste() const
1236 {
1237 if (!IsEditable())
1238 return FALSE;
1239
1240 #if wxMAC_USE_MLTE
1241 return TXNIsScrapPastable() ;
1242 #else
1243 return true ;
1244 #endif
1245 }
1246
1247 void wxTextCtrl::SetEditable(bool editable)
1248 {
1249 if ( editable != m_editable )
1250 {
1251 m_editable = editable ;
1252 #if wxMAC_USE_MLTE
1253 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1254 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1255 TXNSetTXNObjectControls( (TXNObject) m_macTXN , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ;
1256 #else
1257 Boolean value = !editable ;
1258 ::SetControlData( *m_peer, 0, kControlEditTextLockedTag , sizeof( value ) , &value ) ;
1259 #endif
1260 }
1261 }
1262
1263 void wxTextCtrl::SetInsertionPoint(long pos)
1264 {
1265 SetSelection( pos , pos ) ;
1266 }
1267
1268 void wxTextCtrl::SetInsertionPointEnd()
1269 {
1270 long pos = GetLastPosition();
1271 SetInsertionPoint(pos);
1272 }
1273
1274 long wxTextCtrl::GetInsertionPoint() const
1275 {
1276 long begin,end ;
1277 GetSelection( &begin , &end ) ;
1278 return begin ;
1279 }
1280
1281 long wxTextCtrl::GetLastPosition() const
1282 {
1283 long actualsize = 0 ;
1284 #if wxMAC_USE_MLTE
1285 Handle theText ;
1286 OSErr err = TXNGetDataEncoded( (TXNObject) m_macTXN, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1287 /* all done */
1288 if ( err )
1289 {
1290 actualsize = 0 ;
1291 }
1292 else
1293 {
1294 actualsize = GetHandleSize( theText ) ;
1295 DisposeHandle( theText ) ;
1296 }
1297 #endif
1298 return actualsize ;
1299 }
1300
1301 void wxTextCtrl::Replace(long from, long to, const wxString& str)
1302 {
1303 #if wxMAC_USE_MLTE
1304 wxString value = str ;
1305 wxMacConvertNewlines13To10( &value ) ;
1306
1307 bool formerEditable = m_editable ;
1308 if ( !formerEditable )
1309 SetEditable(true) ;
1310 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1311 TXNClear( ((TXNObject) m_macTXN) ) ;
1312 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , str , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1313 if ( !formerEditable )
1314 SetEditable( formerEditable ) ;
1315
1316 Refresh() ;
1317 #endif
1318 }
1319
1320 void wxTextCtrl::Remove(long from, long to)
1321 {
1322 #if wxMAC_USE_MLTE
1323 bool formerEditable = m_editable ;
1324 if ( !formerEditable )
1325 SetEditable(true) ;
1326 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1327 TXNClear( ((TXNObject) m_macTXN) ) ;
1328 if ( !formerEditable )
1329 SetEditable( formerEditable ) ;
1330
1331 Refresh() ;
1332 #endif
1333 }
1334
1335 void wxTextCtrl::SetSelection(long from, long to)
1336 {
1337 #if wxMAC_USE_MLTE
1338 /* change the selection */
1339 if ((from == -1) && (to == -1))
1340 TXNSelectAll((TXNObject) m_macTXN);
1341 else
1342 TXNSetSelection( (TXNObject) m_macTXN, from, to);
1343 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1344 #else
1345 ControlEditTextSelectionRec sel ;
1346 sel.selStart = from ;
1347 sel.selEnd = to ;
1348 verify_noerr( SetControlData( *m_peer , 0, kControlEditTextSelectionTag,
1349 sizeof(ControlEditTextSelectionRec), &sel ) );
1350
1351 #endif
1352 }
1353
1354 bool wxTextCtrl::LoadFile(const wxString& file)
1355 {
1356 if ( wxTextCtrlBase::LoadFile(file) )
1357 {
1358 return TRUE;
1359 }
1360
1361 return FALSE;
1362 }
1363
1364 class wxMacFunctor
1365 {
1366 public :
1367 wxMacFunctor(){}
1368 virtual ~wxMacFunctor() {}
1369 virtual void* operator()() = 0 ;
1370 static void* CallBackProc(void *param)
1371 {
1372 wxMacFunctor* f = (wxMacFunctor*) param ;
1373 void *result = (*f)() ;
1374 return result ;
1375 }
1376 } ;
1377
1378 template<typename classtype,typename param1type>
1379 class wxMacObjectFunctor1 : public wxMacFunctor
1380 {
1381 typedef void (classtype::*function)( param1type p1 ) ;
1382 typedef void (classtype::*ref_function)( const param1type& p1 ) ;
1383 public :
1384 wxMacObjectFunctor1( classtype *obj , function f , param1type p1 ) :
1385 wxMacFunctor( )
1386 {
1387 m_object = obj ;
1388 m_function = f ;
1389 m_param1 = p1 ;
1390 }
1391
1392 wxMacObjectFunctor1( classtype *obj , ref_function f , param1type p1 ) :
1393 wxMacFunctor( )
1394 {
1395 m_object = obj ;
1396 m_refFunction = f ;
1397 m_param1 = p1 ;
1398 }
1399
1400 ~wxMacObjectFunctor1() {}
1401
1402 virtual void* operator()()
1403 {
1404 (m_object->*m_function)(m_param1) ;
1405 return NULL ;
1406 }
1407 private :
1408 classtype* m_object ;
1409 param1type m_param1 ;
1410 union
1411 {
1412 function m_function ;
1413 ref_function m_refFunction ;
1414 } ;
1415 } ;
1416
1417 template<typename classtype, typename param1type>
1418 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
1419 {
1420 wxMacObjectFunctor1<classtype,param1type> params(object,function,p1) ;
1421 void *result =
1422 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
1423 return result ;
1424 }
1425
1426 template<typename classtype, typename param1type>
1427 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
1428 {
1429 wxMacObjectFunctor1<classtype,param1type> params(object,function,p1) ;
1430 void *result =
1431 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
1432 return result ;
1433 }
1434
1435 template<typename classtype, typename param1type>
1436 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
1437 {
1438 wxMutexGuiLeave() ;
1439 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
1440 wxMutexGuiEnter() ;
1441 return result ;
1442 }
1443
1444 template<typename classtype, typename param1type>
1445 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
1446 {
1447 wxMutexGuiLeave() ;
1448 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
1449 wxMutexGuiEnter() ;
1450 return result ;
1451 }
1452
1453 void wxTextCtrl::WriteText(const wxString& str)
1454 {
1455 if ( !wxIsMainThread() )
1456 {
1457 // unfortunately CW 8 is not able to correctly deduce the template types, so we have
1458 // to instantiate explicitely
1459 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( this , &wxTextCtrl::WriteText , str ) ;
1460 return ;
1461 }
1462 else
1463 {
1464 wxString st = str ;
1465 wxMacConvertNewlines13To10( &st ) ;
1466 #if wxMAC_USE_MLTE
1467 bool formerEditable = m_editable ;
1468 if ( !formerEditable )
1469 SetEditable(true) ;
1470 {
1471 wxMacWindowStateSaver s( this ) ;
1472 long start , end , dummy ;
1473 GetSelection( &start , &dummy ) ;
1474 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , st , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1475 GetSelection( &dummy , &end ) ;
1476 SetStyle( start , end , GetDefaultStyle() ) ;
1477 }
1478 if ( !formerEditable )
1479 SetEditable( formerEditable ) ;
1480
1481 MacRedrawControl() ;
1482 #else
1483 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
1484 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1485 CFStringRef value = cf ;
1486 SetControlData( *m_peer , 0, kControlEditTextInsertCFStringRefTag,
1487 sizeof(CFStringRef), &value );
1488 #else
1489 wxString val = GetValue() ;
1490 long start , end ;
1491 GetSelection( &start , &end ) ;
1492 val.Remove( start , end - start ) ;
1493 val.insert( start , str ) ;
1494 SetValue( val ) ;
1495 SetInsertionPoint( start + str.Length() ) ;
1496 #endif
1497 #endif
1498 }
1499 }
1500
1501 void wxTextCtrl::AppendText(const wxString& text)
1502 {
1503 SetInsertionPointEnd();
1504 WriteText(text);
1505 }
1506
1507 void wxTextCtrl::Clear()
1508 {
1509 #if wxMAC_USE_MLTE
1510 bool formerEditable = m_editable ;
1511 if ( !formerEditable )
1512 SetEditable(true) ;
1513 TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ;
1514 TXNClear((TXNObject)m_macTXN);
1515
1516 if ( !formerEditable )
1517 SetEditable( formerEditable ) ;
1518
1519 Refresh() ;
1520 #else
1521 SetValue(wxEmptyString) ;
1522 #endif
1523 }
1524
1525 bool wxTextCtrl::IsModified() const
1526 {
1527 return m_dirty;
1528 }
1529
1530 bool wxTextCtrl::IsEditable() const
1531 {
1532 return IsEnabled() && m_editable ;
1533 }
1534
1535 bool wxTextCtrl::AcceptsFocus() const
1536 {
1537 // we don't want focus if we can't be edited
1538 return /*IsEditable() && */ wxControl::AcceptsFocus();
1539 }
1540
1541 wxSize wxTextCtrl::DoGetBestSize() const
1542 {
1543 int wText = 100 ;
1544
1545 int hText;
1546
1547 switch( m_windowVariant )
1548 {
1549 case wxWINDOW_VARIANT_NORMAL :
1550 hText = 22 ;
1551 break ;
1552 case wxWINDOW_VARIANT_SMALL :
1553 hText = 19 ;
1554 break ;
1555 case wxWINDOW_VARIANT_MINI :
1556 hText= 15 ;
1557 break ;
1558 default :
1559 hText = 22 ;
1560 break ;
1561 }
1562
1563 #if !wxMAC_USE_MLTE
1564 // unicode text control is using client size, ie 3 pixels on every side
1565 // TODO make this fit into normal window size concept, probably having
1566 // to reintroduce the margin vars
1567 hText -= 6 ;
1568 #endif
1569
1570 if ( m_windowStyle & wxTE_MULTILINE )
1571 {
1572 hText *= 5 ;
1573 }
1574
1575 return wxSize(wText, hText);
1576 }
1577
1578 // ----------------------------------------------------------------------------
1579 // Undo/redo
1580 // ----------------------------------------------------------------------------
1581
1582 void wxTextCtrl::Undo()
1583 {
1584 if (CanUndo())
1585 {
1586 #if wxMAC_USE_MLTE
1587 TXNUndo((TXNObject)m_macTXN);
1588 #endif
1589 }
1590 }
1591
1592 void wxTextCtrl::Redo()
1593 {
1594 if (CanRedo())
1595 {
1596 #if wxMAC_USE_MLTE
1597 TXNRedo((TXNObject)m_macTXN);
1598 #endif
1599 }
1600 }
1601
1602 bool wxTextCtrl::CanUndo() const
1603 {
1604 if ( !IsEditable() )
1605 {
1606 return false ;
1607 }
1608 #if wxMAC_USE_MLTE
1609 return TXNCanUndo((TXNObject)m_macTXN,NULL);
1610 #else
1611 return false ;
1612 #endif
1613 }
1614
1615 bool wxTextCtrl::CanRedo() const
1616 {
1617 if ( !IsEditable() )
1618 {
1619 return false ;
1620 }
1621 #if wxMAC_USE_MLTE
1622 return TXNCanRedo((TXNObject)m_macTXN,NULL);
1623 #else
1624 return false ;
1625 #endif
1626 }
1627
1628 // Makes modifie or unmodified
1629 void wxTextCtrl::MarkDirty()
1630 {
1631 m_dirty = true;
1632 }
1633
1634 void wxTextCtrl::DiscardEdits()
1635 {
1636 m_dirty = false;
1637 }
1638
1639 int wxTextCtrl::GetNumberOfLines() const
1640 {
1641 ItemCount lines = 0 ;
1642 #if wxMAC_USE_MLTE
1643 TXNGetLineCount((TXNObject)m_macTXN, &lines ) ;
1644 #else
1645 wxString content = GetValue() ;
1646 lines = 1;
1647 for (size_t i = 0; i < content.Length() ; i++)
1648 {
1649 if (content[i] == '\r') lines++;
1650 }
1651 #endif
1652 return lines ;
1653 }
1654
1655 long wxTextCtrl::XYToPosition(long x, long y) const
1656 {
1657 #if wxMAC_USE_MLTE
1658 Point curpt ;
1659
1660 long lastpos = GetLastPosition() ;
1661
1662 // TODO find a better implementation : while we can get the
1663 // line metrics of a certain line, we don't get its starting
1664 // position, so it would probably be rather a binary search
1665 // for the start position
1666 long xpos = 0 ;
1667 long ypos = 0 ;
1668 int lastHeight = 0 ;
1669
1670 ItemCount n ;
1671 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1672 {
1673 if ( y == ypos && x == xpos )
1674 return n ;
1675
1676 TXNOffsetToPoint( (TXNObject) m_macTXN, n , &curpt);
1677
1678 if ( curpt.v > lastHeight )
1679 {
1680 xpos = 0 ;
1681 if ( n > 0 )
1682 ++ypos ;
1683 lastHeight = curpt.v ;
1684 }
1685 else
1686 ++xpos ;
1687 }
1688 #endif
1689 return 0;
1690 }
1691
1692 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
1693 {
1694 #if wxMAC_USE_MLTE
1695 Point curpt ;
1696
1697 long lastpos = GetLastPosition() ;
1698
1699 if ( y ) *y = 0 ;
1700 if ( x ) *x = 0 ;
1701
1702 if ( pos <= lastpos )
1703 {
1704 // TODO find a better implementation : while we can get the
1705 // line metrics of a certain line, we don't get its starting
1706 // position, so it would probably be rather a binary search
1707 // for the start position
1708 long xpos = 0 ;
1709 long ypos = 0 ;
1710 int lastHeight = 0 ;
1711
1712 ItemCount n ;
1713 for ( n = 0 ; n <= (ItemCount) pos ; ++n )
1714 {
1715 TXNOffsetToPoint( (TXNObject) m_macTXN, n , &curpt);
1716
1717 if ( curpt.v > lastHeight )
1718 {
1719 xpos = 0 ;
1720 if ( n > 0 )
1721 ++ypos ;
1722 lastHeight = curpt.v ;
1723 }
1724 else
1725 ++xpos ;
1726 }
1727 if ( y ) *y = ypos ;
1728 if ( x ) *x = xpos ;
1729 }
1730 #else
1731 if ( y ) *y = 0 ;
1732 if ( x ) *x = 0 ;
1733 #endif
1734 return FALSE ;
1735 }
1736
1737 void wxTextCtrl::ShowPosition(long pos)
1738 {
1739 #if wxMAC_USE_MLTE
1740 #if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER)
1741 {
1742 Point current ;
1743 Point desired ;
1744 TXNOffset selstart , selend ;
1745 TXNGetSelection( (TXNObject) m_macTXN , &selstart , &selend) ;
1746 TXNOffsetToPoint( (TXNObject) m_macTXN, selstart , &current);
1747 TXNOffsetToPoint( (TXNObject) m_macTXN, pos , &desired);
1748 //TODO use HIPoints for 10.3 and above
1749 if ( (UInt32) TXNScroll != (UInt32) kUnresolvedCFragSymbolAddress )
1750 {
1751 OSErr theErr = noErr;
1752 SInt32 dv = desired.v - current.v ;
1753 SInt32 dh = desired.h - current.h ;
1754 TXNShowSelection( (TXNObject) m_macTXN , true ) ;
1755 theErr = TXNScroll( (TXNObject) m_macTXN, kTXNScrollUnitsInPixels , kTXNScrollUnitsInPixels , &dv , &dh );
1756 wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
1757 }
1758 }
1759 #endif
1760 #endif
1761 }
1762
1763 int wxTextCtrl::GetLineLength(long lineNo) const
1764 {
1765 #if wxMAC_USE_MLTE
1766 Point curpt ;
1767 if ( lineNo < GetNumberOfLines() )
1768 {
1769 // TODO find a better implementation : while we can get the
1770 // line metrics of a certain line, we don't get its starting
1771 // position, so it would probably be rather a binary search
1772 // for the start position
1773 long xpos = 0 ;
1774 long ypos = 0 ;
1775 int lastHeight = 0 ;
1776 long lastpos = GetLastPosition() ;
1777
1778 ItemCount n ;
1779 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1780 {
1781 TXNOffsetToPoint( (TXNObject) m_macTXN, n , &curpt);
1782
1783 if ( curpt.v > lastHeight )
1784 {
1785 if ( ypos == lineNo )
1786 return xpos ;
1787
1788 xpos = 0 ;
1789 if ( n > 0 )
1790 ++ypos ;
1791 lastHeight = curpt.v ;
1792 }
1793 else
1794 ++xpos ;
1795 }
1796 }
1797 #else
1798 // TODO change this if possible to reflect real lines
1799 wxString content = GetValue() ;
1800
1801 // Find line first
1802 int count = 0;
1803 for (size_t i = 0; i < content.Length() ; i++)
1804 {
1805 if (count == lineNo)
1806 {
1807 // Count chars in line then
1808 count = 0;
1809 for (size_t j = i; j < content.Length(); j++)
1810 {
1811 count++;
1812 if (content[j] == '\n') return count;
1813 }
1814
1815 return count;
1816 }
1817 if (content[i] == '\n') count++;
1818 }
1819 #endif
1820 return 0;
1821 }
1822
1823 wxString wxTextCtrl::GetLineText(long lineNo) const
1824 {
1825 #if wxMAC_USE_MLTE
1826 wxString line ;
1827 Point curpt ;
1828 wxString content = GetValue() ;
1829
1830 if ( lineNo < GetNumberOfLines() )
1831 {
1832 // TODO find a better implementation : while we can get the
1833 // line metrics of a certain line, we don't get its starting
1834 // position, so it would probably be rather a binary search
1835 // for the start position
1836 long xpos = 0 ;
1837 long ypos = 0 ;
1838 int lastHeight = 0 ;
1839 long lastpos = GetLastPosition() ;
1840
1841 ItemCount n ;
1842 for ( n = 0 ; n <= (ItemCount)lastpos ; ++n )
1843 {
1844 TXNOffsetToPoint( (TXNObject) m_macTXN, n , &curpt);
1845
1846 if ( curpt.v > lastHeight )
1847 {
1848 if ( ypos == lineNo )
1849 return line ;
1850
1851 xpos = 0 ;
1852 if ( n > 0 )
1853 ++ypos ;
1854 lastHeight = curpt.v ;
1855 }
1856 else
1857 {
1858 if ( ypos == lineNo )
1859 line += content[n] ;
1860 ++xpos ;
1861 }
1862 }
1863 }
1864 return line ;
1865 #else
1866 // TODO change this if possible to reflect real lines
1867 wxString content = GetValue() ;
1868
1869 // Find line first
1870 int count = 0;
1871 for (size_t i = 0; i < content.Length() ; i++)
1872 {
1873 if (count == lineNo)
1874 {
1875 // Add chars in line then
1876 wxString tmp;
1877
1878 for (size_t j = i; j < content.Length(); j++)
1879 {
1880 if (content[j] == '\n')
1881 return tmp;
1882
1883 tmp += content[j];
1884 }
1885
1886 return tmp;
1887 }
1888 if (content[i] == '\n') count++;
1889 }
1890 return wxEmptyString ;
1891 #endif
1892 }
1893
1894 /*
1895 * Text item
1896 */
1897
1898 void wxTextCtrl::Command(wxCommandEvent & event)
1899 {
1900 SetValue (event.GetString());
1901 ProcessCommand (event);
1902 }
1903
1904 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
1905 {
1906 // By default, load the first file into the text window.
1907 if (event.GetNumberOfFiles() > 0)
1908 {
1909 LoadFile(event.GetFiles()[0]);
1910 }
1911 }
1912
1913 void wxTextCtrl::OnChar(wxKeyEvent& event)
1914 {
1915 int key = event.GetKeyCode() ;
1916 bool eat_key = false ;
1917
1918 if ( key == 'c' && event.MetaDown() )
1919 {
1920 if ( CanCopy() )
1921 Copy() ;
1922 return ;
1923 }
1924
1925 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
1926 !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1927 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1928 )
1929 {
1930 // eat it
1931 return ;
1932 }
1933
1934 // assume that any key not processed yet is going to modify the control
1935 m_dirty = true;
1936
1937 if ( key == 'v' && event.MetaDown() )
1938 {
1939 if ( CanPaste() )
1940 Paste() ;
1941 return ;
1942 }
1943 if ( key == 'x' && event.MetaDown() )
1944 {
1945 if ( CanCut() )
1946 Cut() ;
1947 return ;
1948 }
1949 switch ( key )
1950 {
1951 case WXK_RETURN:
1952 if (m_windowStyle & wxPROCESS_ENTER)
1953 {
1954 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1955 event.SetEventObject( this );
1956 event.SetString( GetValue() );
1957 if ( GetEventHandler()->ProcessEvent(event) )
1958 return;
1959 }
1960 if ( !(m_windowStyle & wxTE_MULTILINE) )
1961 {
1962 wxWindow *parent = GetParent();
1963 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
1964 parent = parent->GetParent() ;
1965 }
1966 if ( parent && parent->GetDefaultItem() )
1967 {
1968 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
1969 wxButton);
1970 if ( def && def->IsEnabled() )
1971 {
1972 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
1973 event.SetEventObject(def);
1974 def->Command(event);
1975 return ;
1976 }
1977 }
1978
1979 // this will make wxWidgets eat the ENTER key so that
1980 // we actually prevent line wrapping in a single line
1981 // text control
1982 eat_key = TRUE;
1983 }
1984
1985 break;
1986
1987 case WXK_TAB:
1988 if ( !(m_windowStyle & wxTE_PROCESS_TAB))
1989 {
1990 Navigate(!event.ShiftDown(), event.ControlDown());
1991 return;
1992 }
1993 else
1994 {
1995 // This is necessary (don't know why) or the tab will not
1996 // be inserted.
1997 WriteText(wxT("\t"));
1998 }
1999
2000 break;
2001 }
2002
2003 if (!eat_key)
2004 {
2005 // perform keystroke handling
2006 if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
2007 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
2008 else
2009 {
2010 EventRecord rec ;
2011 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
2012 {
2013 EventRecord *ev = &rec ;
2014 short keycode ;
2015 short keychar ;
2016 keychar = short(ev->message & charCodeMask);
2017 keycode = short(ev->message & keyCodeMask) >> 8 ;
2018
2019 ::HandleControlKey( *m_peer , keycode , keychar , ev->modifiers ) ;
2020 }
2021 }
2022 }
2023 if ( ( key >= 0x20 && key < WXK_START ) ||
2024 key == WXK_RETURN ||
2025 key == WXK_DELETE ||
2026 key == WXK_BACK)
2027 {
2028 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
2029 event1.SetString( GetValue() ) ;
2030 event1.SetEventObject( this );
2031 wxPostEvent(GetEventHandler(),event1);
2032 }
2033 }
2034
2035 // ----------------------------------------------------------------------------
2036 // standard handlers for standard edit menu events
2037 // ----------------------------------------------------------------------------
2038
2039 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
2040 {
2041 Cut();
2042 }
2043
2044 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
2045 {
2046 Copy();
2047 }
2048
2049 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
2050 {
2051 Paste();
2052 }
2053
2054 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
2055 {
2056 Undo();
2057 }
2058
2059 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
2060 {
2061 Redo();
2062 }
2063
2064 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
2065 {
2066 event.Enable( CanCut() );
2067 }
2068
2069 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
2070 {
2071 event.Enable( CanCopy() );
2072 }
2073
2074 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
2075 {
2076 event.Enable( CanPaste() );
2077 }
2078
2079 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
2080 {
2081 event.Enable( CanUndo() );
2082 }
2083
2084 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
2085 {
2086 event.Enable( CanRedo() );
2087 }
2088
2089 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
2090 {
2091 return true ;
2092 }
2093
2094 // user pane implementation
2095
2096 void wxTextCtrl::MacControlUserPaneDrawProc(wxInt16 part)
2097 {
2098 }
2099
2100 wxInt16 wxTextCtrl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
2101 {
2102 return kControlNoPart ;
2103 }
2104
2105 wxInt16 wxTextCtrl::MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc)
2106 {
2107 return kControlNoPart ;
2108 }
2109
2110 void wxTextCtrl::MacControlUserPaneIdleProc()
2111 {
2112 }
2113
2114 wxInt16 wxTextCtrl::MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
2115 {
2116 return kControlNoPart ;
2117 }
2118
2119 void wxTextCtrl::MacControlUserPaneActivateProc(bool activating)
2120 {
2121 }
2122
2123 wxInt16 wxTextCtrl::MacControlUserPaneFocusProc(wxInt16 action)
2124 {
2125 return kControlNoPart ;
2126 }
2127
2128 void wxTextCtrl::MacControlUserPaneBackgroundProc(void* info)
2129 {
2130 }
2131
2132 #endif
2133 // wxUSE_TEXTCTRL