From b50fc9d5dee6d6918bdc1be45f679dafe4d0045c Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 26 Jun 2024 12:30:12 +0200 Subject: [PATCH] Add Field graph type --- resources/ui_layout/default/extruder.ui | 2 +- src/libslic3r/Config.hpp | 19 ++++ src/libslic3r/LocalesUtils.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 21 ++++- src/slic3r/GUI/Field.cpp | 114 ++++++++++++++++++++++++ src/slic3r/GUI/Field.hpp | 21 +++++ src/slic3r/GUI/GUI.cpp | 11 +++ src/slic3r/GUI/GraphDialog.hpp | 18 +--- src/slic3r/GUI/OptionsGroup.cpp | 26 +++--- src/slic3r/GUI/Tab.cpp | 39 -------- 10 files changed, 202 insertions(+), 71 deletions(-) diff --git a/resources/ui_layout/default/extruder.ui b/resources/ui_layout/default/extruder.ui index e7db8c7e341..0babd70f4be 100644 --- a/resources/ui_layout/default/extruder.ui +++ b/resources/ui_layout/default/extruder.ui @@ -11,7 +11,7 @@ group:Offsets (for multi-extruder printers) setting:idx:extruder_offset setting:idx:extruder_temperature_offset setting:idx:extruder_fan_offset - extruder_extrusion_multiplier_speed + setting:idx:extruder_extrusion_multiplier_speed group:Retraction setting:idx:retract_length setting:idx:retract_lift diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 6c36ae0cc83..b7c3215cdf6 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -135,6 +135,22 @@ namespace Slic3r { } }; + struct GraphSettings + { + std::string title; + std::string description; + std::string y_label; + std::string x_label; + std::string null_label; + double min_x, max_x, step_x; + double min_y, max_y, step_y; + std::string label_min_x; + std::string label_max_x; + std::string label_min_y; + std::string label_max_y; + std::vector allowed_types; + GraphData reset_vals; + }; } namespace std { @@ -2719,6 +2735,9 @@ class ConfigOptionDef // For enums (when type == coEnum). Maps enum_values to enums. // Initialized by ConfigOptionEnum::get_enum_values() const t_config_enum_values *enum_keys_map = nullptr; + + // Initialized by ConfigOptionEnum::get_enum_values() + std::shared_ptr graph_settings; // for scripted gui widgets // true if it's not a real option but a simplified/composite one that use angelscript for interaction. diff --git a/src/libslic3r/LocalesUtils.cpp b/src/libslic3r/LocalesUtils.cpp index e07a474b12d..dc7506015ab 100644 --- a/src/libslic3r/LocalesUtils.cpp +++ b/src/libslic3r/LocalesUtils.cpp @@ -65,7 +65,7 @@ std::string to_string_nozero(double value, int32_t max_precision) { double intpart; if (modf(value, &intpart) == 0.0) { //shortcut for int - return std::to_string(intpart); + return std::to_string(int64_t(intpart)); } else { std::stringstream ss; //first, get the int part, to see how many digit it takes diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 808ecff3f63..15196b3989d 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1724,9 +1724,26 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("This string is edited by a Dialog and contains extusion multiplier for different speeds."); def->mode = comExpert | comSuSi; def->is_vector_extruder = true; - def->set_default_value((new ConfigOptionGraphs( GraphData(0,10, + def->set_default_value(new ConfigOptionGraphs( GraphData(0,10, GraphData::GraphType::LINEAR, {{10,1.},{20,1.},{30,1.},{40,1.},{60,1.},{80,1.},{120,1.},{160,1.},{240,1.},{320,1.},{480,1.},{640,1.},{960,1.},{1280,1.}} - )))->set_enabled(false)); + ))); + def->graph_settings = std::make_shared(); + def->graph_settings->title = L("Extrusion multiplier per extrusion speed"); + def->graph_settings->description = L("Choose the extrusion multipler value for multiple speeds.\nYou can add/remove points with a right clic."); + def->graph_settings->x_label = L("Print speed (mm/s)"); + def->graph_settings->y_label = L("Extrusion multiplier"); + def->graph_settings->null_label = L("No compensation"); + def->graph_settings->label_min_x = L("Graph min speed"); + def->graph_settings->label_max_x = L("Graph max speed"); + def->graph_settings->label_min_y = L("Minimum flow"); + def->graph_settings->label_max_y = L("Maximum flow"); + def->graph_settings->min_x = 10; + def->graph_settings->max_x = 2000; + def->graph_settings->step_x = 1.; + def->graph_settings->min_y = 0.1; + def->graph_settings->max_y = 2; + def->graph_settings->step_y = 0.1; + def->graph_settings->allowed_types = {GraphData::GraphType::LINEAR, GraphData::GraphType::SQUARE}; def = this->add("extruder_offset", coPoints); def->label = L("Extruder offset"); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 030e833abf2..0325d8c336f 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -5,6 +5,7 @@ #include "BitmapComboBox.hpp" #include "format.hpp" +#include "GraphDialog.hpp" #include "GUI.hpp" #include "GUI_App.hpp" #include "I18N.hpp" @@ -2098,6 +2099,119 @@ void ColourPicker::sys_color_changed() #endif } + +void GraphButton::BUILD() +{ + auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord); + if (m_opt.height >= 0) size.SetHeight(m_opt.height*m_em_unit); + if (m_opt.width >= 0) size.SetWidth(m_opt.width*m_em_unit); + + assert(m_opt.type == coGraph || m_opt.type == coGraphs); + if (m_opt.type == coGraphs) + current_value = m_opt.get_default_value()->get_at(m_opt_idx); + if (m_opt.type == coGraph) + current_value = m_opt.get_default_value()->value; + + wxButton* bt_widget = new wxButton(m_parent, wxID_ANY, _L("Edit graph"), wxDefaultPosition, size); + if (parent_is_custom_ctrl && m_opt.height < 0) + opt_height = (double)bt_widget->GetSize().GetHeight() / m_em_unit; + bt_widget->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + if (!wxOSX) bt_widget->SetBackgroundStyle(wxBG_STYLE_PAINT); + + wxGetApp().UpdateDarkUI(bt_widget); + + // recast as a wxWindow to fit the calling convention + window = dynamic_cast(bt_widget); + + //window->Bind(wxEVT_COLOURPICKER_CHANGED, ([this](wxCommandEvent e) { on_change_field(); }), window->GetId()); + + bt_widget->Bind(wxEVT_BUTTON, ([this](wxCommandEvent &e) { + GraphSettings settings; + assert(m_opt.graph_settings); + if (m_opt.graph_settings) { + settings = *m_opt.graph_settings; + } else { + settings.title = m_opt.full_label.empty() ? m_opt.label : m_opt.full_label; + settings.description = m_opt.tooltip; + settings.x_label = ""; + settings.y_label = ""; + settings.null_label = L("No values"); + settings.label_min_x = L("Minimum x"); + settings.label_max_x = L("Maximum x"); + settings.label_min_y = L("Minimum y"); + settings.label_max_y = L("Maximum y"); + settings.min_x = 0; + settings.max_x = 1000; + settings.step_x = 0.1; + settings.min_y = 0; + settings.max_y = 1000; + settings.step_y = 0.1; + settings.allowed_types = {GraphData::GraphType::LINEAR, GraphData::GraphType::SPLINE, GraphData::GraphType::SQUARE}; + } + if (this->m_opt.type == coGraphs) + settings.reset_vals = m_opt.get_default_value()->get_at(m_opt_idx); + if (this->m_opt.type == coGraph) + settings.reset_vals = m_opt.get_default_value()->value; + GraphDialog dlg(this->window, current_value, settings); + if (dlg.ShowModal() == wxID_OK) { + m_value = current_value = dlg.get_data(); + this->on_change_field(); + } + })); + this->set_tooltip(current_value.serialize()); +} + +void GraphButton::set_any_value(const boost::any &value, bool change_event) +{ + // can be ConfigOptionDef::GUIType::color + m_disable_change_event = !change_event; + if (this->m_opt.type == coGraphs && m_opt_idx >= 0) { + assert(false); // shouldn't happen. or need to be tested + std::vector graphs = boost::any_cast>(value); + assert(!graphs.empty()); + if (!graphs.empty()) { + assert(m_opt_idx m_opt.type == coGraph || this->m_opt.type == coGraphs) { + m_value = current_value = boost::any_cast(value); + } + m_disable_change_event = false; +} + +boost::any& GraphButton::get_value() +{ + m_value = current_value; + return m_value; +} + +void GraphButton::msw_rescale() +{ + Field::msw_rescale(); + + wxButton* field = dynamic_cast(window); + auto size = wxSize(def_width() * m_em_unit, wxDefaultCoord); + if (m_opt.height >= 0) + size.SetHeight(m_opt.height * m_em_unit); + else if (parent_is_custom_ctrl && opt_height > 0) + size.SetHeight(lround(opt_height * m_em_unit)); + if (m_opt.width >= 0) size.SetWidth(m_opt.width * m_em_unit); + if (parent_is_custom_ctrl) + field->SetSize(size); + else + field->SetMinSize(size); + +} + +void GraphButton::sys_color_changed() +{ +#ifdef _WIN32 + if (wxWindow* win = this->getWindow()) + if (wxButton* bt = dynamic_cast(win)) + wxGetApp().UpdateDarkUI(bt); +#endif +} + void PointCtrl::BUILD() { auto temp = new wxBoxSizer(wxHORIZONTAL); diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index db0c6aafc34..192d6f8504f 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -457,6 +457,27 @@ class ColourPicker : public Field { wxWindow* getWindow() override { return window; } }; +class GraphButton : public Field { + using Field::Field; + GraphData current_value; +public: + GraphButton(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} + GraphButton(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} + ~GraphButton() {} + + wxWindow* window{ nullptr }; + void BUILD() override; + + void set_any_value(const boost::any &value, bool change_event = false) override; + boost::any& get_value() override; + void msw_rescale() override; + void sys_color_changed() override; + + void enable() override { dynamic_cast(window)->Enable(); } + void disable() override{ dynamic_cast(window)->Disable(); } + wxWindow* getWindow() override { return window; } +}; + class PointCtrl : public Field { using Field::Field; public: diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 54f81cfc958..e603dfdd46a 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -210,6 +210,17 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio if (! new_val.empty()) new_val.erase(new_val.begin() + new_val.size() - 2, new_val.end()); break; + case coGraph: + if (auto opt = dynamic_cast(conf_substitution.new_value.get())) { + new_val = opt->value.serialize(); + } else assert(false); + break; + case coGraphs: + if (auto opts = dynamic_cast(conf_substitution.new_value.get())) { + for (const GraphData &graph : opts->get_values()) + new_val += graph.serialize() + ", "; + } else assert(false); + break; default: assert(false); } diff --git a/src/slic3r/GUI/GraphDialog.hpp b/src/slic3r/GUI/GraphDialog.hpp index f83cd5bd752..60646ac5a15 100644 --- a/src/slic3r/GUI/GraphDialog.hpp +++ b/src/slic3r/GUI/GraphDialog.hpp @@ -7,27 +7,11 @@ #include #include +#include "libslic3r/Config.hpp" // for GraphSettings #include "RammingChart.hpp" namespace Slic3r { namespace GUI { -struct GraphSettings -{ - std::string title; - std::string description; - std::string y_label; - std::string x_label; - std::string null_label; - double min_x, max_x, step_x; - double min_y, max_y, step_y; - std::string label_min_x; - std::string label_max_x; - std::string label_min_y; - std::string label_max_y; - std::vector allowed_types; - GraphData reset_vals; -}; - class GraphPanel : public wxPanel { public: diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 2ebde4792f6..dcde96ca493 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -25,7 +25,7 @@ const t_field& OptionsGroup::build_field(const Option& opt) { return build_field(opt.opt_id, opt.opt); } const t_field& OptionsGroup::build_field(const t_config_option_key& id) { - const ConfigOptionDef& opt = m_options.at(id).opt; + const ConfigOptionDef& opt = m_options.at(id).opt; return build_field(id, opt); } @@ -54,11 +54,11 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co case coFloatOrPercent: case coFloat: case coFloats: - case coPercent: + case coPercent: case coPercents: case coFloatsOrPercents: - case coString: - case coStrings: + case coString: + case coStrings: m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); break; case coBools: @@ -67,28 +67,32 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); break; } - case coBool: + case coBool: m_fields.emplace(id, CheckBox::Create(this->ctrl_parent(), opt, id)); - break; + break; case coInts: if (id.find('#') == std::string::npos) { // string field with vector serialization m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); break; } - case coInt: + case coInt: m_fields.emplace(id, SpinCtrl::Create(this->ctrl_parent(), opt, id)); - break; + break; case coEnum: m_fields.emplace(id, Choice::Create(this->ctrl_parent(), opt, id)); - break; + break; case coPoint: case coPoints: m_fields.emplace(id, PointCtrl::Create(this->ctrl_parent(), opt, id)); - break; + break; + case coGraph: + case coGraphs: + m_fields.emplace(id, GraphButton::Create(this->ctrl_parent(), opt, id)); + break; case coNone: assert(false); break; default: - throw Slic3r::LogicError("This control doesn't exist till now"); break; + throw Slic3r::LogicError("This control doesn't exist till now"); break; } } // Grab a reference to fields for convenience diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index e6b3499ef94..ec56dcf2c77 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2568,45 +2568,6 @@ std::vector Tab::create_pages(std::string setting_type_nam return sizer; }; current_group->append_line(thisline); - } else if (boost::starts_with(full_line, "extruder_extrusion_multiplier_speed")) { - // don't forget the idx_page as it's on the extruder page. - Line thisline = current_group->create_single_option_line("extruder_extrusion_multiplier_speed", "", idx_page); - thisline.widget = [this, idx_page](wxWindow *parent) { - auto dialog_btn = new wxButton(parent, wxID_ANY, _L("Extrusion multiplier per speed") + dots, - wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - dialog_btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - wxGetApp().UpdateDarkUI(dialog_btn); - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(dialog_btn); - dialog_btn->Bind(wxEVT_BUTTON, ([this, idx_page](wxCommandEvent &e) { - GraphSettings settings; - settings.title = L("Extrusion multiplier per extrusion speed"); - settings.description = L("Choose the extrusion multipler value for multiple speeds.\nYou can add/remove points with a right clic."); - settings.x_label = L("Print speed (mm/s)"); - settings.y_label = L("Extrusion multiplier"); - settings.null_label = L("No compensation"); - settings.label_min_x = L("Graph min speed"); - settings.label_max_x = L("Graph max speed"); - settings.label_min_y = L("Minimum flow"); - settings.label_max_y = L("Maximum flow"); - settings.min_x = 10; - settings.max_x = 2000; - settings.step_x = 1.; - settings.min_y = 0.1; - settings.max_y = 2; - settings.step_y = 0.1; - settings.allowed_types = {GraphData::GraphType::LINEAR, GraphData::GraphType::SQUARE}; - settings.reset_vals = static_cast(m_config_base->def()->get("extruder_extrusion_multiplier_speed")->default_value.get())->get_at(idx_page); - GraphDialog dlg(this, (m_config_base->option("extruder_extrusion_multiplier_speed"))->get_at(idx_page), settings); - if (dlg.ShowModal() == wxID_OK) { - //(m_config_base->option("extruder_extrusion_multiplier_speed"))->get_at(0) = dlg.get_parameters(); - m_config_base->option("extruder_extrusion_multiplier_speed")->set_enabled(!dlg.is_disabled(), idx_page); - load_key_value("extruder_extrusion_multiplier_speed", dlg.get_data(), false, idx_page); - } - })); - return sizer; - }; - current_group->append_line(thisline); } else if (full_line == "bed_shape") { TabPrinter *tab = nullptr; if ((tab = dynamic_cast(this)) == nullptr)