]> git.saurik.com Git - wxWidgets.git/blame - src/motif/textctrl.cpp
(very) preliminary DnD docs
[wxWidgets.git] / src / motif / textctrl.cpp
CommitLineData
4bb6408c
JS
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
02e8b2f9
JS
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
40static void
41wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr);
42static void
43wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs);
44static void
45wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
46static void
47wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
dfc54541
JS
48static void wxTextWindowActivateProc(Widget w, XtPointer clientData,
49 XmAnyCallbackStruct *ptr);
02e8b2f9 50
4bb6408c
JS
51#if !USE_SHARED_LIBRARY
52IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
53
54BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
55 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
02e8b2f9 56 EVT_CHAR(wxTextCtrl::OnChar)
4bb6408c
JS
57END_EVENT_TABLE()
58#endif
59
60// Text item
61wxTextCtrl::wxTextCtrl()
62#ifndef NO_TEXT_WINDOW_STREAM
63 :streambuf()
64#endif
65{
66 m_fileName = "";
02e8b2f9
JS
67 m_tempCallbackStruct = (void*) NULL;
68 m_modified = FALSE;
dfc54541 69 m_processedDefault = FALSE;
4bb6408c
JS
70}
71
72bool 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{
02e8b2f9
JS
79 m_tempCallbackStruct = (void*) NULL;
80 m_modified = FALSE;
dfc54541 81 m_processedDefault = FALSE;
4bb6408c 82 m_fileName = "";
0d57be45
JS
83 m_backgroundColour = parent->GetBackgroundColour();
84 m_foregroundColour = parent->GetForegroundColour();
02e8b2f9 85
4bb6408c
JS
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
02e8b2f9
JS
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
dfc54541 140 XtAddCallback((Widget) m_mainWidget, XmNactivateCallback, (XtCallbackProc)wxTextWindowActivateProc, (XtPointer)this);
02e8b2f9
JS
141
142 XtAddCallback((Widget) m_mainWidget, XmNfocusCallback, (XtCallbackProc)wxTextWindowGainFocusProc, (XtPointer)this);
143
144 XtAddCallback((Widget) m_mainWidget, XmNlosingFocusCallback, (XtCallbackProc)wxTextWindowLoseFocusProc, (XtPointer)this);
145
4b5f3fe6
JS
146 m_windowFont = parent->GetFont();
147 ChangeFont(FALSE);
148
02e8b2f9
JS
149 SetCanAddEventHandler(TRUE);
150 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y);
151
0d57be45 152 ChangeBackgroundColour();
02e8b2f9 153
4bb6408c
JS
154 return TRUE;
155}
156
02e8b2f9 157WXWidget wxTextCtrl::GetTopWidget() const
4bb6408c 158{
dfc54541 159 return ((m_windowStyle & wxTE_MULTILINE) ? (WXWidget) XtParent((Widget) m_mainWidget) : m_mainWidget);
4bb6408c
JS
160}
161
02e8b2f9 162wxString wxTextCtrl::GetValue() const
4bb6408c 163{
dfc54541
JS
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 }
4bb6408c
JS
180}
181
02e8b2f9 182void wxTextCtrl::SetValue(const wxString& value)
4bb6408c 183{
8aa04e8b
JS
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." ) ;
dfc54541
JS
187 m_inSetValue = TRUE;
188
189 XmTextSetString ((Widget) m_mainWidget, (char*) (const char*) value);
190
191 m_inSetValue = FALSE;
4bb6408c
JS
192}
193
194// Clipboard operations
195void wxTextCtrl::Copy()
196{
dfc54541 197 XmTextCopy((Widget) m_mainWidget, CurrentTime);
4bb6408c
JS
198}
199
200void wxTextCtrl::Cut()
201{
dfc54541 202 XmTextCut((Widget) m_mainWidget, CurrentTime);
4bb6408c
JS
203}
204
205void wxTextCtrl::Paste()
206{
dfc54541 207 XmTextPaste((Widget) m_mainWidget);
4bb6408c
JS
208}
209
210void wxTextCtrl::SetEditable(bool editable)
211{
dfc54541 212 XmTextSetEditable((Widget) m_mainWidget, (Boolean) editable);
4bb6408c
JS
213}
214
215void wxTextCtrl::SetInsertionPoint(long pos)
216{
dfc54541 217 XmTextSetInsertionPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
4bb6408c
JS
218}
219
220void wxTextCtrl::SetInsertionPointEnd()
221{
222 long pos = GetLastPosition();
223 SetInsertionPoint(pos);
224}
225
226long wxTextCtrl::GetInsertionPoint() const
227{
dfc54541 228 return (long) XmTextGetInsertionPosition ((Widget) m_mainWidget);
4bb6408c
JS
229}
230
231long wxTextCtrl::GetLastPosition() const
232{
dfc54541 233 return (long) XmTextGetLastPosition ((Widget) m_mainWidget);
4bb6408c
JS
234}
235
236void wxTextCtrl::Replace(long from, long to, const wxString& value)
237{
dfc54541
JS
238 XmTextReplace ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
239 (char*) (const char*) value);
4bb6408c
JS
240}
241
242void wxTextCtrl::Remove(long from, long to)
243{
dfc54541
JS
244 XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
245 (Time) 0);
246 XmTextRemove ((Widget) m_mainWidget);
4bb6408c
JS
247}
248
249void wxTextCtrl::SetSelection(long from, long to)
250{
dfc54541
JS
251 XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
252 (Time) 0);
4bb6408c
JS
253}
254
255bool wxTextCtrl::LoadFile(const wxString& file)
256{
257 if (!wxFileExists(file))
258 return FALSE;
259
260 m_fileName = file;
261
262 Clear();
263
1a3ac83f
JS
264 Widget textWidget = (Widget) m_mainWidget;
265 FILE *fp;
4bb6408c 266
1a3ac83f
JS
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")))
4bb6408c 270 {
1a3ac83f
JS
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;
4bb6408c 293 }
4bb6408c
JS
294}
295
296// If file is null, try saved file name first
297// Returns TRUE if succeeds.
298bool 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
1a3ac83f
JS
307 Widget textWidget = (Widget) m_mainWidget;
308 FILE *fp;
4bb6408c 309
1a3ac83f
JS
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);
4bb6408c 318
1a3ac83f
JS
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 }
4bb6408c
JS
332}
333
334void wxTextCtrl::WriteText(const wxString& text)
335{
dfc54541
JS
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;
4bb6408c
JS
342}
343
344void wxTextCtrl::Clear()
345{
02e8b2f9 346 XmTextSetString ((Widget) m_mainWidget, "");
02e8b2f9 347 m_modified = FALSE;
4bb6408c
JS
348}
349
350bool wxTextCtrl::IsModified() const
351{
02e8b2f9 352 return m_modified;
4bb6408c
JS
353}
354
355// Makes 'unmodified'
356void wxTextCtrl::DiscardEdits()
357{
dfc54541
JS
358 XmTextSetString ((Widget) m_mainWidget, "");
359 m_modified = FALSE;
4bb6408c
JS
360}
361
362int wxTextCtrl::GetNumberOfLines() const
363{
dfc54541
JS
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 }
4bb6408c
JS
390 return 0;
391}
392
393long wxTextCtrl::XYToPosition(long x, long y) const
394{
dfc54541
JS
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;
4bb6408c
JS
405}
406
407void wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
408{
dfc54541
JS
409 Position xx, yy;
410 XmTextPosToXY((Widget) m_mainWidget, pos, &xx, &yy);
411 *x = xx; *y = yy;
4bb6408c
JS
412}
413
414void wxTextCtrl::ShowPosition(long pos)
415{
dfc54541 416 XmTextShowPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
4bb6408c
JS
417}
418
419int wxTextCtrl::GetLineLength(long lineNo) const
420{
dfc54541
JS
421 wxString str = GetLineText (lineNo);
422 return (int) str.Length();
4bb6408c
JS
423}
424
425wxString wxTextCtrl::GetLineText(long lineNo) const
426{
dfc54541
JS
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;
4bb6408c
JS
448}
449
450/*
451 * Text item
452 */
453
454void wxTextCtrl::Command(wxCommandEvent & event)
455{
456 SetValue (event.GetString());
457 ProcessCommand (event);
458}
459
460void 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
479int 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 {
a367b9b3 491 wxError("wxTextCtrl::overflow: Who's trespassing my get area?","Internal error");
4bb6408c
JS
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//=========================================================================
543int 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//=========================================================================
570int wxTextCtrl::underflow()
571{
572 return EOF;
573}
574#endif
575
576wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
577{
578 WriteText(s);
579 return *this;
580}
581
582wxTextCtrl& wxTextCtrl::operator<<(float f)
583{
584 wxString str;
585 str.Printf("%.2f", f);
586 WriteText(str);
587 return *this;
588}
589
590wxTextCtrl& wxTextCtrl::operator<<(double d)
591{
592 wxString str;
593 str.Printf("%.2f", d);
594 WriteText(str);
595 return *this;
596}
597
598wxTextCtrl& wxTextCtrl::operator<<(int i)
599{
600 wxString str;
601 str.Printf("%d", i);
602 WriteText(str);
603 return *this;
604}
605
606wxTextCtrl& wxTextCtrl::operator<<(long i)
607{
608 wxString str;
609 str.Printf("%ld", i);
610 WriteText(str);
611 return *this;
612}
613
614wxTextCtrl& 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
02e8b2f9
JS
624void wxTextCtrl::OnChar(wxKeyEvent& event)
625{
dfc54541
JS
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
02e8b2f9
JS
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
4b5f3fe6 643void wxTextCtrl::ChangeFont(bool keepOriginalSize)
0d57be45 644{
4b5f3fe6 645 wxWindow::ChangeFont(keepOriginalSize);
0d57be45
JS
646}
647
648void wxTextCtrl::ChangeBackgroundColour()
649{
321db4b6 650 wxWindow::ChangeBackgroundColour();
02800301
JS
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);
0d57be45
JS
669}
670
671void wxTextCtrl::ChangeForegroundColour()
672{
321db4b6 673 wxWindow::ChangeForegroundColour();
02800301
JS
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);
0d57be45
JS
692}
693
dfc54541 694static void wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr)
02e8b2f9
JS
695{
696 if (!wxGetWindowFromTable(w))
697 // Widget has been deleted!
698 return;
699
700 wxTextCtrl *tw = (wxTextCtrl *) clientData;
701 tw->SetModified(TRUE);
702}
703
704static void
705wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs)
706{
dfc54541
JS
707 wxTextCtrl *tw = (wxTextCtrl *) clientData;
708 tw->m_processedDefault = FALSE;
02e8b2f9 709
dfc54541
JS
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
a4294b78 793 if (tw->InSetValue())
dfc54541
JS
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;
02e8b2f9 815
02e8b2f9
JS
816 tw->m_tempCallbackStruct = (void*) cbs;
817
818 wxKeyEvent event (wxEVT_CHAR);
819 event.SetId(tw->GetId());
02e8b2f9 820 event.SetEventObject(tw);
dfc54541 821 event.m_keyCode = (cbs->text->ptr[0] == 10 ? 13 : cbs->text->ptr[0]);
02e8b2f9
JS
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
a4294b78 832 if (tw->InSetValue())
dfc54541
JS
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 }
02e8b2f9
JS
842}
843
844static void
845wxTextWindowGainFocusProc (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
856static void
857wxTextWindowLoseFocusProc (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}
dfc54541
JS
867
868static 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
a4294b78 885 if (tw->InSetValue())
dfc54541
JS
886 return;
887
888 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER);
889 event.SetId(tw->GetId());
890 event.SetEventObject(tw);
891 tw->ProcessCommand(event);
892}