Accelerators implemented for wxMotif; some wxComboBox stupidities cured
[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 #ifdef __GNUG__
13 #pragma implementation "textctrl.h"
14 #endif
15
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fstream.h>
19
20 #include "wx/textctrl.h"
21 #include "wx/settings.h"
22 #include "wx/filefn.h"
23 #include "wx/utils.h"
24
25 #if defined(__BORLANDC__) && !defined(__WIN32__)
26 #include <alloc.h>
27 #else
28 #ifndef __GNUWIN32__
29 #include <malloc.h>
30 #endif
31 #endif
32
33 #include <Xm/Text.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <ctype.h>
37
38 #include "wx/motif/private.h"
39
40 static void
41 wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr);
42 static void
43 wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs);
44 static void
45 wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
46 static void
47 wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
48 static void wxTextWindowActivateProc(Widget w, XtPointer clientData,
49 XmAnyCallbackStruct *ptr);
50
51 #if !USE_SHARED_LIBRARY
52 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
53
54 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
55 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
56 EVT_CHAR(wxTextCtrl::OnChar)
57 END_EVENT_TABLE()
58 #endif
59
60 // Text item
61 wxTextCtrl::wxTextCtrl()
62 #ifndef NO_TEXT_WINDOW_STREAM
63 :streambuf()
64 #endif
65 {
66 m_fileName = "";
67 m_tempCallbackStruct = (void*) NULL;
68 m_modified = FALSE;
69 m_processedDefault = FALSE;
70 }
71
72 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
73 const wxString& value,
74 const wxPoint& pos,
75 const wxSize& size, long style,
76 const wxValidator& validator,
77 const wxString& name)
78 {
79 m_tempCallbackStruct = (void*) NULL;
80 m_modified = FALSE;
81 m_processedDefault = FALSE;
82 m_fileName = "";
83 m_backgroundColour = parent->GetBackgroundColour();
84 m_foregroundColour = parent->GetForegroundColour();
85
86 SetName(name);
87 SetValidator(validator);
88 if (parent) parent->AddChild(this);
89
90 m_windowStyle = style;
91
92 if ( id == -1 )
93 m_windowId = (int)NewControlId();
94 else
95 m_windowId = id;
96
97 Widget parentWidget = (Widget) parent->GetClientWidget();
98
99 bool wantHorizScrolling = ((m_windowStyle & wxHSCROLL) != 0);
100
101 // If we don't have horizontal scrollbars, we want word wrap.
102 bool wantWordWrap = !wantHorizScrolling;
103
104 if (m_windowStyle & wxTE_MULTILINE)
105 {
106 Arg args[2];
107 XtSetArg (args[0], XmNscrollHorizontal, wantHorizScrolling ? True : False);
108 XtSetArg (args[1], XmNwordWrap, wantWordWrap ? True : False);
109
110 m_mainWidget = (WXWidget) XmCreateScrolledText (parentWidget, (char*) (const char*) name, args, 2);
111
112 XtVaSetValues ((Widget) m_mainWidget,
113 XmNeditable, ((style & wxTE_READONLY) ? False : True),
114 XmNeditMode, XmMULTI_LINE_EDIT,
115 NULL);
116 XtManageChild ((Widget) m_mainWidget);
117 }
118 else
119 {
120 m_mainWidget = (WXWidget) XtVaCreateManagedWidget ((char*) (const char*) name,
121 xmTextWidgetClass, parentWidget,
122 NULL);
123
124 // TODO: Is this relevant? What does it do?
125 int noCols = 2;
126 if (!value.IsNull() && (value.Length() > (unsigned int) noCols))
127 noCols = value.Length();
128 XtVaSetValues ((Widget) m_mainWidget,
129 XmNcolumns, noCols,
130 NULL);
131 }
132
133 if (!value.IsNull())
134 XmTextSetString ((Widget) m_mainWidget, (char*) (const char*) value);
135
136 XtAddCallback((Widget) m_mainWidget, XmNvalueChangedCallback, (XtCallbackProc)wxTextWindowChangedProc, (XtPointer)this);
137
138 XtAddCallback((Widget) m_mainWidget, XmNmodifyVerifyCallback, (XtCallbackProc)wxTextWindowModifyProc, (XtPointer)this);
139
140 XtAddCallback((Widget) m_mainWidget, XmNactivateCallback, (XtCallbackProc)wxTextWindowActivateProc, (XtPointer)this);
141
142 XtAddCallback((Widget) m_mainWidget, XmNfocusCallback, (XtCallbackProc)wxTextWindowGainFocusProc, (XtPointer)this);
143
144 XtAddCallback((Widget) m_mainWidget, XmNlosingFocusCallback, (XtCallbackProc)wxTextWindowLoseFocusProc, (XtPointer)this);
145
146 m_windowFont = parent->GetFont();
147 ChangeFont(FALSE);
148
149 SetCanAddEventHandler(TRUE);
150 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y);
151
152 ChangeBackgroundColour();
153
154 return TRUE;
155 }
156
157 WXWidget wxTextCtrl::GetTopWidget() const
158 {
159 return ((m_windowStyle & wxTE_MULTILINE) ? (WXWidget) XtParent((Widget) m_mainWidget) : m_mainWidget);
160 }
161
162 wxString wxTextCtrl::GetValue() const
163 {
164 if (m_windowStyle & wxTE_PASSWORD)
165 return m_value;
166 else
167 {
168 char *s = XmTextGetString ((Widget) m_mainWidget);
169 if (s)
170 {
171 wxString str(s);
172 XtFree (s);
173 return str;
174 }
175 else
176 {
177 return wxEmptyString;
178 }
179 }
180 }
181
182 void wxTextCtrl::SetValue(const wxString& value)
183 {
184 // This assert is wrong -- means that you can't set an empty
185 // string (IsNull == IsEmpty).
186 // wxASSERT_MSG( (!value.IsNull()), "Must not pass a null string to wxTextCtrl::SetValue." ) ;
187 m_inSetValue = TRUE;
188
189 XmTextSetString ((Widget) m_mainWidget, (char*) (const char*) value);
190
191 m_inSetValue = FALSE;
192 }
193
194 // Clipboard operations
195 void wxTextCtrl::Copy()
196 {
197 XmTextCopy((Widget) m_mainWidget, CurrentTime);
198 }
199
200 void wxTextCtrl::Cut()
201 {
202 XmTextCut((Widget) m_mainWidget, CurrentTime);
203 }
204
205 void wxTextCtrl::Paste()
206 {
207 XmTextPaste((Widget) m_mainWidget);
208 }
209
210 void wxTextCtrl::SetEditable(bool editable)
211 {
212 XmTextSetEditable((Widget) m_mainWidget, (Boolean) editable);
213 }
214
215 void wxTextCtrl::SetInsertionPoint(long pos)
216 {
217 XmTextSetInsertionPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
218 }
219
220 void wxTextCtrl::SetInsertionPointEnd()
221 {
222 long pos = GetLastPosition();
223 SetInsertionPoint(pos);
224 }
225
226 long wxTextCtrl::GetInsertionPoint() const
227 {
228 return (long) XmTextGetInsertionPosition ((Widget) m_mainWidget);
229 }
230
231 long wxTextCtrl::GetLastPosition() const
232 {
233 return (long) XmTextGetLastPosition ((Widget) m_mainWidget);
234 }
235
236 void wxTextCtrl::Replace(long from, long to, const wxString& value)
237 {
238 XmTextReplace ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
239 (char*) (const char*) value);
240 }
241
242 void wxTextCtrl::Remove(long from, long to)
243 {
244 XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
245 (Time) 0);
246 XmTextRemove ((Widget) m_mainWidget);
247 }
248
249 void wxTextCtrl::SetSelection(long from, long to)
250 {
251 XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
252 (Time) 0);
253 }
254
255 bool wxTextCtrl::LoadFile(const wxString& file)
256 {
257 if (!wxFileExists(file))
258 return FALSE;
259
260 m_fileName = file;
261
262 Clear();
263
264 Widget textWidget = (Widget) m_mainWidget;
265 FILE *fp;
266
267 struct stat statb;
268 if ((stat ((char*) (const char*) file, &statb) == -1) || (statb.st_mode & S_IFMT) != S_IFREG ||
269 !(fp = fopen ((char*) (const char*) file, "r")))
270 {
271 return FALSE;
272 }
273 else
274 {
275 long len = statb.st_size;
276 char *text;
277 if (!(text = XtMalloc ((unsigned) (len + 1))))
278 {
279 fclose (fp);
280 return FALSE;
281 }
282 if (fread (text, sizeof (char), len, fp) != (size_t) len)
283 {
284 }
285 fclose (fp);
286
287 text[len] = 0;
288 XmTextSetString (textWidget, text);
289 // m_textPosition = len;
290 XtFree (text);
291 m_modified = FALSE;
292 return TRUE;
293 }
294 }
295
296 // If file is null, try saved file name first
297 // Returns TRUE if succeeds.
298 bool wxTextCtrl::SaveFile(const wxString& file)
299 {
300 wxString theFile(file);
301 if (theFile == "")
302 theFile = m_fileName;
303 if (theFile == "")
304 return FALSE;
305 m_fileName = theFile;
306
307 Widget textWidget = (Widget) m_mainWidget;
308 FILE *fp;
309
310 if (!(fp = fopen ((char*) (const char*) theFile, "w")))
311 {
312 return FALSE;
313 }
314 else
315 {
316 char *text = XmTextGetString (textWidget);
317 long len = XmTextGetLastPosition (textWidget);
318
319 if (fwrite (text, sizeof (char), len, fp) != (size_t) len)
320 {
321 // Did not write whole file
322 }
323 // Make sure newline terminates the file
324 if (text[len - 1] != '\n')
325 fputc ('\n', fp);
326
327 fclose (fp);
328 XtFree (text);
329 m_modified = FALSE;
330 return TRUE;
331 }
332 }
333
334 void wxTextCtrl::WriteText(const wxString& text)
335 {
336 long textPosition = GetInsertionPoint() + strlen (text);
337 XmTextInsert ((Widget) m_mainWidget, GetInsertionPoint(), (char*) (const char*) text);
338 XtVaSetValues ((Widget) m_mainWidget, XmNcursorPosition, textPosition, NULL);
339 SetInsertionPoint(textPosition);
340 XmTextShowPosition ((Widget) m_mainWidget, textPosition);
341 m_modified = TRUE;
342 }
343
344 void wxTextCtrl::Clear()
345 {
346 XmTextSetString ((Widget) m_mainWidget, "");
347 m_modified = FALSE;
348 }
349
350 bool wxTextCtrl::IsModified() const
351 {
352 return m_modified;
353 }
354
355 // Makes 'unmodified'
356 void wxTextCtrl::DiscardEdits()
357 {
358 XmTextSetString ((Widget) m_mainWidget, "");
359 m_modified = FALSE;
360 }
361
362 int wxTextCtrl::GetNumberOfLines() const
363 {
364 // HIDEOUSLY inefficient, but we have no choice.
365 char *s = XmTextGetString ((Widget) m_mainWidget);
366 if (s)
367 {
368 long i = 0;
369 int currentLine = 0;
370 bool finished = FALSE;
371 while (!finished)
372 {
373 int ch = s[i];
374 if (ch == '\n')
375 {
376 currentLine++;
377 i++;
378 }
379 else if (ch == 0)
380 {
381 finished = TRUE;
382 }
383 else
384 i++;
385 }
386
387 XtFree (s);
388 return currentLine;
389 }
390 return 0;
391 }
392
393 long wxTextCtrl::XYToPosition(long x, long y) const
394 {
395 /* It seems, that there is a bug in some versions of the Motif library,
396 so the original wxWin-Code doesn't work. */
397 /*
398 Widget textWidget = (Widget) handle;
399 return (long) XmTextXYToPos (textWidget, (Position) x, (Position) y);
400 */
401 /* Now a little workaround: */
402 long r=0;
403 for (int i=0; i<y; i++) r+=(GetLineLength(i)+1);
404 return r+x;
405 }
406
407 void wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
408 {
409 Position xx, yy;
410 XmTextPosToXY((Widget) m_mainWidget, pos, &xx, &yy);
411 *x = xx; *y = yy;
412 }
413
414 void wxTextCtrl::ShowPosition(long pos)
415 {
416 XmTextShowPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
417 }
418
419 int wxTextCtrl::GetLineLength(long lineNo) const
420 {
421 wxString str = GetLineText (lineNo);
422 return (int) str.Length();
423 }
424
425 wxString wxTextCtrl::GetLineText(long lineNo) const
426 {
427 // HIDEOUSLY inefficient, but we have no choice.
428 char *s = XmTextGetString ((Widget) m_mainWidget);
429
430 if (s)
431 {
432 wxString buf("");
433 long i;
434 int currentLine = 0;
435 for (i = 0; currentLine != lineNo && s[i]; i++ )
436 if (s[i] == '\n')
437 currentLine++;
438 // Now get the text
439 int j;
440 for (j = 0; s[i] && s[i] != '\n'; i++, j++ )
441 buf += s[i];
442
443 XtFree(s);
444 return buf;
445 }
446 else
447 return wxEmptyString;
448 }
449
450 /*
451 * Text item
452 */
453
454 void wxTextCtrl::Command(wxCommandEvent & event)
455 {
456 SetValue (event.GetString());
457 ProcessCommand (event);
458 }
459
460 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
461 {
462 // By default, load the first file into the text window.
463 if (event.GetNumberOfFiles() > 0)
464 {
465 LoadFile(event.GetFiles()[0]);
466 }
467 }
468
469 // The streambuf code was partly taken from chapter 3 by Jerry Schwarz of
470 // AT&T's "C++ Lanuage System Release 3.0 Library Manual" - Stein Somers
471
472 //=========================================================================
473 // Called then the buffer is full (gcc 2.6.3)
474 // or when "endl" is output (Borland 4.5)
475 //=========================================================================
476 // Class declaration using multiple inheritance doesn't work properly for
477 // Borland. See note in wb_text.h.
478 #ifndef NO_TEXT_WINDOW_STREAM
479 int wxTextCtrl::overflow(int c)
480 {
481 // Make sure there is a holding area
482 if ( allocate()==EOF )
483 {
484 wxError("Streambuf allocation failed","Internal error");
485 return EOF;
486 }
487
488 // Verify that there are no characters in get area
489 if ( gptr() && gptr() < egptr() )
490 {
491 wxError("Who's trespassing my get area?","Internal error");
492 return EOF;
493 }
494
495 // Reset get area
496 setg(0,0,0);
497
498 // Make sure there is a put area
499 if ( ! pptr() )
500 {
501 /* This doesn't seem to be fatal so comment out error message */
502 // wxError("Put area not opened","Internal error");
503 setp( base(), base() );
504 }
505
506 // Determine how many characters have been inserted but no consumed
507 int plen = pptr() - pbase();
508
509 // Now Jerry relies on the fact that the buffer is at least 2 chars
510 // long, but the holding area "may be as small as 1" ???
511 // And we need an additional \0, so let's keep this inefficient but
512 // safe copy.
513
514 // If c!=EOF, it is a character that must also be comsumed
515 int xtra = c==EOF? 0 : 1;
516
517 // Write temporary C-string to wxTextWindow
518 {
519 char *txt = new char[plen+xtra+1];
520 memcpy(txt, pbase(), plen);
521 txt[plen] = (char)c; // append c
522 txt[plen+xtra] = '\0'; // append '\0' or overwrite c
523 // If the put area already contained \0, output will be truncated there
524 WriteText(txt);
525 delete[] txt;
526 }
527
528 // Reset put area
529 setp(pbase(), epptr());
530
531 #if defined(__WATCOMC__)
532 return __NOT_EOF;
533 #elif defined(zapeof) // HP-UX (all cfront based?)
534 return zapeof(c);
535 #else
536 return c!=EOF ? c : 0; // this should make everybody happy
537 #endif
538 }
539
540 //=========================================================================
541 // called then "endl" is output (gcc) or then explicit sync is done (Borland)
542 //=========================================================================
543 int wxTextCtrl::sync()
544 {
545 // Verify that there are no characters in get area
546 if ( gptr() && gptr() < egptr() )
547 {
548 wxError("Who's trespassing my get area?","Internal error");
549 return EOF;
550 }
551
552 if ( pptr() && pptr() > pbase() ) return overflow(EOF);
553
554 return 0;
555 /* OLD CODE
556 int len = pptr() - pbase();
557 char *txt = new char[len+1];
558 strncpy(txt, pbase(), len);
559 txt[len] = '\0';
560 (*this) << txt;
561 setp(pbase(), epptr());
562 delete[] txt;
563 return 0;
564 */
565 }
566
567 //=========================================================================
568 // Should not be called by a "ostream". Used by a "istream"
569 //=========================================================================
570 int wxTextCtrl::underflow()
571 {
572 return EOF;
573 }
574 #endif
575
576 wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
577 {
578 WriteText(s);
579 return *this;
580 }
581
582 wxTextCtrl& wxTextCtrl::operator<<(float f)
583 {
584 wxString str;
585 str.Printf("%.2f", f);
586 WriteText(str);
587 return *this;
588 }
589
590 wxTextCtrl& wxTextCtrl::operator<<(double d)
591 {
592 wxString str;
593 str.Printf("%.2f", d);
594 WriteText(str);
595 return *this;
596 }
597
598 wxTextCtrl& wxTextCtrl::operator<<(int i)
599 {
600 wxString str;
601 str.Printf("%d", i);
602 WriteText(str);
603 return *this;
604 }
605
606 wxTextCtrl& wxTextCtrl::operator<<(long i)
607 {
608 wxString str;
609 str.Printf("%ld", i);
610 WriteText(str);
611 return *this;
612 }
613
614 wxTextCtrl& wxTextCtrl::operator<<(const char c)
615 {
616 char buf[2];
617
618 buf[0] = c;
619 buf[1] = 0;
620 WriteText(buf);
621 return *this;
622 }
623
624 void wxTextCtrl::OnChar(wxKeyEvent& event)
625 {
626 // Indicates that we should generate a normal command, because
627 // we're letting default behaviour happen (otherwise it's vetoed
628 // by virtue of overriding OnChar)
629 m_processedDefault = TRUE;
630
631 if (m_tempCallbackStruct)
632 {
633 XmTextVerifyCallbackStruct *textStruct =
634 (XmTextVerifyCallbackStruct *) m_tempCallbackStruct;
635 textStruct->doit = True;
636 if (isascii(event.m_keyCode) && (textStruct->text->length == 1))
637 {
638 textStruct->text->ptr[0] = ((event.m_keyCode == WXK_RETURN) ? 10 : event.m_keyCode);
639 }
640 }
641 }
642
643 void wxTextCtrl::ChangeFont(bool keepOriginalSize)
644 {
645 wxWindow::ChangeFont(keepOriginalSize);
646 }
647
648 void wxTextCtrl::ChangeBackgroundColour()
649 {
650 wxWindow::ChangeBackgroundColour();
651
652 Widget parent = XtParent ((Widget) m_mainWidget);
653 Widget hsb, vsb;
654
655 XtVaGetValues (parent,
656 XmNhorizontalScrollBar, &hsb,
657 XmNverticalScrollBar, &vsb,
658 NULL);
659
660 /* TODO: should scrollbars be affected? Should probably have separate
661 * function to change them (by default, taken from wxSystemSettings)
662 if (hsb)
663 DoChangeBackgroundColour((WXWidget) hsb, m_backgroundColour, TRUE);
664 if (vsb)
665 DoChangeBackgroundColour((WXWidget) vsb, m_backgroundColour, TRUE);
666 */
667
668 DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, TRUE);
669 }
670
671 void wxTextCtrl::ChangeForegroundColour()
672 {
673 wxWindow::ChangeForegroundColour();
674
675
676 Widget parent = XtParent ((Widget) m_mainWidget);
677 Widget hsb, vsb;
678
679 XtVaGetValues (parent,
680 XmNhorizontalScrollBar, &hsb,
681 XmNverticalScrollBar, &vsb,
682 NULL);
683
684 /* TODO: should scrollbars be affected? Should probably have separate
685 * function to change them (by default, taken from wxSystemSettings)
686 if (hsb)
687 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
688 if (vsb)
689 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
690 */
691 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
692 }
693
694 static void wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr)
695 {
696 if (!wxGetWindowFromTable(w))
697 // Widget has been deleted!
698 return;
699
700 wxTextCtrl *tw = (wxTextCtrl *) clientData;
701 tw->SetModified(TRUE);
702 }
703
704 static void
705 wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs)
706 {
707 wxTextCtrl *tw = (wxTextCtrl *) clientData;
708 tw->m_processedDefault = FALSE;
709
710 // First, do some stuff if it's a password control.
711 // (What does this do exactly?)
712
713 if (tw->GetWindowStyleFlag() & wxTE_PASSWORD)
714 {
715 /* _sm_
716 * At least on my system (SunOS 4.1.3 + Motif 1.2), you need to think of
717 * every event as a replace event. cbs->text->ptr gives the replacement
718 * text, cbs->startPos gives the index of the first char affected by the
719 * replace, and cbs->endPos gives the index one more than the last char
720 * affected by the replace (startPos == endPos implies an empty range).
721 * Hence, a deletion is represented by replacing all input text with a
722 * blank string ("", *not* NULL!). A simple insertion that does not
723 * overwrite any text has startPos == endPos.
724 */
725
726 if (tw->m_value.IsNull())
727 {
728 tw->m_value = cbs->text->ptr;
729 }
730 else
731 {
732 char * passwd = (char*) (const char*) tw->m_value; // Set up a more convenient alias.
733
734 int len = passwd ? strlen(passwd) : 0; // Enough room for old text
735 len += strlen(cbs->text->ptr) + 1; // + new text (if any) + NUL
736 len -= cbs->endPos - cbs->startPos; // - text from affected region.
737
738 char * newS = new char [len];
739 char * p = passwd, * dest = newS, * insert = cbs->text->ptr;
740
741 // Copy (old) text from passwd, up to the start posn of the change.
742 int i;
743 for (i = 0; i < cbs->startPos; ++i)
744 *dest++ = *p++;
745
746 // Copy the text to be inserted).
747 while (*insert)
748 *dest++ = *insert++;
749
750 // Finally, copy into newS any remaining text from passwd[endPos] on.
751 for (p = passwd + cbs->endPos; *p; )
752 *dest++ = *p++;
753 *dest = 0;
754
755 tw->m_value = newS;
756
757 delete[] newS;
758 }
759
760 if (cbs->text->length>0)
761 {
762 int i;
763 for (i = 0; i < cbs->text->length; ++i)
764 cbs->text->ptr[i] = '*';
765 cbs->text->ptr[i] = 0;
766 }
767 }
768
769 // If we're already within an OnChar, return: probably
770 // a programmatic insertion.
771 if (tw->m_tempCallbackStruct)
772 return;
773
774 // Check for a backspace
775 if (cbs->startPos == (cbs->currInsert - 1))
776 {
777 tw->m_tempCallbackStruct = (void*) cbs;
778
779 wxKeyEvent event (wxEVT_CHAR);
780 event.SetId(tw->GetId());
781 event.m_keyCode = WXK_DELETE;
782 event.SetEventObject(tw);
783
784 // Only if wxTextCtrl::OnChar is called
785 // will this be set to True (and the character
786 // passed through)
787 cbs->doit = False;
788
789 tw->GetEventHandler()->ProcessEvent(event);
790
791 tw->m_tempCallbackStruct = NULL;
792
793 if (tw->InSetValue())
794 return;
795
796 if (tw->m_processedDefault)
797 {
798 // Can generate a command
799 wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, tw->GetId());
800 commandEvent.SetEventObject(tw);
801 tw->ProcessCommand(commandEvent);
802 }
803
804 return;
805 }
806
807 // Pasting operation: let it through without
808 // calling OnChar
809 if (cbs->text->length > 1)
810 return;
811
812 // Something other than text
813 if (cbs->text->ptr == NULL)
814 return;
815
816 tw->m_tempCallbackStruct = (void*) cbs;
817
818 wxKeyEvent event (wxEVT_CHAR);
819 event.SetId(tw->GetId());
820 event.SetEventObject(tw);
821 event.m_keyCode = (cbs->text->ptr[0] == 10 ? 13 : cbs->text->ptr[0]);
822
823 // Only if wxTextCtrl::OnChar is called
824 // will this be set to True (and the character
825 // passed through)
826 cbs->doit = False;
827
828 tw->GetEventHandler()->ProcessEvent(event);
829
830 tw->m_tempCallbackStruct = NULL;
831
832 if (tw->InSetValue())
833 return;
834
835 if (tw->m_processedDefault)
836 {
837 // Can generate a command
838 wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, tw->GetId());
839 commandEvent.SetEventObject(tw);
840 tw->ProcessCommand(commandEvent);
841 }
842 }
843
844 static void
845 wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs)
846 {
847 if (!wxGetWindowFromTable(w))
848 return;
849
850 wxTextCtrl *tw = (wxTextCtrl *) clientData;
851 wxFocusEvent event(wxEVT_SET_FOCUS, tw->GetId());
852 event.SetEventObject(tw);
853 tw->GetEventHandler()->ProcessEvent(event);
854 }
855
856 static void
857 wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs)
858 {
859 if (!wxGetWindowFromTable(w))
860 return;
861
862 wxTextCtrl *tw = (wxTextCtrl *) clientData;
863 wxFocusEvent event(wxEVT_KILL_FOCUS, tw->GetId());
864 event.SetEventObject(tw);
865 tw->GetEventHandler()->ProcessEvent(event);
866 }
867
868 static void wxTextWindowActivateProc(Widget w, XtPointer clientData,
869 XmAnyCallbackStruct *ptr)
870 {
871 if (!wxGetWindowFromTable(w))
872 return;
873
874 wxTextCtrl *tw = (wxTextCtrl *) clientData;
875 /*
876 case XmCR_ACTIVATE:
877 type_event = wxEVENT_TYPE_TEXT_ENTER_COMMAND ;
878 break;
879 default:
880 type_event = wxEVENT_TYPE_TEXT_COMMAND ;
881 break;
882 }
883 */
884
885 if (tw->InSetValue())
886 return;
887
888 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER);
889 event.SetId(tw->GetId());
890 event.SetEventObject(tw);
891 tw->ProcessCommand(event);
892 }