From c74045cf2024cbcf776fe10380f03c97d6288fb6 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Mon, 28 Apr 2014 07:07:07 -0700 Subject: [PATCH] Use spin controls for numeric fields in the style editor Closes #1741. --- src/auto4_lua.h | 4 +- src/auto4_lua_dialog.cpp | 44 ++++----------------- src/dialog_style_editor.cpp | 77 ++++++++++++++++++++++--------------- src/dialog_style_editor.h | 9 +---- src/validators.cpp | 15 ++++++++ src/validators.h | 11 ++++++ 6 files changed, 82 insertions(+), 78 deletions(-) diff --git a/src/auto4_lua.h b/src/auto4_lua.h index 26d909954..b647081f1 100644 --- a/src/auto4_lua.h +++ b/src/auto4_lua.h @@ -208,9 +208,9 @@ namespace Automation4 { bool use_buttons; /// Id of the button pushed (once a button has been pushed) - int button_pushed; + int button_pushed = -1; - wxWindow *window; + wxWindow *window = nullptr; public: LuaDialog(lua_State *L, bool include_buttons); diff --git a/src/auto4_lua_dialog.cpp b/src/auto4_lua_dialog.cpp index b20230bef..6b123e2ac 100644 --- a/src/auto4_lua_dialog.cpp +++ b/src/auto4_lua_dialog.cpp @@ -162,13 +162,12 @@ namespace Automation4 { class Edit : public LuaDialogControl { protected: std::string text; - wxTextCtrl *cw; + wxTextCtrl *cw = nullptr; public: Edit(lua_State *L) : LuaDialogControl(L) , text(get_field(L, "value")) - , cw(nullptr) { // Undocumented behaviour, 'value' is also accepted as key for text, // mostly so a text control can stand in for other things. @@ -237,14 +236,13 @@ namespace Automation4 { /// Integer only edit class IntEdit final : public Edit { - wxSpinCtrl *cw; + wxSpinCtrl *cw = nullptr; int value; int min, max; public: IntEdit(lua_State *L) : Edit(L) - , cw(nullptr) , value(get_field(L, "value", 0)) , min(get_field(L, "min", INT_MIN)) , max(get_field(L, "max", INT_MAX)) @@ -277,29 +275,7 @@ namespace Automation4 { double min; double max; double step; - wxSpinCtrlDouble *scd; - - struct DoubleValidator final : public wxValidator { - double *value; - DoubleValidator(double *value) : value(value) { } - wxValidator *Clone() const override { return new DoubleValidator(value); } - bool Validate(wxWindow*) override { return true; } - - bool TransferToWindow() override { - static_cast(GetWindow())->SetValue(*value); - return true; - } - - bool TransferFromWindow() override { - auto ctrl = static_cast(GetWindow()); -#ifndef wxHAS_NATIVE_SPINCTRLDOUBLE - wxFocusEvent evt; - ctrl->OnTextLostFocus(evt); -#endif - *value = ctrl->GetValue(); - return true; - } - }; + wxSpinCtrlDouble *scd = nullptr; public: FloatEdit(lua_State *L) @@ -308,7 +284,6 @@ namespace Automation4 { , min(get_field(L, "min", -DBL_MAX)) , max(get_field(L, "max", DBL_MAX)) , step(get_field(L, "step", 0.0)) - , scd(nullptr) { if (min >= max) { max = DBL_MAX; @@ -323,13 +298,12 @@ namespace Automation4 { wxControl *Create(wxWindow *parent) override { if (step > 0) { scd = new wxSpinCtrlDouble(parent, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, value, step); - scd->SetValidator(DoubleValidator(&value)); + scd->SetValidator(DoubleSpinValidator(&value)); scd->SetToolTip(to_wx(hint)); return scd; } - ::DoubleValidator val(&value, min, max); - + DoubleValidator val(&value, min, max); cw = new wxTextCtrl(parent, -1, "", wxDefaultPosition, wxDefaultSize, 0, val); cw->SetToolTip(to_wx(hint)); return cw; @@ -344,13 +318,12 @@ namespace Automation4 { class Dropdown final : public LuaDialogControl { std::vector items; std::string value; - wxComboBox *cw; + wxComboBox *cw = nullptr; public: Dropdown(lua_State *L) : LuaDialogControl(L) , value(get_field(L, "value")) - , cw(nullptr) { lua_getfield(L, -1, "items"); read_string_array(L, items); @@ -374,14 +347,13 @@ namespace Automation4 { class Checkbox final : public LuaDialogControl { std::string label; bool value; - wxCheckBox *cw; + wxCheckBox *cw = nullptr; public: Checkbox(lua_State *L) : LuaDialogControl(L) , label(get_field(L, "label")) , value(get_field(L, "value", false)) - , cw(nullptr) { } @@ -406,8 +378,6 @@ namespace Automation4 { // LuaDialog LuaDialog::LuaDialog(lua_State *L, bool include_buttons) : use_buttons(include_buttons) - , button_pushed(-1) - , window(nullptr) { LOG_D("automation/lua/dialog") << "creating LuaDialoug, addr: " << this; diff --git a/src/dialog_style_editor.cpp b/src/dialog_style_editor.cpp index c5d41ba64..c36050fac 100644 --- a/src/dialog_style_editor.cpp +++ b/src/dialog_style_editor.cpp @@ -64,8 +64,8 @@ /// updating references to it class StyleRenamer { agi::Context *c; - bool found_any; - bool do_replace; + bool found_any = false; + bool do_replace = false; std::string source_name; std::string new_name; @@ -105,8 +105,6 @@ class StyleRenamer { public: StyleRenamer(agi::Context *c, std::string source_name, std::string new_name) : c(c) - , found_any(false) - , do_replace(false) , source_name(std::move(source_name)) , new_name(std::move(new_name)) { @@ -124,19 +122,6 @@ public: } }; -static void add_with_label(wxSizer *sizer, wxWindow *parent, wxString const& label, wxWindow *ctrl) { - sizer->Add(new wxStaticText(parent, -1, label), wxSizerFlags().Center().Right().Border(wxLEFT | wxRIGHT)); - sizer->Add(ctrl, wxSizerFlags(1).Left().Expand()); -} - -static wxSpinCtrl *spin_ctrl(wxWindow *parent, float value, int max_value) { - return new wxSpinCtrl(parent, -1, wxString::Format("%g", value), wxDefaultPosition, wxSize(60, -1), wxSP_ARROW_KEYS, 0, max_value, value); -} - -static wxTextCtrl *num_text_ctrl(wxWindow *parent, double *value, bool allow_negative, wxSize size = wxSize(70, 20)) { - return new wxTextCtrl(parent, -1, "", wxDefaultPosition, size, 0, DoubleValidator(value, allow_negative)); -} - DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Context *c, AssStyleStorage *store, std::string const& new_name, wxArrayString const& font_list) : wxDialog (parent, -1, _("Style Editor"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) , c(c) @@ -157,6 +142,32 @@ DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Con SetIcon(GETICON(style_toolbutton_16)); + auto add_with_label = [&](wxSizer *sizer, wxString const& label, wxWindow *ctrl) { + sizer->Add(new wxStaticText(this, -1, label), wxSizerFlags().Center().Right().Border(wxLEFT | wxRIGHT)); + sizer->Add(ctrl, wxSizerFlags(1).Left().Expand()); + }; + + auto spin_ctrl = [&](float value, int max_value) { + return new wxSpinCtrl(this, -1, wxString::Format("%g", value), wxDefaultPosition, wxSize(60, -1), wxSP_ARROW_KEYS, 0, max_value, value); + }; + + auto num_text_ctrl = [&](double *value, double min, double max, double step) -> wxSpinCtrlDouble * { + auto scd = new wxSpinCtrlDouble(this, -1, "", wxDefaultPosition, + wxSize(75, -1), wxSP_ARROW_KEYS, min, max, *value, step); + scd->SetValidator(DoubleSpinValidator(value)); + scd->Bind(wxEVT_SPINCTRLDOUBLE, [=](wxSpinDoubleEvent &evt) { + evt.Skip(); + if (updating) return; + + bool old = updating; + updating = true; + scd->GetValidator()->TransferFromWindow(); + updating = old; + SubsPreview->SetStyle(*work); + }); + return scd; + }; + // Prepare control values wxString EncodingValue = std::to_wstring(style->encoding); wxString alignValues[9] = { "7", "8", "9", "4", "5", "6", "1", "2", "3" }; @@ -177,7 +188,7 @@ DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Con // Create controls StyleName = new wxTextCtrl(this, -1, to_wx(style->name)); FontName = new wxComboBox(this, -1, to_wx(style->font), wxDefaultPosition, wxSize(150, -1), 0, nullptr, wxCB_DROPDOWN); - FontSize = num_text_ctrl(this, &work->fontsize, false, wxSize(50, -1)); + auto FontSize = num_text_ctrl(&work->fontsize, 0, 10000.0, 1.0); BoxBold = new wxCheckBox(this, -1, _("&Bold")); BoxItalic = new wxCheckBox(this, -1, _("&Italic")); BoxUnderline = new wxCheckBox(this, -1, _("&Underline")); @@ -189,15 +200,15 @@ DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Con new ColourButton(this, wxSize(55, 16), true, style->shadow, ColorValidator(&work->shadow)) }; for (int i = 0; i < 3; i++) - margin[i] = spin_ctrl(this, style->Margin[i], 9999); + margin[i] = spin_ctrl(style->Margin[i], 9999); Alignment = new wxRadioBox(this, -1, _("Alignment"), wxDefaultPosition, wxDefaultSize, 9, alignValues, 3, wxRA_SPECIFY_COLS); - Outline = num_text_ctrl(this, &work->outline_w, false, wxSize(50, -1)); - Shadow = num_text_ctrl(this, &work->shadow_w, true, wxSize(50, -1)); + auto Outline = num_text_ctrl(&work->outline_w, 0.0, 1000.0, 0.1); + auto Shadow = num_text_ctrl(&work->shadow_w, 0.0, 1000.0, 0.1); OutlineType = new wxCheckBox(this, -1, _("&Opaque box")); - ScaleX = num_text_ctrl(this, &work->scalex, false); - ScaleY = num_text_ctrl(this, &work->scaley, false); - Angle = num_text_ctrl(this, &work->angle, true); - Spacing = num_text_ctrl(this, &work->spacing, true); + auto ScaleX = num_text_ctrl(&work->scalex, 0.0, 10000.0, 1.0); + auto ScaleY = num_text_ctrl(&work->scaley, 0.0, 10000.0, 1.0); + auto Angle = num_text_ctrl(&work->angle, -180.0, 180.0, 1.0); + auto Spacing = num_text_ctrl(&work->spacing, 0.0, 1000.0, 0.1); Encoding = new wxComboBox(this, -1, "", wxDefaultPosition, wxDefaultSize, encodingStrings, wxCB_READONLY); // Set control tooltips @@ -292,19 +303,19 @@ DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Con MarginAlign->Add(Alignment, 0, wxLEFT | wxEXPAND, 5); // Outline - add_with_label(OutlineBox, this, _("Outline:"), Outline); - add_with_label(OutlineBox, this, _("Shadow:"), Shadow); + add_with_label(OutlineBox, _("Outline:"), Outline); + add_with_label(OutlineBox, _("Shadow:"), Shadow); OutlineBox->Add(OutlineType, 0, wxLEFT | wxALIGN_CENTER, 5); // Misc auto MiscBoxTop = new wxFlexGridSizer(2, 4, 5, 5); - add_with_label(MiscBoxTop, this, _("Scale X%:"), ScaleX); - add_with_label(MiscBoxTop, this, _("Scale Y%:"), ScaleY); - add_with_label(MiscBoxTop, this, _("Rotation:"), Angle); - add_with_label(MiscBoxTop, this, _("Spacing:"), Spacing); + add_with_label(MiscBoxTop, _("Scale X%:"), ScaleX); + add_with_label(MiscBoxTop, _("Scale Y%:"), ScaleY); + add_with_label(MiscBoxTop, _("Rotation:"), Angle); + add_with_label(MiscBoxTop, _("Spacing:"), Spacing); wxSizer *MiscBoxBottom = new wxBoxSizer(wxHORIZONTAL); - add_with_label(MiscBoxBottom, this, _("Encoding:"), Encoding); + add_with_label(MiscBoxBottom, _("Encoding:"), Encoding); MiscBox->Add(MiscBoxTop, wxSizerFlags().Expand().Center()); MiscBox->Add(MiscBoxBottom, wxSizerFlags().Expand().Center().Border(wxTOP)); @@ -453,7 +464,9 @@ void DialogStyleEditor::Apply(bool apply, bool close) { } void DialogStyleEditor::UpdateWorkStyle() { + updating = true; TransferDataFromWindow(); + updating = false; work->font = from_wx(FontName->GetValue()); diff --git a/src/dialog_style_editor.h b/src/dialog_style_editor.h index 2aec2ee49..6fa0033fd 100644 --- a/src/dialog_style_editor.h +++ b/src/dialog_style_editor.h @@ -56,6 +56,8 @@ class DialogStyleEditor final : public wxDialog { /// the style bool is_new = false; + bool updating = false; + /// The style currently being edited AssStyle *style; @@ -68,21 +70,14 @@ class DialogStyleEditor final : public wxDialog { wxTextCtrl *StyleName; wxComboBox *FontName; - wxTextCtrl *FontSize; wxCheckBox *BoxBold; wxCheckBox *BoxItalic; wxCheckBox *BoxUnderline; wxCheckBox *BoxStrikeout; wxSpinCtrl *margin[3]; wxRadioBox *Alignment; - wxTextCtrl *Outline; - wxTextCtrl *Shadow; wxCheckBox *OutlineType; - wxTextCtrl *ScaleX; - wxTextCtrl *ScaleY; - wxTextCtrl *Angle; wxComboBox *Encoding; - wxTextCtrl *Spacing; wxTextCtrl *PreviewText; SubtitlesPreview *SubsPreview; diff --git a/src/validators.cpp b/src/validators.cpp index 2ca5f72f4..0971890f6 100644 --- a/src/validators.cpp +++ b/src/validators.cpp @@ -153,6 +153,21 @@ bool DoubleValidator::TransferFromWindow() { return true; } +bool DoubleSpinValidator::TransferToWindow() { + static_cast(GetWindow())->SetValue(*value); + return true; +} + +bool DoubleSpinValidator::TransferFromWindow() { + auto ctrl = static_cast(GetWindow()); +#ifndef wxHAS_NATIVE_SPINCTRLDOUBLE + wxFocusEvent evt; + ctrl->OnTextLostFocus(evt); +#endif + *value = ctrl->GetValue(); + return true; +} + bool StringBinder::TransferFromWindow() { wxWindow *window = GetWindow(); if (wxTextCtrl *ctrl = dynamic_cast(window)) diff --git a/src/validators.h b/src/validators.h index 44b6ffd27..d130b9d9d 100644 --- a/src/validators.h +++ b/src/validators.h @@ -60,6 +60,17 @@ public: explicit DoubleValidator(double *val, double min, double max); }; +class DoubleSpinValidator final : public wxValidator { + double *value; + wxValidator *Clone() const override { return new DoubleSpinValidator(value); } + bool Validate(wxWindow*) override { return true; } + bool TransferToWindow() override; + bool TransferFromWindow() override; + +public: + DoubleSpinValidator(double *value) : value(value) { } +}; + template class EnumBinder final : public wxValidator { T *value;