X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/63f7d5022e786be61c0226314dac98739f49a426..534f87c6c442aa2710a44352bd26d215fec1714b:/src/common/textentrycmn.cpp diff --git a/src/common/textentrycmn.cpp b/src/common/textentrycmn.cpp index a0e31da051..b1480e322e 100644 --- a/src/common/textentrycmn.cpp +++ b/src/common/textentrycmn.cpp @@ -3,7 +3,6 @@ // Purpose: wxTextEntryBase implementation // Author: Vadim Zeitlin // Created: 2007-09-26 -// RCS-ID: $Id$ // Copyright: (c) 2007 Vadim Zeitlin // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// @@ -31,6 +30,7 @@ #endif //WX_PRECOMP #include "wx/textentry.h" +#include "wx/textcompleter.h" #include "wx/clipbrd.h" // ---------------------------------------------------------------------------- @@ -42,46 +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); + wxBIND_OR_CONNECT_HACK(win, wxEVT_TEXT, + wxCommandEventHandler, + wxTextEntryHintData::OnTextChanged, this); } // default dtor is ok + // 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 ( 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: - // are we showing the hint right now? - bool ShowsHint() const + // 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() { - return m_entry->GetValue() == m_hint; + // 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); } - void OnSetFocus(wxFocusEvent& event) + // 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 ( 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_entry->DoSetValue(wxString(), wxTextEntryBase::SetValue_NoEvent); } event.Skip(); @@ -89,26 +133,40 @@ 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(); + } + + 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; + // the original foreground colour of m_win before we changed it wxColour m_colFg; + // The hint passed to wxTextEntry::SetHint(), never empty. wxString m_hint; + // The real text of the window. + wxString m_text; + + wxDECLARE_NO_COPY_CLASS(wxTextEntryHintData); }; @@ -122,9 +180,14 @@ wxTextEntryBase::~wxTextEntryBase() } // ---------------------------------------------------------------------------- -// text operations +// text accessors // ---------------------------------------------------------------------------- +wxString wxTextEntryBase::GetValue() const +{ + return m_hintData ? m_hintData->GetText() : DoGetValue(); +} + wxString wxTextEntryBase::GetRange(long from, long to) const { wxString sel; @@ -138,6 +201,20 @@ wxString wxTextEntryBase::GetRange(long from, long to) const return sel; } +// ---------------------------------------------------------------------------- +// 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(); @@ -146,12 +223,22 @@ void wxTextEntryBase::AppendText(const wxString& text) void wxTextEntryBase::DoSetValue(const wxString& value, int flags) { - EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent)); + if ( value != DoGetValue() ) + { + EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent)); - SelectAll(); - WriteText(value); + SelectAll(); + WriteText(value); - SetInsertionPoint(0); + SetInsertionPoint(0); + } + else // Same value, no need to do anything. + { + // Except that we still need to generate the event for consistency with + // the normal case when the text does change. + if ( flags & SetValue_SendEvent ) + SendTextUpdatedEvent(GetEditableWindow()); + } } void wxTextEntryBase::Replace(long from, long to, const wxString& value) @@ -233,10 +320,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; } @@ -246,4 +343,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_TEXT, 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