]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/textctrl.cpp
new control based view architecture
[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 SetBackgroundColour( *wxWHITE ) ;
774
775 TXNBackground tback;
776 tback.bgType = kTXNBackgroundTypeRGB;
777 tback.bg.color = MAC_WXCOLORREF( GetBackgroundColour().GetPixel() );
778 TXNSetBackground( (TXNObject) m_macTXN , &tback);
779
780 if ( m_windowStyle & wxTE_READONLY)
781 {
782 SetEditable( false ) ;
783 }
784
785 return TRUE;
786 }
787
788 void wxTextCtrl::MacVisibilityChanged()
789 {
790 MLTESetObjectVisibility((STPTextPaneVars*) m_macTXNvars , MacIsReallyShown() , GetWindowStyle() ) ;
791 if ( !MacIsReallyShown() )
792 InvalWindowRect( GetControlOwner( (ControlHandle) m_macControl ) , &((STPTextPaneVars *)m_macTXNvars)->fRBounds ) ;
793
794 }
795
796 void wxTextCtrl::MacEnabledStateChanged()
797 {
798 }
799
800
801 wxString wxTextCtrl::GetValue() const
802 {
803 Size actualSize = 0;
804 wxString result ;
805 OSStatus err ;
806
807 {
808 #if wxUSE_UNICODE
809 Handle theText ;
810 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNUnicodeTextData );
811 // all done
812 if ( err )
813 {
814 actualSize = 0 ;
815 }
816 else
817 {
818 actualSize = GetHandleSize( theText ) / sizeof( UniChar) ;
819 if ( actualSize > 0 )
820 {
821 wxChar *ptr = NULL ;
822 #if SIZEOF_WCHAR_T == 2
823 ptr = new wxChar[actualSize + 1 ] ;
824 wxStrncpy( ptr , (wxChar*) *theText , actualSize ) ;
825
826 #else
827 SetHandleSize( theText , ( actualSize + 1 ) * sizeof( UniChar ) ) ;
828 HLock( theText ) ;
829 (((UniChar*)*theText)[actualSize]) = 0 ;
830 wxMBConvUTF16BE converter ;
831 size_t noChars = converter.MB2WC( NULL , (const char*)*theText , 0 ) ;
832 ptr = new wxChar[noChars + 1] ;
833
834 noChars = converter.MB2WC( ptr , (const char*)*theText , noChars ) ;
835 ptr[noChars] = 0 ;
836 HUnlock( theText ) ;
837 #endif
838 ptr[actualSize] = 0 ;
839 result = wxString( ptr ) ;
840 delete[] ptr ;
841 }
842 DisposeHandle( theText ) ;
843 }
844 #else
845 Handle theText ;
846 err = TXNGetDataEncoded( ((TXNObject) m_macTXN), kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
847 // all done
848 if ( err )
849 {
850 actualSize = 0 ;
851 }
852 else
853 {
854 actualSize = GetHandleSize( theText ) ;
855 if ( actualSize > 0 )
856 {
857 HLock( theText ) ;
858 result = wxString( *theText , wxConvLocal , actualSize ) ;
859 HUnlock( theText ) ;
860 }
861 DisposeHandle( theText ) ;
862 }
863 #endif
864 }
865 wxMacConvertNewlines10To13( &result ) ;
866 return result ;
867 }
868
869 void wxTextCtrl::GetSelection(long* from, long* to) const
870 {
871 TXNGetSelection( (TXNObject) m_macTXN , (TXNOffset*) from , (TXNOffset*) to ) ;
872 }
873
874 void wxTextCtrl::SetValue(const wxString& str)
875 {
876 // optimize redraws
877 if ( GetValue() == str )
878 return ;
879
880 wxString st = str ;
881 wxMacConvertNewlines13To10( &st ) ;
882
883 {
884 wxMacWindowClipper c( this ) ;
885 bool formerEditable = m_editable ;
886 if ( !formerEditable )
887 SetEditable(true) ;
888
889 // otherwise scrolling might have problems ?
890 TPUpdateVisibility( ( (STPTextPaneVars *)m_macTXNvars)->fUserPaneRec ) ;
891 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , st , kTXNStartOffset, kTXNEndOffset ) ;
892 TXNSetSelection( (TXNObject) m_macTXN, 0, 0);
893 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
894 if ( !formerEditable )
895 SetEditable(formerEditable) ;
896 }
897 }
898
899 void wxTextCtrl::SetMaxLength(unsigned long len)
900 {
901 m_maxLength = len ;
902 }
903
904 bool wxTextCtrl::SetFont( const wxFont& font )
905 {
906 if ( !wxTextCtrlBase::SetFont( font ) )
907 return FALSE ;
908
909 wxMacWindowClipper c( this ) ;
910 bool formerEditable = m_editable ;
911 if ( !formerEditable )
912 SetEditable(true) ;
913
914 TXNTypeAttributes typeAttr[4] ;
915 Str255 fontName = "\pMonaco" ;
916 SInt16 fontSize = 12 ;
917 Style fontStyle = normal ;
918 int attrCounter = 0 ;
919
920 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
921 fontSize = font.MacGetFontSize() ;
922 fontStyle = font.MacGetFontStyle() ;
923
924 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
925 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
926 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
927 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
928 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
929 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
930 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
931 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
932 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
933 attrCounter += 3 ;
934 /*
935 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
936 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
937 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
938 color = MAC_WXCOLORREF(GetForegroundColour().GetPixel()) ;
939 attrCounter += 1 ;
940 */
941 verify_noerr( TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, kTXNStartOffset,kTXNEndOffset) );
942
943 if ( !formerEditable )
944 SetEditable(formerEditable) ;
945 return true ;
946 }
947
948 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
949 {
950 bool formerEditable = m_editable ;
951 if ( !formerEditable )
952 SetEditable(true) ;
953 TXNTypeAttributes typeAttr[4] ;
954 Str255 fontName = "\pMonaco" ;
955 SInt16 fontSize = 12 ;
956 Style fontStyle = normal ;
957 RGBColor color ;
958 int attrCounter = 0 ;
959 if ( style.HasFont() )
960 {
961 const wxFont &font = style.GetFont() ;
962 wxMacStringToPascal( font.GetFaceName() , fontName ) ;
963 fontSize = font.GetPointSize() ;
964 if ( font.GetUnderlined() )
965 fontStyle |= underline ;
966 if ( font.GetWeight() == wxBOLD )
967 fontStyle |= bold ;
968 if ( font.GetStyle() == wxITALIC )
969 fontStyle |= italic ;
970
971 typeAttr[attrCounter].tag = kTXNQDFontNameAttribute ;
972 typeAttr[attrCounter].size = kTXNQDFontNameAttributeSize ;
973 typeAttr[attrCounter].data.dataPtr = (void*) fontName ;
974 typeAttr[attrCounter+1].tag = kTXNQDFontSizeAttribute ;
975 typeAttr[attrCounter+1].size = kTXNFontSizeAttributeSize ;
976 typeAttr[attrCounter+1].data.dataValue = (fontSize << 16) ;
977 typeAttr[attrCounter+2].tag = kTXNQDFontStyleAttribute ;
978 typeAttr[attrCounter+2].size = kTXNQDFontStyleAttributeSize ;
979 typeAttr[attrCounter+2].data.dataValue = fontStyle ;
980 attrCounter += 3 ;
981
982 }
983 if ( style.HasTextColour() )
984 {
985 typeAttr[attrCounter].tag = kTXNQDFontColorAttribute ;
986 typeAttr[attrCounter].size = kTXNQDFontColorAttributeSize ;
987 typeAttr[attrCounter].data.dataPtr = (void*) &color ;
988 color = MAC_WXCOLORREF(style.GetTextColour().GetPixel()) ;
989 attrCounter += 1 ;
990 }
991
992 if ( attrCounter > 0 )
993 {
994 verify_noerr( TXNSetTypeAttributes ((TXNObject)m_macTXN, attrCounter , typeAttr, start,end) );
995 }
996 if ( !formerEditable )
997 SetEditable(formerEditable) ;
998
999 return TRUE ;
1000 }
1001
1002 bool wxTextCtrl::SetDefaultStyle(const wxTextAttr& style)
1003 {
1004 wxTextCtrlBase::SetDefaultStyle( style ) ;
1005 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1006 return TRUE ;
1007 }
1008
1009 // Clipboard operations
1010 void wxTextCtrl::Copy()
1011 {
1012 if (CanCopy())
1013 {
1014 ClearCurrentScrap();
1015 TXNCopy((TXNObject)m_macTXN);
1016 TXNConvertToPublicScrap();
1017 }
1018 }
1019
1020 void wxTextCtrl::Cut()
1021 {
1022 if (CanCut())
1023 {
1024 ClearCurrentScrap();
1025 TXNCut((TXNObject)m_macTXN);
1026 TXNConvertToPublicScrap();
1027
1028 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1029 event.SetString( GetValue() ) ;
1030 event.SetEventObject( this );
1031 GetEventHandler()->ProcessEvent(event);
1032 }
1033 }
1034
1035 void wxTextCtrl::Paste()
1036 {
1037 if (CanPaste())
1038 {
1039
1040 TXNConvertFromPublicScrap();
1041 TXNPaste((TXNObject)m_macTXN);
1042 SetStyle( kTXNUseCurrentSelection , kTXNUseCurrentSelection , GetDefaultStyle() ) ;
1043
1044 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1045 event.SetString( GetValue() ) ;
1046 event.SetEventObject( this );
1047 GetEventHandler()->ProcessEvent(event);
1048 }
1049 }
1050
1051 bool wxTextCtrl::CanCopy() const
1052 {
1053 // Can copy if there's a selection
1054 long from, to;
1055 GetSelection(& from, & to);
1056 return (from != to);
1057 }
1058
1059 bool wxTextCtrl::CanCut() const
1060 {
1061 if ( !IsEditable() )
1062 {
1063 return false ;
1064 }
1065 // Can cut if there's a selection
1066 long from, to;
1067 GetSelection(& from, & to);
1068 return (from != to);
1069 }
1070
1071 bool wxTextCtrl::CanPaste() const
1072 {
1073 if (!IsEditable())
1074 return FALSE;
1075
1076 return TXNIsScrapPastable() ;
1077 }
1078
1079 void wxTextCtrl::SetEditable(bool editable)
1080 {
1081 if ( editable != m_editable )
1082 {
1083 m_editable = editable ;
1084
1085 TXNControlTag tag[] = { kTXNIOPrivilegesTag } ;
1086 TXNControlData data[] = { { editable ? kTXNReadWrite : kTXNReadOnly } } ;
1087 TXNSetTXNObjectControls( (TXNObject) m_macTXN , false , sizeof(tag) / sizeof (TXNControlTag) , tag , data ) ;
1088
1089 }
1090 }
1091
1092 void wxTextCtrl::SetInsertionPoint(long pos)
1093 {
1094 SetSelection( pos , pos ) ;
1095 }
1096
1097 void wxTextCtrl::SetInsertionPointEnd()
1098 {
1099 long pos = GetLastPosition();
1100 SetInsertionPoint(pos);
1101 }
1102
1103 long wxTextCtrl::GetInsertionPoint() const
1104 {
1105 long begin,end ;
1106 GetSelection( &begin , &end ) ;
1107 return begin ;
1108 }
1109
1110 long wxTextCtrl::GetLastPosition() const
1111 {
1112 Handle theText ;
1113 long actualsize ;
1114 OSErr err = TXNGetDataEncoded( (TXNObject) m_macTXN, kTXNStartOffset, kTXNEndOffset, &theText , kTXNTextData );
1115 /* all done */
1116 if ( err )
1117 {
1118 actualsize = 0 ;
1119 }
1120 else
1121 {
1122 actualsize = GetHandleSize( theText ) ;
1123 DisposeHandle( theText ) ;
1124 }
1125 return actualsize ;
1126 }
1127
1128 void wxTextCtrl::Replace(long from, long to, const wxString& str)
1129 {
1130 wxString value = str ;
1131 wxMacConvertNewlines13To10( &value ) ;
1132
1133 bool formerEditable = m_editable ;
1134 if ( !formerEditable )
1135 SetEditable(true) ;
1136 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1137 TXNClear( ((TXNObject) m_macTXN) ) ;
1138 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , str , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1139 if ( !formerEditable )
1140 SetEditable( formerEditable ) ;
1141
1142 Refresh() ;
1143 }
1144
1145 void wxTextCtrl::Remove(long from, long to)
1146 {
1147 bool formerEditable = m_editable ;
1148 if ( !formerEditable )
1149 SetEditable(true) ;
1150 TXNSetSelection( ((TXNObject) m_macTXN) , from , to ) ;
1151 TXNClear( ((TXNObject) m_macTXN) ) ;
1152 if ( !formerEditable )
1153 SetEditable( formerEditable ) ;
1154
1155 Refresh() ;
1156 }
1157
1158 void wxTextCtrl::SetSelection(long from, long to)
1159 {
1160 STPTextPaneVars *varsp = (STPTextPaneVars *) m_macTXNvars;
1161 /* and our drawing environment as the operation
1162 may force a redraw in the text area. */
1163 SetPort(varsp->fDrawingEnvironment);
1164 /* change the selection */
1165 if ((from == -1) && (to == -1))
1166 TXNSelectAll((TXNObject) m_macTXN);
1167 else
1168 TXNSetSelection( varsp->fTXNRec, from, to);
1169 TXNShowSelection( (TXNObject) m_macTXN, kTXNShowStart);
1170 }
1171
1172 bool wxTextCtrl::LoadFile(const wxString& file)
1173 {
1174 if ( wxTextCtrlBase::LoadFile(file) )
1175 {
1176 return TRUE;
1177 }
1178
1179 return FALSE;
1180 }
1181
1182 void wxTextCtrl::WriteText(const wxString& str)
1183 {
1184 wxString st = str ;
1185 wxMacConvertNewlines13To10( &st ) ;
1186
1187 bool formerEditable = m_editable ;
1188 if ( !formerEditable )
1189 SetEditable(true) ;
1190 long start , end , dummy ;
1191 GetSelection( &start , &dummy ) ;
1192 SetTXNData( (STPTextPaneVars *)m_macTXNvars , (TXNObject) m_macTXN , st , kTXNUseCurrentSelection, kTXNUseCurrentSelection ) ;
1193 GetSelection( &dummy , &end ) ;
1194 SetStyle( start , end , GetDefaultStyle() ) ;
1195 if ( !formerEditable )
1196 SetEditable( formerEditable ) ;
1197
1198 MacRedrawControl() ;
1199 }
1200
1201 void wxTextCtrl::AppendText(const wxString& text)
1202 {
1203 SetInsertionPointEnd();
1204 WriteText(text);
1205 }
1206
1207 void wxTextCtrl::Clear()
1208 {
1209 bool formerEditable = m_editable ;
1210 if ( !formerEditable )
1211 SetEditable(true) ;
1212 TXNSetSelection( (TXNObject)m_macTXN , kTXNStartOffset , kTXNEndOffset ) ;
1213 TXNClear((TXNObject)m_macTXN);
1214
1215 if ( !formerEditable )
1216 SetEditable( formerEditable ) ;
1217
1218 Refresh() ;
1219 }
1220
1221 bool wxTextCtrl::IsModified() const
1222 {
1223 return m_dirty;
1224 }
1225
1226 bool wxTextCtrl::IsEditable() const
1227 {
1228 return IsEnabled() && m_editable ;
1229 }
1230
1231 bool wxTextCtrl::AcceptsFocus() const
1232 {
1233 // we don't want focus if we can't be edited
1234 return /*IsEditable() && */ wxControl::AcceptsFocus();
1235 }
1236
1237 wxSize wxTextCtrl::DoGetBestSize() const
1238 {
1239 int wText = 100 ;
1240
1241 int hText;
1242
1243 switch( m_windowVariant )
1244 {
1245 case wxWINDOW_VARIANT_NORMAL :
1246 hText = 22 ;
1247 break ;
1248 case wxWINDOW_VARIANT_SMALL :
1249 hText = 19 ;
1250 break ;
1251 case wxWINDOW_VARIANT_MINI :
1252 hText= 15 ;
1253 break ;
1254 default :
1255 hText = 22 ;
1256 break ;
1257 }
1258
1259 if ( m_windowStyle & wxTE_MULTILINE )
1260 {
1261 hText *= 5 ;
1262 }
1263
1264 return wxSize(wText, hText);
1265 }
1266
1267 // ----------------------------------------------------------------------------
1268 // Undo/redo
1269 // ----------------------------------------------------------------------------
1270
1271 void wxTextCtrl::Undo()
1272 {
1273 if (CanUndo())
1274 {
1275 TXNUndo((TXNObject)m_macTXN);
1276 }
1277 }
1278
1279 void wxTextCtrl::Redo()
1280 {
1281 if (CanRedo())
1282 {
1283 TXNRedo((TXNObject)m_macTXN);
1284 }
1285 }
1286
1287 bool wxTextCtrl::CanUndo() const
1288 {
1289 if ( !IsEditable() )
1290 {
1291 return false ;
1292 }
1293 return TXNCanUndo((TXNObject)m_macTXN,NULL);
1294 }
1295
1296 bool wxTextCtrl::CanRedo() const
1297 {
1298 if ( !IsEditable() )
1299 {
1300 return false ;
1301 }
1302 return TXNCanRedo((TXNObject)m_macTXN,NULL);
1303 }
1304
1305 // Makes modifie or unmodified
1306 void wxTextCtrl::MarkDirty()
1307 {
1308 m_dirty = true;
1309 }
1310
1311 void wxTextCtrl::DiscardEdits()
1312 {
1313 m_dirty = false;
1314 }
1315
1316 int wxTextCtrl::GetNumberOfLines() const
1317 {
1318 ItemCount lines ;
1319 TXNGetLineCount((TXNObject)m_macTXN, &lines ) ;
1320 return lines ;
1321 }
1322
1323 long wxTextCtrl::XYToPosition(long x, long y) const
1324 {
1325 // TODO
1326 return 0;
1327 }
1328
1329 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
1330 {
1331 return FALSE ;
1332 }
1333
1334 void wxTextCtrl::ShowPosition(long pos)
1335 {
1336 #if TARGET_RT_MAC_MACHO && defined(AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER)
1337 {
1338 Point current ;
1339 Point desired ;
1340 TXNOffset selstart , selend ;
1341 TXNGetSelection( (TXNObject) m_macTXN , &selstart , &selend) ;
1342 TXNOffsetToPoint( (TXNObject) m_macTXN, selstart , &current);
1343 TXNOffsetToPoint( (TXNObject) m_macTXN, pos , &desired);
1344 //TODO use HIPoints for 10.3 and above
1345 if ( (UInt32) TXNScroll != (UInt32) kUnresolvedCFragSymbolAddress )
1346 {
1347 OSErr theErr = noErr;
1348 SInt32 dv = desired.v - current.v ;
1349 SInt32 dh = desired.h - current.h ;
1350 TXNShowSelection( (TXNObject) m_macTXN , true ) ;
1351 theErr = TXNScroll( (TXNObject) m_macTXN, kTXNScrollUnitsInPixels , kTXNScrollUnitsInPixels , &dv , &dh );
1352 wxASSERT_MSG( theErr == noErr, _T("TXNScroll returned an error!") );
1353 }
1354 }
1355 #endif
1356 }
1357
1358 int wxTextCtrl::GetLineLength(long lineNo) const
1359 {
1360 // TODO change this if possible to reflect real lines
1361 wxString content = GetValue() ;
1362
1363 // Find line first
1364 int count = 0;
1365 for (size_t i = 0; i < content.Length() ; i++)
1366 {
1367 if (count == lineNo)
1368 {
1369 // Count chars in line then
1370 count = 0;
1371 for (size_t j = i; j < content.Length(); j++)
1372 {
1373 count++;
1374 if (content[j] == '\n') return count;
1375 }
1376
1377 return count;
1378 }
1379 if (content[i] == '\n') count++;
1380 }
1381 return 0;
1382 }
1383
1384 wxString wxTextCtrl::GetLineText(long lineNo) const
1385 {
1386 // TODO change this if possible to reflect real lines
1387 wxString content = GetValue() ;
1388
1389 // Find line first
1390 int count = 0;
1391 for (size_t i = 0; i < content.Length() ; i++)
1392 {
1393 if (count == lineNo)
1394 {
1395 // Add chars in line then
1396 wxString tmp;
1397
1398 for (size_t j = i; j < content.Length(); j++)
1399 {
1400 if (content[j] == '\n')
1401 return tmp;
1402
1403 tmp += content[j];
1404 }
1405
1406 return tmp;
1407 }
1408 if (content[i] == '\n') count++;
1409 }
1410 return wxEmptyString ;
1411 }
1412
1413 /*
1414 * Text item
1415 */
1416
1417 void wxTextCtrl::Command(wxCommandEvent & event)
1418 {
1419 SetValue (event.GetString());
1420 ProcessCommand (event);
1421 }
1422
1423 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
1424 {
1425 // By default, load the first file into the text window.
1426 if (event.GetNumberOfFiles() > 0)
1427 {
1428 LoadFile(event.GetFiles()[0]);
1429 }
1430 }
1431
1432 void wxTextCtrl::OnChar(wxKeyEvent& event)
1433 {
1434 int key = event.GetKeyCode() ;
1435 bool eat_key = false ;
1436
1437 if ( key == 'c' && event.MetaDown() )
1438 {
1439 if ( CanCopy() )
1440 Copy() ;
1441 return ;
1442 }
1443
1444 if ( !IsEditable() && key != WXK_LEFT && key != WXK_RIGHT && key != WXK_DOWN && key != WXK_UP && key != WXK_TAB &&
1445 !( key == WXK_RETURN && ( (m_windowStyle & wxPROCESS_ENTER) || (m_windowStyle & wxTE_MULTILINE) ) )
1446 /* && key != WXK_PRIOR && key != WXK_NEXT && key != WXK_HOME && key != WXK_END */
1447 )
1448 {
1449 // eat it
1450 return ;
1451 }
1452
1453 // assume that any key not processed yet is going to modify the control
1454 m_dirty = true;
1455
1456 if ( key == 'v' && event.MetaDown() )
1457 {
1458 if ( CanPaste() )
1459 Paste() ;
1460 return ;
1461 }
1462 if ( key == 'x' && event.MetaDown() )
1463 {
1464 if ( CanCut() )
1465 Cut() ;
1466 return ;
1467 }
1468 switch ( key )
1469 {
1470 case WXK_RETURN:
1471 if (m_windowStyle & wxPROCESS_ENTER)
1472 {
1473 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1474 event.SetEventObject( this );
1475 event.SetString( GetValue() );
1476 if ( GetEventHandler()->ProcessEvent(event) )
1477 return;
1478 }
1479 if ( !(m_windowStyle & wxTE_MULTILINE) )
1480 {
1481 wxWindow *parent = GetParent();
1482 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
1483 parent = parent->GetParent() ;
1484 }
1485 if ( parent && parent->GetDefaultItem() )
1486 {
1487 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
1488 wxButton);
1489 if ( def && def->IsEnabled() )
1490 {
1491 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
1492 event.SetEventObject(def);
1493 def->Command(event);
1494 return ;
1495 }
1496 }
1497
1498 // this will make wxWindows eat the ENTER key so that
1499 // we actually prevent line wrapping in a single line
1500 // text control
1501 eat_key = TRUE;
1502 }
1503
1504 break;
1505
1506 case WXK_TAB:
1507 // always produce navigation event - even if we process TAB
1508 // ourselves the fact that we got here means that the user code
1509 // decided to skip processing of this TAB - probably to let it
1510 // do its default job.
1511 {
1512 wxNavigationKeyEvent eventNav;
1513 eventNav.SetDirection(!event.ShiftDown());
1514 eventNav.SetWindowChange(event.ControlDown());
1515 eventNav.SetEventObject(this);
1516
1517 if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
1518 return;
1519
1520 event.Skip() ;
1521 return;
1522 }
1523 break;
1524 }
1525
1526 if (!eat_key)
1527 {
1528 // perform keystroke handling
1529 if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL )
1530 CallNextEventHandler((EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() , (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
1531 else
1532 {
1533 EventRecord rec ;
1534 if ( wxMacConvertEventToRecord( (EventRef) wxTheApp->MacGetCurrentEvent() , &rec ) )
1535 {
1536 EventRecord *ev = &rec ;
1537 short keycode ;
1538 short keychar ;
1539 keychar = short(ev->message & charCodeMask);
1540 keycode = short(ev->message & keyCodeMask) >> 8 ;
1541
1542 ::HandleControlKey( (ControlRef) m_macControl , keycode , keychar , ev->modifiers ) ;
1543 }
1544 }
1545 }
1546 if ( ( key >= 0x20 && key < WXK_START ) ||
1547 key == WXK_RETURN ||
1548 key == WXK_DELETE ||
1549 key == WXK_BACK)
1550 {
1551 wxCommandEvent event1(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
1552 event1.SetString( GetValue() ) ;
1553 event1.SetEventObject( this );
1554 wxPostEvent(GetEventHandler(),event1);
1555 }
1556 }
1557
1558 // ----------------------------------------------------------------------------
1559 // standard handlers for standard edit menu events
1560 // ----------------------------------------------------------------------------
1561
1562 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
1563 {
1564 Cut();
1565 }
1566
1567 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
1568 {
1569 Copy();
1570 }
1571
1572 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
1573 {
1574 Paste();
1575 }
1576
1577 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
1578 {
1579 Undo();
1580 }
1581
1582 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
1583 {
1584 Redo();
1585 }
1586
1587 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
1588 {
1589 event.Enable( CanCut() );
1590 }
1591
1592 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
1593 {
1594 event.Enable( CanCopy() );
1595 }
1596
1597 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
1598 {
1599 event.Enable( CanPaste() );
1600 }
1601
1602 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
1603 {
1604 event.Enable( CanUndo() );
1605 }
1606
1607 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
1608 {
1609 event.Enable( CanRedo() );
1610 }
1611
1612 bool wxTextCtrl::MacSetupCursor( const wxPoint& pt )
1613 {
1614 return true ;
1615 }
1616
1617 // user pane implementation
1618
1619 void wxTextCtrl::MacControlUserPaneDrawProc(wxInt16 part)
1620 {
1621 }
1622
1623 wxInt16 wxTextCtrl::MacControlUserPaneHitTestProc(wxInt16 x, wxInt16 y)
1624 {
1625 return kControlNoPart ;
1626 }
1627
1628 wxInt16 wxTextCtrl::MacControlUserPaneTrackingProc(wxInt16 x, wxInt16 y, void* actionProc)
1629 {
1630 return kControlNoPart ;
1631 }
1632
1633 void wxTextCtrl::MacControlUserPaneIdleProc()
1634 {
1635 }
1636
1637 wxInt16 wxTextCtrl::MacControlUserPaneKeyDownProc(wxInt16 keyCode, wxInt16 charCode, wxInt16 modifiers)
1638 {
1639 return kControlNoPart ;
1640 }
1641
1642 void wxTextCtrl::MacControlUserPaneActivateProc(bool activating)
1643 {
1644 }
1645
1646 wxInt16 wxTextCtrl::MacControlUserPaneFocusProc(wxInt16 action)
1647 {
1648 return kControlNoPart ;
1649 }
1650
1651 void wxTextCtrl::MacControlUserPaneBackgroundProc(void* info)
1652 {
1653 }
1654
1655 #endif
1656 // wxUSE_TEXTCTRL