added wxTextEntry::SetHint() (a.k.a. cue banner or placeholder string)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59263 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-03-02 12:25:01 +00:00
parent 231728361c
commit 63f7d5022e
21 changed files with 311 additions and 18 deletions

View File

@@ -406,6 +406,7 @@ All (GUI):
- Added support for labels for toolbar controls (Vince Harron).
- Added wxMessageDialog::SetMessage() and SetExtendedMessage().
- Added wxListCtrl::Set/GetColumnsOrder() (Yury Voronov).
- Added wxTextEntry::SetHint().
- Made wxLogWindow thread-safe (Barbara Maren Winkler).
- Added wxWindow::AlwaysShowScrollbars() (Julian Scheid).
- Added wxMouseEvent::GetClickCount() (Julian Scheid).

View File

@@ -149,6 +149,10 @@ public:
virtual void GetSelection(long *from, long *to) const;
virtual bool IsEditable() const;
virtual void SetEditable(bool editable);
private:
// implement wxTextEntry pure virtual method
virtual wxWindow *GetEditableWindow() { return this; }
};
#endif // __WX_COCOA_COMBOBOX_H__

View File

@@ -142,7 +142,7 @@ protected:
private:
// From wxTextEntry:
virtual const wxWindow *GetEditableWindow() const { return this; }
virtual wxWindow *GetEditableWindow() { return this; }
virtual GtkEditable *GetEditable() const;
virtual void EnableTextChangedEvents(bool enable)
{

View File

@@ -177,7 +177,6 @@ protected:
private:
// overridden wxTextEntry virtual methods
virtual const wxWindow *GetEditableWindow() const { return this; }
virtual GtkEditable *GetEditable() const;
virtual void EnableTextChangedEvents(bool enable);

View File

@@ -54,10 +54,6 @@ public:
void SendMaxLenEvent();
private:
// implement this to return the associated window, it will be used for
// event generation
virtual const wxWindow *GetEditableWindow() const = 0;
// implement this to return the associated GtkEntry or another widget
// implementing GtkEditable
virtual GtkEditable *GetEditable() const = 0;

View File

@@ -169,6 +169,9 @@ protected:
virtual wxSize DoGetBestSize() const;
// implement wxTextEntry pure virtual method
virtual wxWindow *GetEditableWindow() { return this; }
// Widgets that use the style->base colour for the BG colour should
// override this and return true.
virtual bool UseGTKStyleBase() const { return true; }

View File

@@ -107,6 +107,8 @@ protected:
int width, int height,
int sizeFlags = wxSIZE_AUTO);
// implement wxTextEntry pure virtual methods
virtual wxWindow *GetEditableWindow() { return this; }
virtual WXWidget GetTextWidget() const;
private:

View File

@@ -116,6 +116,11 @@ public:
virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const;
#if wxUSE_UXTHEME
// override wxTextEntry method to work around Windows bug
virtual bool SetHint(const wxString& hint);
#endif // wxUSE_UXTHEME
protected:
#if wxUSE_TOOLTIPS
virtual void DoSetToolTip(wxToolTip *tip);
@@ -136,8 +141,9 @@ protected:
}
private:
// this is the overridden wxTextEntry method which should only be called
// when we do have an edit control so it asserts if this is not the case
// there are the overridden wxTextEntry methods which should only be called
// when we do have an edit control so they assert if this is not the case
virtual wxWindow *GetEditableWindow();
virtual WXHWND GetEditHWND() const;
// common part of all ctors

View File

@@ -54,6 +54,11 @@ public:
virtual void SetMaxLength(unsigned long len);
#if wxUSE_UXTHEME
virtual bool SetHint(const wxString& hint);
virtual wxString GetHint() const;
#endif // wxUSE_UXTHEME
protected:
// this is really a hook for multiline text controls as the single line
// ones don't need to ever scroll to show the selection but having it here

View File

@@ -122,8 +122,8 @@ class WXDLLIMPEXP_CORE wxComboBox : public wxChoice,
);
private:
// implement wxTextEntry pure virtual: it implements all the operations for
// the simple EDIT controls
// implement wxTextEntry pure virtual methods
virtual wxWindow *GetEditableWindow() { return this; }
virtual WXHWND GetEditHWND() const { return m_hWnd; }
DECLARE_DYNAMIC_CLASS(wxComboBox)

View File

@@ -154,6 +154,9 @@ protected:
virtual void SetClientDataType(wxClientDataType clientDataItemsType);
// implement wxTextEntry pure virtual method
virtual wxWindow *GetEditableWindow() { return this; }
// the subcontrols
wxComboBoxText* m_text;
wxComboBoxChoice* m_choice;

