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