X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/dfc5454127ac2195e10deebb216d82c674e757df..cfad3750c3ecc821ffae8b9b3de852551270846d:/src/motif/textctrl.cpp diff --git a/src/motif/textctrl.cpp b/src/motif/textctrl.cpp index d62cac41f6..bb1a996c02 100644 --- a/src/motif/textctrl.cpp +++ b/src/motif/textctrl.cpp @@ -46,109 +46,112 @@ wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct * static void wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs); static void wxTextWindowActivateProc(Widget w, XtPointer clientData, - XmAnyCallbackStruct *ptr); + XmAnyCallbackStruct *ptr); #if !USE_SHARED_LIBRARY IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl) BEGIN_EVENT_TABLE(wxTextCtrl, wxControl) - EVT_DROP_FILES(wxTextCtrl::OnDropFiles) - EVT_CHAR(wxTextCtrl::OnChar) +EVT_DROP_FILES(wxTextCtrl::OnDropFiles) +EVT_CHAR(wxTextCtrl::OnChar) END_EVENT_TABLE() #endif // Text item wxTextCtrl::wxTextCtrl() #ifndef NO_TEXT_WINDOW_STREAM - :streambuf() +:streambuf() #endif { m_fileName = ""; m_tempCallbackStruct = (void*) NULL; m_modified = FALSE; m_processedDefault = FALSE; - m_inSetValue = FALSE; } bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, long style, - const wxValidator& validator, - const wxString& name) + const wxString& value, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) { m_tempCallbackStruct = (void*) NULL; m_modified = FALSE; m_processedDefault = FALSE; m_fileName = ""; - m_inSetValue = FALSE; - + // 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(); + m_windowId = (int)NewControlId(); else - m_windowId = id; - + m_windowId = id; + Widget parentWidget = (Widget) parent->GetClientWidget(); - + bool wantHorizScrolling = ((m_windowStyle & wxHSCROLL) != 0); - + // If we don't have horizontal scrollbars, we want word wrap. bool wantWordWrap = !wantHorizScrolling; - + 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); + XmNeditable, ((style & wxTE_READONLY) ? False : True), + XmNeditMode, XmMULTI_LINE_EDIT, + NULL); XtManageChild ((Widget) m_mainWidget); } else { m_mainWidget = (WXWidget) XtVaCreateManagedWidget ((char*) (const char*) name, - xmTextWidgetClass, parentWidget, - NULL); - + xmTextWidgetClass, parentWidget, + NULL); + // 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); + XmNcolumns, noCols, + NULL); } - + 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); - - SetFont(* parent->GetFont()); - ChangeColour(m_mainWidget); - + + ChangeBackgroundColour(); + return TRUE; } @@ -166,11 +169,11 @@ wxString wxTextCtrl::GetValue() const char *s = XmTextGetString ((Widget) m_mainWidget); if (s) { - wxString str(s); + wxString str(s); XtFree (s); - return str; - } - else + return str; + } + else { return wxEmptyString; } @@ -179,11 +182,13 @@ wxString wxTextCtrl::GetValue() const void wxTextCtrl::SetValue(const wxString& value) { - wxASSERT_MSG( (!value.IsNull()), "Must not pass a null string to wxTextCtrl::SetValue." ) ; + // 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; } @@ -232,7 +237,7 @@ long wxTextCtrl::GetLastPosition() const void wxTextCtrl::Replace(long from, long to, const wxString& value) { XmTextReplace ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to, - (char*) (const char*) value); + (char*) (const char*) value); } void wxTextCtrl::Remove(long from, long to) @@ -252,42 +257,41 @@ bool wxTextCtrl::LoadFile(const wxString& file) { if (!wxFileExists(file)) return FALSE; - + m_fileName = file; - + Clear(); - - ifstream input((char*) (const char*) file, ios::nocreate | ios::in); - - if (!input.bad()) + + 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"))) { - struct stat stat_buf; - if (stat(file, &stat_buf) < 0) + return FALSE; + } + else + { + long len = statb.st_size; + char *text; + if (!(text = XtMalloc ((unsigned) (len + 1)))) + { + fclose (fp); return FALSE; - // This may need to be a bigger buffer than the file size suggests, - // if it's a UNIX file. Give it an extra 1000 just in case. - char *tmp_buffer = (char*)malloc((size_t)(stat_buf.st_size+1+1000)); - long no_lines = 0; - long pos = 0; - while (!input.eof() && input.peek() != EOF) + } + if (fread (text, sizeof (char), len, fp) != (size_t) len) { - input.getline(wxBuffer, 500); - int len = strlen(wxBuffer); - wxBuffer[len] = 13; - wxBuffer[len+1] = 10; - wxBuffer[len+2] = 0; - strcpy(tmp_buffer+pos, wxBuffer); - pos += strlen(wxBuffer); - no_lines++; - } - - // TODO add line - - free(tmp_buffer); - - return TRUE; + } + fclose (fp); + + text[len] = 0; + XmTextSetString (textWidget, text); + // m_textPosition = len; + XtFree (text); + m_modified = FALSE; + return TRUE; } - return FALSE; } // If file is null, try saved file name first @@ -300,14 +304,32 @@ bool wxTextCtrl::SaveFile(const wxString& file) if (theFile == "") return FALSE; m_fileName = theFile; - - ofstream output((char*) (const char*) theFile); - if (output.bad()) - return FALSE; - - // TODO get and save text - - return FALSE; + + 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) + { + // Did not write whole file + } + // 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) @@ -344,27 +366,27 @@ int wxTextCtrl::GetNumberOfLines() const char *s = XmTextGetString ((Widget) m_mainWidget); if (s) { - long i = 0; - int currentLine = 0; - bool finished = FALSE; - while (!finished) - { - int ch = s[i]; - if (ch == '\n') - { - currentLine++; - i++; - } - else if (ch == 0) - { - finished = TRUE; - } - else - i++; - } - - XtFree (s); - return currentLine; + long i = 0; + int currentLine = 0; + bool finished = FALSE; + while (!finished) + { + int ch = s[i]; + if (ch == '\n') + { + currentLine++; + i++; + } + else if (ch == 0) + { + finished = TRUE; + } + else + i++; + } + + XtFree (s); + return currentLine; } return 0; } @@ -372,11 +394,11 @@ int wxTextCtrl::GetNumberOfLines() const long wxTextCtrl::XYToPosition(long x, long y) const { /* It seems, that there is a bug in some versions of the Motif library, - so the original wxWin-Code doesn't work. */ -/* - Widget textWidget = (Widget) handle; - return (long) XmTextXYToPos (textWidget, (Position) x, (Position) y); -*/ + so the original wxWin-Code doesn't work. */ + /* + Widget textWidget = (Widget) handle; + return (long) XmTextXYToPos (textWidget, (Position) x, (Position) y); + */ /* 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; -*/ + // Verify that there are no characters in get area + if ( gptr() && gptr() < egptr() ) + { + wxError("Who's trespassing my get area?","Internal error"); + return EOF; + } + + if ( pptr() && pptr() > 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; + */ } //========================================================================= @@ -548,7 +570,7 @@ int wxTextCtrl::sync() //========================================================================= int wxTextCtrl::underflow() { - return EOF; + return EOF; } #endif @@ -593,7 +615,7 @@ wxTextCtrl& wxTextCtrl::operator<<(long i) wxTextCtrl& wxTextCtrl::operator<<(const char c) { char buf[2]; - + buf[0] = c; buf[1] = 0; WriteText(buf); @@ -602,31 +624,87 @@ wxTextCtrl& wxTextCtrl::operator<<(const char c) 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; - - if (m_tempCallbackStruct) - { - XmTextVerifyCallbackStruct *textStruct = - (XmTextVerifyCallbackStruct *) m_tempCallbackStruct; - textStruct->doit = True; - if (isascii(event.m_keyCode) && (textStruct->text->length == 1)) + // 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; + + if (m_tempCallbackStruct) { - textStruct->text->ptr[0] = ((event.m_keyCode == WXK_RETURN) ? 10 : event.m_keyCode); + XmTextVerifyCallbackStruct *textStruct = + (XmTextVerifyCallbackStruct *) m_tempCallbackStruct; + textStruct->doit = True; + if (isascii(event.m_keyCode) && (textStruct->text->length == 1)) + { + textStruct->text->ptr[0] = ((event.m_keyCode == WXK_RETURN) ? 10 : event.m_keyCode); + } } - } } -static void wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr) +void wxTextCtrl::ChangeFont(bool keepOriginalSize) +{ + wxWindow::ChangeFont(keepOriginalSize); +} + +void wxTextCtrl::ChangeBackgroundColour() +{ + wxWindow::ChangeBackgroundColour(); + + /* TODO: should scrollbars be affected? Should probably have separate + * function to change them (by default, taken from wxSystemSettings) + */ + if (m_windowStyle & wxTE_MULTILINE) + { + Widget parent = XtParent ((Widget) m_mainWidget); + Widget hsb, vsb; + + XtVaGetValues (parent, + XmNhorizontalScrollBar, &hsb, + XmNverticalScrollBar, &vsb, + NULL); + wxColour backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE); + if (hsb) + DoChangeBackgroundColour((WXWidget) hsb, backgroundColour, TRUE); + if (vsb) + DoChangeBackgroundColour((WXWidget) vsb, backgroundColour, TRUE); + + DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, TRUE); + } +} + +void wxTextCtrl::ChangeForegroundColour() { - if (!wxGetWindowFromTable(w)) - // Widget has been deleted! - return; + 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) + DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour); + if (vsb) + DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour); + */ + DoChangeForegroundColour((WXWidget) parent, m_foregroundColour); + } +} - wxTextCtrl *tw = (wxTextCtrl *) clientData; - tw->SetModified(TRUE); +static void wxTextWindowChangedProc (Widget w, XtPointer clientData, XtPointer ptr) +{ + if (!wxGetWindowFromTable(w)) + // Widget has been deleted! + return; + + wxTextCtrl *tw = (wxTextCtrl *) clientData; + tw->SetModified(TRUE); } static void @@ -634,23 +712,23 @@ wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStru { 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) { - /* _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. - */ - + /* _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; @@ -658,33 +736,33 @@ wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStru 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++; - + *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) { int i; @@ -693,71 +771,71 @@ wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStru cbs->text->ptr[i] = 0; } } - + // 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->m_inSetValue) + + if (tw->InSetValue()) return; - + if (tw->m_processedDefault) { // Can generate a command wxCommandEvent commandEvent(wxEVT_COMMAND_TEXT_UPDATED, tw->GetId()); - commandEvent.SetEventObject(tw); + commandEvent.SetEventObject(tw); tw->ProcessCommand(commandEvent); - } - + } + return; } - + // 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->m_inSetValue) + + if (tw->InSetValue()) return; if (tw->m_processedDefault) @@ -772,49 +850,49 @@ wxTextWindowModifyProc (Widget w, XtPointer clientData, XmTextVerifyCallbackStru static void wxTextWindowGainFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs) { - if (!wxGetWindowFromTable(w)) - return; - - wxTextCtrl *tw = (wxTextCtrl *) clientData; - wxFocusEvent event(wxEVT_SET_FOCUS, tw->GetId()); - event.SetEventObject(tw); - tw->GetEventHandler()->ProcessEvent(event); + if (!wxGetWindowFromTable(w)) + return; + + wxTextCtrl *tw = (wxTextCtrl *) clientData; + wxFocusEvent event(wxEVT_SET_FOCUS, tw->GetId()); + event.SetEventObject(tw); + tw->GetEventHandler()->ProcessEvent(event); } static void wxTextWindowLoseFocusProc (Widget w, XtPointer clientData, XmAnyCallbackStruct *cbs) { - if (!wxGetWindowFromTable(w)) - return; - - wxTextCtrl *tw = (wxTextCtrl *) clientData; - wxFocusEvent event(wxEVT_KILL_FOCUS, tw->GetId()); - event.SetEventObject(tw); - tw->GetEventHandler()->ProcessEvent(event); + if (!wxGetWindowFromTable(w)) + return; + + wxTextCtrl *tw = (wxTextCtrl *) clientData; + wxFocusEvent event(wxEVT_KILL_FOCUS, tw->GetId()); + event.SetEventObject(tw); + tw->GetEventHandler()->ProcessEvent(event); } static void wxTextWindowActivateProc(Widget w, XtPointer clientData, - XmAnyCallbackStruct *ptr) + XmAnyCallbackStruct *ptr) { - if (!wxGetWindowFromTable(w)) - return; - - wxTextCtrl *tw = (wxTextCtrl *) clientData; - /* - case XmCR_ACTIVATE: + if (!wxGetWindowFromTable(w)) + return; + + wxTextCtrl *tw = (wxTextCtrl *) clientData; + /* + case XmCR_ACTIVATE: type_event = wxEVENT_TYPE_TEXT_ENTER_COMMAND ; break; - default: + default: type_event = wxEVENT_TYPE_TEXT_COMMAND ; break; - } - */ - - if (tw->m_inSetValue) - return; + } + */ + + if (tw->InSetValue()) + return; - wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER); - event.SetId(tw->GetId()); - event.SetEventObject(tw); - tw->ProcessCommand(event); + wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER); + event.SetId(tw->GetId()); + event.SetEventObject(tw); + tw->ProcessCommand(event); }