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