X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/135b23b266fffceb26b29d832c7d25db99038d0d..ab7049776d45e622f621dd06216a4c1a1ad34b15:/src/common/textentrycmn.cpp diff --git a/src/common/textentrycmn.cpp b/src/common/textentrycmn.cpp index cb81ea0779..5b08496492 100644 --- a/src/common/textentrycmn.cpp +++ b/src/common/textentrycmn.cpp @@ -31,6 +31,7 @@ #endif //WX_PRECOMP #include "wx/textentry.h" +#include "wx/textcompleter.h" #include "wx/clipbrd.h" // ---------------------------------------------------------------------------- @@ -42,48 +43,90 @@ class WXDLLIMPEXP_CORE wxTextEntryHintData wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLAS public: wxTextEntryHintData(wxTextEntryBase *entry, wxWindow *win) : m_entry(entry), - m_win(win) + m_win(win), + m_text(m_entry->GetValue()) { wxBIND_OR_CONNECT_HACK(win, wxEVT_SET_FOCUS, wxFocusEventHandler, wxTextEntryHintData::OnSetFocus, this); wxBIND_OR_CONNECT_HACK(win, wxEVT_KILL_FOCUS, wxFocusEventHandler, wxTextEntryHintData::OnKillFocus, this); - - // we don't have any hint yet - m_showsHint = false; + wxBIND_OR_CONNECT_HACK(win, wxEVT_COMMAND_TEXT_UPDATED, + wxCommandEventHandler, + wxTextEntryHintData::OnTextChanged, this); } // default dtor is ok - // are we showing the hint right now? - bool ShowsHint() const { return m_showsHint; } + // Get the real text of the control such as it was before we replaced it + // with the hint. + const wxString& GetText() const { return m_text; } + // Set the hint to show, shouldn't be empty normally. + // + // This should be called after creating a new wxTextEntryHintData object + // and may be called more times in the future. void SetHintString(const wxString& hint) { m_hint = hint; - if ( m_showsHint ) - { - // update it immediately - m_entry->ChangeValue(hint); - } - //else: the new hint will be shown later + if ( !m_win->HasFocus() ) + ShowHintIfAppropriate(); + //else: The new hint will be shown later when we lose focus. } const wxString& GetHintString() const { return m_hint; } + // This is called whenever the text control contents changes. + // + // We call it ourselves when this change generates an event but it's also + // necessary to call it explicitly from wxTextEntry::ChangeValue() as it, + // by design, does not generate any events. + void HandleTextUpdate(const wxString& text) + { + m_text = text; + + // If we're called because of a call to Set or ChangeValue(), the + // control may still have the hint text colour, reset it in this case. + RestoreTextColourIfNecessary(); + } + private: - void OnSetFocus(wxFocusEvent& event) + // Show the hint in the window if we should do it, i.e. if the window + // doesn't have any text of its own. + void ShowHintIfAppropriate() + { + // Never overwrite existing window text. + if ( !m_text.empty() ) + return; + + // Save the old text colour and set a more inconspicuous one for the + // hint. + m_colFg = m_win->GetForegroundColour(); + m_win->SetForegroundColour(*wxLIGHT_GREY); + + m_entry->DoSetValue(m_hint, wxTextEntryBase::SetValue_NoEvent); + } + + // Restore the original text colour if we had changed it to show the hint + // and not restored it yet. + void RestoreTextColourIfNecessary() { - // hide the hint if we were showing it - if ( m_showsHint ) + if ( m_colFg.IsOk() ) { - // Clear() would send an event which we don't want, so do it like - // this - m_entry->ChangeValue(wxString()); m_win->SetForegroundColour(m_colFg); + m_colFg = wxColour(); + } + } + + void OnSetFocus(wxFocusEvent& event) + { + // If we had been showing the hint before, remove it now and restore + // the normal colour. + if ( m_text.empty() ) + { + RestoreTextColourIfNecessary(); - m_showsHint = false; + m_entry->DoSetValue(wxString(), wxTextEntryBase::SetValue_NoEvent); } event.Skip(); @@ -91,20 +134,26 @@ private: void OnKillFocus(wxFocusEvent& event) { - // restore the hint if the user didn't do anything in the control - if ( m_entry->IsEmpty() ) - { - m_entry->ChangeValue(m_hint); + // Restore the hint if the user didn't enter anything. + ShowHintIfAppropriate(); - m_colFg = m_win->GetForegroundColour(); - m_win->SetForegroundColour(*wxLIGHT_GREY); + event.Skip(); + } - m_showsHint = true; - } + void OnTextChanged(wxCommandEvent& event) + { + // Update the stored window text. + // + // Notice that we can't use GetValue() nor wxCommandEvent::GetString() + // which uses it internally because this would just forward back to us + // so go directly to the private method which returns the real control + // contents. + HandleTextUpdate(m_entry->DoGetValue()); event.Skip(); } + // the text control we're associated with (as its interface and its window) wxTextEntryBase * const m_entry; wxWindow * const m_win; @@ -112,12 +161,12 @@ private: // the original foreground colour of m_win before we changed it wxColour m_colFg; - // the hint passed to wxTextEntry::SetHint() + // The hint passed to wxTextEntry::SetHint(), never empty. wxString m_hint; - // true if we're currently showing it, for this we must be empty and not - // have focus - bool m_showsHint; + // The real text of the window. + wxString m_text; + wxDECLARE_NO_COPY_CLASS(wxTextEntryHintData); }; @@ -137,7 +186,7 @@ wxTextEntryBase::~wxTextEntryBase() wxString wxTextEntryBase::GetValue() const { - return m_hintData && m_hintData->ShowsHint() ? wxString() : DoGetValue(); + return m_hintData ? m_hintData->GetText() : DoGetValue(); } wxString wxTextEntryBase::GetRange(long from, long to) const @@ -157,6 +206,16 @@ wxString wxTextEntryBase::GetRange(long from, long to) const // text operations // ---------------------------------------------------------------------------- +void wxTextEntryBase::ChangeValue(const wxString& value) +{ + DoSetValue(value, SetValue_NoEvent); + + // As we didn't generate any events for wxTextEntryHintData to catch, + // notify it explicitly about our changed contents. + if ( m_hintData ) + m_hintData->HandleTextUpdate(value); +} + void wxTextEntryBase::AppendText(const wxString& text) { SetInsertionPointEnd(); @@ -252,10 +311,20 @@ bool wxTextEntryBase::CanPaste() const bool wxTextEntryBase::SetHint(const wxString& hint) { - if ( !m_hintData ) - m_hintData = new wxTextEntryHintData(this, GetEditableWindow()); + if ( !hint.empty() ) + { + if ( !m_hintData ) + m_hintData = new wxTextEntryHintData(this, GetEditableWindow()); - m_hintData->SetHintString(hint); + m_hintData->SetHintString(hint); + } + else if ( m_hintData ) + { + // Setting empty hint removes any currently set one. + delete m_hintData; + m_hintData = NULL; + } + //else: Setting empty hint when we don't have any doesn't do anything. return true; } @@ -265,4 +334,74 @@ wxString wxTextEntryBase::GetHint() const return m_hintData ? m_hintData->GetHintString() : wxString(); } +// ---------------------------------------------------------------------------- +// margins support +// ---------------------------------------------------------------------------- + +bool wxTextEntryBase::DoSetMargins(const wxPoint& WXUNUSED(pt)) +{ + return false; +} + +wxPoint wxTextEntryBase::DoGetMargins() const +{ + return wxPoint(-1, -1); +} + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +/* static */ +bool wxTextEntryBase::SendTextUpdatedEvent(wxWindow *win) +{ + wxCHECK_MSG( win, false, "can't send an event without a window" ); + + wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, win->GetId()); + + // do not do this as it could be very inefficient if the text control + // contains a lot of text and we're not using ref-counted wxString + // implementation -- instead, event.GetString() will query the control for + // its current text if needed + //event.SetString(win->GetValue()); + + event.SetEventObject(win); + return win->HandleWindowEvent(event); +} + +// ---------------------------------------------------------------------------- +// auto-completion stubs +// ---------------------------------------------------------------------------- + +wxTextCompleter::~wxTextCompleter() +{ +} + +bool wxTextCompleterSimple::Start(const wxString& prefix) +{ + m_index = 0; + m_completions.clear(); + GetCompletions(prefix, m_completions); + + return !m_completions.empty(); +} + +wxString wxTextCompleterSimple::GetNext() +{ + if ( m_index == m_completions.size() ) + return wxString(); + + return m_completions[m_index++]; +} + +bool wxTextEntryBase::DoAutoCompleteCustom(wxTextCompleter *completer) +{ + // We don't do anything here but we still need to delete the completer for + // consistency with the ports that do implement this method and take + // ownership of the pointer. + delete completer; + + return false; +} + #endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX