]> git.saurik.com Git - wxWidgets.git/blame - src/motif/textctrl.cpp
AIX patches from Hans-Joachim Baader <hans-joachim.baader@cjt.de>
[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
66a007fb 9// Licence: wxWindows licence
4bb6408c
JS
10/////////////////////////////////////////////////////////////////////////////
11
66a007fb
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
4bb6408c 20#ifdef __GNUG__
66a007fb 21 #pragma implementation "textctrl.h"
4bb6408c
JS
22#endif
23
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fstream.h>
66a007fb 27#include <ctype.h>
4bb6408c
JS
28
29#include "wx/textctrl.h"
30#include "wx/settings.h"
31#include "wx/filefn.h"
32#include "wx/utils.h"
33
02e8b2f9 34#include <Xm/Text.h>
02e8b2f9
JS
35
36#include "wx/motif/private.h"
37
66a007fb
VZ
38// ----------------------------------------------------------------------------
39// private functions
40// ----------------------------------------------------------------------------
41
42// callbacks
43static void wxTextWindowChangedProc(Widget w, XtPointer clientData, XtPointer ptr);
44static void wxTextWindowModifyProc(Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs);
45static void wxTextWindowGainFocusProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
46static void wxTextWindowLoseFocusProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs);
47static void wxTextWindowActivateProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *ptr);
02e8b2f9 48
4bb6408c 49#if !USE_SHARED_LIBRARY
66a007fb 50 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
4bb6408c 51
66a007fb
VZ
52 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
53 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
54 EVT_CHAR(wxTextCtrl::OnChar)
55 END_EVENT_TABLE()
4bb6408c
JS
56#endif
57
66a007fb
VZ
58// ============================================================================
59// implementation
60// ============================================================================
61
62// ----------------------------------------------------------------------------
63// wxTextCtrl
64// ----------------------------------------------------------------------------
65
4bb6408c
JS
66// Text item
67wxTextCtrl::wxTextCtrl()
68#ifndef NO_TEXT_WINDOW_STREAM
66a007fb 69 : streambuf()
4bb6408c
JS
70#endif
71{
02e8b2f9
JS
72 m_tempCallbackStruct = (void*) NULL;
73 m_modified = FALSE;
dfc54541 74 m_processedDefault = FALSE;
4bb6408c
JS
75}
76
66a007fb
VZ
77bool wxTextCtrl::Create(wxWindow *parent,
78 wxWindowID id,
2d120f83
JS
79 const wxString& value,
80 const wxPoint& pos,
66a007fb
VZ
81 const wxSize& size,
82 long style,
2d120f83
JS
83 const wxValidator& validator,
84 const wxString& name)
4bb6408c 85{
02e8b2f9
JS
86 m_tempCallbackStruct = (void*) NULL;
87 m_modified = FALSE;
dfc54541 88 m_processedDefault = FALSE;
94b49b93
JS
89 // m_backgroundColour = parent->GetBackgroundColour();
90 m_backgroundColour = * wxWHITE;
0d57be45 91 m_foregroundColour = parent->GetForegroundColour();
66a007fb 92
4bb6408c
JS
93 SetName(name);
94 SetValidator(validator);
66a007fb
VZ
95 if (parent)
96 parent->AddChild(this);
97
4bb6408c 98 m_windowStyle = style;
66a007fb 99
4bb6408c 100 if ( id == -1 )
2d120f83 101 m_windowId = (int)NewControlId();
4bb6408c 102 else
2d120f83 103 m_windowId = id;
66a007fb 104
02e8b2f9 105 Widget parentWidget = (Widget) parent->GetClientWidget();
66a007fb 106
02e8b2f9 107 bool wantHorizScrolling = ((m_windowStyle & wxHSCROLL) != 0);
66a007fb 108
02e8b2f9
JS
109 // If we don't have horizontal scrollbars, we want word wrap.
110 bool wantWordWrap = !wantHorizScrolling;
66a007fb 111
02e8b2f9
JS
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);
66a007fb
VZ
117
118 m_mainWidget = (WXWidget) XmCreateScrolledText(parentWidget,
119 (char*)name.c_str(),
120 args, 2);
121
02e8b2f9 122 XtVaSetValues ((Widget) m_mainWidget,
66a007fb
VZ
123 XmNeditable, ((style & wxTE_READONLY) ? False : True),
124 XmNeditMode, XmMULTI_LINE_EDIT,
125 NULL);
02e8b2f9
JS
126 XtManageChild ((Widget) m_mainWidget);
127 }
128 else
129 {
66a007fb
VZ
130 m_mainWidget = (WXWidget)XtVaCreateManagedWidget
131 (
132 (char*)name.c_str(),
133 xmTextWidgetClass,
134 parentWidget,
135 NULL
136 );
137
02e8b2f9
JS
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();
66a007fb
VZ
142 XtVaSetValues((Widget) m_mainWidget,
143 XmNcolumns, noCols,
144 NULL);
02e8b2f9 145 }
66a007fb
VZ
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
02e8b2f9 159 XtAddCallback((Widget) m_mainWidget, XmNvalueChangedCallback, (XtCallbackProc)wxTextWindowChangedProc, (XtPointer)this);
66a007fb 160
02e8b2f9 161 XtAddCallback((Widget) m_mainWidget, XmNmodifyVerifyCallback, (XtCallbackProc)wxTextWindowModifyProc, (XtPointer)this);
66a007fb 162
dfc54541 163 XtAddCallback((Widget) m_mainWidget, XmNactivateCallback, (XtCallbackProc)wxTextWindowActivateProc, (XtPointer)this);
66a007fb 164
02e8b2f9 165 XtAddCallback((Widget) m_mainWidget, XmNfocusCallback, (XtCallbackProc)wxTextWindowGainFocusProc, (XtPointer)this);
66a007fb 166
02e8b2f9 167 XtAddCallback((Widget) m_mainWidget, XmNlosingFocusCallback, (XtCallbackProc)wxTextWindowLoseFocusProc, (XtPointer)this);
66a007fb
VZ
168
169 // font
4b5f3fe6
JS
170 m_windowFont = parent->GetFont();
171 ChangeFont(FALSE);
66a007fb 172
02e8b2f9
JS
173 SetCanAddEventHandler(TRUE);
174 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y);
66a007fb 175
0d57be45 176 ChangeBackgroundColour();
66a007fb 177
4bb6408c
JS
178 return TRUE;
179}
180
02e8b2f9 181WXWidget wxTextCtrl::GetTopWidget() const
4bb6408c 182{
dfc54541 183 return ((m_windowStyle & wxTE_MULTILINE) ? (WXWidget) XtParent((Widget) m_mainWidget) : m_mainWidget);
4bb6408c
JS
184}
185
02e8b2f9 186wxString wxTextCtrl::GetValue() const
4bb6408c 187{
dfc54541
JS
188 if (m_windowStyle & wxTE_PASSWORD)
189 return m_value;
190 else
191 {
192 char *s = XmTextGetString ((Widget) m_mainWidget);
193 if (s)
194 {
2d120f83 195 wxString str(s);
dfc54541 196 XtFree (s);
2d120f83
JS
197 return str;
198 }
199 else
dfc54541
JS
200 {
201 return wxEmptyString;
202 }
203 }
4bb6408c
JS
204}
205
02e8b2f9 206void wxTextCtrl::SetValue(const wxString& value)
4bb6408c 207{
dfc54541 208 m_inSetValue = TRUE;
66a007fb
VZ
209
210 XmTextSetString ((Widget) m_mainWidget, (char*)value.c_str());
211
dfc54541 212 m_inSetValue = FALSE;
4bb6408c
JS
213}
214
215// Clipboard operations
216void wxTextCtrl::Copy()
217{
dfc54541 218 XmTextCopy((Widget) m_mainWidget, CurrentTime);
4bb6408c
JS
219}
220
221void wxTextCtrl::Cut()
222{
dfc54541 223 XmTextCut((Widget) m_mainWidget, CurrentTime);
4bb6408c
JS
224}
225
226void wxTextCtrl::Paste()
227{
dfc54541 228 XmTextPaste((Widget) m_mainWidget);
4bb6408c
JS
229}
230
231void wxTextCtrl::SetEditable(bool editable)
232{
dfc54541 233 XmTextSetEditable((Widget) m_mainWidget, (Boolean) editable);
4bb6408c
JS
234}
235
236void wxTextCtrl::SetInsertionPoint(long pos)
237{
dfc54541 238 XmTextSetInsertionPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
4bb6408c
JS
239}
240
241void wxTextCtrl::SetInsertionPointEnd()
242{
243 long pos = GetLastPosition();
244 SetInsertionPoint(pos);
245}
246
247long wxTextCtrl::GetInsertionPoint() const
248{
dfc54541 249 return (long) XmTextGetInsertionPosition ((Widget) m_mainWidget);
4bb6408c
JS
250}
251
252long wxTextCtrl::GetLastPosition() const
253{
dfc54541 254 return (long) XmTextGetLastPosition ((Widget) m_mainWidget);
4bb6408c
JS
255}
256
257void wxTextCtrl::Replace(long from, long to, const wxString& value)
258{
dfc54541 259 XmTextReplace ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
2d120f83 260 (char*) (const char*) value);
4bb6408c
JS
261}
262
263void wxTextCtrl::Remove(long from, long to)
264{
dfc54541 265 XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
66a007fb 266 (Time) 0);
dfc54541 267 XmTextRemove ((Widget) m_mainWidget);
4bb6408c
JS
268}
269
270void wxTextCtrl::SetSelection(long from, long to)
271{
dfc54541 272 XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to,
66a007fb 273 (Time) 0);
4bb6408c
JS
274}
275
276bool wxTextCtrl::LoadFile(const wxString& file)
277{
278 if (!wxFileExists(file))
279 return FALSE;
66a007fb 280
4bb6408c 281 m_fileName = file;
66a007fb 282
4bb6408c 283 Clear();
66a007fb 284
1a3ac83f
JS
285 Widget textWidget = (Widget) m_mainWidget;
286 FILE *fp;
66a007fb 287
1a3ac83f
JS
288 struct stat statb;
289 if ((stat ((char*) (const char*) file, &statb) == -1) || (statb.st_mode & S_IFMT) != S_IFREG ||
2d120f83 290 !(fp = fopen ((char*) (const char*) file, "r")))
4bb6408c 291 {
2d120f83 292 return FALSE;
1a3ac83f
JS
293 }
294 else
295 {
2d120f83
JS
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);
66a007fb 307
2d120f83
JS
308 text[len] = 0;
309 XmTextSetString (textWidget, text);
310 // m_textPosition = len;
311 XtFree (text);
312 m_modified = FALSE;
313 return TRUE;
4bb6408c 314 }
4bb6408c
JS
315}
316
317// If file is null, try saved file name first
318// Returns TRUE if succeeds.
319bool 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;
66a007fb 327
2d120f83
JS
328 Widget textWidget = (Widget) m_mainWidget;
329 FILE *fp;
66a007fb 330
2d120f83 331 if (!(fp = fopen ((char*) (const char*) theFile, "w")))
1a3ac83f 332 {
2d120f83 333 return FALSE;
1a3ac83f 334 }
2d120f83 335 else
1a3ac83f 336 {
2d120f83
JS
337 char *text = XmTextGetString (textWidget);
338 long len = XmTextGetLastPosition (textWidget);
66a007fb 339
2d120f83
JS
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);
66a007fb 347
2d120f83
JS
348 fclose (fp);
349 XtFree (text);
350 m_modified = FALSE;
351 return TRUE;
1a3ac83f 352 }
4bb6408c
JS
353}
354
355void wxTextCtrl::WriteText(const wxString& text)
356{
dfc54541
JS
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;
4bb6408c
JS
363}
364
4dba84be
JS
365void 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
4bb6408c
JS
375void wxTextCtrl::Clear()
376{
02e8b2f9 377 XmTextSetString ((Widget) m_mainWidget, "");
02e8b2f9 378 m_modified = FALSE;
4bb6408c
JS
379}
380
381bool wxTextCtrl::IsModified() const
382{
02e8b2f9 383 return m_modified;
4bb6408c
JS
384}
385
386// Makes 'unmodified'
387void wxTextCtrl::DiscardEdits()
388{
dfc54541
JS
389 XmTextSetString ((Widget) m_mainWidget, "");
390 m_modified = FALSE;
4bb6408c
JS
391}
392
393int wxTextCtrl::GetNumberOfLines() const
394{
dfc54541
JS
395 // HIDEOUSLY inefficient, but we have no choice.
396 char *s = XmTextGetString ((Widget) m_mainWidget);
397 if (s)
398 {
2d120f83
JS
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 }
66a007fb 417
2d120f83
JS
418 XtFree (s);
419 return currentLine;
dfc54541 420 }
4bb6408c
JS
421 return 0;
422}
423
424long wxTextCtrl::XYToPosition(long x, long y) const
425{
dfc54541 426/* It seems, that there is a bug in some versions of the Motif library,
2d120f83
JS
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 */
dfc54541
JS
432 /* Now a little workaround: */
433 long r=0;
434 for (int i=0; i<y; i++) r+=(GetLineLength(i)+1);
66a007fb 435 return r+x;
4bb6408c
JS
436}
437
438void wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
439{
dfc54541
JS
440 Position xx, yy;
441 XmTextPosToXY((Widget) m_mainWidget, pos, &xx, &yy);
442 *x = xx; *y = yy;
4bb6408c
JS
443}
444
445void wxTextCtrl::ShowPosition(long pos)
446{
dfc54541 447 XmTextShowPosition ((Widget) m_mainWidget, (XmTextPosition) pos);
4bb6408c
JS
448}
449
450int wxTextCtrl::GetLineLength(long lineNo) const
451{
dfc54541
JS
452 wxString str = GetLineText (lineNo);
453 return (int) str.Length();
4bb6408c
JS
454}
455
456wxString wxTextCtrl::GetLineText(long lineNo) const
457{
dfc54541
JS
458 // HIDEOUSLY inefficient, but we have no choice.
459 char *s = XmTextGetString ((Widget) m_mainWidget);
66a007fb 460
dfc54541
JS
461 if (s)
462 {
463 wxString buf("");
464 long i;
465 int currentLine = 0;
466 for (i = 0; currentLine != lineNo && s[i]; i++ )
2d120f83
JS
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];
66a007fb 473
2d120f83
JS
474 XtFree(s);
475 return buf;
476 }
477 else
478 return wxEmptyString;
4bb6408c
JS
479}
480
481/*
2d120f83
JS
482* Text item
483*/
484
4bb6408c
JS
485void wxTextCtrl::Command(wxCommandEvent & event)
486{
487 SetValue (event.GetString());
488 ProcessCommand (event);
489}
490
491void 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//=========================================================================
66a007fb 504// Called then the buffer is full (gcc 2.6.3)
4bb6408c
JS
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
510int wxTextCtrl::overflow(int c)
511{
2d120f83
JS
512 // Make sure there is a holding area
513 if ( allocate()==EOF )
514 {
515 wxError("Streambuf allocation failed","Internal error");
516 return EOF;
517 }
66a007fb 518
2d120f83
JS
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 }
66a007fb 525
2d120f83
JS
526 // Reset get area
527 setg(0,0,0);
66a007fb 528
2d120f83
JS
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 }
66a007fb 536
2d120f83
JS
537 // Determine how many characters have been inserted but no consumed
538 int plen = pptr() - pbase();
66a007fb 539
2d120f83
JS
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.
66a007fb 544
2d120f83
JS
545 // If c!=EOF, it is a character that must also be comsumed
546 int xtra = c==EOF? 0 : 1;
66a007fb 547
2d120f83
JS
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 }
66a007fb 558
2d120f83
JS
559 // Reset put area
560 setp(pbase(), epptr());
66a007fb 561
4bb6408c 562#if defined(__WATCOMC__)
2d120f83 563 return __NOT_EOF;
4bb6408c 564#elif defined(zapeof) // HP-UX (all cfront based?)
2d120f83 565 return zapeof(c);
4bb6408c 566#else
2d120f83 567 return c!=EOF ? c : 0; // this should make everybody happy
4bb6408c
JS
568#endif
569}
570
571//=========================================================================
572// called then "endl" is output (gcc) or then explicit sync is done (Borland)
573//=========================================================================
574int wxTextCtrl::sync()
575{
2d120f83
JS
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 }
66a007fb 582
2d120f83 583 if ( pptr() && pptr() > pbase() ) return overflow(EOF);
66a007fb 584
2d120f83
JS
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 */
4bb6408c
JS
596}
597
598//=========================================================================
599// Should not be called by a "ostream". Used by a "istream"
600//=========================================================================
601int wxTextCtrl::underflow()
602{
2d120f83 603 return EOF;
4bb6408c
JS
604}
605#endif
606
607wxTextCtrl& wxTextCtrl::operator<<(const wxString& s)
608{
4dba84be 609 AppendText(s);
4bb6408c
JS
610 return *this;
611}
612
613wxTextCtrl& wxTextCtrl::operator<<(float f)
614{
615 wxString str;
616 str.Printf("%.2f", f);
4dba84be 617 AppendText(str);
4bb6408c
JS
618 return *this;
619}
620
621wxTextCtrl& wxTextCtrl::operator<<(double d)
622{
623 wxString str;
624 str.Printf("%.2f", d);
4dba84be 625 AppendText(str);
4bb6408c
JS
626 return *this;
627}
628
629wxTextCtrl& wxTextCtrl::operator<<(int i)
630{
631 wxString str;
632 str.Printf("%d", i);
4dba84be 633 AppendText(str);
4bb6408c
JS
634 return *this;
635}
636
637wxTextCtrl& wxTextCtrl::operator<<(long i)
638{
639 wxString str;
640 str.Printf("%ld", i);
4dba84be 641 AppendText(str);
4bb6408c
JS
642 return *this;
643}
644
645wxTextCtrl& wxTextCtrl::operator<<(const char c)
646{
647 char buf[2];
66a007fb 648
4bb6408c
JS
649 buf[0] = c;
650 buf[1] = 0;
4dba84be 651 AppendText(buf);
4bb6408c
JS
652 return *this;
653}
654
02e8b2f9
JS
655void wxTextCtrl::OnChar(wxKeyEvent& event)
656{
2d120f83
JS
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;
66a007fb 661
2d120f83 662 if (m_tempCallbackStruct)
02e8b2f9 663 {
2d120f83
JS
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 }
02e8b2f9 671 }
02e8b2f9
JS
672}
673
4b5f3fe6 674void wxTextCtrl::ChangeFont(bool keepOriginalSize)
0d57be45 675{
4b5f3fe6 676 wxWindow::ChangeFont(keepOriginalSize);
0d57be45
JS
677}
678
679void wxTextCtrl::ChangeBackgroundColour()
680{
321db4b6 681 wxWindow::ChangeBackgroundColour();
66a007fb 682
94b49b93 683 /* TODO: should scrollbars be affected? Should probably have separate
2d120f83
JS
684 * function to change them (by default, taken from wxSystemSettings)
685 */
94b49b93
JS
686 if (m_windowStyle & wxTE_MULTILINE)
687 {
688 Widget parent = XtParent ((Widget) m_mainWidget);
689 Widget hsb, vsb;
66a007fb 690
94b49b93 691 XtVaGetValues (parent,
2d120f83
JS
692 XmNhorizontalScrollBar, &hsb,
693 XmNverticalScrollBar, &vsb,
694 NULL);
94b49b93
JS
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);
66a007fb 700
94b49b93
JS
701 DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, TRUE);
702 }
0d57be45
JS
703}
704
705void wxTextCtrl::ChangeForegroundColour()
706{
321db4b6 707 wxWindow::ChangeForegroundColour();
66a007fb 708
94b49b93
JS
709 if (m_windowStyle & wxTE_MULTILINE)
710 {
711 Widget parent = XtParent ((Widget) m_mainWidget);
712 Widget hsb, vsb;
66a007fb 713
94b49b93 714 XtVaGetValues (parent,
2d120f83
JS
715 XmNhorizontalScrollBar, &hsb,
716 XmNverticalScrollBar, &vsb,
717 NULL);
66a007fb 718
2d120f83
JS
719 /* TODO: should scrollbars be affected? Should probably have separate
720 * function to change them (by default, taken from wxSystemSettings)
721 if (hsb)
94b49b93 722 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
2d120f83 723 if (vsb)
94b49b93 724 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
2d120f83 725 */
94b49b93
JS
726 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
727 }
0d57be45
JS
728}
729
dfc54541 730static void wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr)
02e8b2f9 731{
2d120f83
JS
732 if (!wxGetWindowFromTable(w))
733 // Widget has been deleted!
734 return;
66a007fb 735
2d120f83
JS
736 wxTextCtrl *tw = (wxTextCtrl *) clientData;
737 tw->SetModified(TRUE);
02e8b2f9
JS
738}
739
66a007fb 740static void
02e8b2f9
JS
741wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs)
742{
dfc54541
JS
743 wxTextCtrl *tw = (wxTextCtrl *) clientData;
744 tw->m_processedDefault = FALSE;
66a007fb 745
dfc54541
JS
746 // First, do some stuff if it's a password control.
747 // (What does this do exactly?)
66a007fb 748
dfc54541
JS
749 if (tw->GetWindowStyleFlag() & wxTE_PASSWORD)
750 {
66a007fb
VZ
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.
2d120f83 760 */
66a007fb 761
dfc54541
JS
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.
66a007fb 769
dfc54541
JS
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.
66a007fb 773
dfc54541
JS
774 char * newS = new char [len];
775 char * p = passwd, * dest = newS, * insert = cbs->text->ptr;
66a007fb 776
dfc54541
JS
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++;
66a007fb 781
dfc54541
JS
782 // Copy the text to be inserted).
783 while (*insert)
2d120f83 784 *dest++ = *insert++;
66a007fb 785
dfc54541
JS
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;
66a007fb 790
dfc54541 791 tw->m_value = newS;
66a007fb 792
dfc54541
JS
793 delete[] newS;
794 }
66a007fb 795
dfc54541
JS
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 }
66a007fb 804
dfc54541
JS
805 // If we're already within an OnChar, return: probably
806 // a programmatic insertion.
807 if (tw->m_tempCallbackStruct)
808 return;
66a007fb 809
dfc54541
JS
810 // Check for a backspace
811 if (cbs->startPos == (cbs->currInsert - 1))
812 {
813 tw->m_tempCallbackStruct = (void*) cbs;
66a007fb 814
dfc54541
JS
815 wxKeyEvent event (wxEVT_CHAR);
816 event.SetId(tw->GetId());
817 event.m_keyCode = WXK_DELETE;
818 event.SetEventObject(tw);
66a007fb 819
dfc54541
JS
820 // Only if wxTextCtrl::OnChar is called
821 // will this be set to True (and the character
822 // passed through)
823 cbs->doit = False;
66a007fb 824
dfc54541 825 tw->GetEventHandler()->ProcessEvent(event);
66a007fb 826
dfc54541 827 tw->m_tempCallbackStruct = NULL;
66a007fb 828
a4294b78 829 if (tw->InSetValue())
dfc54541 830 return;
66a007fb 831
dfc54541
JS
832 if (tw->m_processedDefault)
833 {
834 // Can generate a command
835 wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, tw->GetId());
2d120f83 836 commandEvent.SetEventObject(tw);
dfc54541 837 tw->ProcessCommand(commandEvent);
2d120f83 838 }
66a007fb 839
dfc54541
JS
840 return;
841 }
66a007fb 842
dfc54541
JS
843 // Pasting operation: let it through without
844 // calling OnChar
845 if (cbs->text->length > 1)
846 return;
66a007fb 847
dfc54541
JS
848 // Something other than text
849 if (cbs->text->ptr == NULL)
850 return;
66a007fb 851
02e8b2f9 852 tw->m_tempCallbackStruct = (void*) cbs;
66a007fb 853
02e8b2f9
JS
854 wxKeyEvent event (wxEVT_CHAR);
855 event.SetId(tw->GetId());
02e8b2f9 856 event.SetEventObject(tw);
dfc54541 857 event.m_keyCode = (cbs->text->ptr[0] == 10 ? 13 : cbs->text->ptr[0]);
66a007fb 858
02e8b2f9
JS
859 // Only if wxTextCtrl::OnChar is called
860 // will this be set to True (and the character
861 // passed through)
862 cbs->doit = False;
66a007fb 863
02e8b2f9 864 tw->GetEventHandler()->ProcessEvent(event);
66a007fb 865
02e8b2f9 866 tw->m_tempCallbackStruct = NULL;
66a007fb 867
a4294b78 868 if (tw->InSetValue())
dfc54541 869 return;
66a007fb 870
dfc54541
JS
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 }
02e8b2f9
JS
878}
879
66a007fb
VZ
880// ----------------------------------------------------------------------------
881// callbacks
882// ----------------------------------------------------------------------------
883
884static void
02e8b2f9
JS
885wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs)
886{
2d120f83
JS
887 if (!wxGetWindowFromTable(w))
888 return;
66a007fb 889
2d120f83
JS
890 wxTextCtrl *tw = (wxTextCtrl *) clientData;
891 wxFocusEvent event(wxEVT_SET_FOCUS, tw->GetId());
892 event.SetEventObject(tw);
893 tw->GetEventHandler()->ProcessEvent(event);
02e8b2f9
JS
894}
895
66a007fb 896static void
02e8b2f9
JS
897wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs)
898{
2d120f83
JS
899 if (!wxGetWindowFromTable(w))
900 return;
66a007fb 901
2d120f83
JS
902 wxTextCtrl *tw = (wxTextCtrl *) clientData;
903 wxFocusEvent event(wxEVT_KILL_FOCUS, tw->GetId());
904 event.SetEventObject(tw);
905 tw->GetEventHandler()->ProcessEvent(event);
02e8b2f9 906}
dfc54541
JS
907
908static void wxTextWindowActivateProc(Widget w, XtPointer clientData,
2d120f83 909 XmAnyCallbackStruct *ptr)
dfc54541 910{
2d120f83
JS
911 if (!wxGetWindowFromTable(w))
912 return;
66a007fb 913
2d120f83 914 wxTextCtrl *tw = (wxTextCtrl *) clientData;
66a007fb 915
2d120f83
JS
916 if (tw->InSetValue())
917 return;
66a007fb 918
2d120f83
JS
919 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER);
920 event.SetId(tw->GetId());
921 event.SetEventObject(tw);
922 tw->ProcessCommand(event);
dfc54541 923}