X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/501358073ba90c87257dd2c3a48a429f9c004f19..2e49a8074e7c9179b642852ff00ed8fdf0768bb1:/src/common/textentrycmn.cpp?ds=sidebyside diff --git a/src/common/textentrycmn.cpp b/src/common/textentrycmn.cpp index 9dc8ca9461..51020ddcb4 100644 --- a/src/common/textentrycmn.cpp +++ b/src/common/textentrycmn.cpp @@ -42,48 +42,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() { - // hide the hint if we were showing it - if ( m_showsHint ) + // 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() + { + 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 +133,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 +160,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 +185,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 +205,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 +310,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; }