View File

@@ -771,16 +771,13 @@ public:
static const wxArrayString& GetAvailableFontNames();
static void ClearAvailableFontNames();
// FIXME: this does not work, it allows this code to compile but will fail
// during run-time
#ifdef __WXMSW__
virtual WXHWND GetEditHWND() const { return GetHWND(); }
#endif
#ifdef __WXGTK__
// implement this to return the associated window, it will be used for
// event generation
virtual const wxWindow *GetEditableWindow() const { return NULL; }
// implement this to return the associated GtkEntry or another widget
// implementing GtkEditable
virtual const wxWindow *GetEditableWindow() { return this; }
virtual GtkEditable *GetEditable() const { return NULL; }
#endif

View File

@@ -64,6 +64,10 @@ public:
virtual void ShowCancelButton( bool show ) = 0;
virtual bool IsCancelButtonVisible() const = 0;
private:
// implement wxTextEntry pure virtual method
virtual wxWindow *GetEditableWindow() { return this; }
};

View File

@@ -692,6 +692,9 @@ protected:
virtual bool DoLoadFile(const wxString& file, int fileType);
virtual bool DoSaveFile(const wxString& file, int fileType);
private:
// implement the wxTextEntry pure virtual method
virtual wxWindow *GetEditableWindow() { return this; }
wxDECLARE_NO_COPY_CLASS(wxTextCtrlBase);
DECLARE_ABSTRACT_CLASS(wxTextCtrlBase)

View File

@@ -16,6 +16,7 @@
typedef long wxTextPos;
class WXDLLIMPEXP_FWD_BASE wxArrayString;
class WXDLLIMPEXP_FWD_CORE wxTextEntryHintData;
// ----------------------------------------------------------------------------
// wxTextEntryBase
@@ -24,8 +25,8 @@ class WXDLLIMPEXP_FWD_BASE wxArrayString;
class WXDLLIMPEXP_CORE wxTextEntryBase
{
public:
wxTextEntryBase() { m_eventsBlock = 0; }
virtual ~wxTextEntryBase() { }
wxTextEntryBase() { m_eventsBlock = 0; m_hintData = NULL; }
virtual ~wxTextEntryBase();
// accessing the value
@@ -129,6 +130,17 @@ public:
virtual void SetMaxLength(unsigned long WXUNUSED(len)) { }
// hints
// -----
// hint is the (usually greyed out) text shown in the control as long as
// it's empty and doesn't have focus, it is typically used in controls used
// for searching to let the user know what is supposed to be entered there
virtual bool SetHint(const wxString& hint);
virtual wxString GetHint() const;
protected:
// flags for DoSetValue(): common part of SetValue() and ChangeValue() and
// also used to implement WriteText() in wxMSW
@@ -172,6 +184,11 @@ protected:
bool EventsAllowed() const { return m_eventsBlock == 0; }
private:
// override this to return the associated window, it will be used for event
// generation and also by generic hints implementation
virtual wxWindow *GetEditableWindow() = 0;
// suppress or resume the text changed events generation: don't use these
// functions directly, use EventsSuppressor class above instead
void SuppressTextChangedEvents()
@@ -196,6 +213,9 @@ private:
// if this counter is non-null, events are blocked
unsigned m_eventsBlock;
// hint-related stuff, only allocated if/when SetHint() is used
wxTextEntryHintData *m_hintData;
};
#ifdef __WXUNIVERSAL__

View File

@@ -166,6 +166,9 @@ protected:
wxListBox *GetLBox() const { return m_lbox; }
private:
// implement wxTextEntry pure virtual method
virtual wxWindow *GetEditableWindow() { return this; }
// the popup listbox
wxListBox *m_lbox;

View File

