]> git.saurik.com Git - wxWidgets.git/blob - src/motif/textctrl.cpp
Split wxWakeUpPipe class in MT-unsafe and MT-safe parts.
[wxWidgets.git] / src / motif / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <ctype.h>
26
27 #include "wx/textctrl.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/utils.h"
31 #include "wx/settings.h"
32 #endif
33
34 #include "wx/filefn.h"
35
36 #ifdef __VMS__
37 #pragma message disable nosimpint
38 #endif
39 #include <Xm/Text.h>
40 #ifdef __VMS__
41 #pragma message enable nosimpint
42 #endif
43
44 #include "wx/motif/private.h"
45
46 // ----------------------------------------------------------------------------
47 // private functions
48 // ----------------------------------------------------------------------------
49
50 // helper: inserts the new text in the value of the text ctrl and returns the
51 // result in place
52 static void MergeChangesIntoString(wxString& value,
53 XmTextVerifyCallbackStruct *textStruct);
54
55 // callbacks
56 static void wxTextWindowChangedProc(Widget w, XtPointer clientData, XtPointer ptr);
57 static void wxTextWindowModifyProc(Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs);
58 static void wxTextWindowGainFocusProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
59 static void wxTextWindowLoseFocusProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
60 static void wxTextWindowActivateProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *ptr);
61
62 BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
63 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
64 EVT_CHAR(wxTextCtrl::OnChar)
65
66 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
67 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
68 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
69 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
70 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
71
72 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
73 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
74 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
75 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
76 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
77
78 END_EVENT_TABLE()
79
80 // ============================================================================
81 // implementation
82 // ============================================================================
83
84 // ----------------------------------------------------------------------------
85 // wxTextCtrl
86 // ----------------------------------------------------------------------------
87
88 // Text item
89 wxTextCtrl::wxTextCtrl()
90 {
91 m_tempCallbackStruct = NULL;
92 m_modified = false;
93 m_processedDefault = false;
94 }
95
96 bool wxTextCtrl::Create(wxWindow *parent,
97 wxWindowID id,
98 const wxString& value,
99 const wxPoint& pos,
100 const wxSize& size,
101 long style,
102 const wxValidator& validator,
103 const wxString& name)
104 {
105 if( !CreateControl( parent, id, pos, size, style, validator, name ) )
106 return false;
107 PreCreation();
108
109 m_tempCallbackStruct = NULL;
110 m_modified = false;
111 m_processedDefault = false;
112
113 Widget parentWidget = (Widget) parent->GetClientWidget();
114
115 Bool wantHorizScroll = (m_windowStyle & wxHSCROLL) != 0 ? True : False;
116 // If we don't have horizontal scrollbars, we want word wrap.
117 // OpenMotif 2.1 crashes if wantWordWrap is True in Japanese
118 // locale (and probably other multibyte locales). The check might be
119 // more precise
120 #if wxCHECK_LESSTIF() || wxCHECK_MOTIF_VERSION( 2, 2 )
121 Bool wantWordWrap = wantHorizScroll == True ? False : True;
122 #else
123 Bool wantWordWrap = False;
124 #endif
125
126 if (m_windowStyle & wxTE_MULTILINE)
127 {
128 Arg args[8];
129 int count = 0;
130 XtSetArg (args[count], XmNscrollHorizontal, wantHorizScroll); ++count;
131 if( m_font.IsOk() )
132 XtSetArg (args[count], (String) wxFont::GetFontTag(),
133 m_font.GetFontType( XtDisplay(parentWidget) ) ); ++count;
134 XtSetArg (args[count], XmNwordWrap, wantWordWrap); ++count;
135 XtSetArg (args[count], XmNvalue, (const char*)value.mb_str()); ++count;
136 XtSetArg (args[count], XmNeditable,
137 style & wxTE_READONLY ? False : True); ++count;
138 XtSetArg (args[count], XmNeditMode, XmMULTI_LINE_EDIT ); ++count;
139
140 m_mainWidget =
141 (WXWidget) XmCreateScrolledText(parentWidget,
142 name.char_str(),
143 args, count);
144
145 XtManageChild ((Widget) m_mainWidget);
146 }
147 else
148 {
149 m_mainWidget = (WXWidget)XtVaCreateManagedWidget
150 (
151 name.mb_str(),
152 xmTextWidgetClass,
153 parentWidget,
154 wxFont::GetFontTag(), m_font.GetFontType( XtDisplay(parentWidget) ),
155 XmNvalue, (const char*)value.mb_str(),
156 XmNeditable, (style & wxTE_READONLY) ?
157 False : True,
158 NULL
159 );
160
161 #if 0
162 // TODO: Is this relevant? What does it do?
163 int noCols = 2;
164 if (!value.empty() && (value.length() > (unsigned int) noCols))
165 noCols = value.length();
166 XtVaSetValues((Widget) m_mainWidget,
167 XmNcolumns, noCols,
168 NULL);
169 #endif
170 }
171
172 // remove border if asked for
173 if ( style & wxNO_BORDER )
174 {
175 XtVaSetValues((Widget)m_mainWidget,
176 XmNshadowThickness, 0,
177 NULL);
178 }
179
180 // install callbacks
181 XtAddCallback((Widget) m_mainWidget, XmNvalueChangedCallback, (XtCallbackProc)wxTextWindowChangedProc, (XtPointer)this);
182
183 XtAddCallback((Widget) m_mainWidget, XmNmodifyVerifyCallback, (XtCallbackProc)wxTextWindowModifyProc, (XtPointer)this);
184
185 XtAddCallback((Widget) m_mainWidget, XmNactivateCallback, (XtCallbackProc)wxTextWindowActivateProc, (XtPointer)this);
186
187 XtAddCallback((Widget) m_mainWidget, XmNfocusCallback, (XtCallbackProc)wxTextWindowGainFocusProc, (XtPointer)this);
188
189 XtAddCallback((Widget) m_mainWidget, XmNlosingFocusCallback, (XtCallbackProc)wxTextWindowLoseFocusProc, (XtPointer)this);
190
191 PostCreation();
192 AttachWidget (parent, m_mainWidget, (WXWidget) NULL,
193 pos.x, pos.y, size.x, size.y);
194
195 return true;
196 }
197
198 WXWidget wxTextCtrl::GetTopWidget() const
199 {
200 return IsMultiLine() ? (WXWidget)XtParent((Widget)m_mainWidget)
201 : m_mainWidget;
202 }
203
204 wxString wxTextCtrl::GetValue() const
205 {
206 wxString str; // result
207
208 if (m_windowStyle & wxTE_PASSWORD)
209 {
210 // the value is stored always in m_value because it can't be retrieved
211 // from the text control
212 str = m_value;
213 }
214 else
215 {
216 str = wxTextEntry::GetValue();
217
218 if ( m_tempCallbackStruct )
219 {
220 // the string in the control isn't yet updated, can't use it as is
221 MergeChangesIntoString(str, (XmTextVerifyCallbackStruct *)
222 m_tempCallbackStruct);
223 }
224 }
225
226 return str;
227 }
228
229 void wxTextCtrl::DoSetValue(const wxString& text, int flags)
230 {
231 m_inSetValue = true;
232
233 XmTextSetString ((Widget) m_mainWidget, text.char_str());
234 XtVaSetValues ((Widget) m_mainWidget,
235 XmNcursorPosition, text.length(),
236 NULL);
237
238 SetInsertionPoint(text.length());
239 XmTextShowPosition ((Widget) m_mainWidget, text.length());
240 m_modified = true;
241
242 m_inSetValue = false;
243
244 if ( flags & SetValue_SendEvent )
245 SendTextUpdatedEvent();
246 }
247
248 bool wxTextCtrl::IsModified() const
249 {
250 return m_modified;
251 }
252
253 // Makes modified or unmodified
254 void wxTextCtrl::MarkDirty()
255 {
256 m_modified = true;
257 }
258
259 void wxTextCtrl::DiscardEdits()
260 {
261 m_modified = false;
262 }
263
264 int wxTextCtrl::GetNumberOfLines() const
265 {
266 // HIDEOUSLY inefficient, but we have no choice.
267 char *s = XmTextGetString ((Widget) m_mainWidget);
268 if (s)
269 {
270 long i = 0;
271 int currentLine = 0;
272 bool finished = false;
273 while (!finished)
274 {
275 int ch = s[i];
276 if (ch == '\n')
277 {
278 currentLine++;
279 i++;
280 }
281 else if (ch == 0)
282 {
283 finished = true;
284 }
285 else
286 i++;
287 }
288
289 XtFree (s);
290 return currentLine;
291 }
292 return 0;
293 }
294
295 long wxTextCtrl::XYToPosition(long x, long y) const
296 {
297 /* It seems, that there is a bug in some versions of the Motif library,
298 so the original wxWin-Code doesn't work. */
299 /*
300 Widget textWidget = (Widget) handle;
301 return (long) XmTextXYToPos (textWidget, (Position) x, (Position) y);
302 */
303 /* Now a little workaround: */
304 long r=0;
305 for (int i=0; i<y; i++) r+=(GetLineLength(i)+1);
306 return r+x;
307 }
308
309 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
310 {
311 Position xx, yy;
312 XmTextPosToXY((Widget) m_mainWidget, pos, &xx, &yy);
313 if ( x )
314 *x = xx;
315 if ( y )
316 *y = yy;
317
318 return true;
319 }
320
321 void wxTextCtrl::ShowPosition(long pos)
322 {
323 XmTextShowPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
324 }
325
326 int wxTextCtrl::GetLineLength(long lineNo) const
327 {
328 wxString str = GetLineText (lineNo);
329 return (int) str.length();
330 }
331
332 wxString wxTextCtrl::GetLineText(long lineNo) const
333 {
334 // HIDEOUSLY inefficient, but we have no choice.
335 char *s = XmTextGetString ((Widget) m_mainWidget);
336
337 if (s)
338 {
339 wxString buf;
340 long i;
341 int currentLine = 0;
342 for (i = 0; currentLine != lineNo && s[i]; i++ )
343 if (s[i] == '\n')
344 currentLine++;
345 // Now get the text
346 int j;
347 for (j = 0; s[i] && s[i] != '\n'; i++, j++ )
348 buf += s[i];
349
350 XtFree(s);
351 return buf;
352 }
353 else
354 return wxEmptyString;
355 }
356
357 /*
358 * Text item
359 */
360
361 void wxTextCtrl::Command(wxCommandEvent & event)
362 {
363 SetValue (event.GetString());
364 ProcessCommand (event);
365 }
366
367 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
368 {
369 // By default, load the first file into the text window.
370 if (event.GetNumberOfFiles() > 0)
371 {
372 LoadFile(event.GetFiles()[0]);
373 }
374 }
375
376 void wxTextCtrl::OnChar(wxKeyEvent& event)
377 {
378 // Indicates that we should generate a normal command, because
379 // we're letting default behaviour happen (otherwise it's vetoed
380 // by virtue of overriding OnChar)
381 m_processedDefault = true;
382
383 if (m_tempCallbackStruct)
384 {
385 XmTextVerifyCallbackStruct *textStruct =
386 (XmTextVerifyCallbackStruct *) m_tempCallbackStruct;
387 textStruct->doit = True;
388 if (wxIsascii(event.m_keyCode) && (textStruct->text->length == 1))
389 {
390 textStruct->text->ptr[0] = (char)((event.m_keyCode == WXK_RETURN) ? 10 : event.m_keyCode);
391 }
392 }
393 }
394
395 void wxTextCtrl::ChangeFont(bool keepOriginalSize)
396 {
397 wxWindow::ChangeFont(keepOriginalSize);
398 }
399
400 void wxTextCtrl::ChangeBackgroundColour()
401 {
402 wxWindow::ChangeBackgroundColour();
403
404 /* TODO: should scrollbars be affected? Should probably have separate
405 * function to change them (by default, taken from wxSystemSettings)
406 */
407 if (m_windowStyle & wxTE_MULTILINE)
408 {
409 Widget parent = XtParent ((Widget) m_mainWidget);
410 Widget hsb, vsb;
411
412 XtVaGetValues (parent,
413 XmNhorizontalScrollBar, &hsb,
414 XmNverticalScrollBar, &vsb,
415 NULL);
416 wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
417 if (hsb)
418 wxDoChangeBackgroundColour((WXWidget) hsb, backgroundColour, true);
419 if (vsb)
420 wxDoChangeBackgroundColour((WXWidget) vsb, backgroundColour, true);
421
422 // MBN: why change parent background?
423 // DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, true);
424 }
425 }
426
427 void wxTextCtrl::ChangeForegroundColour()
428 {
429 wxWindow::ChangeForegroundColour();
430
431 if (m_windowStyle & wxTE_MULTILINE)
432 {
433 Widget parent = XtParent ((Widget) m_mainWidget);
434 Widget hsb, vsb;
435
436 XtVaGetValues (parent,
437 XmNhorizontalScrollBar, &hsb,
438 XmNverticalScrollBar, &vsb,
439 NULL);
440
441 /* TODO: should scrollbars be affected? Should probably have separate
442 * function to change them (by default, taken from wxSystemSettings)
443 if (hsb)
444 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
445 if (vsb)
446 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
447 */
448 wxDoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
449 }
450 }
451
452 void wxTextCtrl::DoSendEvents(void *wxcbs, long keycode)
453 {
454 // we're in process of updating the text control
455 m_tempCallbackStruct = wxcbs;
456
457 XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)wxcbs;
458
459 wxKeyEvent event (wxEVT_CHAR);
460 event.SetId(GetId());
461 event.m_keyCode = keycode;
462 event.SetEventObject(this);
463
464 // Only if wxTextCtrl::OnChar is called will this be set to True (and
465 // the character passed through)
466 cbs->doit = False;
467
468 HandleWindowEvent(event);
469
470 if ( !InSetValue() && m_processedDefault )
471 {
472 // Can generate a command
473 wxCommandEvent commandEvent(wxEVT_TEXT, GetId());
474 commandEvent.SetEventObject(this);
475 ProcessCommand(commandEvent);
476 }
477
478 // do it after the (user) event handlers processed the events because
479 // otherwise GetValue() would return incorrect (not yet updated value)
480 m_tempCallbackStruct = NULL;
481 }
482
483 wxSize wxDoGetSingleTextCtrlBestSize( Widget textWidget,
484 const wxWindow* window )
485 {
486 Dimension xmargin, ymargin, highlight, shadow;
487 char* value;
488
489 XtVaGetValues( textWidget,
490 XmNmarginWidth, &xmargin,
491 XmNmarginHeight, &ymargin,
492 XmNvalue, &value,
493 XmNhighlightThickness, &highlight,
494 XmNshadowThickness, &shadow,
495 NULL );
496
497 if( !value )
498 value = wxMOTIF_STR("|");
499
500 int x, y;
501 window->GetTextExtent( value, &x, &y );
502
503 if( x < 90 )
504 x = 90;
505
506 return wxSize( x + 2 * xmargin + 2 * highlight + 2 * shadow,
507 // MBN: +2 necessary: Lesstif bug or mine?
508 y + 2 * ymargin + 2 * highlight + 2 * shadow + 2 );
509 }
510
511 wxSize wxTextCtrl::DoGetBestSize() const
512 {
513 if( IsSingleLine() )
514 {
515 wxSize best = wxControl::DoGetBestSize();
516 #if wxCHECK_MOTIF_VERSION( 2, 3 )
517 // OpenMotif 2.3 gives way too big X sizes
518 wxSize other_best = wxDoGetSingleTextCtrlBestSize
519 ( (Widget) GetTopWidget(), this );
520 return wxSize( other_best.x, best.y );
521 #else
522 if( best.x < 90 ) best.x = 90;
523
524 return best;
525 #endif
526 }
527 else
528 return wxWindow::DoGetBestSize();
529 }
530
531 // ----------------------------------------------------------------------------
532 // helpers and Motif callbacks
533 // ----------------------------------------------------------------------------
534
535 static void MergeChangesIntoString(wxString& value,
536 XmTextVerifyCallbackStruct *cbs)
537 {
538 /* _sm_
539 * At least on my system (SunOS 4.1.3 + Motif 1.2), you need to think of
540 * every event as a replace event. cbs->text->ptr gives the replacement
541 * text, cbs->startPos gives the index of the first char affected by the
542 * replace, and cbs->endPos gives the index one more than the last char
543 * affected by the replace (startPos == endPos implies an empty range).
544 * Hence, a deletion is represented by replacing all input text with a
545 * blank string ("", *not* NULL!). A simple insertion that does not
546 * overwrite any text has startPos == endPos.
547 */
548
549 if ( !value )
550 {
551 // easy case: the ol value was empty
552 value = cbs->text->ptr;
553 }
554 else
555 {
556 // merge the changes into the value
557 const char * const passwd = value;
558 int len = value.length();
559
560 len += ( cbs->text->ptr ?
561 strlen(cbs->text->ptr) :
562 0 ) + 1; // + new text (if any) + NUL
563 len -= cbs->endPos - cbs->startPos; // - text from affected region.
564
565 char * newS = new char [len];
566 char * dest = newS,
567 * insert = cbs->text->ptr;
568
569 // Copy (old) text from passwd, up to the start posn of the change.
570 int i;
571 const char * p = passwd;
572 for (i = 0; i < cbs->startPos; ++i)
573 *dest++ = *p++;
574
575 // Copy the text to be inserted).
576 if (insert)
577 while (*insert)
578 *dest++ = *insert++;
579
580 // Finally, copy into newS any remaining text from passwd[endPos] on.
581 for (p = passwd + cbs->endPos; *p; )
582 *dest++ = *p++;
583 *dest = 0;
584
585 value = newS;
586
587 delete[] newS;
588 }
589 }
590
591 static void
592 wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
593 {
594 if (!wxGetWindowFromTable(w))
595 // Widget has been deleted!
596 return;
597
598 wxTextCtrl *tw = (wxTextCtrl *) clientData;
599 tw->SetModified(true);
600 }
601
602 static void
603 wxTextWindowModifyProc (Widget WXUNUSED(w), XtPointer clientData, XmTextVerifyCallbackStruct *cbs)
604 {
605 wxTextCtrl *tw = (wxTextCtrl *) clientData;
606 tw->m_processedDefault = false;
607
608 // First, do some stuff if it's a password control: in this case, we need
609 // to store the string inside the class because GetValue() can't retrieve
610 // it from the text ctrl. We do *not* do it in other circumstances because
611 // it would double the amount of memory needed.
612
613 if ( tw->GetWindowStyleFlag() & wxTE_PASSWORD )
614 {
615 MergeChangesIntoString(tw->m_value, cbs);
616
617 if ( cbs->text->length > 0 )
618 {
619 int i;
620 for (i = 0; i < cbs->text->length; ++i)
621 cbs->text->ptr[i] = '*';
622 cbs->text->ptr[i] = '\0';
623 }
624 }
625
626 if(tw->InSetValue())
627 return;
628
629 // If we're already within an OnChar, return: probably a programmatic
630 // insertion.
631 if (tw->m_tempCallbackStruct)
632 return;
633
634 // Check for a backspace
635 if (cbs->startPos == (cbs->currInsert - 1))
636 {
637 tw->DoSendEvents((void *)cbs, WXK_DELETE);
638
639 return;
640 }
641
642 // Pasting operation: let it through without calling OnChar
643 if (cbs->text->length > 1)
644 return;
645
646 // Something other than text
647 if (cbs->text->ptr == NULL)
648 return;
649
650 // normal key press
651 char ch = cbs->text->ptr[0];
652 tw->DoSendEvents((void *)cbs, ch == '\n' ? '\r' : ch);
653 }
654
655 static void
656 wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *WXUNUSED(cbs))
657 {
658 if (!wxGetWindowFromTable(w))
659 return;
660
661 wxTextCtrl *tw = (wxTextCtrl *) clientData;
662 wxFocusEvent event(wxEVT_SET_FOCUS, tw->GetId());
663 event.SetEventObject(tw);
664 tw->HandleWindowEvent(event);
665 }
666
667 static void
668 wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *WXUNUSED(cbs))
669 {
670 if (!wxGetWindowFromTable(w))
671 return;
672
673 wxTextCtrl *tw = (wxTextCtrl *) clientData;
674 wxFocusEvent event(wxEVT_KILL_FOCUS, tw->GetId());
675 event.SetEventObject(tw);
676 tw->HandleWindowEvent(event);
677 }
678
679 static void wxTextWindowActivateProc(Widget w, XtPointer clientData,
680 XmAnyCallbackStruct *WXUNUSED(ptr))
681 {
682 if (!wxGetWindowFromTable(w))
683 return;
684
685 wxTextCtrl *tw = (wxTextCtrl *) clientData;
686
687 if (tw->InSetValue())
688 return;
689
690 wxCommandEvent event(wxEVT_TEXT_ENTER);
691 event.SetId(tw->GetId());
692 event.SetEventObject(tw);
693 tw->ProcessCommand(event);
694 }
695
696 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
697 {
698 Cut();
699 }
700
701 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
702 {
703 Copy();
704 }
705
706 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
707 {
708 Paste();
709 }
710
711 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
712 {
713 Undo();
714 }
715
716 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
717 {
718 Redo();
719 }
720
721 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
722 {
723 event.Enable( CanCut() );
724 }
725
726 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
727 {
728 event.Enable( CanCopy() );
729 }
730
731 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
732 {
733 event.Enable( CanPaste() );
734 }
735
736 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
737 {
738 event.Enable( CanUndo() );
739 }
740
741 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
742 {
743 event.Enable( CanRedo() );
744 }