diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 7c9c696efa..5c6811932e 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1981,7 +1981,7 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config) set_extrusion_width("solid_infill_extrusion_width", 0.45); } -class SpinCtrlDouble: public wxSpinCtrlDouble +class SpinCtrlDouble: public ::SpinInputDouble { public: SpinCtrlDouble(wxWindow* parent) @@ -1991,10 +1991,7 @@ public: #else long style = wxSP_ARROW_KEYS; #endif - Create(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, style); -#ifdef _WIN32 - wxGetApp().UpdateDarkUI(this->GetText()); -#endif + Create(parent, "", wxEmptyString, wxDefaultPosition, wxSize(6* wxGetApp().em_unit(), -1), style); this->Refresh(); } ~SpinCtrlDouble() {} diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index ce43fd5e71..3bbc9649d9 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -32,6 +32,7 @@ #include "SavePresetDialog.hpp" #include "wxExtensions.hpp" +#include "Widgets/SpinInput.hpp" namespace fs = boost::filesystem; @@ -510,8 +511,8 @@ struct PageDiameters: ConfigWizardPage struct PageTemperatures: ConfigWizardPage { - wxSpinCtrlDouble *spin_extr; - wxSpinCtrlDouble *spin_bed; + ::SpinInputDouble *spin_extr; + ::SpinInputDouble *spin_bed; PageTemperatures(ConfigWizard *parent); virtual void apply_custom_config(DynamicPrintConfig &config); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 7c69131c80..a27a4c8682 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1093,6 +1093,16 @@ bool GUI_App::OnInit() } } +static int get_app_font_pt_size(const AppConfig* app_config) +{ + if (!app_config->has("font_pt_size")) + return -1; + const int font_pt_size = atoi(app_config->get("font_pt_size").c_str()); + const int max_font_pt_size = wxGetApp().get_max_font_pt_size(); + + return (font_pt_size > max_font_pt_size) ? max_font_pt_size : font_pt_size; +} + bool GUI_App::on_init_inner() { // Set initialization of image handlers before any UI actions - See GH issue #7469 @@ -1326,7 +1336,7 @@ bool GUI_App::on_init_inner() if (!delayed_error_load_presets.empty()) show_error(nullptr, delayed_error_load_presets); - mainframe = new MainFrame(app_config->has("font_pt_size") ? atoi(app_config->get("font_pt_size").c_str()) : -1); + mainframe = new MainFrame(get_app_font_pt_size(app_config)); // hide settings tabs after first Layout if (is_editor()) mainframe->select_tab(size_t(0)); @@ -1662,6 +1672,17 @@ void GUI_App::SetWindowVariantForButton(wxButton* btn) #endif } +int GUI_App::get_max_font_pt_size() +{ + const unsigned disp_count = wxDisplay::GetCount(); + for (int i = 0; i < disp_count; i++) { + const wxRect display_rect = wxDisplay(i).GetGeometry(); + if (display_rect.width >= 2560 && display_rect.height >= 1440) + return 20; + } + return 15; +} + void GUI_App::init_fonts() { m_small_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); @@ -1863,7 +1884,7 @@ void GUI_App::recreate_GUI(const wxString& msg_name) dlg.Update(10, _L("Recreating") + dots); MainFrame *old_main_frame = mainframe; - mainframe = new MainFrame(app_config->has("font_pt_size") ? atoi(app_config->get("font_pt_size").c_str()) : -1); + mainframe = new MainFrame(get_app_font_pt_size(app_config)); if (is_editor()) // hide settings tabs after first Layout mainframe->select_tab(size_t(0)); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 66c259b813..059804edf3 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -251,6 +251,7 @@ public: bool tabs_as_menu() const; bool suppress_round_corners() const; wxSize get_min_size(wxWindow* display_win) const; + int get_max_font_pt_size(); float toolbar_icon_scale(const bool is_limited = false) const; void set_auto_toolbar_icon_scale(float scale) const; void check_printer_presets(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index e1fa4b07f6..f3651be9b2 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1094,17 +1094,6 @@ void PreferencesDialog::create_settings_mode_color_widget() append_preferences_option_to_searcher(m_optgroup_gui, opt_key, title); } -static int get_max_font_pt_size() -{ - const unsigned disp_count = wxDisplay::GetCount(); - for (int i = 0; i < disp_count; i++) { - const wxRect display_rect = wxDisplay(i).GetGeometry(); - if (display_rect.width >= 2560 && display_rect.height >= 1440) - return 20; - } - return 15; -} - void PreferencesDialog::create_settings_font_widget() { wxWindow* parent = m_optgroup_other->parent(); @@ -1125,7 +1114,7 @@ void PreferencesDialog::create_settings_font_widget() #ifdef _WIN32 | wxBORDER_SIMPLE #endif - , 8, get_max_font_pt_size()); + , 8, wxGetApp().get_max_font_pt_size()); wxGetApp().UpdateDarkUI(size_sc); auto apply_font = [this, font_example, opt_key, stb_sizer](const int val, const wxFont& font) { diff --git a/src/slic3r/GUI/Widgets/SpinInput.cpp b/src/slic3r/GUI/Widgets/SpinInput.cpp index 6634638784..c693a52843 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.cpp +++ b/src/slic3r/GUI/Widgets/SpinInput.cpp @@ -10,22 +10,23 @@ #include #include -BEGIN_EVENT_TABLE(SpinInput, wxPanel) +BEGIN_EVENT_TABLE(SpinInputBase, wxPanel) -EVT_KEY_DOWN(SpinInput::keyPressed) -EVT_MOUSEWHEEL(SpinInput::mouseWheelMoved) +EVT_KEY_DOWN(SpinInputBase::keyPressed) +EVT_MOUSEWHEEL(SpinInputBase::mouseWheelMoved) -EVT_PAINT(SpinInput::paintEvent) +EVT_PAINT(SpinInputBase::paintEvent) END_EVENT_TABLE() + /* * Called by the system of by wxWidgets when the panel needs * to be redrawn. You can also trigger this call by * calling Refresh()/Update(). */ -SpinInput::SpinInput() +SpinInputBase::SpinInputBase() : label_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x6B6B6B, (int) StateColor::Normal)) , text_color(std::make_pair(0x909090, (int) StateColor::Disabled), std::make_pair(0x262E30, (int) StateColor::Normal)) { @@ -34,6 +35,230 @@ SpinInput::SpinInput() border_width = 1; } +Button * SpinInputBase::create_button(ButtonId id) +{ + auto btn = new Button(this, "", id == ButtonId::btnIncrease ? "spin_inc_act" : "spin_dec_act", wxBORDER_NONE, wxSize(12, 7)); + btn->SetCornerRadius(0); + btn->SetInactiveIcon(id == ButtonId::btnIncrease ? "spin_inc" : "spin_dec"); + btn->DisableFocusFromKeyboard(); + btn->SetSelected(false); + + bind_inc_dec_button(btn, id); + + return btn; +} + +void SpinInputBase::SetCornerRadius(double radius) +{ + this->radius = radius; + Refresh(); +} + +void SpinInputBase::SetLabel(const wxString &label) +{ + wxWindow::SetLabel(label); + messureSize(); + Refresh(); +} + +void SpinInputBase::SetLabelColor(StateColor const &color) +{ + label_color = color; + state_handler.update_binds(); +} + +void SpinInputBase::SetTextColor(StateColor const &color) +{ + text_color = color; + state_handler.update_binds(); +} + +void SpinInputBase::SetSize(wxSize const &size) +{ + wxWindow::SetSize(size); + Rescale(); +} + +wxString SpinInputBase::GetTextValue() const +{ + return text_ctrl->GetValue(); +} + +void SpinInput::SetRange(int min, int max) +{ + this->min = min; + this->max = max; +} + +void SpinInputBase::SetSelection(long from, long to) +{ + if (text_ctrl) + text_ctrl->SetSelection(from, to); +} + +bool SpinInputBase::SetFont(wxFont const& font) +{ + if (text_ctrl) + return text_ctrl->SetFont(font); + return StaticBox::SetFont(font); +} + +bool SpinInputBase::SetBackgroundColour(const wxColour& colour) +{ + const int clr_background_disabled = Slic3r::GUI::wxGetApp().dark_mode() ? clr_background_disabled_dark : clr_background_disabled_light; + StateColor clr_state(std::make_pair(clr_background_disabled, (int)StateColor::Disabled), + std::make_pair(clr_background_focused, (int)StateColor::Checked), + std::make_pair(colour, (int)StateColor::Focused), + std::make_pair(colour, (int)StateColor::Normal)); + + StaticBox::SetBackgroundColor(clr_state); + if (text_ctrl) + text_ctrl->SetBackgroundColour(colour); + if (button_inc) + button_inc->SetBackgroundColor(clr_state); + if (button_dec) + button_dec->SetBackgroundColor(clr_state); + + return true; +} + +bool SpinInputBase::SetForegroundColour(const wxColour& colour) +{ + StateColor clr_state(std::make_pair(clr_foreground_disabled, (int)StateColor::Disabled), + std::make_pair(colour, (int)StateColor::Normal)); + + SetLabelColor(clr_state); + SetTextColor(clr_state); + + if (text_ctrl) + text_ctrl->SetForegroundColour(colour); + if (button_inc) + button_inc->SetTextColor(clr_state); + if (button_dec) + button_dec->SetTextColor(clr_state); + + return true; +} + +void SpinInputBase::SetBorderColor(StateColor const &color) +{ + StaticBox::SetBorderColor(color); + if (button_inc) + button_inc->SetBorderColor(color); + if (button_dec) + button_dec->SetBorderColor(color); +} + +void SpinInputBase::DoSetToolTipText(wxString const &tip) +{ + wxWindow::DoSetToolTipText(tip); + text_ctrl->SetToolTip(tip); +} + +void SpinInputBase::Rescale() +{ + SetFont(Slic3r::GUI::wxGetApp().normal_font()); + text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); + + button_inc->Rescale(); + button_dec->Rescale(); + messureSize(); +} + +bool SpinInputBase::Enable(bool enable) +{ + bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable); + if (result) { + wxCommandEvent e(EVT_ENABLE_CHANGED); + e.SetEventObject(this); + GetEventHandler()->ProcessEvent(e); + text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); + text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); + button_inc->Enable(enable); + button_dec->Enable(enable); + } + return result; +} + +void SpinInputBase::paintEvent(wxPaintEvent& evt) +{ + // depending on your system you may need to look at double-buffered dcs + wxPaintDC dc(this); + render(dc); +} + +/* + * Here we do the actual rendering. I put it in a separate + * method so that it can work no matter what type of DC + * (e.g. wxPaintDC or wxClientDC) is used. + */ +void SpinInputBase::render(wxDC& dc) +{ + StaticBox::render(dc); + int states = state_handler.states(); + wxSize size = GetSize(); + // draw seperator of buttons + wxPoint pt = button_inc->GetPosition(); + pt.y = size.y / 2; + dc.SetPen(wxPen(border_color.defaultColor())); + + const double scale = dc.GetContentScaleFactor(); + const int btn_w = button_inc->GetSize().GetWidth(); + dc.DrawLine(pt, pt + wxSize{ btn_w - int(scale), 0}); + // draw label + auto label = GetLabel(); + if (!label.IsEmpty()) { + pt.x = size.x - labelSize.x - 5; + pt.y = (size.y - labelSize.y) / 2; + dc.SetFont(GetFont()); + dc.SetTextForeground(label_color.colorForStates(states)); + dc.DrawText(label, pt); + } +} + +void SpinInputBase::messureSize() +{ + wxSize size = GetSize(); + wxSize textSize = text_ctrl->GetSize(); + int h = textSize.y + 8; + if (size.y != h) { + size.y = h; + SetSize(size); + SetMinSize(size); + } + + wxSize btnSize = {14, (size.y - 4) / 2}; + btnSize.x = btnSize.x * btnSize.y / 10; + + const double scale = this->GetContentScaleFactor(); + + wxClientDC dc(this); + labelSize = dc.GetMultiLineTextExtent(GetLabel()); + textSize.x = size.x - labelSize.x - btnSize.x - 16; + text_ctrl->SetSize(textSize); + text_ctrl->SetPosition({int(3. * scale), (size.y - textSize.y) / 2}); + button_inc->SetSize(btnSize); + button_dec->SetSize(btnSize); + button_inc->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 - btnSize.y/* - 1*/}); + button_dec->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 + 1}); +} + +void SpinInputBase::onText(wxCommandEvent &event) +{ + sendSpinEvent(); + event.SetId(GetId()); + ProcessEventLocally(event); +} + +void SpinInputBase::sendSpinEvent() +{ + wxCommandEvent event(wxEVT_SPINCTRL, GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + + +// SpinInput SpinInput::SpinInput(wxWindow *parent, wxString text, @@ -42,7 +267,7 @@ SpinInput::SpinInput(wxWindow *parent, const wxSize & size, long style, int min, int max, int initial) - : SpinInput() + : SpinInputBase() { Create(parent, text, label, pos, size, style, min, max, initial); } @@ -91,35 +316,29 @@ void SpinInput::Create(wxWindow *parent, messureSize(); } -void SpinInput::SetCornerRadius(double radius) +void SpinInput::bind_inc_dec_button(Button *btn, ButtonId id) { - this->radius = radius; - Refresh(); -} - -void SpinInput::SetLabel(const wxString &label) -{ - wxWindow::SetLabel(label); - messureSize(); - Refresh(); -} - -void SpinInput::SetLabelColor(StateColor const &color) -{ - label_color = color; - state_handler.update_binds(); -} - -void SpinInput::SetTextColor(StateColor const &color) -{ - text_color = color; - state_handler.update_binds(); -} - -void SpinInput::SetSize(wxSize const &size) -{ - wxWindow::SetSize(size); - Rescale(); + btn->Bind(wxEVT_LEFT_DOWN, [this, btn, id](auto& e) { + delta = id == ButtonId::btnIncrease ? 1 : -1; + SetValue(val + delta); + text_ctrl->SetFocus(); + btn->CaptureMouse(); + delta *= 8; + timer.Start(100); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_DCLICK, [this, btn, id](auto& e) { + delta = id == ButtonId::btnIncrease ? 1 : -1; + btn->CaptureMouse(); + SetValue(val + delta); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_UP, [this, btn](auto& e) { + btn->ReleaseMouse(); + timer.Stop(); + text_ctrl->SelectAll(); + delta = 0; + }); } void SpinInput::SetValue(const wxString &text) @@ -144,202 +363,6 @@ int SpinInput::GetValue()const return val; } -wxString SpinInput::GetTextValue() const -{ - return text_ctrl->GetValue(); -} - -void SpinInput::SetRange(int min, int max) -{ - this->min = min; - this->max = max; -} - -void SpinInput::SetSelection(long from, long to) -{ - if (text_ctrl) - text_ctrl->SetSelection(from, to); -} - -bool SpinInput::SetFont(wxFont const& font) -{ - if (text_ctrl) - return text_ctrl->SetFont(font); - return StaticBox::SetFont(font); -} - -bool SpinInput::SetBackgroundColour(const wxColour& colour) -{ - const int clr_background_disabled = Slic3r::GUI::wxGetApp().dark_mode() ? clr_background_disabled_dark : clr_background_disabled_light; - StateColor clr_state(std::make_pair(clr_background_disabled, (int)StateColor::Disabled), - std::make_pair(clr_background_focused, (int)StateColor::Checked), - std::make_pair(colour, (int)StateColor::Focused), - std::make_pair(colour, (int)StateColor::Normal)); - - StaticBox::SetBackgroundColor(clr_state); - if (text_ctrl) - text_ctrl->SetBackgroundColour(colour); - if (button_inc) - button_inc->SetBackgroundColor(clr_state); - if (button_dec) - button_dec->SetBackgroundColor(clr_state); - - return true; -} - -bool SpinInput::SetForegroundColour(const wxColour& colour) -{ - StateColor clr_state(std::make_pair(clr_foreground_disabled, (int)StateColor::Disabled), - std::make_pair(colour, (int)StateColor::Normal)); - - SetLabelColor(clr_state); - SetTextColor(clr_state); - - if (text_ctrl) - text_ctrl->SetForegroundColour(colour); - if (button_inc) - button_inc->SetTextColor(clr_state); - if (button_dec) - button_dec->SetTextColor(clr_state); - - return true; -} - -void SpinInput::SetBorderColor(StateColor const &color) -{ - StaticBox::SetBorderColor(color); - if (button_inc) - button_inc->SetBorderColor(color); - if (button_dec) - button_dec->SetBorderColor(color); -} - -void SpinInput::DoSetToolTipText(wxString const &tip) -{ - wxWindow::DoSetToolTipText(tip); - text_ctrl->SetToolTip(tip); -} - -void SpinInput::Rescale() -{ - SetFont(Slic3r::GUI::wxGetApp().normal_font()); - text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); - - button_inc->Rescale(); - button_dec->Rescale(); - messureSize(); -} - -bool SpinInput::Enable(bool enable) -{ - bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable); - if (result) { - wxCommandEvent e(EVT_ENABLE_CHANGED); - e.SetEventObject(this); - GetEventHandler()->ProcessEvent(e); - text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states())); - text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states())); - button_inc->Enable(enable); - button_dec->Enable(enable); - } - return result; -} - -void SpinInput::paintEvent(wxPaintEvent& evt) -{ - // depending on your system you may need to look at double-buffered dcs - wxPaintDC dc(this); - render(dc); -} - -/* - * Here we do the actual rendering. I put it in a separate - * method so that it can work no matter what type of DC - * (e.g. wxPaintDC or wxClientDC) is used. - */ -void SpinInput::render(wxDC& dc) -{ - StaticBox::render(dc); - int states = state_handler.states(); - wxSize size = GetSize(); - // draw seperator of buttons - wxPoint pt = button_inc->GetPosition(); - pt.y = size.y / 2; - dc.SetPen(wxPen(border_color.defaultColor())); - - const double scale = dc.GetContentScaleFactor(); - const int btn_w = button_inc->GetSize().GetWidth(); - dc.DrawLine(pt, pt + wxSize{ btn_w - int(scale), 0}); - // draw label - auto label = GetLabel(); - if (!label.IsEmpty()) { - pt.x = size.x - labelSize.x - 5; - pt.y = (size.y - labelSize.y) / 2; - dc.SetFont(GetFont()); - dc.SetTextForeground(label_color.colorForStates(states)); - dc.DrawText(label, pt); - } -} - -void SpinInput::messureSize() -{ - wxSize size = GetSize(); - wxSize textSize = text_ctrl->GetSize(); - int h = textSize.y + 8; - if (size.y != h) { - size.y = h; - SetSize(size); - SetMinSize(size); - } - - wxSize btnSize = {14, (size.y - 4) / 2}; - btnSize.x = btnSize.x * btnSize.y / 10; - - const double scale = this->GetContentScaleFactor(); - - wxClientDC dc(this); - labelSize = dc.GetMultiLineTextExtent(GetLabel()); - textSize.x = size.x - labelSize.x - btnSize.x - 16; - text_ctrl->SetSize(textSize); - text_ctrl->SetPosition({int(3. * scale), (size.y - textSize.y) / 2}); - button_inc->SetSize(btnSize); - button_dec->SetSize(btnSize); - button_inc->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 - btnSize.y/* - 1*/}); - button_dec->SetPosition({size.x - btnSize.x - int(3. * scale), size.y / 2 + 1}); -} - -Button *SpinInput::create_button(ButtonId id) -{ - auto btn = new Button(this, "", id == ButtonId::btnIncrease ? "spin_inc_act" : "spin_dec_act", wxBORDER_NONE, wxSize(12, 7)); - btn->SetCornerRadius(0); - btn->SetInactiveIcon(id == ButtonId::btnIncrease ? "spin_inc" : "spin_dec"); - btn->DisableFocusFromKeyboard(); - btn->SetSelected(false); - - btn->Bind(wxEVT_LEFT_DOWN, [=](auto &e) { - delta = id == ButtonId::btnIncrease ? 1 : -1; - SetValue(val + delta); - text_ctrl->SetFocus(); - btn->CaptureMouse(); - delta *= 8; - timer.Start(100); - sendSpinEvent(); - }); - btn->Bind(wxEVT_LEFT_DCLICK, [=](auto &e) { - delta = id == ButtonId::btnIncrease ? 1 : -1; - btn->CaptureMouse(); - SetValue(val + delta); - sendSpinEvent(); - }); - btn->Bind(wxEVT_LEFT_UP, [=](auto &e) { - btn->ReleaseMouse(); - timer.Stop(); - text_ctrl->SelectAll(); - delta = 0; - }); - return btn; -} - void SpinInput::onTimer(wxTimerEvent &evnet) { if (delta < -1 || delta > 1) { delta /= 2; @@ -367,7 +390,9 @@ void SpinInput::onTextLostFocus(wxEvent &event) void SpinInput::onTextEnter(wxCommandEvent &event) { long value; - if (!text_ctrl->GetValue().ToLong(&value)) { value = val; } + if (!text_ctrl->GetValue().ToLong(&value)) + value = val; + if (value != val) { SetValue(value); sendSpinEvent(); @@ -376,13 +401,6 @@ void SpinInput::onTextEnter(wxCommandEvent &event) ProcessEventLocally(event); } -void SpinInput::onText(wxCommandEvent &event) -{ - sendSpinEvent(); - event.SetId(GetId()); - ProcessEventLocally(event); -} - void SpinInput::mouseWheelMoved(wxMouseEvent &event) { auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? 1 : -1; @@ -412,9 +430,204 @@ void SpinInput::keyPressed(wxKeyEvent &event) } } -void SpinInput::sendSpinEvent() + + +// SpinInputDouble + +SpinInputDouble::SpinInputDouble(wxWindow * parent, + wxString text, + wxString label, + const wxPoint &pos, + const wxSize & size, + long style, + double min, double max, double initial, + double inc) + : SpinInputBase() { - wxCommandEvent event(wxEVT_SPINCTRL, GetId()); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); + Create(parent, text, label, pos, size, style, min, max, initial, inc); } + +void SpinInputDouble::Create(wxWindow *parent, + wxString text, + wxString label, + const wxPoint &pos, + const wxSize & size, + long style, + double min, double max, double initial, + double inc) +{ + StaticBox::Create(parent, wxID_ANY, pos, size); + wxWindow::SetLabel(label); + + state_handler.attach({&label_color, &text_color}); + state_handler.update_binds(); + + text_ctrl = new wxTextCtrl(this, wxID_ANY, text, {20, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER, wxTextValidator(wxFILTER_DIGITS)); +#ifdef __WXOSX__ + text_ctrl->OSXDisableAllSmartSubstitutions(); +#endif // __WXOSX__ + text_ctrl->SetInitialSize(text_ctrl->GetBestSize()); + state_handler.attach_child(text_ctrl); + + text_ctrl->Bind(wxEVT_KILL_FOCUS, &SpinInputDouble::onTextLostFocus, this); + text_ctrl->Bind(wxEVT_TEXT, &SpinInputDouble::onText, this); + text_ctrl->Bind(wxEVT_TEXT_ENTER, &SpinInputDouble::onTextEnter, this); + text_ctrl->Bind(wxEVT_KEY_DOWN, &SpinInputDouble::keyPressed, this); + text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu + button_inc = create_button(ButtonId::btnIncrease); + button_dec = create_button(ButtonId::btnDecrease); + delta = 0; + timer.Bind(wxEVT_TIMER, &SpinInputDouble::onTimer, this); + + SetFont(Slic3r::GUI::wxGetApp().normal_font()); + if (parent) { + SetBackgroundColour(parent->GetBackgroundColour()); + SetForegroundColour(parent->GetForegroundColour()); + } + + double initialFromText; + if (text.ToDouble(&initialFromText)) initial = initialFromText; + SetRange(min, max); + SetIncrement(inc); + SetValue(initial); + messureSize(); +} + +void SpinInputDouble::bind_inc_dec_button(Button *btn, ButtonId id) +{ + btn->Bind(wxEVT_LEFT_DOWN, [this, btn, id](auto& e) { + delta = id == ButtonId::btnIncrease ? inc : -inc; + SetValue(val + delta); + text_ctrl->SetFocus(); + btn->CaptureMouse(); + delta *= 8; + timer.Start(100); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_DCLICK, [this, btn, id](auto& e) { + delta = id == ButtonId::btnIncrease ? inc : -inc; + btn->CaptureMouse(); + SetValue(val + delta); + sendSpinEvent(); + }); + btn->Bind(wxEVT_LEFT_UP, [this, btn](auto& e) { + btn->ReleaseMouse(); + timer.Stop(); + text_ctrl->SelectAll(); + delta = 0; + }); +} + +void SpinInputDouble::SetValue(const wxString &text) +{ + double value; + if ( text.ToDouble(&value) ) + SetValue(value); + else + text_ctrl->SetValue(text); +} + +void SpinInputDouble::SetValue(double value) +{ + if (Slic3r::is_approx(value, val)) + return; + + if (value < min) value = min; + else if (value > max) value = max; + this->val = value; + wxString str_val = wxString::FromDouble(value, digits); + text_ctrl->SetValue(str_val); +} + +double SpinInputDouble::GetValue()const +{ + return val; +} + +void SpinInputDouble::SetRange(double min, double max) +{ + this->min = min; + this->max = max; +} + +void SpinInputDouble::SetIncrement(double inc_in) +{ + inc = inc_in; +} + +void SpinInputDouble::SetDigits(unsigned digits_in) +{ + digits = int(digits_in); +} + +void SpinInputDouble::onTimer(wxTimerEvent &evnet) { + if (delta < -inc || delta > inc) { + delta /= 2; + return; + } + SetValue(val + delta); + sendSpinEvent(); +} + +void SpinInputDouble::onTextLostFocus(wxEvent &event) +{ + timer.Stop(); + for (auto * child : GetChildren()) + if (auto btn = dynamic_cast(child)) + if (btn->HasCapture()) + btn->ReleaseMouse(); + wxCommandEvent e; + onTextEnter(e); + // pass to outer + event.SetId(GetId()); + ProcessEventLocally(event); + e.Skip(); +} + +void SpinInputDouble::onTextEnter(wxCommandEvent &event) +{ + double value; + if (!text_ctrl->GetValue().ToDouble(&value)) + val = value; + + if (!Slic3r::is_approx(value, val)) { + SetValue(value); + sendSpinEvent(); + } + event.SetId(GetId()); + ProcessEventLocally(event); +} + +void SpinInputDouble::mouseWheelMoved(wxMouseEvent &event) +{ + auto delta = (event.GetWheelRotation() < 0 == event.IsWheelInverted()) ? inc : -inc; + SetValue(val + delta); + sendSpinEvent(); + text_ctrl->SetFocus(); +} + +void SpinInputDouble::keyPressed(wxKeyEvent &event) +{ + switch (event.GetKeyCode()) { + case WXK_UP: + case WXK_DOWN: + double value; + if (!text_ctrl->GetValue().ToDouble(&value)) + val = value; + + if (event.GetKeyCode() == WXK_DOWN && value > min) { + value -= inc; + } else if (event.GetKeyCode() == WXK_UP && value + inc < max) { + value += inc; + } + if (!Slic3r::is_approx(value, val)) { + SetValue(value); + sendSpinEvent(); + } + break; + default: event.Skip(); break; + } +} + + + diff --git a/src/slic3r/GUI/Widgets/SpinInput.hpp b/src/slic3r/GUI/Widgets/SpinInput.hpp index 364d8c71d5..f81ec0b80d 100644 --- a/src/slic3r/GUI/Widgets/SpinInput.hpp +++ b/src/slic3r/GUI/Widgets/SpinInput.hpp @@ -6,20 +6,16 @@ class Button; -class SpinInput : public wxNavigationEnabled +class SpinInputBase : public wxNavigationEnabled { - wxSize labelSize; - StateColor label_color; - StateColor text_color; - wxTextCtrl * text_ctrl{nullptr}; - Button * button_inc {nullptr}; - Button * button_dec {nullptr}; - wxTimer timer; - - int val; - int min; - int max; - int delta; +protected: + wxSize labelSize; + StateColor label_color; + StateColor text_color; + wxTextCtrl * text_ctrl{nullptr}; + Button * button_inc {nullptr}; + Button * button_dec {nullptr}; + wxTimer timer; static const int SpinInputWidth = 200; static const int SpinInputHeight = 50; @@ -31,8 +27,69 @@ class SpinInput : public wxNavigationEnabled }; public: - SpinInput(); + SpinInputBase(); + void SetCornerRadius(double radius); + + void SetLabel(const wxString &label) wxOVERRIDE; + + void SetLabelColor(StateColor const &color); + + void SetTextColor(StateColor const &color); + + void SetSize(wxSize const &size); + + void Rescale(); + + virtual bool Enable(bool enable = true) wxOVERRIDE; + + wxTextCtrl * GetText() { return text_ctrl; } + + virtual void SetValue(const wxString &text) = 0; + + wxString GetTextValue() const; + + bool SetFont(wxFont const& font) override; + + bool SetBackgroundColour(const wxColour& colour) override; + bool SetForegroundColour(const wxColour& colour) override; + void SetBorderColor(StateColor const& color); + void SetSelection(long from, long to); + +protected: + void DoSetToolTipText(wxString const &tip) override; + + void paintEvent(wxPaintEvent& evt); + + void render(wxDC& dc); + + void messureSize(); + + Button *create_button(ButtonId id); + virtual void bind_inc_dec_button(Button *btn, ButtonId id) = 0; + + // some useful events + virtual void mouseWheelMoved(wxMouseEvent& event) = 0; + virtual void keyPressed(wxKeyEvent& event) = 0; + virtual void onTimer(wxTimerEvent &evnet) = 0; + virtual void onTextLostFocus(wxEvent &event) = 0; + virtual void onTextEnter(wxCommandEvent &event) = 0; + + void onText(wxCommandEvent &event); + + void sendSpinEvent(); + + DECLARE_EVENT_TABLE() +}; + +class SpinInput : public SpinInputBase +{ + int val; + int min; + int max; + int delta; + +public: SpinInput(wxWindow * parent, wxString text, wxString label = "", @@ -51,64 +108,83 @@ public: int max = 100, int initial = 0); - void SetCornerRadius(double radius); - - void SetLabel(const wxString &label) wxOVERRIDE; - - void SetLabelColor(StateColor const &color); - - void SetTextColor(StateColor const &color); - - void SetSize(wxSize const &size); - - void Rescale(); - - virtual bool Enable(bool enable = true) wxOVERRIDE; - - wxTextCtrl * GetText() { return text_ctrl; } - - void SetValue(const wxString &text); + void SetValue(const wxString &text) override; void SetValue (int value); - - int GetValue () const; - wxString GetTextValue() const; + int GetValue () const; void SetRange(int min, int max); - bool SetFont(wxFont const& font) override; - - bool SetBackgroundColour(const wxColour& colour) override; - bool SetForegroundColour(const wxColour& colour) override; - void SetBorderColor(StateColor const& color); - int GetMin() const { return this->min; } int GetMax() const { return this->max; } - void SetSelection(long from, long to); protected: - void DoSetToolTipText(wxString const &tip) override; - -private: - void paintEvent(wxPaintEvent& evt); - - void render(wxDC& dc); - - void messureSize(); - - Button *create_button(ButtonId id); - + void bind_inc_dec_button(Button* btn, ButtonId id) override; // some useful events - void mouseWheelMoved(wxMouseEvent& event); - void keyPressed(wxKeyEvent& event); - void onTimer(wxTimerEvent &evnet); - void onTextLostFocus(wxEvent &event); - void onText(wxCommandEvent &event); - void onTextEnter(wxCommandEvent &event); + void mouseWheelMoved(wxMouseEvent& event) override; + void keyPressed(wxKeyEvent& event) override; + void onTimer(wxTimerEvent& evnet) override; + void onTextLostFocus(wxEvent& event) override; + void onTextEnter(wxCommandEvent& event) override; +}; - void sendSpinEvent(); +class SpinInputDouble : public SpinInputBase +{ + double val; + double min; + double max; + double inc; + double delta; + int digits {-1}; - DECLARE_EVENT_TABLE() +public: + + SpinInputDouble() : SpinInputBase() {} + + SpinInputDouble(wxWindow* parent, + wxString text, + wxString label = "", + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + double min = 0., + double max = 100., + double initial = 0., + double inc = 1.); + + void Create(wxWindow* parent, + wxString text, + wxString label = "", + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + double min = 0., + double max = 100., + double initial = 0., + double inc = 1.); + + void SetValue(const wxString& text) override; + + void SetValue(double value); + double GetValue() const; + + //wxString GetTextValue() const override; + + void SetRange(double min, double max); + void SetIncrement(double inc); + void SetDigits(unsigned digits); + + double GetMin() const { return this->min; } + double GetMax() const { return this->max; } + +protected: + void bind_inc_dec_button(Button* btn, ButtonId id) override; + // some useful events + void mouseWheelMoved(wxMouseEvent& event) override; + void keyPressed(wxKeyEvent& event) override; + void onTimer(wxTimerEvent& evnet) override; + void onTextLostFocus(wxEvent& event) override; + void onTextEnter(wxCommandEvent& event) override; }; #endif // !slic3r_GUI_SpinInput_hpp_ diff --git a/src/slic3r/GUI/WipeTowerDialog.cpp b/src/slic3r/GUI/WipeTowerDialog.cpp index 061245d52d..664223c1d3 100644 --- a/src/slic3r/GUI/WipeTowerDialog.cpp +++ b/src/slic3r/GUI/WipeTowerDialog.cpp @@ -109,7 +109,8 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) #endif sizer_chart->Add(m_chart, 0, wxALL, 5); - m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0.,5.0,3.,0.5); + m_widget_time = new ::SpinInputDouble(this,"", wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH(), -1), style, 0., 5., 3., 0.5); + m_widget_time->SetDigits(2); m_widget_volume = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,0,10000,0); m_widget_ramming_line_width_multiplicator = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); m_widget_ramming_step_multiplicator = new ::SpinInput(this,"",wxEmptyString,wxDefaultPosition,wxSize(ITEM_WIDTH(), -1),style,10,200,100); @@ -136,7 +137,6 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) sizer_param->Add(gsizer_param, 0, wxTOP, scale(10)); m_widget_time->SetValue(m_chart->get_time()); - m_widget_time->SetDigits(2); m_widget_volume->SetValue(m_chart->get_volume()); m_widget_volume->Disable(); m_widget_ramming_line_width_multiplicator->SetValue(m_ramming_line_width_multiplicator); @@ -152,8 +152,9 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters) sizer->SetSizeHints(this); SetSizer(sizer); - m_widget_time->Bind(wxEVT_TEXT,[this](wxCommandEvent&) {m_chart->set_xy_range(m_widget_time->GetValue(),-1);}); + m_widget_time->Bind(wxEVT_SPINCTRL,[this](wxCommandEvent&) { m_chart->set_xy_range(m_widget_time->GetValue(),-1); }); m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value + m_widget_time->GetText()->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} ); Refresh(true); // erase background diff --git a/src/slic3r/GUI/WipeTowerDialog.hpp b/src/slic3r/GUI/WipeTowerDialog.hpp index f64d1363a5..f6dd110262 100644 --- a/src/slic3r/GUI/WipeTowerDialog.hpp +++ b/src/slic3r/GUI/WipeTowerDialog.hpp @@ -26,7 +26,7 @@ private: ::SpinInput* m_widget_volume = nullptr; ::SpinInput* m_widget_ramming_line_width_multiplicator = nullptr; ::SpinInput* m_widget_ramming_step_multiplicator = nullptr; - wxSpinCtrlDouble* m_widget_time = nullptr; + ::SpinInputDouble* m_widget_time = nullptr; int m_ramming_step_multiplicator; int m_ramming_line_width_multiplicator;