wxTextPos for all GetLastPosition with constants for special cases. Make it virtual...
[wxWidgets.git] / src / motif / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "textctrl.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __VMS
28 #define XtParent XTPARENT
29 #endif
30
31 #include "wx/defs.h"
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <ctype.h>
36
37 #include "wx/textctrl.h"
38 #include "wx/settings.h"
39 #include "wx/filefn.h"
40 #include "wx/utils.h"
41
42 #ifdef __VMS__
43 #pragma message disable nosimpint
44 #endif
45 #include <Xm/Text.h>
46 #ifdef __VMS__
47 #pragma message enable nosimpint
48 #endif
49
50 #include "wx/motif/private.h"
51
52 // ----------------------------------------------------------------------------
53 // private functions
54 // ----------------------------------------------------------------------------
55
56 // helper: inserts the new text in the value of the text ctrl and returns the
57 // result in place
58 static void MergeChangesIntoString(wxString& value,
59 XmTextVerifyCallbackStruct *textStruct);
60
61 // callbacks
62 static void wxTextWindowChangedProc(Widget w, XtPointer clientData, XtPointer ptr);
63 static void wxTextWindowModifyProc(Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs);
64 static void wxTextWindowGainFocusProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
65 static void wxTextWindowLoseFocusProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
66 static void wxTextWindowActivateProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *ptr);
67
68 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
69
70 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
71 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
72 EVT_CHAR(wxTextCtrl::OnChar)
73
74 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
75 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
76 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
77 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
78 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
79
80 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
81 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
82 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
83 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
84 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
85
86 END_EVENT_TABLE()
87
88 // ============================================================================
89 // implementation
90 // ============================================================================
91
92 // ----------------------------------------------------------------------------
93 // wxTextCtrl
94 // ----------------------------------------------------------------------------
95
96 // Text item
97 wxTextCtrl::wxTextCtrl()
98 {
99 m_tempCallbackStruct = (void*) NULL;
100 m_modified = false;
101 m_processedDefault = false;
102 }
103
104 bool wxTextCtrl::Create(wxWindow *parent,
105 wxWindowID id,
106 const wxString& value,
107 const wxPoint& pos,
108 const wxSize& size,
109 long style,
110 const wxValidator& validator,
111 const wxString& name)
112 {
113 if( !CreateControl( parent, id, pos, size, style, validator, name ) )
114 return false;
115
116 m_tempCallbackStruct = (void*) NULL;
117 m_modified = false;
118 m_processedDefault = false;
119
120 m_backgroundColour = *wxWHITE;
121
122 Widget parentWidget = (Widget) parent->GetClientWidget();
123
124 bool wantHorizScrolling = ((m_windowStyle & wxHSCROLL) != 0);
125
126 // If we don't have horizontal scrollbars, we want word wrap.
127 bool wantWordWrap = !wantHorizScrolling;
128
129 if (m_windowStyle & wxTE_MULTILINE)
130 {
131 Arg args[2];
132 XtSetArg (args[0], XmNscrollHorizontal, wantHorizScrolling ? True : False);
133 XtSetArg (args[1], XmNwordWrap, wantWordWrap ? True : False);
134
135 m_mainWidget = (WXWidget) XmCreateScrolledText(parentWidget,
136 wxConstCast(name.c_str(), char),
137 args, 2);
138
139 XtVaSetValues ((Widget) m_mainWidget,
140 XmNeditable, ((style & wxTE_READONLY) ? False : True),
141 XmNeditMode, XmMULTI_LINE_EDIT,
142 NULL);
143 XtManageChild ((Widget) m_mainWidget);
144 }
145 else
146 {
147 m_mainWidget = (WXWidget)XtVaCreateManagedWidget
148 (
149 wxConstCast(name.c_str(), char),
150 xmTextWidgetClass,
151 parentWidget,
152 NULL
153 );
154
155 XtVaSetValues ((Widget) m_mainWidget,
156 XmNeditable, ((style & wxTE_READONLY) ? False : True),
157 NULL);
158
159 // TODO: Is this relevant? What does it do?
160 int noCols = 2;
161 if (!value.IsNull() && (value.Length() > (unsigned int) noCols))
162 noCols = value.Length();
163 XtVaSetValues((Widget) m_mainWidget,
164 XmNcolumns, noCols,
165 NULL);
166 }
167
168 // remove border if asked for
169 if ( style & wxNO_BORDER )
170 {
171 XtVaSetValues((Widget)m_mainWidget,
172 XmNshadowThickness, 0,
173 NULL);
174 }
175
176 if ( !value.empty() )
177 {
178 // do this instead... MB
179 //
180 XtVaSetValues( (Widget) m_mainWidget,
181 XmNvalue, wxConstCast(value.c_str(), char),
182 NULL);
183 }
184
185 // install callbacks
186 XtAddCallback((Widget) m_mainWidget, XmNvalueChangedCallback, (XtCallbackProc)wxTextWindowChangedProc, (XtPointer)this);
187
188 XtAddCallback((Widget) m_mainWidget, XmNmodifyVerifyCallback, (XtCallbackProc)wxTextWindowModifyProc, (XtPointer)this);
189
190 XtAddCallback((Widget) m_mainWidget, XmNactivateCallback, (XtCallbackProc)wxTextWindowActivateProc, (XtPointer)this);
191
192 XtAddCallback((Widget) m_mainWidget, XmNfocusCallback, (XtCallbackProc)wxTextWindowGainFocusProc, (XtPointer)this);
193
194 XtAddCallback((Widget) m_mainWidget, XmNlosingFocusCallback, (XtCallbackProc)wxTextWindowLoseFocusProc, (XtPointer)this);
195
196 // font
197 ChangeFont(false);
198
199 wxSize best = GetBestSize();
200 if( size.x != -1 ) best.x = size.x;
201 if( size.y != -1 ) best.y = size.y;
202
203 AttachWidget (parent, m_mainWidget, (WXWidget) NULL,
204 pos.x, pos.y, best.x, best.y);
205
206 ChangeBackgroundColour();
207
208 return true;
209 }
210
211 WXWidget wxTextCtrl::GetTopWidget() const
212 {
213 return IsMultiLine() ? (WXWidget)XtParent((Widget)m_mainWidget)
214 : m_mainWidget;
215 }
216
217 wxString wxTextCtrl::GetValue() const
218 {
219 wxString str; // result
220
221 if (m_windowStyle & wxTE_PASSWORD)
222 {
223 // the value is stored always in m_value because it can't be retrieved
224 // from the text control
225 str = m_value;
226 }
227 else
228 {
229 // just get the string from Motif
230 char *s = XmTextGetString ((Widget) m_mainWidget);
231 if ( s )
232 {
233 str = s;
234 XtFree (s);
235 }
236 //else: return empty string
237
238 if ( m_tempCallbackStruct )
239 {
240 // the string in the control isn't yet updated, can't use it as is
241 MergeChangesIntoString(str, (XmTextVerifyCallbackStruct *)
242 m_tempCallbackStruct);
243 }
244 }
245
246 return str;
247 }
248
249 void wxTextCtrl::SetValue(const wxString& value)
250 {
251 m_inSetValue = true;
252
253 // do this instead... MB
254 //
255 // with (at least) OpenMotif 2.1 this causes a lot of flicker
256 #if 0
257 XtVaSetValues( (Widget) m_mainWidget,
258 XmNvalue, wxConstCast(value.c_str(), char),
259 NULL);
260 #endif
261
262 Clear();
263 AppendText( value );
264
265 m_inSetValue = false;
266 }
267
268 // Clipboard operations
269 void wxTextCtrl::Copy()
270 {
271 XmTextCopy((Widget) m_mainWidget, CurrentTime);
272 }
273
274 void wxTextCtrl::Cut()
275 {
276 XmTextCut((Widget) m_mainWidget, CurrentTime);
277 }
278
279 void wxTextCtrl::Paste()
280 {
281 XmTextPaste((Widget) m_mainWidget);
282 }
283
284 bool wxTextCtrl::CanCopy() const
285 {
286 // Can copy if there's a selection
287 long from, to;
288 GetSelection(& from, & to);
289 return (from != to) ;
290 }
291
292 bool wxTextCtrl::CanCut() const
293 {
294 // Can cut if there's a selection
295 long from, to;
296 GetSelection(& from, & to);
297 return (from != to) && (IsEditable());
298 }
299
300 bool wxTextCtrl::CanPaste() const
301 {
302 return IsEditable() ;
303 }
304
305 // Undo/redo
306 void wxTextCtrl::Undo()
307 {
308 // Not possible in Motif
309 }
310
311 void wxTextCtrl::Redo()
312 {
313 // Not possible in Motif
314 }
315
316 bool wxTextCtrl::CanUndo() const
317 {
318 // No Undo in Motif
319 return false;
320 }
321
322 bool wxTextCtrl::CanRedo() const
323 {
324 // No Redo in Motif
325 return false;
326 }
327
328 // If the return values from and to are the same, there is no
329 // selection.
330 void wxTextCtrl::GetSelection(long* from, long* to) const
331 {
332 XmTextPosition left, right;
333
334 XmTextGetSelectionPosition((Widget) m_mainWidget, & left, & right);
335
336 *from = (long) left;
337 *to = (long) right;
338 }
339
340 bool wxTextCtrl::IsEditable() const
341 {
342 return (XmTextGetEditable((Widget) m_mainWidget) != 0);
343 }
344
345 void wxTextCtrl::SetEditable(bool editable)
346 {
347 XmTextSetEditable((Widget) m_mainWidget, (Boolean) editable);
348 }
349
350 void wxTextCtrl::SetInsertionPoint(long pos)
351 {
352 XmTextSetInsertionPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
353 }
354
355 void wxTextCtrl::SetInsertionPointEnd()
356 {
357 wxTextPos pos = GetLastPosition();
358 SetInsertionPoint(pos);
359 }
360
361 long wxTextCtrl::GetInsertionPoint() const
362 {
363 return (long) XmTextGetInsertionPosition ((Widget) m_mainWidget);
364 }
365
366 wxTextPos wxTextCtrl::GetLastPosition() const
367 {
368 return (long) XmTextGetLastPosition ((Widget) m_mainWidget);
369 }
370
371 void wxTextCtrl::Replace(long from, long to, const wxString& value)
372 {
373 XmTextReplace ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
374 wxConstCast(value.c_str(), char));
375 }
376
377 void wxTextCtrl::Remove(long from, long to)
378 {
379 XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
380 (Time) 0);
381 XmTextRemove ((Widget) m_mainWidget);
382 }
383
384 void wxTextCtrl::SetSelection(long from, long to)
385 {
386 if( to == -1 )
387 to = GetLastPosition();
388
389 XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
390 (Time) 0);
391 }
392
393 void wxTextCtrl::WriteText(const wxString& text)
394 {
395 long textPosition = GetInsertionPoint() + strlen (text);
396 XmTextInsert ((Widget) m_mainWidget, GetInsertionPoint(),
397 wxConstCast(text.c_str(), char));
398 XtVaSetValues ((Widget) m_mainWidget, XmNcursorPosition, textPosition, NULL);
399 SetInsertionPoint(textPosition);
400 XmTextShowPosition ((Widget) m_mainWidget, textPosition);
401 m_modified = true;
402 }
403
404 void wxTextCtrl::AppendText(const wxString& text)
405 {
406 wxTextPos textPosition = GetLastPosition() + text.length();
407 XmTextInsert ((Widget) m_mainWidget, GetLastPosition(),
408 wxConstCast(text.c_str(), char));
409 XtVaSetValues ((Widget) m_mainWidget, XmNcursorPosition, textPosition, NULL);
410 SetInsertionPoint(textPosition);
411 XmTextShowPosition ((Widget) m_mainWidget, textPosition);
412 m_modified = true;
413 }
414
415 void wxTextCtrl::Clear()
416 {
417 XmTextSetString ((Widget) m_mainWidget, "");
418 m_modified = false;
419 }
420
421 bool wxTextCtrl::IsModified() const
422 {
423 return m_modified;
424 }
425
426 // Makes modified or unmodified
427 void wxTextCtrl::MarkDirty()
428 {
429 m_modified = true;
430 }
431
432 void wxTextCtrl::DiscardEdits()
433 {
434 m_modified = false;
435 }
436
437 int wxTextCtrl::GetNumberOfLines() const
438 {
439 // HIDEOUSLY inefficient, but we have no choice.
440 char *s = XmTextGetString ((Widget) m_mainWidget);
441 if (s)
442 {
443 long i = 0;
444 int currentLine = 0;
445 bool finished = false;
446 while (!finished)
447 {
448 int ch = s[i];
449 if (ch == '\n')
450 {
451 currentLine++;
452 i++;
453 }
454 else if (ch == 0)
455 {
456 finished = true;
457 }
458 else
459 i++;
460 }
461
462 XtFree (s);
463 return currentLine;
464 }
465 return 0;
466 }
467
468 long wxTextCtrl::XYToPosition(long x, long y) const
469 {
470 /* It seems, that there is a bug in some versions of the Motif library,
471 so the original wxWin-Code doesn't work. */
472 /*
473 Widget textWidget = (Widget) handle;
474 return (long) XmTextXYToPos (textWidget, (Position) x, (Position) y);
475 */
476 /* Now a little workaround: */
477 long r=0;
478 for (int i=0; i<y; i++) r+=(GetLineLength(i)+1);
479 return r+x;
480 }
481
482 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
483 {
484 Position xx, yy;
485 XmTextPosToXY((Widget) m_mainWidget, pos, &xx, &yy);
486 if ( x )
487 *x = xx;
488 if ( y )
489 *y = yy;
490
491 return true;
492 }
493
494 void wxTextCtrl::ShowPosition(long pos)
495 {
496 XmTextShowPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
497 }
498
499 int wxTextCtrl::GetLineLength(long lineNo) const
500 {
501 wxString str = GetLineText (lineNo);
502 return (int) str.Length();
503 }
504
505 wxString wxTextCtrl::GetLineText(long lineNo) const
506 {
507 // HIDEOUSLY inefficient, but we have no choice.
508 char *s = XmTextGetString ((Widget) m_mainWidget);
509
510 if (s)
511 {
512 wxString buf("");
513 long i;
514 int currentLine = 0;
515 for (i = 0; currentLine != lineNo && s[i]; i++ )
516 if (s[i] == '\n')
517 currentLine++;
518 // Now get the text
519 int j;
520 for (j = 0; s[i] && s[i] != '\n'; i++, j++ )
521 buf += s[i];
522
523 XtFree(s);
524 return buf;
525 }
526 else
527 return wxEmptyString;
528 }
529
530 /*
531 * Text item
532 */
533
534 void wxTextCtrl::Command(wxCommandEvent & event)
535 {
536 SetValue (event.GetString());
537 ProcessCommand (event);
538 }
539
540 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
541 {
542 // By default, load the first file into the text window.
543 if (event.GetNumberOfFiles() > 0)
544 {
545 LoadFile(event.GetFiles()[0]);
546 }
547 }
548
549 void wxTextCtrl::OnChar(wxKeyEvent& event)
550 {
551 // Indicates that we should generate a normal command, because
552 // we're letting default behaviour happen (otherwise it's vetoed
553 // by virtue of overriding OnChar)
554 m_processedDefault = true;
555
556 if (m_tempCallbackStruct)
557 {
558 XmTextVerifyCallbackStruct *textStruct =
559 (XmTextVerifyCallbackStruct *) m_tempCallbackStruct;
560 textStruct->doit = True;
561 if (isascii(event.m_keyCode) && (textStruct->text->length == 1))
562 {
563 textStruct->text->ptr[0] = ((event.m_keyCode == WXK_RETURN) ? 10 : event.m_keyCode);
564 }
565 }
566 }
567
568 void wxTextCtrl::ChangeFont(bool keepOriginalSize)
569 {
570 wxWindow::ChangeFont(keepOriginalSize);
571 }
572
573 void wxTextCtrl::ChangeBackgroundColour()
574 {
575 wxWindow::ChangeBackgroundColour();
576
577 /* TODO: should scrollbars be affected? Should probably have separate
578 * function to change them (by default, taken from wxSystemSettings)
579 */
580 if (m_windowStyle & wxTE_MULTILINE)
581 {
582 Widget parent = XtParent ((Widget) m_mainWidget);
583 Widget hsb, vsb;
584
585 XtVaGetValues (parent,
586 XmNhorizontalScrollBar, &hsb,
587 XmNverticalScrollBar, &vsb,
588 NULL);
589 wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
590 if (hsb)
591 wxDoChangeBackgroundColour((WXWidget) hsb, backgroundColour, true);
592 if (vsb)
593 wxDoChangeBackgroundColour((WXWidget) vsb, backgroundColour, true);
594
595 // MBN: why change parent background?
596 // DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, true);
597 }
598 }
599
600 void wxTextCtrl::ChangeForegroundColour()
601 {
602 wxWindow::ChangeForegroundColour();
603
604 if (m_windowStyle & wxTE_MULTILINE)
605 {
606 Widget parent = XtParent ((Widget) m_mainWidget);
607 Widget hsb, vsb;
608
609 XtVaGetValues (parent,
610 XmNhorizontalScrollBar, &hsb,
611 XmNverticalScrollBar, &vsb,
612 NULL);
613
614 /* TODO: should scrollbars be affected? Should probably have separate
615 * function to change them (by default, taken from wxSystemSettings)
616 if (hsb)
617 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
618 if (vsb)
619 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
620 */
621 wxDoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
622 }
623 }
624
625 void wxTextCtrl::DoSendEvents(void *wxcbs, long keycode)
626 {
627 // we're in process of updating the text control
628 m_tempCallbackStruct = wxcbs;
629
630 XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)wxcbs;
631
632 wxKeyEvent event (wxEVT_CHAR);
633 event.SetId(GetId());
634 event.m_keyCode = keycode;
635 event.SetEventObject(this);
636
637 // Only if wxTextCtrl::OnChar is called will this be set to True (and
638 // the character passed through)
639 cbs->doit = False;
640
641 GetEventHandler()->ProcessEvent(event);
642
643 if ( !InSetValue() && m_processedDefault )
644 {
645 // Can generate a command
646 wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, GetId());
647 commandEvent.SetEventObject(this);
648 ProcessCommand(commandEvent);
649 }
650
651 // do it after the (user) event handlers processed the events because
652 // otherwise GetValue() would return incorrect (not yet updated value)
653 m_tempCallbackStruct = NULL;
654 }
655
656 wxSize wxDoGetSingleTextCtrlBestSize( Widget textWidget,
657 const wxWindow* window )
658 {
659 Dimension xmargin, ymargin, highlight, shadow;
660 char* value;
661
662 XtVaGetValues( textWidget,
663 XmNmarginWidth, &xmargin,
664 XmNmarginHeight, &ymargin,
665 XmNvalue, &value,
666 XmNhighlightThickness, &highlight,
667 XmNshadowThickness, &shadow,
668 NULL );
669
670 if( !value )
671 value = "|";
672
673 int x, y;
674 window->GetTextExtent( value, &x, &y );
675
676 if( x < 100 ) x = 100;
677
678 return wxSize( x + 2 * xmargin + 2 * highlight + 2 * shadow,
679 // MBN: +2 necessary: Lesstif bug or mine?
680 y + 2 * ymargin + 2 * highlight + 2 * shadow + 2 );
681 }
682
683 wxSize wxTextCtrl::DoGetBestSize() const
684 {
685 if( IsSingleLine() )
686 return wxDoGetSingleTextCtrlBestSize( (Widget)m_mainWidget, this );
687 else
688 return wxWindow::DoGetBestSize();
689 }
690
691 // ----------------------------------------------------------------------------
692 // helpers and Motif callbacks
693 // ----------------------------------------------------------------------------
694
695 static void MergeChangesIntoString(wxString& value,
696 XmTextVerifyCallbackStruct *cbs)
697 {
698 /* _sm_
699 * At least on my system (SunOS 4.1.3 + Motif 1.2), you need to think of
700 * every event as a replace event. cbs->text->ptr gives the replacement
701 * text, cbs->startPos gives the index of the first char affected by the
702 * replace, and cbs->endPos gives the index one more than the last char
703 * affected by the replace (startPos == endPos implies an empty range).
704 * Hence, a deletion is represented by replacing all input text with a
705 * blank string ("", *not* NULL!). A simple insertion that does not
706 * overwrite any text has startPos == endPos.
707 */
708
709 if ( !value )
710 {
711 // easy case: the ol value was empty
712 value = cbs->text->ptr;
713 }
714 else
715 {
716 // merge the changes into the value
717 const char * const passwd = value;
718 int len = value.length();
719
720 len += ( cbs->text->ptr ?
721 strlen(cbs->text->ptr) :
722 0 ) + 1; // + new text (if any) + NUL
723 len -= cbs->endPos - cbs->startPos; // - text from affected region.
724
725 char * newS = new char [len];
726 char * dest = newS,
727 * insert = cbs->text->ptr;
728
729 // Copy (old) text from passwd, up to the start posn of the change.
730 int i;
731 const char * p = passwd;
732 for (i = 0; i < cbs->startPos; ++i)
733 *dest++ = *p++;
734
735 // Copy the text to be inserted).
736 if (insert)
737 while (*insert)
738 *dest++ = *insert++;
739
740 // Finally, copy into newS any remaining text from passwd[endPos] on.
741 for (p = passwd + cbs->endPos; *p; )
742 *dest++ = *p++;
743 *dest = 0;
744
745 value = newS;
746
747 delete[] newS;
748 }
749 }
750
751 static void
752 wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
753 {
754 if (!wxGetWindowFromTable(w))
755 // Widget has been deleted!
756 return;
757
758 wxTextCtrl *tw = (wxTextCtrl *) clientData;
759 tw->SetModified(true);
760 }
761
762 static void
763 wxTextWindowModifyProc (Widget WXUNUSED(w), XtPointer clientData, XmTextVerifyCallbackStruct *cbs)
764 {
765 wxTextCtrl *tw = (wxTextCtrl *) clientData;
766 tw->m_processedDefault = false;
767
768 // First, do some stuff if it's a password control: in this case, we need
769 // to store the string inside the class because GetValue() can't retrieve
770 // it from the text ctrl. We do *not* do it in other circumstances because
771 // it would double the amount of memory needed.
772
773 if ( tw->GetWindowStyleFlag() & wxTE_PASSWORD )
774 {
775 MergeChangesIntoString(tw->m_value, cbs);
776
777 if ( cbs->text->length > 0 )
778 {
779 int i;
780 for (i = 0; i < cbs->text->length; ++i)
781 cbs->text->ptr[i] = '*';
782 cbs->text->ptr[i] = '\0';
783 }
784 }
785
786 if(tw->InSetValue())
787 return;
788
789 // If we're already within an OnChar, return: probably a programmatic
790 // insertion.
791 if (tw->m_tempCallbackStruct)
792 return;
793
794 // Check for a backspace
795 if (cbs->startPos == (cbs->currInsert - 1))
796 {
797 tw->DoSendEvents((void *)cbs, WXK_DELETE);
798
799 return;
800 }
801
802 // Pasting operation: let it through without calling OnChar
803 if (cbs->text->length > 1)
804 return;
805
806 // Something other than text
807 if (cbs->text->ptr == NULL)
808 return;
809
810 // normal key press
811 char ch = cbs->text->ptr[0];
812 tw->DoSendEvents((void *)cbs, ch == '\n' ? '\r' : ch);
813 }
814
815 static void
816 wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *WXUNUSED(cbs))
817 {
818 if (!wxGetWindowFromTable(w))
819 return;
820
821 wxTextCtrl *tw = (wxTextCtrl *) clientData;
822 wxFocusEvent event(wxEVT_SET_FOCUS, tw->GetId());
823 event.SetEventObject(tw);
824 tw->GetEventHandler()->ProcessEvent(event);
825 }
826
827 static void
828 wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *WXUNUSED(cbs))
829 {
830 if (!wxGetWindowFromTable(w))
831 return;
832
833 wxTextCtrl *tw = (wxTextCtrl *) clientData;
834 wxFocusEvent event(wxEVT_KILL_FOCUS, tw->GetId());
835 event.SetEventObject(tw);
836 tw->GetEventHandler()->ProcessEvent(event);
837 }
838
839 static void wxTextWindowActivateProc(Widget w, XtPointer clientData,
840 XmAnyCallbackStruct *WXUNUSED(ptr))
841 {
842 if (!wxGetWindowFromTable(w))
843 return;
844
845 wxTextCtrl *tw = (wxTextCtrl *) clientData;
846
847 if (tw->InSetValue())
848 return;
849
850 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER);
851 event.SetId(tw->GetId());
852 event.SetEventObject(tw);
853 tw->ProcessCommand(event);
854 }
855
856 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
857 {
858 Cut();
859 }
860
861 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
862 {
863 Copy();
864 }
865
866 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
867 {
868 Paste();
869 }
870
871 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
872 {
873 Undo();
874 }
875
876 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
877 {
878 Redo();
879 }
880
881 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
882 {
883 event.Enable( CanCut() );
884 }
885
886 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
887 {
888 event.Enable( CanCopy() );
889 }
890
891 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
892 {
893 event.Enable( CanPaste() );
894 }
895
896 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
897 {
898 event.Enable( CanUndo() );
899 }
900
901 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
902 {
903 event.Enable( CanRedo() );
904 }