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