introduction of m_peer
[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
823 wxMacWindowClipper c(this) ;
824 STPTextPaneVars *varsp ;
825 mUPOpenControl( varsp, *m_peer, m_windowStyle );
826 m_macTXNvars = varsp ;
827 m_macTXN = varsp->fTXNRec ;
828 #endif
829
830 if ( style & wxTE_PASSWORD )
831 {
832 UniChar c = 0xA5 ;
833 verify_noerr(TXNEchoMode( (TXNObject) m_macTXN , c , 0 , true )) ;
834 }
835 }
836 MacPostControlCreate(pos,size) ;
837
838 #if !wxMAC_USE_MLTE_HIVIEW
839 if ( MacIsReallyShown() )
840 MLTESetObjectVisibility( (STPTextPaneVars*) m_macTXNvars, true , GetWindowStyle() ) ;
841 #endif
842
843 {
844 wxMacWindowClipper clipper( this ) ;
845 #if !wxMAC_USE_MLTE_HIVIEW
846 TPUpdateVisibility( *m_peer ) ;
847 #endif
848 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
849
850 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
851 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
852 }
853
854 // in case MLTE is catching events before we get the chance to do so, we'd have to reintroduce the tlw-handler in front :
855 // parent->MacGetTopLevelWindow()->MacInstallTopLevelWindowEventHandler() ;
856
857 SetBackgroundColour( *wxWHITE ) ;
858
859 TXNBackground tback;
860 tback.bgType = kTXNBackgroundTypeRGB;
861 tback.bg.color = MAC_WXCOLORREF( GetBackgroundColour().GetPixel() );
862 TXNSetBackground( (TXNObject) m_macTXN , &tback);
863
864 #else
865 wxMacCFStringHolder cf(st , m_font.GetEncoding()) ;
866 CFStringRef cfr = cf ;
867 Boolean isPassword = ( m_windowStyle & wxTE_PASSWORD ) != 0 ;
868 m_peer = new wxMacControl() ;
869 CreateEditUnicodeTextControl( MAC_WXHWND(parent->MacGetTopLevelWindowRef()), &bounds , cfr , isPassword , NULL , *m_peer ) ;
870
871 if ( !(m_windowStyle & wxTE_MULTILINE) )
872 {
873 Boolean singleline = true ;
874 ::SetControlData( *m_peer, kControlEditTextPart , kControlEditTextSingleLineTag , sizeof( singleline ) , &singleline ) ;
875 }
876 MacPostControlCreate(pos,size) ;
877
878 #endif
879 if ( m_windowStyle & wxTE_READONLY)
880 {
881 SetEditable( false ) ;
882 }
883
884
885 return TRUE;
886 }
887
888 void wxTextCtrl::MacVisibilityChanged()
889 {
890 #if wxMAC_USE_MLTE
891 #if !wxMAC_USE_MLTE_HIVIEW
892 MLTESetObjectVisibility((STPTextPaneVars*) m_macTXNvars , MacIsReallyShown() , GetWindowStyle() ) ;
893 if ( !MacIsReallyShown() )
894 InvalWindowRect( GetControlOwner( *m_peer ) , &((STPTextPaneVars *)m_macTXNvars)->fRBounds ) ;
895 #endif
896 #else
897 if ( !(m_windowStyle & wxTE_MULTILINE) && MacIsReallyShown() )
898 {
899 // work around a refresh issue insofar as not always the entire content is shown even if this would be possible
900 ControlEditTextSelectionRec sel ;
901 CFStringRef value = NULL ;
902 Size actualSize = 0 ;
903 ResType datatag = GetWindowStyle() & wxTE_PASSWORD ?
904 kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag ;
905
906 verify_noerr( GetControlData( *m_peer , 0, kControlEditTextSelectionTag,
907 sizeof(ControlEditTextSelectionRec), &sel, &actualSize ) );
908 verify_noerr( GetControlData( *m_peer , 0, datatag , sizeof(CFStringRef), &value, &actualSize ) );
909
910 verify_noerr( SetControlData( *m_peer , 0, datatag, sizeof(CFStringRef), &value ) );
911 verify_noerr( SetControlData( *m_peer , 0, kControlEditTextSelectionTag, sizeof(ControlEditTextSelectionRec), &sel ) );
912
913 CFRelease( value ) ;
914 }
915 #endif
916 }
917
918 void wxTextCtrl::MacEnabledStateChanged()
919 {
920 }
921
922
923 wxString wxTextCtrl::GetValue() const
924 {
925 wxString result ;
926 #if wxMAC_USE_MLTE
927 OSStatus err ;
928 Size actualSize = 0;
929 {
930 #if wxUSE_UNICODE
931 Handle theText ;
932 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
933 // all done
934 if ( err )
935 {
936 actualSize = 0 ;
937 }
938 else
939 {
940 actualSize = GetHandleSize( theText ) / sizeof( UniChar) ;
941 if ( actualSize > 0 )
942 {
943 wxChar *ptr = NULL ;
944 #if SIZEOF_WCHAR_T == 2
945 ptr = new wxChar[actualSize + 1 ] ;
946 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
947
948 #else
949 SetHandleSize( theText , ( actualSize + 1 ) * sizeof( UniChar ) ) ;
950 HLock( theText ) ;
951 (((UniChar*)*theText)[actualSize]) = 0 ;
952 wxMBConvUTF16BE converter ;
953 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
954 ptr = new wxChar[noChars + 1] ;
955
956 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars ) ;
957 ptr[noChars] = 0 ;
958 HUnlock( theText ) ;
959 #endif
960 ptr[actualSize] = 0 ;
961 result = wxString( ptr ) ;
962 delete[] ptr ;
963 }
964 DisposeHandle( theText ) ;
965 }
966 #else
967 Handle theText ;
968 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
969 // all done
970 if ( err )
971 {
972 actualSize = 0 ;
973 }
974 else
975 {
976 actualSize = GetHandleSize( theText ) ;
977 if ( actualSize > 0 )
978 {
979 HLock( theText ) ;
980 result = wxString( *theText , wxConvLocal , actualSize ) ;
981 HUnlock( theText ) ;
982 }
983 DisposeHandle( theText ) ;
984 }
985 #endif
986 }
987 #else
988 CFStringRef value = NULL ;
989 Size actualSize = 0 ;
990
991 verify_noerr( GetControlData( *m_peer , 0, GetWindowStyle() & wxTE_PASSWORD ?
992 kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag,
993 sizeof(CFStringRef), &value, &actualSize ) );
994 if ( value )
995 {
996 wxMacCFStringHolder cf(value) ;
997 result = cf.AsString() ;
998 }
999 #endif
1000 wxMacConvertNewlines10To13( &result ) ;
1001 return result ;
1002 }
1003
1004 void wxTextCtrl::GetSelection(long* from, long* to) const
1005 {
1006 #if wxMAC_USE_MLTE
1007 TXNGetSelection( (TXNObject) m_macTXN , (TXNOffset*) from , (TXNOffset*) to ) ;
1008 #else
1009 ControlEditTextSelectionRec sel ;
1010 Size actualSize ;
1011 verify_noerr( GetControlData( *m_peer , 0, kControlEditTextSelectionTag,
1012 sizeof(ControlEditTextSelectionRec), &sel, &actualSize ) );
1013 if ( from ) *from = sel.selStart ;
1014 if ( to ) *to = sel.selEnd ;
1015 #endif
1016 }
1017
1018 void wxTextCtrl::SetValue(const wxString& str)
1019 {
1020 // optimize redraws
1021 if ( GetValue() == str )
1022 return ;
1023
1024 wxString st = str ;
1025 wxMacConvertNewlines13To10( &st ) ;
1026 #if wxMAC_USE_MLTE
1027 {
1028 wxMacWindowClipper c( this ) ;
1029 bool formerEditable = m_editable ;
1030 if ( !formerEditable )
1031 SetEditable(true) ;
1032
1033 #if !wxMAC_USE_MLTE_HIVIEW
1034 // otherwise scrolling might have problems ?
1035 TPUpdateVisibility( ( (STPTextPaneVars *)m_macTXNvars)->fUserPaneRec ) ;
1036 #endif
1037 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
1038 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
1039 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1040 if ( !formerEditable )
1041 SetEditable(formerEditable) ;
1042 }
1043 #else
1044 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1045 CFStringRef value = cf ;
1046 verify_noerr( SetControlData( *m_peer , 0, GetWindowStyle() & wxTE_PASSWORD ?
1047 kControlEditTextPasswordCFStringTag : kControlEditTextCFStringTag,
1048 sizeof(CFStringRef), &value ) );
1049 #endif
1050 }
1051
1052 void wxTextCtrl::SetMaxLength(unsigned long len)
1053 {
1054 m_maxLength = len ;
1055 }
1056
1057 bool wxTextCtrl::SetFont( const wxFont& font )
1058 {
1059 if ( !wxTextCtrlBase::SetFont( font ) )
1060 return FALSE ;
1061
1062 #if wxMAC_USE_MLTE
1063 wxMacWindowClipper c( this ) ;
1064 bool formerEditable = m_editable ;
1065 if ( !formerEditable )
1066 SetEditable(true) ;
1067
1068 TXNTypeAttributes typeAttr[4] ;
1069 Str255 fontName = "\pMonaco" ;
1070 SInt16 fontSize = 12 ;
1071 Style fontStyle = normal ;
1072 int attrCounter = 0 ;
1073
1074 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
1075 fontSize = font.MacGetFontSize() ;
1076 fontStyle = font.MacGetFontStyle() ;
1077
1078 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
1079 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
1080 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
1081 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
1082 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
1083 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
1084 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
1085 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
1086 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
1087 attrCounter += 3 ;
1088 /*
1089 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
1090 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
1091 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
1092 color = MAC_WXCOLORREF(GetForegroundColour().GetPixel()) ;
1093 attrCounter += 1 ;
1094 */
1095 verify_noerr( TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, kTXNStartOffset,kTXNEndOffset) );
1096
1097 if ( !formerEditable )
1098 SetEditable(formerEditable) ;
1099 #endif
1100 return true ;
1101 }
1102
1103 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
1104 {
1105 #if wxMAC_USE_MLTE
1106 bool formerEditable = m_editable ;
1107 if ( !formerEditable )
1108 SetEditable(true) ;
1109 TXNTypeAttributes typeAttr[4] ;
1110 Str255 fontName = "\pMonaco" ;
1111 SInt16 fontSize = 12 ;
1112 Style fontStyle = normal ;
1113 RGBColor color ;
1114 int attrCounter = 0 ;
1115 if ( style.HasFont() )
1116 {
1117 const wxFont &font = style.GetFont() ;
1118 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
1119 fontSize = font.GetPointSize() ;
1120 if ( font.GetUnderlined() )
1121 fontStyle |= underline ;
1122 if ( font.GetWeight() == wxBOLD )
1123 fontStyle |= bold ;
1124 if ( font.GetStyle() == wxITALIC )
1125 fontStyle |= italic ;
1126
1127 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
1128 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
1129 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
1130 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
1131 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
1132 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
1133 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
1134 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
1135 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
1136 attrCounter += 3 ;
1137
1138 }
1139 if ( style.HasTextColour() )
1140 {
1141 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
1142 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
1143 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
1144 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
1145 attrCounter += 1 ;
1146 }
1147
1148 if ( attrCounter > 0 )
1149 {
1150 verify_noerr( TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, start,end) );
1151 }
1152 if ( !formerEditable )
1153 SetEditable(formerEditable) ;
1154 #endif
1155 return TRUE ;
1156 }
1157
1158 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
1159 {
1160 wxTextCtrlBase::SetDefaultStyle( style ) ;
1161 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1162 return TRUE ;
1163 }
1164
1165 // Clipboard operations
1166 void wxTextCtrl::Copy()
1167 {
1168 if (CanCopy())
1169 {
1170 #if wxMAC_USE_MLTE
1171 ClearCurrentScrap();
1172 TXNCopy((TXNObject)m_macTXN);
1173 TXNConvertToPublicScrap();
1174 #else
1175 m_peer->SendHICommand( kHICommandCopy ) ;
1176 #endif
1177 }
1178 }
1179
1180 void wxTextCtrl::Cut()
1181 {
1182 if (CanCut())
1183 {
1184 #if wxMAC_USE_MLTE
1185 ClearCurrentScrap();
1186 TXNCut((TXNObject)m_macTXN);
1187 TXNConvertToPublicScrap();
1188 #else
1189 m_peer->SendHICommand( kHICommandCut ) ;
1190 #endif
1191 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1192 event.SetString( GetValue() ) ;
1193 event.SetEventObject( this );
1194 GetEventHandler()->ProcessEvent(event);
1195 }
1196 }
1197
1198 void wxTextCtrl::Paste()
1199 {
1200 if (CanPaste())
1201 {
1202 #if wxMAC_USE_MLTE
1203 TXNConvertFromPublicScrap();
1204 TXNPaste((TXNObject)m_macTXN);
1205 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1206 #else
1207 m_peer->SendHICommand( kHICommandPaste ) ;
1208 #endif
1209 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1210 event.SetString( GetValue() ) ;
1211 event.SetEventObject( this );
1212 GetEventHandler()->ProcessEvent(event);
1213 }
1214 }
1215
1216 bool wxTextCtrl::CanCopy() const
1217 {
1218 // Can copy if there's a selection
1219 long from, to;
1220 GetSelection(& from, & to);
1221 return (from != to);
1222 }
1223
1224 bool wxTextCtrl::CanCut() const
1225 {
1226 if ( !IsEditable() )
1227 {
1228 return false ;
1229 }
1230 // Can cut if there's a selection
1231 long from, to;
1232 GetSelection(& from, & to);
1233 return (from != to);
1234 }
1235
1236 bool wxTextCtrl::CanPaste() const
1237 {
1238 if (!IsEditable())
1239 return FALSE;
1240
1241 #if wxMAC_USE_MLTE
1242 return TXNIsScrapPastable() ;
1243 #else
1244 return true ;
1245 #endif
1246 }
1247
1248 void wxTextCtrl::SetEditable(bool editable)
1249 {
1250 if ( editable != m_editable )
1251 {
1252 m_editable = editable ;
1253 #if wxMAC_USE_MLTE
1254 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1255 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1256 TXNSetTXNObjectControls( (TXNObject) m_macTXN , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ;
1257 #else
1258 Boolean value = !editable ;
1259 ::SetControlData( *m_peer, 0, kControlEditTextLockedTag , sizeof( value ) , &value ) ;
1260 #endif
1261 }
1262 }
1263
1264 void wxTextCtrl::SetInsertionPoint(long pos)
1265 {
1266 SetSelection( pos , pos ) ;
1267 }
1268
1269 void wxTextCtrl::SetInsertionPointEnd()
1270 {
1271 long pos = GetLastPosition();
1272 SetInsertionPoint(pos);
1273 }
1274
1275 long wxTextCtrl::GetInsertionPoint() const
1276 {
1277 long begin,end ;
1278 GetSelection( &begin , &end ) ;
1279 return begin ;
1280 }
1281
1282 long wxTextCtrl::GetLastPosition() const
1283 {
1284 long actualsize = 0 ;
1285 #if wxMAC_USE_MLTE
1286 Handle theText ;
1287 OSErr err = TXNGetDataEncoded( (TXNObject) m_macTXN, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1288 /* all done */
1289 if ( err )
1290 {
1291 actualsize = 0 ;
1292 }
1293 else
1294 {
1295 actualsize = GetHandleSize( theText ) ;
1296 DisposeHandle( theText ) ;
1297 }
1298 #endif
1299 return actualsize ;
1300 }
1301
1302 void wxTextCtrl::Replace(long from, long to, const wxString& str)
1303 {
1304 #if wxMAC_USE_MLTE
1305 wxString value = str ;
1306 wxMacConvertNewlines13To10( &value ) ;
1307
1308 bool formerEditable = m_editable ;
1309 if ( !formerEditable )
1310 SetEditable(true) ;
1311 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1312 TXNClear( ((TXNObject) m_macTXN) ) ;
1313 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , str , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1314 if ( !formerEditable )
1315 SetEditable( formerEditable ) ;
1316
1317 Refresh() ;
1318 #endif
1319 }
1320
1321 void wxTextCtrl::Remove(long from, long to)
1322 {
1323 #if wxMAC_USE_MLTE
1324 bool formerEditable = m_editable ;
1325 if ( !formerEditable )
1326 SetEditable(true) ;
1327 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1328 TXNClear( ((TXNObject) m_macTXN) ) ;
1329 if ( !formerEditable )
1330 SetEditable( formerEditable ) ;
1331
1332 Refresh() ;
1333 #endif
1334 }
1335
1336 void wxTextCtrl::SetSelection(long from, long to)
1337 {
1338 #if wxMAC_USE_MLTE
1339 /* change the selection */
1340 if ((from == -1) && (to == -1))
1341 TXNSelectAll((TXNObject) m_macTXN);
1342 else
1343 TXNSetSelection( (TXNObject) m_macTXN, from, to);
1344 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1345 #else
1346 ControlEditTextSelectionRec sel ;
1347 sel.selStart = from ;
1348 sel.selEnd = to ;
1349 verify_noerr( SetControlData( *m_peer , 0, kControlEditTextSelectionTag,
1350 sizeof(ControlEditTextSelectionRec), &sel ) );
1351
1352 #endif
1353 }
1354
1355 bool wxTextCtrl::LoadFile(const wxString& file)
1356 {
1357 if ( wxTextCtrlBase::LoadFile(file) )
1358 {
1359 return TRUE;
1360 }
1361
1362 return FALSE;
1363 }
1364
1365 class wxMacFunctor
1366 {
1367 public :
1368 wxMacFunctor(){}
1369 virtual ~wxMacFunctor() {}
1370 virtual void* operator()() = 0 ;
1371 static void* CallBackProc(void *param)
1372 {
1373 wxMacFunctor* f = (wxMacFunctor*) param ;
1374 void *result = (*f)() ;
1375 return result ;
1376 }
1377 } ;
1378
1379 template<typename classtype,typename param1type>
1380 class wxMacObjectFunctor1 : public wxMacFunctor
1381 {
1382 typedef void (classtype::*function)( param1type p1 ) ;
1383 typedef void (classtype::*ref_function)( const param1type& p1 ) ;
1384 public :
1385 wxMacObjectFunctor1( classtype *obj , function f , param1type p1 ) :
1386 wxMacFunctor( )
1387 {
1388 m_object = obj ;
1389 m_function = f ;
1390 m_param1 = p1 ;
1391 }
1392
1393 wxMacObjectFunctor1( classtype *obj , ref_function f , param1type p1 ) :
1394 wxMacFunctor( )
1395 {
1396 m_object = obj ;
1397 m_refFunction = f ;
1398 m_param1 = p1 ;
1399 }
1400
1401 ~wxMacObjectFunctor1() {}
1402
1403 virtual void* operator()()
1404 {
1405 (m_object->*m_function)(m_param1) ;
1406 return NULL ;
1407 }
1408 private :
1409 classtype* m_object ;
1410 param1type m_param1 ;
1411 union
1412 {
1413 function m_function ;
1414 ref_function m_refFunction ;
1415 } ;
1416 } ;
1417
1418 template<typename classtype, typename param1type>
1419 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
1420 {
1421 wxMacObjectFunctor1<classtype,param1type> params(object,function,p1) ;
1422 void *result =
1423 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
1424 return result ;
1425 }
1426
1427 template<typename classtype, typename param1type>
1428 void* wxMacMPRemoteCall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
1429 {
1430 wxMacObjectFunctor1<classtype,param1type> params(object,function,p1) ;
1431 void *result =
1432 MPRemoteCall( wxMacFunctor::CallBackProc , &params , kMPOwningProcessRemoteContext ) ;
1433 return result ;
1434 }
1435
1436 template<typename classtype, typename param1type>
1437 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( param1type p1 ) , param1type p1 )
1438 {
1439 wxMutexGuiLeave() ;
1440 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
1441 wxMutexGuiEnter() ;
1442 return result ;
1443 }
1444
1445 template<typename classtype, typename param1type>
1446 void* wxMacMPRemoteGUICall( classtype *object , void (classtype::*function)( const param1type& p1 ) , param1type p1 )
1447 {
1448 wxMutexGuiLeave() ;
1449 void *result = wxMacMPRemoteCall( object , function , p1 ) ;
1450 wxMutexGuiEnter() ;
1451 return result ;
1452 }
1453
1454 void wxTextCtrl::WriteText(const wxString& str)
1455 {
1456 if ( !wxIsMainThread() )
1457 {
1458 // unfortunately CW 8 is not able to correctly deduce the template types, so we have
1459 // to instantiate explicitely
1460 wxMacMPRemoteGUICall<wxTextCtrl,wxString>( this , &wxTextCtrl::WriteText , str ) ;
1461 return ;
1462 }
1463 else
1464 {
1465 wxString st = str ;
1466 wxMacConvertNewlines13To10( &st ) ;
1467 #if wxMAC_USE_MLTE
1468 bool formerEditable = m_editable ;
1469 if ( !formerEditable )
1470 SetEditable(true) ;
1471 {
1472 wxMacWindowStateSaver s( this ) ;
1473 long start , end , dummy ;
1474 GetSelection( &start , &dummy ) ;
1475 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , st , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1476 GetSelection( &dummy , &end ) ;
1477 SetStyle( start , end , GetDefaultStyle() ) ;
1478 }
1479 if ( !formerEditable )
1480 SetEditable( formerEditable ) ;
1481
1482 MacRedrawControl() ;
1483 #else
1484 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
1485 wxMacCFStringHolder cf(st , m_font.GetEncoding() ) ;
1486 CFStringRef value = cf ;
1487 SetControlData( *m_peer , 0, kControlEditTextInsertCFStringRefTag,
1488 sizeof(CFStringRef), &value );
1489 #else
1490 wxString val = GetValue() ;
1491 long start , end ;
1492 GetSelection( &start , &end ) ;
1493 val.Remove( start , end - start ) ;
1494 val.insert( start , str ) ;
1495 SetValue( val ) ;
1496 SetInsertionPoint( start + str.Length() ) ;
1497 #endif
1498 #endif
1499 }
1500 }
1501
1502 void wxTextCtrl::AppendText(const wxString& text)
1503 {
1504 SetInsertionPointEnd();
1505 WriteText(text);
1506 }
1507
1508 void wxTextCtrl::Clear()
1509 {
1510 #if wxMAC_USE_MLTE
1511 bool formerEditable = m_editable ;
1512 if ( !formerEditable )
1513 SetEditable(true) ;
1514 TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ;
1515 TXNClear((TXNObject)m_macTXN);
1516
1517 if ( !formerEditable )
1518 SetEditable( formerEditable ) ;
1519
1520 Refresh() ;
1521 #else
1522 SetValue(wxEmptyString) ;
1523 #endif
1524 }
1525
1526 bool wxTextCtrl::IsModified() const
1527 {
1528 return m_dirty;
1529 }
1530
1531 bool wxTextCtrl::IsEditable() const
1532 {
1533 return IsEnabled() && m_editable ;
1534 }
1535
1536 bool wxTextCtrl::AcceptsFocus() const
1537 {
1538 // we don't want focus if we can't be edited
1539 return /*IsEditable() && */ wxControl::AcceptsFocus();
1540 }
1541
1542 wxSize wxTextCtrl::DoGetBestSize() const
1543 {
1544 int wText = 100 ;
1545
1546 int hText;
1547
1548 switch( m_windowVariant )
1549 {
1550 case wxWINDOW_VARIANT_NORMAL :
1551 hText = 22 ;
1552 break ;
1553 case wxWINDOW_VARIANT_SMALL :
1554 hText = 19 ;
1555 break ;
1556 case wxWINDOW_VARIANT_MINI :
1557 hText= 15 ;
1558 break ;
1559 default :
1560 hText = 22 ;
1561 break ;
1562 }
1563
1564 #if !wxMAC_USE_MLTE
1565 // unicode text control is using client size, ie 3 pixels on every side
1566 // TODO make this fit into normal window size concept, probably having
1567 // to reintroduce the margin vars
1568 hText -= 6 ;
1569 #endif
1570
1571 if ( m_windowStyle & wxTE_MULTILINE )
1572 {
1573 hText *= 5 ;
1574 }
1575
1576 return wxSize(wText, hText);
1577 }
1578
1579 // ----------------------------------------------------------------------------
1580 // Undo/redo
1581 // ----------------------------------------------------------------------------
1582
1583 void wxTextCtrl::Undo()
1584 {
1585 if (CanUndo())
1586 {
1587 #if wxMAC_USE_MLTE
1588 TXNUndo((TXNObject)m_macTXN);
1589 #endif
1590 }
1591 }
1592
1593 void wxTextCtrl::Redo()
1594 {
1595 if (CanRedo())
1596 {
1597 #if wxMAC_USE_MLTE
1598 TXNRedo((TXNObject)m_macTXN);
1599 #endif
1600 }
1601 }
1602
1603 bool wxTextCtrl::CanUndo() const
1604 {
1605 if ( !IsEditable() )
1606 {
1607 return false ;
1608 }
1609 #if wxMAC_USE_MLTE
1610 return TXNCanUndo((TXNObject)m_macTXN,NULL);
1611 #else
1612 return false ;
1613 #endif
1614 }
1615
1616 bool wxTextCtrl::CanRedo() const
1617 {
1618 if ( !IsEditable() )
1619 {
1620 return false ;
1621 }
1622 #if wxMAC_USE_MLTE
1623 return TXNCanRedo((TXNObject)m_macTXN,NULL);
1624 #else
1625 return false ;
1626 #endif
1627 }
1628
1629 // Makes modifie or unmodified
1630 void wxTextCtrl::MarkDirty()
1631 {
1632 m_dirty = true;
1633 }
1634
1635 void wxTextCtrl::DiscardEdits()
1636 {
1637 m_dirty = false;
1638 }
1639
1640 int wxTextCtrl::GetNumberOfLines() const
1641 {
1642 ItemCount lines = 0 ;
1643 #if wxMAC_USE_MLTE
1644 TXNGetLineCount((TXNObject)m_macTXN, &lines ) ;
1645 #else
1646 wxString content = GetValue() ;
1647 lines = 1;
1648 for (size_t i = 0; i < content.Length() ; i++)
1649 {
1650 if (content[i] == '\r') lines++;
1651 }
1652 #endif
1653 return lines ;
1654 }
1655
1656 long wxTextCtrl::XYToPosition(long x, long y) const
1657 {
1658 #if wxMAC_USE_MLTE
1659 Point curpt ;
1660
1661 long lastpos = GetLastPosition() ;
1662
1663 // TODO find a better implementation : while we can get the
1664 // line metrics of a certain line, we don't get its starting
1665 // position, so it would probably be rather a binary search
1666 // for the start position
1667 long xpos = 0 ;
1668 long ypos = 0 ;
1669 int lastHeight = 0 ;
1670
1671 ItemCount n ;
1672 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1673 {
1674 if ( y == ypos && x == xpos )
1675 return n ;
1676
1677 TXNOffsetToPoint( (TXNObject) m_macTXN, n , &curpt);
1678
1679 if ( curpt.v > lastHeight )
1680 {
1681 xpos = 0 ;
1682 if ( n > 0 )
1683 ++ypos ;
1684 lastHeight = curpt.v ;
1685 }
1686 else
1687 ++xpos ;
1688 }
1689 #endif
1690 return 0;
1691 }
1692
1693 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
1694 {
1695 #if wxMAC_USE_MLTE
1696 Point curpt ;
1697
1698 long lastpos = GetLastPosition() ;
1699
1700 if ( y ) *y = 0 ;
1701 if ( x ) *x = 0 ;
1702
1703 if ( pos <= lastpos )
1704 {
1705 // TODO find a better implementation : while we can get the
1706 // line metrics of a certain line, we don't get its starting
1707 // position, so it would probably be rather a binary search
1708 // for the start position
1709 long xpos = 0 ;
1710 long ypos = 0 ;
1711 int lastHeight = 0 ;
1712
1713 ItemCount n ;
1714 for ( n = 0 ; n <= (ItemCount) pos ; ++n )
1715 {
1716 TXNOffsetToPoint( (TXNObject) m_macTXN, n , &curpt);
1717
1718 if ( curpt.v > lastHeight )
1719 {
1720 xpos = 0 ;
1721 if ( n > 0 )
1722 ++ypos ;
1723 lastHeight = curpt.v ;
1724 }
1725 else
1726 ++xpos ;
1727 }
1728 if ( y ) *y = ypos ;
1729 if ( x ) *x = xpos ;
1730 }
1731 #else
1732 if ( y ) *y = 0 ;
1733 if ( x ) *x = 0 ;
1734 #endif
1735 return FALSE ;
1736 }
1737
1738 void wxTextCtrl::ShowPosition(long pos)
1739 {
1740 #if wxMAC_USE_MLTE
1741 #if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER)
1742 {
1743 Point current ;
1744 Point desired ;
1745 TXNOffset selstart , selend ;
1746 TXNGetSelection( (TXNObject) m_macTXN , &selstart , &selend) ;
1747 TXNOffsetToPoint( (TXNObject) m_macTXN, selstart , &current);
1748 TXNOffsetToPoint( (TXNObject) m_macTXN, pos , &desired);
1749 //TODO use HIPoints for 10.3 and above
1750 if ( (UInt32) TXNScroll != (UInt32) kUnresolvedCFragSymbolAddress )
1751 {
1752 OSErr theErr = noErr;
1753 SInt32 dv = desired.v - current.v ;
1754 SInt32 dh = desired.h - current.h ;
1755 TXNShowSelection( (TXNObject) m_macTXN , true ) ;
1756 theErr = TXNScroll( (TXNObject) m_macTXN, kTXNScrollUnitsInPixels , kTXNScrollUnitsInPixels , &dv , &dh );
1757 wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
1758 }
1759 }
1760 #endif
1761 #endif
1762 }
1763
1764 int wxTextCtrl::GetLineLength(long lineNo) const
1765 {
1766 #if wxMAC_USE_MLTE
1767 Point curpt ;
1768 if ( lineNo < GetNumberOfLines() )
1769 {
1770 // TODO find a better implementation : while we can get the
1771 // line metrics of a certain line, we don't get its starting
1772 // position, so it would probably be rather a binary search
1773 // for the start position
1774 long xpos = 0 ;
1775 long ypos = 0 ;
1776 int lastHeight = 0 ;
1777 long lastpos = GetLastPosition() ;
1778
1779 ItemCount n ;
1780 for ( n = 0 ; n <= (ItemCount) lastpos ; ++n )
1781 {
1782 TXNOffsetToPoint( (TXNObject) m_macTXN, n , &curpt);
1783
1784 if ( curpt.v > lastHeight )
1785 {
1786 if ( ypos == lineNo )
1787 return xpos ;
1788
1789 xpos = 0 ;
1790 if ( n > 0 )
1791 ++ypos ;
1792 lastHeight = curpt.v ;
1793 }
1794 else
1795 ++xpos ;
1796 }
1797 }
1798 #else
1799 // TODO change this if possible to reflect real lines
1800 wxString content = GetValue() ;
1801
1802 // Find line first
1803 int count = 0;
1804 for (size_t i = 0; i < content.Length() ; i++)
1805 {
1806 if (count == lineNo)
1807 {
1808 // Count chars in line then
1809 count = 0;
1810 for (size_t j = i; j < content.Length(); j++)
1811 {
1812 count++;
1813 if (content[j] == '\n') return count;
1814 }
1815
1816 return count;
1817 }
1818 if (content[i] == '\n') count++;
1819 }
1820 #endif
1821 return 0;
1822 }
1823
1824 wxString wxTextCtrl::GetLineText(long lineNo) const
1825 {
1826 #if wxMAC_USE_MLTE
1827 wxString line ;
1828 Point curpt ;
1829 wxString content = GetValue() ;
1830
1831 if ( lineNo < GetNumberOfLines() )
1832 {
1833 // TODO find a better implementation : while we can get the
1834 // line metrics of a certain line, we don't get its starting
1835 // position, so it would probably be rather a binary search
1836 // for the start position
1837 long xpos = 0 ;
1838 long ypos = 0 ;
1839 int lastHeight = 0 ;
1840 long lastpos = GetLastPosition() ;
1841
1842 ItemCount n ;
1843 for ( n = 0 ; n <= (ItemCount)lastpos ; ++n )
1844 {
1845 TXNOffsetToPoint( (TXNObject) m_macTXN, n , &curpt);
1846
1847 if ( curpt.v > lastHeight )
1848 {
1849 if ( ypos == lineNo )
1850 return line ;
1851
1852 xpos = 0 ;
1853 if ( n > 0 )
1854 ++ypos ;
1855 lastHeight = curpt.v ;
1856 }
1857 else
1858 {
1859 if ( ypos == lineNo )
1860 line += content[n] ;
1861 ++xpos ;
1862 }
1863 }
1864 }
1865 return line ;
1866 #else
1867 // TODO change this if possible to reflect real lines
1868 wxString content = GetValue() ;
1869
1870 // Find line first
1871 int count = 0;
1872 for (size_t i = 0; i < content.Length() ; i++)
1873 {
1874 if (count == lineNo)
1875 {
1876 // Add chars in line then
1877 wxString tmp;
1878
1879 for (size_t j = i; j < content.Length(); j++)
1880 {
1881 if (content[j] == '\n')
1882 return tmp;
1883
1884 tmp += content[j];
1885 }
1886
1887 return tmp;
1888 }
1889 if (content[i] == '\n') count++;
1890 }
1891 return wxEmptyString ;
1892 #endif
1893 }
1894
1895 /*
1896 * Text item
1897 */
1898
1899 void wxTextCtrl::Command(wxCommandEvent & event)
1900 {
1901 SetValue (event.GetString());
1902 ProcessCommand (event);
1903 }
1904
1905 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
1906 {
1907 // By default, load the first file into the text window.
1908 if (event.GetNumberOfFiles() > 0)
1909 {
1910 LoadFile(event.GetFiles()[0]);
1911 }
1912 }
1913
1914 void wxTextCtrl::OnChar(wxKeyEvent& event)
1915 {
1916 int key = event.GetKeyCode() ;
1917 bool eat_key = false ;
1918
1919 if ( key == 'c' && event.MetaDown() )
1920 {
1921 if ( CanCopy() )
1922 Copy() ;
1923 return ;
1924 }
1925
1926 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
1927 !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1928 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1929 )
1930 {
1931 // eat it
1932 return ;
1933 }
1934
1935 // assume that any key not processed yet is going to modify the control
1936 m_dirty = true;
1937
1938 if ( key == 'v' && event.MetaDown() )
1939 {
1940 if ( CanPaste() )
1941 Paste() ;
1942 return ;
1943 }
1944 if ( key == 'x' && event.MetaDown() )
1945 {
1946 if ( CanCut() )
1947 Cut() ;
1948 return ;
1949 }
1950 switch ( key )
1951 {
1952 case WXK_RETURN:
1953 if (m_windowStyle & wxPROCESS_ENTER)
1954 {
1955 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1956 event.SetEventObject( this );
1957 event.SetString( GetValue() );
1958 if ( GetEventHandler()->ProcessEvent(event) )
1959 return;
1960 }
1961 if ( !(m_windowStyle & wxTE_MULTILINE) )
1962 {
1963 wxWindow *parent = GetParent();
1964 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
1965 parent = parent->GetParent() ;
1966 }
1967 if ( parent && parent->GetDefaultItem() )
1968 {
1969 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
1970 wxButton);
1971 if ( def && def->IsEnabled() )
1972 {
1973 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
1974 event.SetEventObject(def);
1975 def->Command(event);
1976 return ;
1977 }
1978 }
1979
1980 // this will make wxWidgets eat the ENTER key so that
1981 // we actually prevent line wrapping in a single line
1982 // text control
1983 eat_key = TRUE;
1984 }
1985
1986 break;
1987
1988 case WXK_TAB:
1989 // always produce navigation event - even if we process TAB
1990 // ourselves the fact that we got here means that the user code
1991 // decided to skip processing of this TAB - probably to let it
1992 // do its default job.
1993 {
1994 wxNavigationKeyEvent eventNav;
1995 eventNav.SetDirection(!event.ShiftDown());
1996 eventNav.SetWindowChange(event.ControlDown());
1997 eventNav.SetEventObject(this);
1998
1999 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
2000 return;
2001
2002 event.Skip() ;
2003 return;
2004 }
2005 break;
2006 }
2007
2008 if (!eat_key)
2009 {
2010 // perform keystroke handling
2011 if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
2012 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
2013 else
2014 {
2015 EventRecord rec ;
2016 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
2017 {
2018 EventRecord *ev = &rec ;
2019 short keycode ;
2020 short keychar ;
2021 keychar = short(ev->message & charCodeMask);
2022 keycode = short(ev->message & keyCodeMask) >> 8 ;
2023
2024 ::HandleControlKey( *m_peer , keycode , keychar , ev->modifiers ) ;
2025 }
2026 }
2027 }
2028 if ( ( key >= 0x20 && key < WXK_START ) ||
2029 key == WXK_RETURN ||
2030 key == WXK_DELETE ||
2031 key == WXK_BACK)
2032 {
2033 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
2034 event1.SetString( GetValue() ) ;
2035 event1.SetEventObject( this );
2036 wxPostEvent(GetEventHandler(),event1);
2037 }
2038 }
2039
2040 // ----------------------------------------------------------------------------
2041 // standard handlers for standard edit menu events
2042 // ----------------------------------------------------------------------------
2043
2044 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
2045 {
2046 Cut();
2047 }
2048
2049 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
2050 {
2051 Copy();
2052 }
2053
2054 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
2055 {
2056 Paste();
2057 }
2058
2059 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
2060 {
2061 Undo();
2062 }
2063
2064 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
2065 {
2066 Redo();
2067 }
2068
2069 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
2070 {
2071 event.Enable( CanCut() );
2072 }
2073
2074 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
2075 {
2076 event.Enable( CanCopy() );
2077 }
2078
2079 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
2080 {
2081 event.Enable( CanPaste() );
2082 }
2083
2084 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
2085 {
2086 event.Enable( CanUndo() );
2087 }
2088
2089 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
2090 {
2091 event.Enable( CanRedo() );
2092 }
2093
2094 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
2095 {
2096 return true ;
2097 }
2098
2099 // user pane implementation
2100
2101 void wxTextCtrl::MacControlUserPaneDrawProc(wxInt16 part)
2102 {
2103 }
2104
2105 wxInt16 wxTextCtrl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
2106 {
2107 return kControlNoPart ;
2108 }
2109
2110 wxInt16 wxTextCtrl::MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc)
2111 {
2112 return kControlNoPart ;
2113 }
2114
2115 void wxTextCtrl::MacControlUserPaneIdleProc()
2116 {
2117 }
2118
2119 wxInt16 wxTextCtrl::MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
2120 {
2121 return kControlNoPart ;
2122 }
2123
2124 void wxTextCtrl::MacControlUserPaneActivateProc(bool activating)
2125 {
2126 }
2127
2128 wxInt16 wxTextCtrl::MacControlUserPaneFocusProc(wxInt16 action)
2129 {
2130 return kControlNoPart ;
2131 }
2132
2133 void wxTextCtrl::MacControlUserPaneBackgroundProc(void* info)
2134 {
2135 }
2136
2137 #endif
2138 // wxUSE_TEXTCTRL