Factor out the placeholder text behavior from SubsEditBox and make it work better
Handle switching from placeholder/normal mode when the value is changed externally (such as from the active line changing) in addition to on focus/blur, and improve behavior when the user sets the text to the placeholder text. Originally committed to SVN as r6321.
This commit is contained in:
parent
1ce9b0d31b
commit
4675dbb29d
4 changed files with 124 additions and 49 deletions
|
@ -633,6 +633,10 @@
|
||||||
RelativePath="..\..\src\help_button.h"
|
RelativePath="..\..\src\help_button.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\placeholder_ctrl.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\src\scintilla_text_ctrl.cpp"
|
RelativePath="..\..\src\scintilla_text_ctrl.cpp"
|
||||||
>
|
>
|
||||||
|
|
104
aegisub/src/placeholder_ctrl.h
Normal file
104
aegisub/src/placeholder_ctrl.h
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
|
//
|
||||||
|
// 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/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file placeholder_ctrl.h
|
||||||
|
/// @ingroup custom_control
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <wx/settings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @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 BaseCtrl>
|
||||||
|
class Placeholder : 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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()) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> inline void Placeholder<wxComboBox>::Create(wxWindow *parent, wxSize const& size, long style) {
|
||||||
|
wxComboBox::Create(parent, -1, "", wxDefaultPosition, size, 0, 0, style);
|
||||||
|
}
|
|
@ -63,6 +63,7 @@
|
||||||
#include "include/aegisub/hotkey.h"
|
#include "include/aegisub/hotkey.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "placeholder_ctrl.h"
|
||||||
#include "subs_edit_ctrl.h"
|
#include "subs_edit_ctrl.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "timeedit_ctrl.h"
|
#include "timeedit_ctrl.h"
|
||||||
|
@ -113,34 +114,6 @@ static T get_value(AssDialogue const& line, int blockn, T initial, wxString tag,
|
||||||
return initial;
|
return initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Control>
|
|
||||||
struct FocusHandler : std::unary_function<wxFocusEvent &, void> {
|
|
||||||
wxString value;
|
|
||||||
wxString alt;
|
|
||||||
wxColor color;
|
|
||||||
Control *control;
|
|
||||||
void operator()(wxFocusEvent &event) const {
|
|
||||||
event.Skip();
|
|
||||||
|
|
||||||
if (control->GetValue() == alt) {
|
|
||||||
control->Freeze();
|
|
||||||
control->ChangeValue(value);
|
|
||||||
control->SetForegroundColour(color);
|
|
||||||
control->Thaw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Event, class T>
|
|
||||||
void bind_focus_handler(T *control, Event event, wxString value, wxString alt, wxColor color) {
|
|
||||||
FocusHandler<T> handler;
|
|
||||||
handler.value = value;
|
|
||||||
handler.alt = alt;
|
|
||||||
handler.color = color;
|
|
||||||
handler.control = control;
|
|
||||||
control->Bind(event, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the block index in the text of the position
|
/// Get the block index in the text of the position
|
||||||
int block_at_pos(wxString const& text, int pos) {
|
int block_at_pos(wxString const& text, int pos) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
@ -182,10 +155,14 @@ SubsEditBox::SubsEditBox(wxWindow *parent, agi::Context *context)
|
||||||
TopSizer->Add(CommentBox, 0, wxRIGHT | wxALIGN_CENTER, 5);
|
TopSizer->Add(CommentBox, 0, wxRIGHT | wxALIGN_CENTER, 5);
|
||||||
|
|
||||||
StyleBox = MakeComboBox("Default", wxCB_READONLY, &SubsEditBox::OnStyleChange, _("Style for this line."));
|
StyleBox = MakeComboBox("Default", wxCB_READONLY, &SubsEditBox::OnStyleChange, _("Style for this line."));
|
||||||
ActorBox = MakeComboBox("Actor", wxCB_DROPDOWN, &SubsEditBox::OnActorChange, _("Actor name for this speech. This is only for reference, and is mainly useless."));
|
|
||||||
|
|
||||||
Effect = new wxTextCtrl(this,-1,"",wxDefaultPosition,wxSize(80,-1),wxTE_PROCESS_ENTER);
|
ActorBox = new Placeholder<wxComboBox>(this, "Actor", wxSize(110, -1), wxCB_DROPDOWN | wxTE_PROCESS_ENTER, _("Actor name for this speech. This is only for reference, and is mainly useless."));
|
||||||
Effect->SetToolTip(_("Effect for this line. This can be used to store extra information for karaoke scripts, or for the effects supported by the renderer."));
|
Bind(wxEVT_COMMAND_TEXT_UPDATED, &SubsEditBox::OnActorChange, this, ActorBox->GetId());
|
||||||
|
Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &SubsEditBox::OnActorChange, this, ActorBox->GetId());
|
||||||
|
TopSizer->Add(ActorBox, wxSizerFlags(2).Center().Border(wxRIGHT));
|
||||||
|
|
||||||
|
Effect = new Placeholder<wxTextCtrl>(this, "Effect", wxSize(80,-1), wxTE_PROCESS_ENTER, _("Effect for this line. This can be used to store extra information for karaoke scripts, or for the effects supported by the renderer."));
|
||||||
|
Bind(wxEVT_COMMAND_TEXT_UPDATED, &SubsEditBox::OnEffectChange, this, Effect->GetId());
|
||||||
TopSizer->Add(Effect, 3, wxALIGN_CENTER, 5);
|
TopSizer->Add(Effect, 3, wxALIGN_CENTER, 5);
|
||||||
|
|
||||||
// Middle controls
|
// Middle controls
|
||||||
|
@ -243,24 +220,11 @@ SubsEditBox::SubsEditBox(wxWindow *parent, agi::Context *context)
|
||||||
|
|
||||||
SetSizerAndFit(MainSizer);
|
SetSizerAndFit(MainSizer);
|
||||||
|
|
||||||
wxColour text = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
|
||||||
wxColour grey = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
|
|
||||||
|
|
||||||
// Setup placeholders for effect and actor boxes
|
|
||||||
bind_focus_handler(Effect, wxEVT_SET_FOCUS, "", "Effect", text);
|
|
||||||
bind_focus_handler(Effect, wxEVT_KILL_FOCUS, "Effect", "", grey);
|
|
||||||
Effect->SetForegroundColour(grey);
|
|
||||||
|
|
||||||
bind_focus_handler(ActorBox, wxEVT_SET_FOCUS, "", "Actor", text);
|
|
||||||
bind_focus_handler(ActorBox, wxEVT_KILL_FOCUS, "Actor", "", grey);
|
|
||||||
ActorBox->SetForegroundColour(grey);
|
|
||||||
|
|
||||||
TextEdit->Bind(wxEVT_STC_MODIFIED, &SubsEditBox::OnChange, this);
|
TextEdit->Bind(wxEVT_STC_MODIFIED, &SubsEditBox::OnChange, this);
|
||||||
TextEdit->SetModEventMask(wxSTC_MOD_INSERTTEXT | wxSTC_MOD_DELETETEXT);
|
TextEdit->SetModEventMask(wxSTC_MOD_INSERTTEXT | wxSTC_MOD_DELETETEXT);
|
||||||
|
|
||||||
Bind(wxEVT_COMMAND_TEXT_UPDATED, &SubsEditBox::OnLayerEnter, this, Layer->GetId());
|
Bind(wxEVT_COMMAND_TEXT_UPDATED, &SubsEditBox::OnLayerEnter, this, Layer->GetId());
|
||||||
Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &SubsEditBox::OnLayerChange, this, Layer->GetId());
|
Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &SubsEditBox::OnLayerChange, this, Layer->GetId());
|
||||||
Bind(wxEVT_COMMAND_TEXT_UPDATED, &SubsEditBox::OnEffectChange, this, Effect->GetId());
|
|
||||||
Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &SubsEditBox::OnCommentChange, this, CommentBox->GetId());
|
Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &SubsEditBox::OnCommentChange, this, CommentBox->GetId());
|
||||||
|
|
||||||
Bind(wxEVT_SIZE, &SubsEditBox::OnSize, this);
|
Bind(wxEVT_SIZE, &SubsEditBox::OnSize, this);
|
||||||
|
@ -361,12 +325,12 @@ void SubsEditBox::OnCommit(int type) {
|
||||||
change_value(MarginL, line->GetMarginString(0,false));
|
change_value(MarginL, line->GetMarginString(0,false));
|
||||||
change_value(MarginR, line->GetMarginString(1,false));
|
change_value(MarginR, line->GetMarginString(1,false));
|
||||||
change_value(MarginV, line->GetMarginString(2,false));
|
change_value(MarginV, line->GetMarginString(2,false));
|
||||||
Effect->ChangeValue(line->Effect.empty() ? "Effect" : line->Effect);
|
Effect->ChangeValue(line->Effect);
|
||||||
CommentBox->SetValue(line->Comment);
|
CommentBox->SetValue(line->Comment);
|
||||||
StyleBox->Select(StyleBox->FindString(line->Style));
|
StyleBox->Select(StyleBox->FindString(line->Style));
|
||||||
|
|
||||||
PopulateActorList();
|
PopulateActorList();
|
||||||
ActorBox->ChangeValue(line->Actor.empty() ? "Actor" : line->Actor);
|
ActorBox->ChangeValue(line->Actor);
|
||||||
ActorBox->SetStringSelection(line->Actor);
|
ActorBox->SetStringSelection(line->Actor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
#include "selection_controller.h"
|
#include "selection_controller.h"
|
||||||
|
|
||||||
|
namespace agi { namespace vfr { class Framerate; } }
|
||||||
namespace agi { struct Context; }
|
namespace agi { struct Context; }
|
||||||
struct AssColor;
|
struct AssColor;
|
||||||
class AssDialogue;
|
class AssDialogue;
|
||||||
|
@ -61,7 +62,7 @@ class wxStyledTextCtrl;
|
||||||
class wxStyledTextEvent;
|
class wxStyledTextEvent;
|
||||||
class wxTextCtrl;
|
class wxTextCtrl;
|
||||||
|
|
||||||
namespace agi { namespace vfr { class Framerate; } }
|
template<class Base> class Placeholder;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class SubsEditBox
|
/// @class SubsEditBox
|
||||||
|
@ -92,7 +93,7 @@ class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
|
||||||
// Box controls
|
// Box controls
|
||||||
wxCheckBox *CommentBox;
|
wxCheckBox *CommentBox;
|
||||||
wxComboBox *StyleBox;
|
wxComboBox *StyleBox;
|
||||||
wxComboBox *ActorBox;
|
Placeholder<wxComboBox> *ActorBox;
|
||||||
TimeEdit *StartTime;
|
TimeEdit *StartTime;
|
||||||
TimeEdit *EndTime;
|
TimeEdit *EndTime;
|
||||||
TimeEdit *Duration;
|
TimeEdit *Duration;
|
||||||
|
@ -100,7 +101,7 @@ class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
|
||||||
wxTextCtrl *MarginL;
|
wxTextCtrl *MarginL;
|
||||||
wxTextCtrl *MarginR;
|
wxTextCtrl *MarginR;
|
||||||
wxTextCtrl *MarginV;
|
wxTextCtrl *MarginV;
|
||||||
wxTextCtrl *Effect;
|
Placeholder<wxTextCtrl> *Effect;
|
||||||
wxRadioButton *ByTime;
|
wxRadioButton *ByTime;
|
||||||
wxRadioButton *ByFrame;
|
wxRadioButton *ByFrame;
|
||||||
|
|
||||||
|
@ -159,6 +160,8 @@ class SubsEditBox : public wxPanel, protected SelectionListener<AssDialogue> {
|
||||||
void OnColorButton(AssColor (AssStyle::*field), const char *tag, const char *alt);
|
void OnColorButton(AssColor (AssStyle::*field), const char *tag, const char *alt);
|
||||||
void OnFontButton();
|
void OnFontButton();
|
||||||
|
|
||||||
|
void SetPlaceholderCtrl(wxControl *ctrl, wxString const& value);
|
||||||
|
|
||||||
/// @brief Set the value of a tag for the currently selected text
|
/// @brief Set the value of a tag for the currently selected text
|
||||||
/// @param tag Tag to set
|
/// @param tag Tag to set
|
||||||
/// @param value New value of tag
|
/// @param value New value of tag
|
||||||
|
|
Loading…
Reference in a new issue