@@ -351,6 +351,36 @@ public:
*/
virtual void SelectAll();
/**
Sets a hint shown in an empty unfocused text control.
The hints are usually used to indicate to the user what is supposed to
be entered into the given entry field, e.g. a common use of them is to
show an explanation of what can be entered in a wxSearchCtrl.
The hint is shown (usually greyed out) for an empty control until it
gets focus and is shown again if the control loses it and remains
empty. It won't be shown once the control has a non-empty value,
although it will be shown again if the control contents is cleared.
Because of this, it generally only makes sense to use hints with the
controls which are initially empty.
Notice that hints are known as <em>cue banners</em> under MSW or
<em>placeholder strings</em> under OS X.
@since 2.9.0
*/
virtual void SetHint(const wxString& hint);
/**
Returns the current hint string.
See SetHint() for more information about hints.
@since 2.9.0
*/
virtual wxString GetHint() const;
/**
Sets the new text control value.

View File

@@ -97,6 +97,8 @@ enum
TextEntry_DisableAutoComplete = TextEntry_Begin,
TextEntry_AutoCompleteFixed,
TextEntry_AutoCompleteFilenames,
TextEntry_SetHint,
TextEntry_End
};
@@ -164,10 +166,13 @@ protected:
void OnToggleGlobalBusyCursor(wxCommandEvent& event);
void OnToggleBusyCursor(wxCommandEvent& event);
// wxTextEntry-specific tests
void OnDisableAutoComplete(wxCommandEvent& event);
void OnAutoCompleteFixed(wxCommandEvent& event);
void OnAutoCompleteFilenames(wxCommandEvent& event);
void OnSetHint(wxCommandEvent& event);
void OnUpdateTextUI(wxUpdateUIEvent& event)
{
event.Enable( CurrentPage()->GetTextEntry() != NULL );
@@ -308,6 +313,8 @@ BEGIN_EVENT_TABLE(WidgetsFrame, wxFrame)
EVT_MENU(TextEntry_AutoCompleteFixed, WidgetsFrame::OnAutoCompleteFixed)
EVT_MENU(TextEntry_AutoCompleteFilenames, WidgetsFrame::OnAutoCompleteFilenames)
EVT_MENU(TextEntry_SetHint, WidgetsFrame::OnSetHint)
EVT_UPDATE_UI_RANGE(TextEntry_Begin, TextEntry_End - 1,
WidgetsFrame::OnUpdateTextUI)
@@ -419,6 +426,8 @@ WidgetsFrame::WidgetsFrame(const wxString& title)
_T("Fixed-&list auto-completion"));
menuTextEntry->AppendRadioItem(TextEntry_AutoCompleteFilenames,
_T("&Files names auto-completion"));
menuTextEntry->AppendSeparator();
menuTextEntry->Append(TextEntry_SetHint, "Set help &hint");
mbar->Append(menuTextEntry, _T("&Text"));
@@ -948,6 +957,25 @@ void WidgetsFrame::OnAutoCompleteFilenames(wxCommandEvent& WXUNUSED(event))
wxLogMessage("AutoCompleteFileNames() failed.");
}
void WidgetsFrame::OnSetHint(wxCommandEvent& WXUNUSED(event))
{
wxTextEntryBase *entry = CurrentPage()->GetTextEntry();
wxCHECK_RET( entry, "menu item should be disabled" );
static wxString s_hint("Type here");
wxString
hint = wxGetTextFromUser("Text hint:", "Widgets sample", s_hint, this);
if ( hint.empty() )
return;
s_hint = hint;
if ( entry->SetHint(hint) )
wxLogMessage("Set hint to \"%s\".", hint);
else
wxLogMessage("Text hints not supported.");
}
#endif // wxUSE_MENUS
// ----------------------------------------------------------------------------

View File

@@ -33,10 +33,98 @@
#include "wx/textentry.h"
#include "wx/clipbrd.h"
// ----------------------------------------------------------------------------
// wxTextEntryHintData
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_CORE wxTextEntryHintData wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS
{
public:
wxTextEntryHintData(wxTextEntryBase *entry, wxWindow *win)
: m_entry(entry),
m_win(win)
{
wxBIND_OR_CONNECT_HACK(win, wxEVT_SET_FOCUS, wxFocusEventHandler,
wxTextEntryHintData::OnSetFocus, this);
wxBIND_OR_CONNECT_HACK(win, wxEVT_KILL_FOCUS, wxFocusEventHandler,
wxTextEntryHintData::OnKillFocus, this);
}
// default dtor is ok
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
}
const wxString& GetHintString() const { return m_hint; }
private:
// are we showing the hint right now?
bool ShowsHint() const
{
return m_entry->GetValue() == m_hint;
}
void OnSetFocus(wxFocusEvent& event)
{
// hide the hint if we were showing it
if ( ShowsHint() )
{
// Clear() would send an event which we don't want, so do it like
// this
m_entry->ChangeValue(wxString());
m_win->SetForegroundColour(m_colFg);
}
event.Skip();
}
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);
m_colFg = m_win->GetForegroundColour();
m_win->SetForegroundColour(*wxLIGHT_GREY);
}
event.Skip();
}
wxTextEntryBase * const m_entry;
wxWindow * const m_win;
wxColour m_colFg;
wxString m_hint;
wxDECLARE_NO_COPY_CLASS(wxTextEntryHintData);
};
// ============================================================================
// wxTextEntryBase implementation
// ============================================================================
wxTextEntryBase::~wxTextEntryBase()
{
delete m_hintData;
}
// ----------------------------------------------------------------------------
// text operations
// ----------------------------------------------------------------------------
wxString wxTextEntryBase::GetRange(long from, long to) const
{
wxString sel;
@@ -77,6 +165,10 @@ void wxTextEntryBase::Replace(long from, long to, const wxString& value)
WriteText(value);
}
// ----------------------------------------------------------------------------
// selection
// ----------------------------------------------------------------------------
bool wxTextEntryBase::HasSelection() const
{
long from, to;
@@ -101,6 +193,10 @@ wxString wxTextEntryBase::GetStringSelection() const
return GetRange(from, to);
}
// ----------------------------------------------------------------------------
// clipboard
// ----------------------------------------------------------------------------
bool wxTextEntryBase::CanCopy() const
{
return HasSelection();
@@ -131,4 +227,23 @@ bool wxTextEntryBase::CanPaste() const
return false;
}
// ----------------------------------------------------------------------------
// hints support
// ----------------------------------------------------------------------------
bool wxTextEntryBase::SetHint(const wxString& hint)
{
if ( !m_hintData )
m_hintData = new wxTextEntryHintData(this, GetEditableWindow());
m_hintData->SetHintString(hint);
return true;
}
wxString wxTextEntryBase::GetHint() const
{
return m_hintData ? m_hintData->GetHintString() : wxString();
}
#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX

View File

@@ -42,6 +42,10 @@
#include "wx/wupdlock.h"
#include "wx/msw/private.h"
#if wxUSE_UXTHEME
#include "wx/msw/uxtheme.h"
#endif
#if wxUSE_TOOLTIPS
#include "wx/tooltip.h"
#endif // wxUSE_TOOLTIPS
@@ -445,6 +449,14 @@ WXHWND wxComboBox::GetEditHWND() const
return hWndEdit;
}
wxWindow *wxComboBox::GetEditableWindow()
{
wxASSERT_MSG( !HasFlag(wxCB_READONLY),
_T("read-only combobox doesn't have any edit control") );
return this;
}
// ----------------------------------------------------------------------------
// wxComboBox creation
// ----------------------------------------------------------------------------
@@ -665,4 +677,22 @@ void wxComboBox::DoSetToolTip(wxToolTip *tip)
#endif // wxUSE_TOOLTIPS
#if wxUSE_UXTHEME
bool wxComboBox::SetHint(const wxString& hintOrig)
{
wxString hint(hintOrig);
if ( wxUxThemeEngine::GetIfActive() )
{
// under XP (but not Vista) there is a bug in cue banners
// implementation for combobox edit control: the first character is
// partially chopped off, so prepend a space to make it fully visible
hint.insert(0, " ");
}
return wxTextEntry::SetHint(hint);
}
#endif // wxUSE_UXTHEME
#endif // wxUSE_COMBOBOX

View File

@@ -35,6 +35,10 @@
#include "wx/msw/private.h"
#if wxUSE_UXTHEME
#include "wx/msw/uxtheme.h"
#endif
#define GetEditHwnd() ((HWND)(GetEditHWND()))
// ----------------------------------------------------------------------------
@@ -416,4 +420,44 @@ void wxTextEntry::SetMaxLength(unsigned long len)
::SendMessage(GetEditHwnd(), EM_LIMITTEXT, len, 0);
}
// ----------------------------------------------------------------------------
// hints
// ----------------------------------------------------------------------------
#if wxUSE_UXTHEME
#ifndef EM_SETCUEBANNER
#define EM_SETCUEBANNER 0x1501
#define EM_GETCUEBANNER 0x1502
#endif
bool wxTextEntry::SetHint(const wxString& hint)
{
if ( wxUxThemeEngine::GetIfActive() )
{
// notice that this message always works with Unicode strings
if ( ::SendMessage(GetEditHwnd(), EM_SETCUEBANNER,
0, (LPARAM)(const wchar_t *)hint.wc_str()) )
return true;
}
return wxTextEntryBase::SetHint(hint);
}
wxString wxTextEntry::GetHint() const
{
if ( wxUxThemeEngine::GetIfActive() )
{
wchar_t buf[256];
if ( ::SendMessage(GetEditHwnd(), EM_GETCUEBANNER,
(WPARAM)buf, WXSIZEOF(buf)) )
return buf;
}
return wxTextEntryBase::GetHint();
}
#endif // wxUSE_UXTHEME
#endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX