diff --git a/src/slic3r/GUI/EditGCodeDialog.cpp b/src/slic3r/GUI/EditGCodeDialog.cpp index 4af46d89e9..3f56c672d5 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" #define BTN_GAP FromDIP(20) #define BTN_SIZE wxSize(FromDIP(58), FromDIP(24)) @@ -29,27 +31,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,26 +54,22 @@ EditGCodeDialog::EditGCodeDialog(wxWindow* parent, const std::string& key, const SetFont(wxGetApp().normal_font()); SetBackgroundColour(*wxWHITE); wxGetApp().UpdateDarkUI(this); + wxGetApp().UpdateDlgDarkUI(this); 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 @@ -94,7 +79,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); @@ -102,6 +87,10 @@ 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()); + + //Orca: use custom buttons auto btn_sizer = create_btn_sizer(wxOK | wxCANCEL); for(auto btn : m_button_list) wxGetApp().UpdateDarkUI(btn.second); @@ -110,6 +99,7 @@ EditGCodeDialog::EditGCodeDialog(wxWindow* parent, const std::string& key, const 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(btn_sizer , 0, wxEXPAND | wxALL, border); SetSizer(topSizer); @@ -120,13 +110,106 @@ EditGCodeDialog::EditGCodeDialog(wxWindow* parent, const std::string& key, const this->CenterOnScreen(); - wxGetApp().UpdateDlgDarkUI(this); + init_params_list(); + bind_list_and_button(); +} - 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); +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_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(); }); } @@ -134,17 +217,9 @@ 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 }); - + //Orca: use custom buttons for (auto button_item : m_button_list) { - if (button_item.first == wxRESET) - { - button_item.second->SetMinSize(wxSize(FromDIP(75), FromDIP(24))); - button_item.second->SetCornerRadius(FromDIP(12)); - } if (button_item.first == wxOK) { button_item.second->SetMinSize(BTN_SIZE); button_item.second->SetCornerRadius(FromDIP(12)); @@ -167,11 +242,6 @@ void EditGCodeDialog::on_sys_color_changed() m_add_btn->sys_color_changed(); } -void EditGCodeDialog::OnOK(wxEvent& event) -{ - event.Skip(); -} - //Orca wxBoxSizer* EditGCodeDialog::create_btn_sizer(long flags) { @@ -248,4 +318,313 @@ wxBoxSizer* EditGCodeDialog::create_btn_sizer(long flags) return btn_sizer; } +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 == 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 == 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(); +} +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 4464301a3b..83ef423c80 100644 --- a/src/slic3r/GUI/EditGCodeDialog.hpp +++ b/src/slic3r/GUI/EditGCodeDialog.hpp @@ -7,18 +7,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 @@ -26,16 +26,21 @@ 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: std::unordered_map m_button_list; @@ -45,6 +50,198 @@ protected: }; + + +// ---------------------------------------------------------------------------- +// 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 0d4c1bcda7..bdfaa95170 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3181,14 +3181,17 @@ void GUI_App::UpdateDVCDarkUI(wxDataViewCtrl* dvc, bool highlited/* = false*/) UpdateDarkUI(dvc, highlited ? dark_mode() : false); #ifdef _MSW_DARK_MODE //dvc->RefreshHeaderDarkMode(&m_normal_font); - HWND hwnd = (HWND)dvc->GenericGetHeader()->GetHandle(); - hwnd = GetWindow(hwnd, GW_CHILD); - if (hwnd != NULL) - NppDarkMode::SetDarkListViewHeader(hwnd); - wxItemAttr attr; - attr.SetTextColour(NppDarkMode::GetTextColor()); - attr.SetFont(m_normal_font); - dvc->SetHeaderAttr(attr); + HWND hwnd; + if (!dvc->HasFlag(wxDV_NO_HEADER)) { + hwnd = (HWND) dvc->GenericGetHeader()->GetHandle(); + hwnd = GetWindow(hwnd, GW_CHILD); + if (hwnd != NULL) + NppDarkMode::SetDarkListViewHeader(hwnd); + wxItemAttr attr; + attr.SetTextColour(NppDarkMode::GetTextColor()); + attr.SetFont(m_normal_font); + dvc->SetHeaderAttr(attr); + } #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 be2aee36ee..2b6ca330c7 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2869,12 +2869,39 @@ static void validate_custom_gcode_cb(Tab* tab, ConfigOptionsGroupShp opt_group, 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, unsigned(m_presets_choice->GetSelection()))).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::add_filament_overrides_page() diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 64f88f35b6..ca1604f216 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -408,7 +408,9 @@ public: bool validate_custom_gcodes_was_shown{ false }; void set_just_edit(bool just_edit); - 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); @@ -562,7 +564,9 @@ public: void update() override; void clear_pages() override; bool supports_printer_technology(const PrinterTechnology tech) const override { return tech == ptFFF; } - 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; }; class TabPrinter : public Tab