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