// Copyright (c) 2012, Thomas Goyne // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ #include // Defined in osx_utils.mm void SetPlaceholderText(wxWindow *window, wxString const& placeholder); /// @class Placeholder /// @brief A wrapper around a control to add placeholder text /// /// This control wraps a base control to add default greyed-out placeholder /// text describing the control when the value would otherwise be empty, which /// is removed when the control is focused to begin typing in it, and restored /// when the control loses focus and the value is empty template class Placeholder final : public BaseCtrl { wxString placeholder; ///< Placeholder string bool is_placeholder; ///< Should the value be cleared on focus? /// Wrapper around Create to make it possible to override it for specific /// base classes inline void Create(wxWindow *parent, wxSize const& size, long style) { BaseCtrl::Create(parent, -1, placeholder, wxDefaultPosition, size, style); } #ifndef __WXOSX__ /// Focus gained event handler void OnSetFocus(wxFocusEvent& evt) { evt.Skip(); if (is_placeholder) { BaseCtrl::ChangeValue(""); BaseCtrl::SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); } } /// Focus lost event handler void OnKillFocus(wxFocusEvent& evt) { evt.Skip(); ChangeValue(BaseCtrl::GetValue()); } public: /// Constructor /// @param parent Parent window /// @param placeholder Placeholder string /// @param size Control size /// @param style Style flags to pass to the base control /// @param tooltip Tooltip string Placeholder(wxWindow *parent, wxString const& placeholder, wxSize const& size, long style, wxString const& tooltip) : placeholder(placeholder) , is_placeholder(true) { Create(parent, size, style); BaseCtrl::SetToolTip(tooltip); BaseCtrl::SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); BaseCtrl::Bind(wxEVT_SET_FOCUS, &Placeholder::OnSetFocus, this); BaseCtrl::Bind(wxEVT_KILL_FOCUS, &Placeholder::OnKillFocus, this); } /// @brief Change the value of the control without triggering events /// @param new_value New value of the control /// /// If new_value is empty, the control will switch to placeholder mode void ChangeValue(wxString new_value) { if (new_value.empty() && !this->HasFocus()) { is_placeholder = true; new_value = placeholder; BaseCtrl::SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT)); } else { is_placeholder = false; BaseCtrl::SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); } // This check should be pointless, but wxGTK is awesome and generates // change events in wxComboBox::ChangeValue if (new_value != BaseCtrl::GetValue()) BaseCtrl::ChangeValue(new_value); } /// Override GetValue to return empty when in placeholder mode rather than the placeholder text wxString GetValue() const { if (is_placeholder && !this->HasFocus()) return ""; return BaseCtrl::GetValue(); } #else public: Placeholder(wxWindow *parent, wxString const& placeholder, wxSize const& size, long style, wxString const& tooltip) : placeholder(placeholder) { Create(parent, size, style); BaseCtrl::SetToolTip(tooltip); SetPlaceholderText(this, placeholder); } #endif }; template<> inline void Placeholder::Create(wxWindow *parent, wxSize const& size, long style) { wxComboBox::Create(parent, -1, "", wxDefaultPosition, size, 0, nullptr, style); }