From c577b7fb38d6ea2696bccf539230eeb35fda0f18 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 5 Jun 2023 17:23:28 +0200 Subject: [PATCH] Editing of Custom G-code: Implemented ParamsViewCtrl + GUI_App : Fixed update of the dark mode, when DataViewCtrl doesn't have header --- src/slic3r/GUI/EditGCodeDialog.cpp | 477 ++++++++++++++++++++++++++--- src/slic3r/GUI/EditGCodeDialog.hpp | 211 ++++++++++++- src/slic3r/GUI/GUI_App.cpp | 3 +- src/slic3r/GUI/Tab.cpp | 33 +- src/slic3r/GUI/Tab.hpp | 7 +- 5 files changed, 672 insertions(+), 59 deletions(-) diff --git a/src/slic3r/GUI/EditGCodeDialog.cpp b/src/slic3r/GUI/EditGCodeDialog.cpp index 45feb050197..c29fe7d3958 100644 --- a/src/slic3r/GUI/EditGCodeDialog.cpp +++ b/src/slic3r/GUI/EditGCodeDialog.cpp @@ -7,8 +7,6 @@ #include #include #include -#include -#include #include #include "GUI.hpp" @@ -18,7 +16,11 @@ #include "Tab.hpp" #include "wxExtensions.hpp" #include "BitmapCache.hpp" +#include "ExtraRenderers.hpp" #include "MsgDialog.hpp" +#include "Plater.hpp" + +#include "libslic3r/Preset.hpp" namespace Slic3r { namespace GUI { @@ -26,27 +28,14 @@ namespace GUI { static wxArrayString get_patterns_list() { wxArrayString patterns; - for (const wxString& item : { - ";comment"//format_wxstr(";%1%",_L("comment")) - , "M862.3 P \"[printer_model]\" ; printer model check" - , "M862.1 P[nozzle_diameter]; nozzle diameter check" - , "M115 U3.12.2; tell printer latest fw version" - , "G90; use absolute coordinates" - , "M83; extruder relative mode" - , "M104 S[first_layer_temperature]; set extruder temp" - , "M140 S[first_layer_bed_temperature]; set bed temp" - , "M190 S[first_layer_bed_temperature]; wait for bed temp" - , "M109 S[first_layer_temperature]; wait for extruder temp" - , "G28 W; home all without mesh bed level" - , "G80; mesh bed leveling" - , "M403 E0 F {\n" - " + ((filament_type[0] == \"FLEX\") ? 1 : ((filament_type[0] == \"PVA\") ? 2 : 0))\n" - "}" - , "{if not OPTION}" - , "G1" - , "T[initial_tool]; select extruder" - , "G92 E0" - , "{endif}" + for (const wxString& item : { + "printer_model" + , "nozzle_diameter" + , "first_layer_temperature" + , "first_layer_bed_temperature" + , "first_layer_bed_temperature" + , "first_layer_temperature" + , "initial_tool" }) patterns.Add(item); return patterns; @@ -65,22 +54,17 @@ EditGCodeDialog::EditGCodeDialog(wxWindow* parent, const std::string& key, const int border = 10; int em = em_unit(); - wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Edit your custom G-code using patterns")); - label_top->SetFont(wxGetApp().bold_font()); + wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Built-in placeholders (Double click item to add to G-code)") + ":"); auto* grid_sizer = new wxFlexGridSizer(1, 3, 5, 15); grid_sizer->SetFlexibleDirection(wxBOTH); - m_patterns_list = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(em * 15, em * 30), get_patterns_list(), wxLB_SINGLE | wxLB_NEEDED_SB | wxLB_SORT -#ifdef _WIN32 - | wxBORDER_SIMPLE -#endif - ); - m_patterns_list->SetFont(wxGetApp().code_font()); - wxGetApp().UpdateDarkUI(m_patterns_list); + m_params_list = new ParamsViewCtrl(this, wxSize(em * 20, em * 30)); + m_params_list->SetFont(wxGetApp().code_font()); + wxGetApp().UpdateDarkUI(m_params_list); m_add_btn = new ScalableButton(this, wxID_ANY, "add_copies"); - m_add_btn->SetToolTip(_L("Add selected pettern to the G-code")); + m_add_btn->SetToolTip(_L("Add selected placeholder to G-code")); m_gcode_editor = new wxTextCtrl(this, wxID_ANY, value, wxDefaultPosition, wxSize(em * 45, em * 30), wxTE_MULTILINE #ifdef _WIN32 @@ -90,7 +74,7 @@ EditGCodeDialog::EditGCodeDialog(wxWindow* parent, const std::string& key, const m_gcode_editor->SetFont(wxGetApp().code_font()); wxGetApp().UpdateDarkUI(m_gcode_editor); - grid_sizer->Add(m_patterns_list, 1, wxEXPAND); + grid_sizer->Add(m_params_list, 1, wxEXPAND); grid_sizer->Add(m_add_btn, 0, wxALIGN_CENTER_VERTICAL); grid_sizer->Add(m_gcode_editor, 2, wxEXPAND); @@ -98,15 +82,18 @@ EditGCodeDialog::EditGCodeDialog(wxWindow* parent, const std::string& key, const grid_sizer->AddGrowableCol(0, 1); grid_sizer->AddGrowableCol(2, 1); + m_param_label = new wxStaticText(this, wxID_ANY, _L("Select placeholder")); + m_param_label->SetFont(wxGetApp().bold_font()); + wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxOK | wxCANCEL); - wxButton* btnOK = static_cast(this->FindWindowById(wxID_OK, this)); - wxGetApp().UpdateDarkUI(btnOK); - wxGetApp().UpdateDarkUI(static_cast(this->FindWindowById(wxID_CANCEL, this))); + wxGetApp().UpdateDarkUI(this->FindWindowById(wxID_OK, this)); + wxGetApp().UpdateDarkUI(this->FindWindowById(wxID_CANCEL, this)); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); topSizer->Add(label_top , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border); topSizer->Add(grid_sizer , 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border); + topSizer->Add(m_param_label , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border); topSizer->Add(btns , 0, wxEXPAND | wxALL, border); SetSizer(topSizer); @@ -117,12 +104,106 @@ EditGCodeDialog::EditGCodeDialog(wxWindow* parent, const std::string& key, const this->CenterOnScreen(); + init_params_list(); + bind_list_and_button(); +} + +std::string EditGCodeDialog::get_edited_gcode() const +{ + return into_u8(m_gcode_editor->GetValue()); +} + +void EditGCodeDialog::init_params_list() +{ + auto list = get_patterns_list(); + + m_params_list->AppendGroup(GroupParamsType::SlicingState); + for (const auto& sub_gr : { SubSlicingState::ReadOnly, SubSlicingState::ReadWrite }) { + int i = 0; + for (const wxString& name : list) { + const auto param_type = static_cast(1 + std::modulus()(i, 3)); + m_params_list->AppendParam(GroupParamsType::SlicingState, param_type, into_u8(name), sub_gr); + ++i; + } + } + + auto get_set_from_vec = [](const std::vector& vec) { + return std::set(vec.begin(), vec.end()); + }; + + const bool is_fff = wxGetApp().plater()->printer_technology() == ptFFF; + const std::set print_options = get_set_from_vec(is_fff ? Preset::print_options() : Preset::sla_print_options()); + const std::set material_options = get_set_from_vec(is_fff ? Preset::filament_options() : Preset::sla_material_options()); + const std::set printer_options = get_set_from_vec(is_fff ? Preset::printer_options() : Preset::sla_printer_options()); + + const auto& full_config = wxGetApp().preset_bundle->full_config(); + + const auto& def = full_config.def()->get("")->label; + + m_params_list->AppendGroup(GroupParamsType::PrintSettings); + for (const auto& opt : print_options) + if (const ConfigOption *optptr = full_config.optptr(opt)) + m_params_list->AppendParam(GroupParamsType::PrintSettings, optptr->is_scalar() ? ParamType::Scalar : ParamType::Vector, opt); - m_patterns_list->Bind(wxEVT_LISTBOX_DCLICK, [this](wxCommandEvent& evt) { - wxString val = m_patterns_list->GetString(m_patterns_list->GetSelection()); - assert(!val.IsEmpty()); - auto insert_to = m_gcode_editor->GetInsertionPoint(); - m_gcode_editor->WriteText(val); + m_params_list->AppendGroup(GroupParamsType::MaterialSettings); + for (const auto& opt : material_options) + if (const ConfigOption *optptr = full_config.optptr(opt)) + m_params_list->AppendParam(GroupParamsType::MaterialSettings, optptr->is_scalar() ? ParamType::Scalar : ParamType::FilamentVector, opt); + + m_params_list->AppendGroup(GroupParamsType::PrinterSettings); + for (const auto& opt : printer_options) + if (const ConfigOption *optptr = full_config.optptr(opt)) + m_params_list->AppendParam(GroupParamsType::PrinterSettings, optptr->is_scalar() ? ParamType::Scalar : ParamType::Vector, opt); +} + +void EditGCodeDialog::add_selected_value_to_gcode() +{ + const wxString val = m_params_list->GetSelectedValue(); + if (!val.IsEmpty()) + m_gcode_editor->WriteText(val + "\n"); +} + +void EditGCodeDialog::bind_list_and_button() +{ + m_params_list->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent& evt) { + wxString label; + + const std::string opt_key = m_params_list->GetSelectedParamKey(); + if (!opt_key.empty()) { + const auto& full_config = wxGetApp().preset_bundle->full_config(); + if (const ConfigDef* def = full_config.def(); + def && def->has(opt_key)) { + const ConfigOptionDef* cod = def->get(opt_key); + const ConfigOption* optptr = full_config.optptr(opt_key); + const ConfigOptionType type = optptr->type(); + + wxString type_str = type == coNone ? "none" : + type == coFloat || type == coFloats ? "float" : + type == coInt || type == coInts ? "integer" : + type == coString || type == coStrings ? "string" : + type == coPercent || type == coPercents ? "percent" : + type == coFloatOrPercent || type == coFloatsOrPercents ? "float ar percent" : + type == coPoint || type == coPoints || type == coPoint3 ? "point" : + type == coBool || type == coBools ? "bool" : + type == coEnum ? "enum" : "undef"; + + label = ( cod->full_label.empty() && cod->label.empty() ) ? format_wxstr("Undef Label\n(%1%)", type_str) : + (!cod->full_label.empty() && !cod->label.empty() ) ? + format_wxstr("%1% > %2%\n(%3%)", _(cod->full_label), _(cod->label), type_str) : + format_wxstr("%1%\n(%2%)", cod->label.empty() ? _(cod->full_label) : _(cod->label), type_str); + } + } + + m_param_label->SetLabel(label); + Layout(); + }); + + m_params_list->Bind(wxEVT_DATAVIEW_ITEM_ACTIVATED, [this](wxDataViewEvent& ) { + add_selected_value_to_gcode(); + }); + + m_add_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { + add_selected_value_to_gcode(); }); } @@ -130,8 +211,6 @@ void EditGCodeDialog::on_dpi_changed(const wxRect&suggested_rect) { const int& em = em_unit(); - //m_optgroup->msw_rescale(); - msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL }); const wxSize& size = wxSize(45 * em, 35 * em); @@ -146,10 +225,316 @@ void EditGCodeDialog::on_sys_color_changed() m_add_btn->sys_color_changed(); } -void EditGCodeDialog::OnOK(wxEvent& event) + +const std::map> GroupParamsInfo { +// Type Name BitmapName + { GroupParamsType::SlicingState, {L("Slicing State"), "re_slice" }, }, + { GroupParamsType::PrintSettings, {L("Print settings"), "cog" }, }, + { GroupParamsType::MaterialSettings,{L("Material Settings"),"spool" }, }, + { GroupParamsType::PrinterSettings, {L("Printer Settings"), "printer" }, }, +}; + +const std::map> SubSlicingStateInfo { +// Type Name BitmapName + { SubSlicingState::ReadOnly, {L("Read Only"), "lock_closed" }, }, + { SubSlicingState::ReadWrite, {L("Read Write"), "lock_open" }, }, +}; + +const std::map ParamsInfo { +// Type BitmapName + { ParamType::Scalar, "scalar_param" }, + { ParamType::Vector, "vector_param" }, + { ParamType::FilamentVector,"vector_filament_param" }, +}; + +static void make_bold(wxString& str) +{ +#if defined(SUPPORTS_MARKUP) && !defined(__APPLE__) + str = format_wxstr("%1%", str); +#endif +} + +// ---------------------------------------------------------------------------- +// ParamsModelNode: a node inside ParamsModel +// ---------------------------------------------------------------------------- + +ParamsNode::ParamsNode(GroupParamsType type) + : m_group_type (type) +{ + const auto& [name, icon_n] = GroupParamsInfo.at(type); + text = _(name); + make_bold(text); + icon_name = icon_n; +} + +ParamsNode::ParamsNode(ParamsNode *parent, SubSlicingState sub_type) + : m_parent(parent) + , m_group_type(parent->m_group_type) +{ + const auto& [name, icon_n] = SubSlicingStateInfo.at(sub_type); + text = _(name); + icon_name = icon_n; +} + +ParamsNode::ParamsNode( ParamsNode* parent, + ParamType param_type, + const std::string& param_key, + SubSlicingState subgroup_type) + : m_parent(parent) + , m_group_type(parent->m_group_type) + , m_sub_type(subgroup_type) + , m_param_type(param_type) + , m_container(false) + , param_key(param_key) +{ + text = from_u8(param_key); + if (param_type == ParamType::Vector) + text += "[]"; + else if (param_type == ParamType::FilamentVector) + text += "[current_extruder]"; + + icon_name = ParamsInfo.at(param_type); +} + + +// ---------------------------------------------------------------------------- +// ParamsModel +// ---------------------------------------------------------------------------- + +ParamsModel::ParamsModel() +{ +} + + +wxDataViewItem ParamsModel::AppendGroup(GroupParamsType type) +{ + m_group_nodes[type] = std::make_unique(type); + + wxDataViewItem parent(nullptr); + wxDataViewItem child((void*)m_group_nodes[type].get()); + + ItemAdded(parent, child); + m_ctrl->Expand(parent); + return child; +} + +wxDataViewItem ParamsModel::AppendSubGroup(GroupParamsType type, SubSlicingState sub_type) +{ + m_sub_slicing_state_nodes[sub_type] = std::make_unique(m_group_nodes[type].get(), sub_type); + + const wxDataViewItem group_item ((void*)m_group_nodes[type].get()); + const wxDataViewItem sub_group_item((void*)m_sub_slicing_state_nodes[sub_type].get()); + + ItemAdded(group_item, sub_group_item); + + m_ctrl->Expand(group_item); + return sub_group_item; +} + +wxDataViewItem ParamsModel::AppendParam(GroupParamsType type, + ParamType param_type, + const std::string& param_key, + SubSlicingState subgroup_type) +{ + ParamsNode* parent_node{ nullptr }; + if (subgroup_type == SubSlicingState::Undef) + parent_node = m_group_nodes[type].get(); + else { + if (m_sub_slicing_state_nodes.find(subgroup_type) == m_sub_slicing_state_nodes.end()) + AppendSubGroup(type, subgroup_type); + parent_node = m_sub_slicing_state_nodes[subgroup_type].get(); + } + + parent_node->Append(std::make_unique(m_group_nodes[type].get(), param_type, param_key, subgroup_type)); + + const wxDataViewItem parent_item((void*)parent_node); + const wxDataViewItem child_item((void*)parent_node->GetChildren().back().get()); + + ItemAdded(parent_item, child_item); + return child_item; +} + +wxString ParamsModel::GetParamName(wxDataViewItem item) +{ + if (item.IsOk()) { + ParamsNode* node = static_cast(item.GetID()); + if (node->IsParamNode()) + return node->text; + } + return wxEmptyString; +} + +std::string ParamsModel::GetParamKey(wxDataViewItem item) +{ + if (item.IsOk()) { + ParamsNode* node = static_cast(item.GetID()); + return node->param_key; + } + return std::string(); +} + +void ParamsModel::Rescale() +{ + +} + +void ParamsModel::Clear() +{ + +} + +void ParamsModel::GetValue(wxVariant& variant, const wxDataViewItem& item, unsigned int col) const { + assert(item.IsOk()); + + ParamsNode* node = static_cast(item.GetID()); + if (col == unsigned int(0)) +#ifdef __linux__ + variant << wxDataViewIconText(node->text, get_bmp_bundle(node->icon_name)->GetIconFor(m_ctrl->GetParent())); +#else + variant << DataViewBitmapText(node->text, get_bmp_bundle(node->icon_name)->GetBitmapFor(m_ctrl->GetParent())); +#endif //__linux__ + else + wxLogError("DiffModel::GetValue: wrong column %d", col); +} + +bool ParamsModel::SetValue(const wxVariant& variant, const wxDataViewItem& item, unsigned int col) +{ + assert(item.IsOk()); + + ParamsNode* node = static_cast(item.GetID()); + if (col == unsigned int(0)) { +#ifdef __linux__ + wxDataViewIconText data; + data << variant; + node->m_icon = data.GetIcon(); +#else + DataViewBitmapText data; + data << variant; + node->icon = data.GetBitmap(); +#endif + node->text = data.GetText(); + return true; + } + + wxLogError("DiffModel::SetValue: wrong column"); + return false; +} + +wxDataViewItem ParamsModel::GetParent(const wxDataViewItem&item) const +{ + // the invisible root node has no parent + if (!item.IsOk()) + return wxDataViewItem(nullptr); + + ParamsNode* node = static_cast(item.GetID()); + + if (node->IsGroupNode()) + return wxDataViewItem(nullptr); + + return wxDataViewItem((void*)node->GetParent()); +} + +bool ParamsModel::IsContainer(const wxDataViewItem& item) const +{ + // the invisble root node can have children + if (!item.IsOk()) + return true; + + ParamsNode* node = static_cast(item.GetID()); + return node->IsContainer(); +} - event.Skip(); +unsigned int ParamsModel::GetChildren(const wxDataViewItem& parent, wxDataViewItemArray& array) const +{ + ParamsNode* parent_node = (ParamsNode*)parent.GetID(); + + if (parent_node == nullptr) { + for (const auto& [type, group] : m_group_nodes) + array.Add(wxDataViewItem((void*)group.get())); + } + else if (parent_node->IsGroupNode() && parent_node->GetChildren().empty()) { + for (const auto& [type, sub_group] : m_sub_slicing_state_nodes) + array.Add(wxDataViewItem((void*)sub_group.get())); + } + else { + const ParamsNodePtrArray& children = parent_node->GetChildren(); + for (const std::unique_ptr& child : children) + array.Add(wxDataViewItem((void*)child.get())); + } + + return array.Count(); +} + + +// ---------------------------------------------------------------------------- +// ParamsViewCtrl +// ---------------------------------------------------------------------------- + +ParamsViewCtrl::ParamsViewCtrl(wxWindow *parent, wxSize size) + : wxDataViewCtrl(parent, wxID_ANY, wxDefaultPosition, size, wxDV_SINGLE | wxDV_NO_HEADER// | wxDV_ROW_LINES +#ifdef _WIN32 + | wxBORDER_SIMPLE +#endif + ), + m_em_unit(em_unit(parent)) +{ + wxGetApp().UpdateDVCDarkUI(this); + + model = new ParamsModel(); + this->AssociateModel(model); + model->SetAssociatedControl(this); + +#ifdef __linux__ + wxDataViewIconTextRenderer* rd = new wxDataViewIconTextRenderer(); +#ifdef SUPPORTS_MARKUP + rd->EnableMarkup(true); +#endif + wxDataViewColumn* column = new wxDataViewColumn("", rd, 0, width * m_em_unit, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_CELL_INERT); +#else + wxDataViewColumn* column = new wxDataViewColumn("", new BitmapTextRenderer(true, wxDATAVIEW_CELL_INERT), 0, 20 * m_em_unit, wxALIGN_TOP, wxDATAVIEW_COL_RESIZABLE); +#endif //__linux__ + this->AppendColumn(column); + this->SetExpanderColumn(column); +} + +wxDataViewItem ParamsViewCtrl::AppendGroup(GroupParamsType type) +{ + return model->AppendGroup(type); +} + +wxDataViewItem ParamsViewCtrl::AppendParam( GroupParamsType group_type, + ParamType param_type, + const std::string& param_key, + SubSlicingState subgroup_type /*= SubSlicingState::Undef*/) +{ + return model->AppendParam(group_type, param_type, param_key, subgroup_type); +} + +wxString ParamsViewCtrl::GetValue(wxDataViewItem item) +{ + return model->GetParamName(item); +} + +wxString ParamsViewCtrl::GetSelectedValue() +{ + return model->GetParamName(this->GetSelection()); +} + +std::string ParamsViewCtrl::GetSelectedParamKey() +{ + return model->GetParamKey(this->GetSelection()); +} + +void ParamsViewCtrl::Clear() +{ + model->Clear(); +} + +void ParamsViewCtrl::Rescale(int em/* = 0*/) +{ + model->Rescale(); + Refresh(); } }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/EditGCodeDialog.hpp b/src/slic3r/GUI/EditGCodeDialog.hpp index eaf3948c85d..fddd76a091a 100644 --- a/src/slic3r/GUI/EditGCodeDialog.hpp +++ b/src/slic3r/GUI/EditGCodeDialog.hpp @@ -6,18 +6,18 @@ #include #include "GUI_Utils.hpp" +#include "wxExtensions.hpp" +#include "libslic3r/Preset.hpp" class wxListBox; class wxTextCtrl; -//class wxStaticText; class ScalableButton; -//class wxBoxSizer; namespace Slic3r { namespace GUI { -class PresetComboBox; +class ParamsViewCtrl; //------------------------------------------ // EditGCodeDialog @@ -25,22 +25,219 @@ class PresetComboBox; class EditGCodeDialog : public DPIDialog { - wxListBox* m_patterns_list {nullptr}; + ParamsViewCtrl* m_params_list {nullptr}; ScalableButton* m_add_btn {nullptr}; wxTextCtrl* m_gcode_editor {nullptr}; - - void OnOK(wxEvent& event); + wxStaticText* m_param_label {nullptr}; public: - EditGCodeDialog(wxWindow* parent, const std::string& key, const std::string& value); + EditGCodeDialog(wxWindow*parent, const std::string&key, const std::string&value); ~EditGCodeDialog() {} + std::string get_edited_gcode() const; + + void init_params_list(); + void add_selected_value_to_gcode(); + void bind_list_and_button(); + protected: void on_dpi_changed(const wxRect& suggested_rect) override; void on_sys_color_changed() override; }; + + +// ---------------------------------------------------------------------------- +// ParamsModelNode: a node inside ParamsModel +// ---------------------------------------------------------------------------- + +class ParamsNode; +using ParamsNodePtrArray = std::vector>; + +// Discard and Cancel buttons are always but next buttons are optional +enum class GroupParamsType { + SlicingState, + PrintSettings, + MaterialSettings, + PrinterSettings, +}; +using GroupParamsNodePtrMap = std::map>; + +enum class SubSlicingState { + Undef, + ReadOnly, + ReadWrite, +}; +using SubSlicingStateNodePtrMap = std::map>; + +enum class ParamType { + Undef, + Scalar, + Vector, + FilamentVector, +}; + +// On all of 3 different platforms Bitmap+Text icon column looks different +// because of Markup text is missed or not implemented. +// As a temporary workaround, we will use: +// MSW - DataViewBitmapText (our custom renderer wxBitmap + wxString, supported Markup text) +// OSX - -//-, but Markup text is not implemented right now +// GTK - wxDataViewIconText (wxWidgets for GTK renderer wxIcon + wxString, supported Markup text) +class ParamsNode +{ + ParamsNode* m_parent{ nullptr }; + ParamsNodePtrArray m_children; + + GroupParamsType m_group_type{ GroupParamsType::SlicingState }; + SubSlicingState m_sub_type { SubSlicingState::Undef }; + ParamType m_param_type{ ParamType::Undef }; + + // TODO/FIXME: + // the GTK version of wxDVC (in particular wxDataViewCtrlInternal::ItemAdded) + // needs to know in advance if a node is or _will be_ a container. + // Thus implementing: + // bool IsContainer() const + // { return m_children.size()>0; } + // doesn't work with wxGTK when DiffModel::AddToClassical is called + // AND the classical node was removed (a new node temporary without children + // would be added to the control) + bool m_container{ true }; + +public: + +#ifdef __linux__ + wxIcon icon; +#else + wxBitmap icon; +#endif //__linux__ + std::string icon_name; + std::string param_key; + wxString text; + + // Group params(root) node + ParamsNode(GroupParamsType type); + + // sub SlicingState node + ParamsNode(ParamsNode* parent, SubSlicingState sub_type); + + // parametre node + ParamsNode( ParamsNode* parent, + ParamType param_type, + const std::string& param_key, + SubSlicingState subgroup_type); + + bool IsContainer() const { return m_container; } + bool IsGroupNode() const { return m_parent == nullptr; } + bool IsSubGroupNode() const { return m_sub_type != SubSlicingState::Undef; } + bool IsParamNode() const { return m_param_type != ParamType::Undef; } + + ParamsNode* GetParent() { return m_parent; } + ParamsNodePtrArray& GetChildren() { return m_children; } + + void Append(std::unique_ptr child) { m_children.emplace_back(std::move(child)); } +}; + + +// ---------------------------------------------------------------------------- +// ParamsModel +// ---------------------------------------------------------------------------- + +class ParamsModel : public wxDataViewModel +{ + GroupParamsNodePtrMap m_group_nodes; + SubSlicingStateNodePtrMap m_sub_slicing_state_nodes; + + wxDataViewCtrl* m_ctrl{ nullptr }; + +public: + + ParamsModel(); + ~ParamsModel() override = default; + + void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; } + + wxDataViewItem AppendGroup(GroupParamsType type); + + wxDataViewItem AppendSubGroup( GroupParamsType type, + SubSlicingState sub_type); + + wxDataViewItem AppendParam(GroupParamsType type, + ParamType param_type, + const std::string& param_key, + SubSlicingState subgroup_type = SubSlicingState::Undef); + + wxString GetParamName(wxDataViewItem item); + std::string GetParamKey(wxDataViewItem item); + + void Rescale(); + + void Clear(); + + wxDataViewItem GetParent(const wxDataViewItem& item) const override; + unsigned int GetChildren(const wxDataViewItem& parent, wxDataViewItemArray& array) const override; + + void GetValue(wxVariant& variant, const wxDataViewItem& item, unsigned int col) const override; + bool SetValue(const wxVariant& variant, const wxDataViewItem& item, unsigned int col) override; + + bool IsContainer(const wxDataViewItem& item) const override; + // Is the container just a header or an item with all columns + // In our case it is an item with all columns + bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } +}; + + +// ---------------------------------------------------------------------------- +// ParamsViewCtrl +// ---------------------------------------------------------------------------- + +class ParamsViewCtrl : public wxDataViewCtrl +{ + int m_em_unit; + + //struct ItemData + //{ + // std::string opt_key; + // wxString opt_name; + // wxString old_val; + // wxString mod_val; + // wxString new_val; + // Preset::Type type; + // bool is_long{ false }; + //}; + + //// tree items related to the options + //std::map m_items_map; + +public: + ParamsViewCtrl(wxWindow* parent, wxSize size); + ~ParamsViewCtrl() override { + if (model) { + Clear(); + model->DecRef(); + } + } + + ParamsModel* model{ nullptr }; + + wxDataViewItem AppendGroup( GroupParamsType type); + + wxDataViewItem AppendParam( GroupParamsType group_type, + ParamType param_type, + const std::string& param_key, + SubSlicingState group_subgroup_type = SubSlicingState::Undef); + + wxString GetValue(wxDataViewItem item); + wxString GetSelectedValue(); + std::string GetSelectedParamKey(); + + void Clear(); + void Rescale(int em = 0); + + void set_em_unit(int em) { m_em_unit = em; } +}; + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e06830ec9cb..b614e5d1be5 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1658,7 +1658,8 @@ void GUI_App::UpdateDVCDarkUI(wxDataViewCtrl* dvc, bool highlited/* = false*/) #ifdef _WIN32 UpdateDarkUI(dvc, highlited ? dark_mode() : false); #ifdef _MSW_DARK_MODE - dvc->RefreshHeaderDarkMode(&m_normal_font); + if (!dvc->HasFlag(wxDV_NO_HEADER)) + dvc->RefreshHeaderDarkMode(&m_normal_font); #endif //_MSW_DARK_MODE if (dvc->HasFlag(wxDV_ROW_LINES)) dvc->SetAlternateRowColour(m_color_highlight_default); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 5566921c91a..8b06b8f0a32 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1861,12 +1861,39 @@ static void validate_custom_gcode_cb(Tab* tab, const wxString& title, const t_co void Tab::edit_custom_gcode(const t_config_option_key& opt_key) { - EditGCodeDialog(this, opt_key, m_config->opt_string(opt_key)).ShowModal(); + EditGCodeDialog dlg = EditGCodeDialog(this, opt_key, get_custom_gcode(opt_key)); + if (dlg.ShowModal() == wxID_OK) { + set_custom_gcode(opt_key, dlg.get_edited_gcode()); + update_dirty(); + update(); + } } -void TabFilament::edit_custom_gcode(const t_config_option_key& opt_key) +const std::string& Tab::get_custom_gcode(const t_config_option_key& opt_key) { - EditGCodeDialog(this, opt_key, m_config->opt_string(opt_key, m_active_extruder < 0 ? unsigned(0) : unsigned(m_active_extruder))).ShowModal(); + return m_config->opt_string(opt_key); +} + +void Tab::set_custom_gcode(const t_config_option_key& opt_key, const std::string& value) +{ + DynamicPrintConfig new_conf = *m_config; + new_conf.set_key_value(opt_key, new ConfigOptionString(value)); + load_config(new_conf); +} + +const std::string& TabFilament::get_custom_gcode(const t_config_option_key& opt_key) +{ + return m_config->opt_string(opt_key, unsigned(0)); +} + +void TabFilament::set_custom_gcode(const t_config_option_key& opt_key, const std::string& value) +{ + std::vector gcodes = static_cast(m_config->option(opt_key))->values; + gcodes[0] = value; + + DynamicPrintConfig new_conf = *m_config; + new_conf.set_key_value(opt_key, new ConfigOptionStrings(gcodes)); + load_config(new_conf); } void TabFilament::create_line_with_near_label_widget(ConfigOptionsGroupShp optgroup, const std::string& opt_key, int opt_index/* = 0*/) diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index b95d835000e..2fb123964ba 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -391,7 +391,9 @@ class Tab: public wxPanel bool validate_custom_gcodes(); bool validate_custom_gcodes_was_shown{ false }; - virtual void edit_custom_gcode(const t_config_option_key &opt_key); + void edit_custom_gcode(const t_config_option_key& opt_key); + virtual const std::string& get_custom_gcode(const t_config_option_key& opt_key); + virtual void set_custom_gcode(const t_config_option_key& opt_key, const std::string& value); protected: void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const std::string& path, widget_t widget); @@ -476,7 +478,8 @@ class TabFilament : public Tab void update_extruder_combobox(); int get_active_extruder() const { return m_active_extruder; } - void edit_custom_gcode(const t_config_option_key& opt_key) override; + const std::string& get_custom_gcode(const t_config_option_key& opt_key) override; + void set_custom_gcode(const t_config_option_key& opt_key, const std::string& value) override; protected: bool select_preset_by_name(const std::string& name_w_suffix, bool force) override;