X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2d120f8391920145647ec10e84629bc21fa9f1bb..dc8c61bef78e406080de2be91bc6e8d746edb647:/src/motif/textctrl.cpp diff --git a/src/motif/textctrl.cpp b/src/motif/textctrl.cpp index bb1a996c02..f637e1fa42 100644 --- a/src/motif/textctrl.cpp +++ b/src/motif/textctrl.cpp @@ -1,351 +1,248 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: textctrl.cpp +// Name: src/motif/textctrl.cpp // Purpose: wxTextCtrl // Author: Julian Smart // Modified by: // Created: 17/09/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart -// Licence: wxWindows licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "textctrl.h" -#endif +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" #include #include -#include +#include #include "wx/textctrl.h" -#include "wx/settings.h" -#include "wx/filefn.h" -#include "wx/utils.h" -#if defined(__BORLANDC__) && !defined(__WIN32__) -#include -#else -#ifndef __GNUWIN32__ -#include -#endif +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/settings.h" #endif +#include "wx/filefn.h" + +#ifdef __VMS__ +#pragma message disable nosimpint +#endif #include -#include -#include -#include +#ifdef __VMS__ +#pragma message enable nosimpint +#endif #include "wx/motif/private.h" -static void -wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr); -static void -wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs); -static void -wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs); -static void -wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs); -static void wxTextWindowActivateProc(Widget w, XtPointer clientData, - XmAnyCallbackStruct *ptr); +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl) +// helper: inserts the new text in the value of the text ctrl and returns the +// result in place +static void MergeChangesIntoString(wxString& value, + XmTextVerifyCallbackStruct *textStruct); -BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) -EVT_DROP_FILES(wxTextCtrl::OnDropFiles) -EVT_CHAR(wxTextCtrl::OnChar) -END_EVENT_TABLE() -#endif +// callbacks +static void wxTextWindowChangedProc(Widget w, XtPointer clientData, XtPointer ptr); +static void wxTextWindowModifyProc(Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs); +static void wxTextWindowGainFocusProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs); +static void wxTextWindowLoseFocusProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs); +static void wxTextWindowActivateProc(Widget w, XtPointer clientData, XmAnyCallbackStruct *ptr); + + BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase) + EVT_DROP_FILES(wxTextCtrl::OnDropFiles) + EVT_CHAR(wxTextCtrl::OnChar) + + EVT_MENU(wxID_CUT, wxTextCtrl::OnCut) + EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy) + EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste) + EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo) + EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo) + + EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut) + EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy) + EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste) + EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo) + EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo) + + END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxTextCtrl +// ---------------------------------------------------------------------------- // Text item wxTextCtrl::wxTextCtrl() -#ifndef NO_TEXT_WINDOW_STREAM -:streambuf() -#endif { - m_fileName = ""; - m_tempCallbackStruct = (void*) NULL; - m_modified = FALSE; - m_processedDefault = FALSE; + m_tempCallbackStruct = NULL; + m_modified = false; + m_processedDefault = false; } -bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, +bool wxTextCtrl::Create(wxWindow *parent, + wxWindowID id, const wxString& value, const wxPoint& pos, - const wxSize& size, long style, + const wxSize& size, + long style, const wxValidator& validator, const wxString& name) { - m_tempCallbackStruct = (void*) NULL; - m_modified = FALSE; - m_processedDefault = FALSE; - m_fileName = ""; - // m_backgroundColour = parent->GetBackgroundColour(); - m_backgroundColour = * wxWHITE; - m_foregroundColour = parent->GetForegroundColour(); - - SetName(name); - SetValidator(validator); - if (parent) parent->AddChild(this); - - m_windowStyle = style; - - if ( id == -1 ) - m_windowId = (int)NewControlId(); - else - m_windowId = id; - + if( !CreateControl( parent, id, pos, size, style, validator, name ) ) + return false; + PreCreation(); + + m_tempCallbackStruct = NULL; + m_modified = false; + m_processedDefault = false; + Widget parentWidget = (Widget) parent->GetClientWidget(); - - bool wantHorizScrolling = ((m_windowStyle & wxHSCROLL) != 0); - + + Bool wantHorizScroll = (m_windowStyle & wxHSCROLL) != 0 ? True : False; // If we don't have horizontal scrollbars, we want word wrap. - bool wantWordWrap = !wantHorizScrolling; - + // OpenMotif 2.1 crashes if wantWordWrap is True in Japanese + // locale (and probably other multibyte locales). The check might be + // more precise +#if wxCHECK_LESSTIF() || wxCHECK_MOTIF_VERSION( 2, 2 ) + Bool wantWordWrap = wantHorizScroll == True ? False : True; +#else + Bool wantWordWrap = False; +#endif + if (m_windowStyle & wxTE_MULTILINE) { - Arg args[2]; - XtSetArg (args[0], XmNscrollHorizontal, wantHorizScrolling ? True : False); - XtSetArg (args[1], XmNwordWrap, wantWordWrap ? True : False); - - m_mainWidget = (WXWidget) XmCreateScrolledText (parentWidget, (char*) (const char*) name, args, 2); - - XtVaSetValues ((Widget) m_mainWidget, - XmNeditable, ((style & wxTE_READONLY) ? False : True), - XmNeditMode, XmMULTI_LINE_EDIT, - NULL); + Arg args[8]; + int count = 0; + XtSetArg (args[count], XmNscrollHorizontal, wantHorizScroll); ++count; + if( m_font.IsOk() ) + XtSetArg (args[count], (String) wxFont::GetFontTag(), + m_font.GetFontType( XtDisplay(parentWidget) ) ); ++count; + XtSetArg (args[count], XmNwordWrap, wantWordWrap); ++count; + XtSetArg (args[count], XmNvalue, (const char*)value.mb_str()); ++count; + XtSetArg (args[count], XmNeditable, + style & wxTE_READONLY ? False : True); ++count; + XtSetArg (args[count], XmNeditMode, XmMULTI_LINE_EDIT ); ++count; + + m_mainWidget = + (WXWidget) XmCreateScrolledText(parentWidget, + name.char_str(), + args, count); + XtManageChild ((Widget) m_mainWidget); } else { - m_mainWidget = (WXWidget) XtVaCreateManagedWidget ((char*) (const char*) name, - xmTextWidgetClass, parentWidget, - NULL); - + m_mainWidget = (WXWidget)XtVaCreateManagedWidget + ( + name.mb_str(), + xmTextWidgetClass, + parentWidget, + wxFont::GetFontTag(), m_font.GetFontType( XtDisplay(parentWidget) ), + XmNvalue, (const char*)value.mb_str(), + XmNeditable, (style & wxTE_READONLY) ? + False : True, + NULL + ); + +#if 0 // TODO: Is this relevant? What does it do? int noCols = 2; - if (!value.IsNull() && (value.Length() > (unsigned int) noCols)) - noCols = value.Length(); - XtVaSetValues ((Widget) m_mainWidget, - XmNcolumns, noCols, - NULL); + if (!value.empty() && (value.length() > (unsigned int) noCols)) + noCols = value.length(); + XtVaSetValues((Widget) m_mainWidget, + XmNcolumns, noCols, + NULL); +#endif } - - if (!value.IsNull()) - XmTextSetString ((Widget) m_mainWidget, (char*) (const char*) value); - - XtAddCallback((Widget) m_mainWidget, XmNvalueChangedCallback, (XtCallbackProc)wxTextWindowChangedProc, (XtPointer)this); - - XtAddCallback((Widget) m_mainWidget, XmNmodifyVerifyCallback, (XtCallbackProc)wxTextWindowModifyProc, (XtPointer)this); - - XtAddCallback((Widget) m_mainWidget, XmNactivateCallback, (XtCallbackProc)wxTextWindowActivateProc, (XtPointer)this); - - XtAddCallback((Widget) m_mainWidget, XmNfocusCallback, (XtCallbackProc)wxTextWindowGainFocusProc, (XtPointer)this); - - XtAddCallback((Widget) m_mainWidget, XmNlosingFocusCallback, (XtCallbackProc)wxTextWindowLoseFocusProc, (XtPointer)this); - - m_windowFont = parent->GetFont(); - ChangeFont(FALSE); - - SetCanAddEventHandler(TRUE); - AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y); - - ChangeBackgroundColour(); - - return TRUE; -} -WXWidget wxTextCtrl::GetTopWidget() const -{ - return ((m_windowStyle & wxTE_MULTILINE) ? (WXWidget) XtParent((Widget) m_mainWidget) : m_mainWidget); -} - -wxString wxTextCtrl::GetValue() const -{ - if (m_windowStyle & wxTE_PASSWORD) - return m_value; - else + // remove border if asked for + if ( style & wxNO_BORDER ) { - char *s = XmTextGetString ((Widget) m_mainWidget); - if (s) - { - wxString str(s); - XtFree (s); - return str; - } - else - { - return wxEmptyString; - } + XtVaSetValues((Widget)m_mainWidget, + XmNshadowThickness, 0, + NULL); } -} - -void wxTextCtrl::SetValue(const wxString& value) -{ - // This assert is wrong -- means that you can't set an empty - // string (IsNull == IsEmpty). - // wxASSERT_MSG( (!value.IsNull()), "Must not pass a null string to wxTextCtrl::SetValue." ) ; - m_inSetValue = TRUE; - - XmTextSetString ((Widget) m_mainWidget, (char*) (const char*) value); - - m_inSetValue = FALSE; -} -// Clipboard operations -void wxTextCtrl::Copy() -{ - XmTextCopy((Widget) m_mainWidget, CurrentTime); -} - -void wxTextCtrl::Cut() -{ - XmTextCut((Widget) m_mainWidget, CurrentTime); -} - -void wxTextCtrl::Paste() -{ - XmTextPaste((Widget) m_mainWidget); -} + // install callbacks + XtAddCallback((Widget) m_mainWidget, XmNvalueChangedCallback, (XtCallbackProc)wxTextWindowChangedProc, (XtPointer)this); -void wxTextCtrl::SetEditable(bool editable) -{ - XmTextSetEditable((Widget) m_mainWidget, (Boolean) editable); -} + XtAddCallback((Widget) m_mainWidget, XmNmodifyVerifyCallback, (XtCallbackProc)wxTextWindowModifyProc, (XtPointer)this); -void wxTextCtrl::SetInsertionPoint(long pos) -{ - XmTextSetInsertionPosition ((Widget) m_mainWidget, (XmTextPosition) pos); -} + XtAddCallback((Widget) m_mainWidget, XmNactivateCallback, (XtCallbackProc)wxTextWindowActivateProc, (XtPointer)this); -void wxTextCtrl::SetInsertionPointEnd() -{ - long pos = GetLastPosition(); - SetInsertionPoint(pos); -} + XtAddCallback((Widget) m_mainWidget, XmNfocusCallback, (XtCallbackProc)wxTextWindowGainFocusProc, (XtPointer)this); -long wxTextCtrl::GetInsertionPoint() const -{ - return (long) XmTextGetInsertionPosition ((Widget) m_mainWidget); -} + XtAddCallback((Widget) m_mainWidget, XmNlosingFocusCallback, (XtCallbackProc)wxTextWindowLoseFocusProc, (XtPointer)this); -long wxTextCtrl::GetLastPosition() const -{ - return (long) XmTextGetLastPosition ((Widget) m_mainWidget); -} + PostCreation(); + AttachWidget (parent, m_mainWidget, (WXWidget) NULL, + pos.x, pos.y, size.x, size.y); -void wxTextCtrl::Replace(long from, long to, const wxString& value) -{ - XmTextReplace ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to, - (char*) (const char*) value); + return true; } -void wxTextCtrl::Remove(long from, long to) +WXWidget wxTextCtrl::GetTopWidget() const { - XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to, - (Time) 0); - XmTextRemove ((Widget) m_mainWidget); + return IsMultiLine() ? (WXWidget)XtParent((Widget)m_mainWidget) + : m_mainWidget; } -void wxTextCtrl::SetSelection(long from, long to) +wxString wxTextCtrl::GetValue() const { - XmTextSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to, - (Time) 0); -} + wxString str; // result -bool wxTextCtrl::LoadFile(const wxString& file) -{ - if (!wxFileExists(file)) - return FALSE; - - m_fileName = file; - - Clear(); - - Widget textWidget = (Widget) m_mainWidget; - FILE *fp; - - struct stat statb; - if ((stat ((char*) (const char*) file, &statb) == -1) || (statb.st_mode & S_IFMT) != S_IFREG || - !(fp = fopen ((char*) (const char*) file, "r"))) + if (m_windowStyle & wxTE_PASSWORD) { - return FALSE; + // the value is stored always in m_value because it can't be retrieved + // from the text control + str = m_value; } else { - long len = statb.st_size; - char *text; - if (!(text = XtMalloc ((unsigned) (len + 1)))) - { - fclose (fp); - return FALSE; - } - if (fread (text, sizeof (char), len, fp) != (size_t) len) - { - } - fclose (fp); - - text[len] = 0; - XmTextSetString (textWidget, text); - // m_textPosition = len; - XtFree (text); - m_modified = FALSE; - return TRUE; - } -} + str = wxTextEntry::GetValue(); -// If file is null, try saved file name first -// Returns TRUE if succeeds. -bool wxTextCtrl::SaveFile(const wxString& file) -{ - wxString theFile(file); - if (theFile == "") - theFile = m_fileName; - if (theFile == "") - return FALSE; - m_fileName = theFile; - - Widget textWidget = (Widget) m_mainWidget; - FILE *fp; - - if (!(fp = fopen ((char*) (const char*) theFile, "w"))) - { - return FALSE; - } - else - { - char *text = XmTextGetString (textWidget); - long len = XmTextGetLastPosition (textWidget); - - if (fwrite (text, sizeof (char), len, fp) != (size_t) len) + if ( m_tempCallbackStruct ) { - // Did not write whole file + // the string in the control isn't yet updated, can't use it as is + MergeChangesIntoString(str, (XmTextVerifyCallbackStruct *) + m_tempCallbackStruct); } - // Make sure newline terminates the file - if (text[len - 1] != '\n') - fputc ('\n', fp); - - fclose (fp); - XtFree (text); - m_modified = FALSE; - return TRUE; } -} -void wxTextCtrl::WriteText(const wxString& text) -{ - long textPosition = GetInsertionPoint() + strlen (text); - XmTextInsert ((Widget) m_mainWidget, GetInsertionPoint(), (char*) (const char*) text); - XtVaSetValues ((Widget) m_mainWidget, XmNcursorPosition, textPosition, NULL); - SetInsertionPoint(textPosition); - XmTextShowPosition ((Widget) m_mainWidget, textPosition); - m_modified = TRUE; + return str; } -void wxTextCtrl::Clear() +void wxTextCtrl::DoSetValue(const wxString& text, int flags) { - XmTextSetString ((Widget) m_mainWidget, ""); - m_modified = FALSE; + m_inSetValue = true; + + XmTextSetString ((Widget) m_mainWidget, text.char_str()); + XtVaSetValues ((Widget) m_mainWidget, + XmNcursorPosition, text.length(), + NULL); + + SetInsertionPoint(text.length()); + XmTextShowPosition ((Widget) m_mainWidget, text.length()); + m_modified = true; + + m_inSetValue = false; + + if ( flags & SetValue_SendEvent ) + SendTextUpdatedEvent(); } bool wxTextCtrl::IsModified() const @@ -353,11 +250,15 @@ bool wxTextCtrl::IsModified() const return m_modified; } -// Makes 'unmodified' +// Makes modified or unmodified +void wxTextCtrl::MarkDirty() +{ + m_modified = true; +} + void wxTextCtrl::DiscardEdits() { - XmTextSetString ((Widget) m_mainWidget, ""); - m_modified = FALSE; + m_modified = false; } int wxTextCtrl::GetNumberOfLines() const @@ -368,7 +269,7 @@ int wxTextCtrl::GetNumberOfLines() const { long i = 0; int currentLine = 0; - bool finished = FALSE; + bool finished = false; while (!finished) { int ch = s[i]; @@ -379,12 +280,12 @@ int wxTextCtrl::GetNumberOfLines() const } else if (ch == 0) { - finished = TRUE; + finished = true; } else i++; } - + XtFree (s); return currentLine; } @@ -402,14 +303,19 @@ long wxTextCtrl::XYToPosition(long x, long y) const /* Now a little workaround: */ long r=0; for (int i=0; i pbase() ) return overflow(EOF); - - return 0; - /* OLD CODE - int len = pptr() - pbase(); - char *txt = new char[len+1]; - strncpy(txt, pbase(), len); - txt[len] = '\0'; - (*this) << txt; - setp(pbase(), epptr()); - delete[] txt; - return 0; - */ -} - -//========================================================================= -// Should not be called by a "ostream". Used by a "istream" -//========================================================================= -int wxTextCtrl::underflow() -{ - return EOF; -} -#endif - -wxTextCtrl& wxTextCtrl::operator<<(const wxString& s) -{ - WriteText(s); - return *this; -} - -wxTextCtrl& wxTextCtrl::operator<<(float f) -{ - wxString str; - str.Printf("%.2f", f); - WriteText(str); - return *this; -} - -wxTextCtrl& wxTextCtrl::operator<<(double d) -{ - wxString str; - str.Printf("%.2f", d); - WriteText(str); - return *this; -} - -wxTextCtrl& wxTextCtrl::operator<<(int i) -{ - wxString str; - str.Printf("%d", i); - WriteText(str); - return *this; -} - -wxTextCtrl& wxTextCtrl::operator<<(long i) -{ - wxString str; - str.Printf("%ld", i); - WriteText(str); - return *this; -} - -wxTextCtrl& wxTextCtrl::operator<<(const char c) -{ - char buf[2]; - - buf[0] = c; - buf[1] = 0; - WriteText(buf); - return *this; -} - void wxTextCtrl::OnChar(wxKeyEvent& event) { // Indicates that we should generate a normal command, because // we're letting default behaviour happen (otherwise it's vetoed // by virtue of overriding OnChar) - m_processedDefault = TRUE; - + m_processedDefault = true; + if (m_tempCallbackStruct) { XmTextVerifyCallbackStruct *textStruct = (XmTextVerifyCallbackStruct *) m_tempCallbackStruct; textStruct->doit = True; - if (isascii(event.m_keyCode) && (textStruct->text->length == 1)) + if (wxIsascii(event.m_keyCode) && (textStruct->text->length == 1)) { - textStruct->text->ptr[0] = ((event.m_keyCode == WXK_RETURN) ? 10 : event.m_keyCode); + textStruct->text->ptr[0] = (char)((event.m_keyCode == WXK_RETURN) ? 10 : event.m_keyCode); } } } @@ -649,7 +400,7 @@ void wxTextCtrl::ChangeFont(bool keepOriginalSize) void wxTextCtrl::ChangeBackgroundColour() { wxWindow::ChangeBackgroundColour(); - + /* TODO: should scrollbars be affected? Should probably have separate * function to change them (by default, taken from wxSystemSettings) */ @@ -657,35 +408,36 @@ void wxTextCtrl::ChangeBackgroundColour() { Widget parent = XtParent ((Widget) m_mainWidget); Widget hsb, vsb; - + XtVaGetValues (parent, XmNhorizontalScrollBar, &hsb, XmNverticalScrollBar, &vsb, NULL); - wxColour backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE); + wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE); if (hsb) - DoChangeBackgroundColour((WXWidget) hsb, backgroundColour, TRUE); + wxDoChangeBackgroundColour((WXWidget) hsb, backgroundColour, true); if (vsb) - DoChangeBackgroundColour((WXWidget) vsb, backgroundColour, TRUE); - - DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, TRUE); + wxDoChangeBackgroundColour((WXWidget) vsb, backgroundColour, true); + + // MBN: why change parent background? + // DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, true); } } void wxTextCtrl::ChangeForegroundColour() { wxWindow::ChangeForegroundColour(); - + if (m_windowStyle & wxTE_MULTILINE) { Widget parent = XtParent ((Widget) m_mainWidget); Widget hsb, vsb; - + XtVaGetValues (parent, XmNhorizontalScrollBar, &hsb, XmNverticalScrollBar, &vsb, NULL); - + /* TODO: should scrollbars be affected? Should probably have separate * function to change them (by default, taken from wxSystemSettings) if (hsb) @@ -693,206 +445,300 @@ void wxTextCtrl::ChangeForegroundColour() if (vsb) DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour); */ - DoChangeForegroundColour((WXWidget) parent, m_foregroundColour); + wxDoChangeForegroundColour((WXWidget) parent, m_foregroundColour); } } -static void wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr) +void wxTextCtrl::DoSendEvents(void *wxcbs, long keycode) +{ + // we're in process of updating the text control + m_tempCallbackStruct = wxcbs; + + XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)wxcbs; + + wxKeyEvent event (wxEVT_CHAR); + event.SetId(GetId()); + event.m_keyCode = keycode; + event.SetEventObject(this); + + // Only if wxTextCtrl::OnChar is called will this be set to True (and + // the character passed through) + cbs->doit = False; + + HandleWindowEvent(event); + + if ( !InSetValue() && m_processedDefault ) + { + // Can generate a command + wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, GetId()); + commandEvent.SetEventObject(this); + ProcessCommand(commandEvent); + } + + // do it after the (user) event handlers processed the events because + // otherwise GetValue() would return incorrect (not yet updated value) + m_tempCallbackStruct = NULL; +} + +wxSize wxDoGetSingleTextCtrlBestSize( Widget textWidget, + const wxWindow* window ) +{ + Dimension xmargin, ymargin, highlight, shadow; + char* value; + + XtVaGetValues( textWidget, + XmNmarginWidth, &xmargin, + XmNmarginHeight, &ymargin, + XmNvalue, &value, + XmNhighlightThickness, &highlight, + XmNshadowThickness, &shadow, + NULL ); + + if( !value ) + value = wxMOTIF_STR("|"); + + int x, y; + window->GetTextExtent( value, &x, &y ); + + if( x < 90 ) + x = 90; + + return wxSize( x + 2 * xmargin + 2 * highlight + 2 * shadow, + // MBN: +2 necessary: Lesstif bug or mine? + y + 2 * ymargin + 2 * highlight + 2 * shadow + 2 ); +} + +wxSize wxTextCtrl::DoGetBestSize() const +{ + if( IsSingleLine() ) + { + wxSize best = wxControl::DoGetBestSize(); +#if wxCHECK_MOTIF_VERSION( 2, 3 ) + // OpenMotif 2.3 gives way too big X sizes + wxSize other_best = wxDoGetSingleTextCtrlBestSize + ( (Widget) GetTopWidget(), this ); + return wxSize( other_best.x, best.y ); +#else + if( best.x < 90 ) best.x = 90; + + return best; +#endif + } + else + return wxWindow::DoGetBestSize(); +} + +// ---------------------------------------------------------------------------- +// helpers and Motif callbacks +// ---------------------------------------------------------------------------- + +static void MergeChangesIntoString(wxString& value, + XmTextVerifyCallbackStruct *cbs) +{ + /* _sm_ + * At least on my system (SunOS 4.1.3 + Motif 1.2), you need to think of + * every event as a replace event. cbs->text->ptr gives the replacement + * text, cbs->startPos gives the index of the first char affected by the + * replace, and cbs->endPos gives the index one more than the last char + * affected by the replace (startPos == endPos implies an empty range). + * Hence, a deletion is represented by replacing all input text with a + * blank string ("", *not* NULL!). A simple insertion that does not + * overwrite any text has startPos == endPos. + */ + + if ( !value ) + { + // easy case: the ol value was empty + value = cbs->text->ptr; + } + else + { + // merge the changes into the value + const char * const passwd = value; + int len = value.length(); + + len += ( cbs->text->ptr ? + strlen(cbs->text->ptr) : + 0 ) + 1; // + new text (if any) + NUL + len -= cbs->endPos - cbs->startPos; // - text from affected region. + + char * newS = new char [len]; + char * dest = newS, + * insert = cbs->text->ptr; + + // Copy (old) text from passwd, up to the start posn of the change. + int i; + const char * p = passwd; + for (i = 0; i < cbs->startPos; ++i) + *dest++ = *p++; + + // Copy the text to be inserted). + if (insert) + while (*insert) + *dest++ = *insert++; + + // Finally, copy into newS any remaining text from passwd[endPos] on. + for (p = passwd + cbs->endPos; *p; ) + *dest++ = *p++; + *dest = 0; + + value = newS; + + delete[] newS; + } +} + +static void +wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr)) { if (!wxGetWindowFromTable(w)) // Widget has been deleted! return; - + wxTextCtrl *tw = (wxTextCtrl *) clientData; - tw->SetModified(TRUE); + tw->SetModified(true); } -static void -wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStruct *cbs) +static void +wxTextWindowModifyProc (Widget WXUNUSED(w), XtPointer clientData, XmTextVerifyCallbackStruct *cbs) { wxTextCtrl *tw = (wxTextCtrl *) clientData; - tw->m_processedDefault = FALSE; - - // First, do some stuff if it's a password control. - // (What does this do exactly?) - - if (tw->GetWindowStyleFlag() & wxTE_PASSWORD) + tw->m_processedDefault = false; + + // First, do some stuff if it's a password control: in this case, we need + // to store the string inside the class because GetValue() can't retrieve + // it from the text ctrl. We do *not* do it in other circumstances because + // it would double the amount of memory needed. + + if ( tw->GetWindowStyleFlag() & wxTE_PASSWORD ) { - /* _sm_ - * At least on my system (SunOS 4.1.3 + Motif 1.2), you need to think of - * every event as a replace event. cbs->text->ptr gives the replacement - * text, cbs->startPos gives the index of the first char affected by the - * replace, and cbs->endPos gives the index one more than the last char - * affected by the replace (startPos == endPos implies an empty range). - * Hence, a deletion is represented by replacing all input text with a - * blank string ("", *not* NULL!). A simple insertion that does not - * overwrite any text has startPos == endPos. - */ - - if (tw->m_value.IsNull()) - { - tw->m_value = cbs->text->ptr; - } - else - { - char * passwd = (char*) (const char*) tw->m_value; // Set up a more convenient alias. - - int len = passwd ? strlen(passwd) : 0; // Enough room for old text - len += strlen(cbs->text->ptr) + 1; // + new text (if any) + NUL - len -= cbs->endPos - cbs->startPos; // - text from affected region. - - char * newS = new char [len]; - char * p = passwd, * dest = newS, * insert = cbs->text->ptr; - - // Copy (old) text from passwd, up to the start posn of the change. - int i; - for (i = 0; i < cbs->startPos; ++i) - *dest++ = *p++; - - // Copy the text to be inserted). - while (*insert) - *dest++ = *insert++; - - // Finally, copy into newS any remaining text from passwd[endPos] on. - for (p = passwd + cbs->endPos; *p; ) - *dest++ = *p++; - *dest = 0; - - tw->m_value = newS; - - delete[] newS; - } - - if (cbs->text->length>0) + MergeChangesIntoString(tw->m_value, cbs); + + if ( cbs->text->length > 0 ) { int i; for (i = 0; i < cbs->text->length; ++i) cbs->text->ptr[i] = '*'; - cbs->text->ptr[i] = 0; + cbs->text->ptr[i] = '\0'; } } - - // If we're already within an OnChar, return: probably - // a programmatic insertion. + + if(tw->InSetValue()) + return; + + // If we're already within an OnChar, return: probably a programmatic + // insertion. if (tw->m_tempCallbackStruct) return; - + // Check for a backspace if (cbs->startPos == (cbs->currInsert - 1)) { - tw->m_tempCallbackStruct = (void*) cbs; - - wxKeyEvent event (wxEVT_CHAR); - event.SetId(tw->GetId()); - event.m_keyCode = WXK_DELETE; - event.SetEventObject(tw); - - // Only if wxTextCtrl::OnChar is called - // will this be set to True (and the character - // passed through) - cbs->doit = False; - - tw->GetEventHandler()->ProcessEvent(event); - - tw->m_tempCallbackStruct = NULL; - - if (tw->InSetValue()) - return; - - if (tw->m_processedDefault) - { - // Can generate a command - wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, tw->GetId()); - commandEvent.SetEventObject(tw); - tw->ProcessCommand(commandEvent); - } - + tw->DoSendEvents((void *)cbs, WXK_DELETE); + return; } - - // Pasting operation: let it through without - // calling OnChar + + // Pasting operation: let it through without calling OnChar if (cbs->text->length > 1) return; - + // Something other than text if (cbs->text->ptr == NULL) return; - - tw->m_tempCallbackStruct = (void*) cbs; - - wxKeyEvent event (wxEVT_CHAR); - event.SetId(tw->GetId()); - event.SetEventObject(tw); - event.m_keyCode = (cbs->text->ptr[0] == 10 ? 13 : cbs->text->ptr[0]); - - // Only if wxTextCtrl::OnChar is called - // will this be set to True (and the character - // passed through) - cbs->doit = False; - - tw->GetEventHandler()->ProcessEvent(event); - - tw->m_tempCallbackStruct = NULL; - - if (tw->InSetValue()) - return; - - if (tw->m_processedDefault) - { - // Can generate a command - wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, tw->GetId()); - commandEvent.SetEventObject(tw); - tw->ProcessCommand(commandEvent); - } + + // normal key press + char ch = cbs->text->ptr[0]; + tw->DoSendEvents((void *)cbs, ch == '\n' ? '\r' : ch); } -static void -wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs) +static void +wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *WXUNUSED(cbs)) { if (!wxGetWindowFromTable(w)) return; - + wxTextCtrl *tw = (wxTextCtrl *) clientData; wxFocusEvent event(wxEVT_SET_FOCUS, tw->GetId()); event.SetEventObject(tw); - tw->GetEventHandler()->ProcessEvent(event); + tw->HandleWindowEvent(event); } -static void -wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs) +static void +wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *WXUNUSED(cbs)) { if (!wxGetWindowFromTable(w)) return; - + wxTextCtrl *tw = (wxTextCtrl *) clientData; wxFocusEvent event(wxEVT_KILL_FOCUS, tw->GetId()); event.SetEventObject(tw); - tw->GetEventHandler()->ProcessEvent(event); + tw->HandleWindowEvent(event); } static void wxTextWindowActivateProc(Widget w, XtPointer clientData, - XmAnyCallbackStruct *ptr) + XmAnyCallbackStruct *WXUNUSED(ptr)) { if (!wxGetWindowFromTable(w)) return; - + wxTextCtrl *tw = (wxTextCtrl *) clientData; - /* - case XmCR_ACTIVATE: - type_event = wxEVENT_TYPE_TEXT_ENTER_COMMAND ; - break; - default: - type_event = wxEVENT_TYPE_TEXT_COMMAND ; - break; - } - */ - + if (tw->InSetValue()) return; - + wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER); event.SetId(tw->GetId()); event.SetEventObject(tw); tw->ProcessCommand(event); } + +void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event)) +{ + Cut(); +} + +void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event)) +{ + Copy(); +} + +void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event)) +{ + Paste(); +} + +void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event)) +{ + Undo(); +} + +void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event)) +{ + Redo(); +} + +void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event) +{ + event.Enable( CanCut() ); +} + +void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event) +{ + event.Enable( CanCopy() ); +} + +void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event) +{ + event.Enable( CanPaste() ); +} + +void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event) +{ + event.Enable( CanUndo() ); +} + +void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event) +{ + event.Enable( CanRedo() ); +}