From c07a193b4ef28b08f939feba4164966f2defc43d Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 30 Sep 2019 14:03:50 +0200 Subject: [PATCH 1/7] Implemented BitmapChoiseRenderer --- src/slic3r/GUI/Plater.cpp | 19 +++-- src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/wxExtensions.cpp | 136 +++++++++++++++++++++++++++++++- src/slic3r/GUI/wxExtensions.hpp | 34 ++++++++ 4 files changed, 183 insertions(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b172ad489..53287eedf 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -521,12 +521,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : const std::vector &init_matrix = (project_config.option("wiping_volumes_matrix"))->values; const std::vector &init_extruders = (project_config.option("wiping_volumes_extruders"))->values; - const DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config; - std::vector extruder_colours = (config->option("extruder_colour"))->values; - const std::vector& filament_colours = (wxGetApp().plater()->get_plater_config()->option("filament_colour"))->values; - for (size_t i=0; i extruder_colours = wxGetApp().plater()->get_extruder_colors_from_plater_config(); WipingDialog dlg(parent, cast(init_matrix), cast(init_extruders), extruder_colours); @@ -4891,6 +4886,18 @@ const DynamicPrintConfig* Plater::get_plater_config() const return p->config; } +std::vector Plater::get_extruder_colors_from_plater_config() const +{ + const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config; + std::vector extruder_colors = (config->option("extruder_colour"))->values; + const std::vector& filament_colours = (p->config->option("filament_colour"))->values; + for (size_t i = 0; i < extruder_colors.size(); ++i) + if (extruder_colors[i] == "" && i < filament_colours.size()) + extruder_colors[i] = filament_colours[i]; + + return extruder_colors; +} + wxString Plater::get_project_filename(const wxString& extension) const { return p->get_project_filename(extension); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 93df68738..f19ac9e77 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -215,6 +215,7 @@ public: // On activating the parent window. void on_activate(); const DynamicPrintConfig* get_plater_config() const; + std::vector get_extruder_colors_from_plater_config() const; void update_object_menu(); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 59406b6e9..8e4e3520a 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -7,6 +7,7 @@ #include "libslic3r/Model.hpp" #include +#include #include #include #include @@ -20,6 +21,7 @@ #include "libslic3r/GCode/PreviewData.hpp" #include "I18N.hpp" #include "GUI_Utils.hpp" +#include "PresetBundle.hpp" #include "../Utils/MacDarkMode.hpp" using Slic3r::GUI::from_u8; @@ -1840,7 +1842,7 @@ void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bo } //----------------------------------------------------------------------------- -// PrusaDataViewBitmapText +// DataViewBitmapText //----------------------------------------------------------------------------- wxIMPLEMENT_DYNAMIC_CLASS(DataViewBitmapText, wxObject) @@ -1966,6 +1968,138 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value return true; } +// ---------------------------------------------------------------------------- +// BitmapChoiseRenderer +// ---------------------------------------------------------------------------- + +bool BitmapChoiseRenderer::SetValue(const wxVariant& value) +{ + m_value << value; + return true; +} +bool BitmapChoiseRenderer::GetValue(wxVariant& value) const +{ + value << m_value; + return true; +} +bool BitmapChoiseRenderer::Render(wxRect rect, wxDC* dc, int state) +{ + int xoffset = 0; + + const wxBitmap& icon = m_value.GetBitmap(); + if (icon.IsOk()) + { + dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2); + xoffset = icon.GetWidth() + 4; + } + + RenderText(m_value.GetText(), xoffset, rect, dc, state); + + return true; +} + +wxSize BitmapChoiseRenderer::GetSize() const +{ + if (!m_value.GetText().empty()) + { + wxSize size = GetTextExtent(m_value.GetText()); + + if (m_value.GetBitmap().IsOk()) + size.x += m_value.GetBitmap().GetWidth() + 4; + return size; + } + return wxSize(80, 20); + + /* from wxDataViewChoiceRenderer + wxSize sz; + + for ( wxArrayString::const_iterator i = m_choices.begin(); i != m_choices.end(); ++i ) + sz.IncTo(GetTextExtent(*i)); + + // Allow some space for the right-side button, which is approximately the + // size of a scrollbar (and getting pixel-exact value would be complicated). + // Also add some whitespace between the text and the button: + sz.x += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); + sz.x += GetTextExtent("M").x; + + return sz; + */ +} + +static void update_extruder_color_icons_in_cache() +{ + // Create the bitmap with color bars. + std::vector bmps; + std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); + + unsigned char rgb[3]; + + /* It's supposed that standard size of an icon is 36px*16px for 100% scaled display. + * So set sizes for solid_colored icons used for filament preset + * and scale them in respect to em_unit value + */ + const double em = Slic3r::GUI::wxGetApp().em_unit(); + const int icon_width = lround(3.6 * em); + const int icon_height = lround(1.6 * em); + + for (const std::string& color : colors) + { + wxBitmap* bitmap = m_bitmap_cache->find(color); + if (bitmap == nullptr) { + // Paint the color icon. + Slic3r::PresetBundle::parse_color(color, rgb); + bitmap = m_bitmap_cache->insert(color, m_bitmap_cache->mksolid(icon_width, icon_height, rgb)); + } + bmps.emplace_back(bitmap); + } +} + + +wxWindow* BitmapChoiseRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelRect, const wxVariant& value) +{ + wxDataViewCtrl* const dv_ctrl = GetOwner()->GetOwner(); + ObjectDataViewModel* const model = dynamic_cast(dv_ctrl->GetModel()); + + if (!(model->GetItemType(dv_ctrl->GetSelection()) & (itVolume | itObject))) + return nullptr; + + DataViewBitmapText data; + data << value; + +// m_was_unusable_symbol = false; + + wxPoint position = labelRect.GetPosition(); + if (data.GetBitmap().IsOk()) { + const int bmp_width = data.GetBitmap().GetWidth(); + position.x += bmp_width; + labelRect.SetWidth(labelRect.GetWidth() - bmp_width); + } + + auto c_editor = new wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, //data.GetText(), + labelRect.GetTopLeft(), wxSize(labelRect.GetWidth(), -1), + 0, nullptr , wxCB_READONLY); + + c_editor->Move(labelRect.GetRight() - c_editor->GetRect().width, wxDefaultCoord); + c_editor->SetStringSelection(data.GetText()); + return c_editor; +} + +bool BitmapChoiseRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) +{ + wxBitmapComboBox* c = (wxBitmapComboBox*)ctrl; + int selection = c->GetSelection(); + if (selection < 0) + return false; + + DataViewBitmapText bmpText; + + bmpText.SetText(c->GetString(selection)); + bmpText.SetBitmap(c->GetItemBitmap(selection)); + + value << bmpText; + return true; +} + // ---------------------------------------------------------------------------- // DoubleSlider // ---------------------------------------------------------------------------- diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 54d1bf7cb..3d90e966c 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -563,6 +563,40 @@ private: }; +// ---------------------------------------------------------------------------- +// BitmapChoiseRenderer +// ---------------------------------------------------------------------------- + +class BitmapChoiseRenderer : public wxDataViewCustomRenderer +{ +public: + BitmapChoiseRenderer(wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT + + , int align = wxDVR_DEFAULT_ALIGNMENT + ) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {} + + bool SetValue(const wxVariant& value); + bool GetValue(wxVariant& value) const; +#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY + virtual wxString GetAccessibleDescription() const override; +#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING + + virtual bool Render(wxRect cell, wxDC* dc, int state); + virtual wxSize GetSize() const; + + bool HasEditorCtrl() const override { return true; } + wxWindow* CreateEditorCtrl(wxWindow* parent, + wxRect labelRect, + const wxVariant& value) override; + bool GetValueFromEditorCtrl(wxWindow* ctrl, + wxVariant& value) override; + +private: + DataViewBitmapText m_value; + wxArrayString m_choices; +}; + + // ---------------------------------------------------------------------------- // MyCustomRenderer // ---------------------------------------------------------------------------- From d7ebc4de5baca66df1820627222a804caa2568df Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 1 Oct 2019 18:19:28 +0200 Subject: [PATCH 2/7] Added color for extruder --- src/slic3r/GUI/GUI_ObjectList.cpp | 47 ++---- src/slic3r/GUI/GUI_ObjectList.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 +- src/slic3r/GUI/wxExtensions.cpp | 242 +++++++++++++++++++++--------- src/slic3r/GUI/wxExtensions.hpp | 37 ++--- 5 files changed, 208 insertions(+), 126 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 19dedc7b0..7d650dcd1 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -267,7 +267,8 @@ void ObjectList::create_objects_ctrl() wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); // column Extruder of the view control: - AppendColumn(create_objects_list_extruder_column(4)); + AppendColumn(new wxDataViewColumn(_(L("Extruder")), new BitmapChoiceRenderer(), + colExtruder, 8*em, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE)); // column ItemEditing of the view control: AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, 3*em, @@ -434,19 +435,6 @@ DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) cons (*m_objects)[obj_idx]->config; } -wxDataViewColumn* ObjectList::create_objects_list_extruder_column(size_t extruders_count) -{ - wxArrayString choices; - choices.Add(_(L("default"))); - for (int i = 1; i <= extruders_count; ++i) - choices.Add(wxString::Format("%d", i)); - wxDataViewChoiceRenderer *c = - new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL); - wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, colExtruder, - 8*wxGetApp().em_unit()/*80*/, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); - return column; -} - void ObjectList::update_extruder_values_for_items(const size_t max_extruder) { for (size_t i = 0; i < m_objects->size(); ++i) @@ -462,7 +450,7 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder) else extruder = wxString::Format("%d", object->config.option("extruder")->value); - m_objects_model->SetValue(extruder, item, colExtruder); + m_objects_model->SetExtruder(extruder, item); if (object->volumes.size() > 1) { for (size_t id = 0; id < object->volumes.size(); id++) { @@ -474,7 +462,7 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder) else extruder = wxString::Format("%d", object->volumes[id]->config.option("extruder")->value); - m_objects_model->SetValue(extruder, item, colExtruder); + m_objects_model->SetExtruder(extruder, item); } } } @@ -486,19 +474,13 @@ void ObjectList::update_objects_list_extruder_column(size_t extruders_count) if (printer_technology() == ptSLA) extruders_count = 1; - wxDataViewChoiceRenderer* ch_render = dynamic_cast(GetColumn(colExtruder)->GetRenderer()); - if (ch_render->GetChoices().GetCount() - 1 == extruders_count) - return; - m_prevent_update_extruder_in_config = true; if (m_objects && extruders_count > 1) update_extruder_values_for_items(extruders_count); - // delete old extruder column - DeleteColumn(GetColumn(colExtruder)); - // insert new created extruder column - InsertColumn(colExtruder, create_objects_list_extruder_column(extruders_count)); + update_extruder_colors(); + // set show/hide for this column set_extruder_column_hidden(extruders_count <= 1); //a workaround for a wrong last column width updating under OSX @@ -507,6 +489,11 @@ void ObjectList::update_objects_list_extruder_column(size_t extruders_count) m_prevent_update_extruder_in_config = false; } +void ObjectList::update_extruder_colors() +{ + m_objects_model->UpdateColumValues(colExtruder); +} + void ObjectList::set_extruder_column_hidden(const bool hide) const { GetColumn(colExtruder)->SetHidden(hide); @@ -535,14 +522,10 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item) m_config = &get_item_config(item); } - wxVariant variant; - m_objects_model->GetValue(variant, item, colExtruder); - const wxString selection = variant.GetString(); - - if (!m_config || selection.empty()) + if (!m_config) return; - const int extruder = /*selection.size() > 1 ? 0 : */atoi(selection.c_str()); + const int extruder = m_objects_model->GetExtruderNumber(item); m_config->set_key_value("extruder", new ConfigOptionInt(extruder)); // update scene @@ -2547,7 +2530,7 @@ void ObjectList::delete_from_model_and_list(const std::vector& it (*m_objects)[item->obj_idx]->config.has("extruder")) { const wxString extruder = wxString::Format("%d", (*m_objects)[item->obj_idx]->config.option("extruder")->value); - m_objects_model->SetValue(extruder, m_objects_model->GetItemById(item->obj_idx), colExtruder); + m_objects_model->SetExtruder(extruder, m_objects_model->GetItemById(item->obj_idx)); } wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx); } @@ -3822,7 +3805,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const /* We can change extruder for Object/Volume only. * So, if Instance is selected, get its Object item and change it */ - m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, colExtruder); + m_objects_model->SetExtruder(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item); const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) : m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 4dd618a90..b89d8943d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -183,8 +183,8 @@ public: void create_objects_ctrl(); void create_popup_menus(); - wxDataViewColumn* create_objects_list_extruder_column(size_t extruders_count); void update_objects_list_extruder_column(size_t extruders_count); + void update_extruder_colors(); // show/hide "Extruder" column for Objects List void set_extruder_column_hidden(const bool hide) const; // update extruder in current config diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 53287eedf..baf84befc 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4785,6 +4785,7 @@ void Plater::on_config_change(const DynamicPrintConfig &config) filament_colors.push_back(filaments.find_preset(filament_preset, true)->config.opt_string("filament_colour", (unsigned)0)); p->config->option(opt_key)->values = filament_colors; + p->sidebar->obj_list()->update_extruder_colors(); continue; } } @@ -4810,6 +4811,7 @@ void Plater::on_config_change(const DynamicPrintConfig &config) else if(opt_key == "extruder_colour") { update_scheduled = true; p->preview->set_number_extruders(p->config->option(opt_key)->values.size()); + p->sidebar->obj_list()->update_extruder_colors(); } else if(opt_key == "max_print_height") { update_scheduled = true; } @@ -4858,8 +4860,10 @@ void Plater::force_filament_colors_update() } } - if (update_scheduled) + if (update_scheduled) { update(); + p->sidebar->obj_list()->update_extruder_colors(); + } if (p->main_frame->is_loaded()) this->p->schedule_background_process(); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 8e4e3520a..b692d1cae 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -447,6 +447,47 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, return *bmp; } + +Slic3r::GUI::BitmapCache* m_bitmap_cache = nullptr; +static std::vector get_extruder_color_icons() +{ + // Create the bitmap with color bars. + std::vector bmps; + std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); + + unsigned char rgb[3]; + + /* It's supposed that standard size of an icon is 36px*16px for 100% scaled display. + * So set sizes for solid_colored icons used for filament preset + * and scale them in respect to em_unit value + */ + const double em = Slic3r::GUI::wxGetApp().em_unit(); + const int icon_width = lround(3.2 * em); + const int icon_height = lround(1.6 * em); + + for (const std::string& color : colors) + { + wxBitmap* bitmap = m_bitmap_cache->find(color); + if (bitmap == nullptr) { + // Paint the color icon. + Slic3r::PresetBundle::parse_color(color, rgb); + bitmap = m_bitmap_cache->insert(color, m_bitmap_cache->mksolid(icon_width, icon_height, rgb)); + } + bmps.emplace_back(bitmap); + } + + return bmps; +} + + +static wxBitmap get_extruder_color_icon(size_t extruder_idx) +{ + // Create the bitmap with color bars. + std::vector bmps = get_extruder_color_icons(); + + return *bmps[extruder_idx >= bmps.size() ? 0 : extruder_idx]; +} + // ***************************************************************************** // ---------------------------------------------------------------------------- // ObjectDataViewModelNode @@ -479,7 +520,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent m_idx = parent->GetChildCount(); m_name = wxString::Format(_(L("Instance %d")), m_idx + 1); - set_action_icon(); + set_action_and_extruder_icons(); } else if (type == itLayerRoot) { @@ -514,7 +555,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")"; m_bmp = create_scaled_bitmap(nullptr, LAYER_ICON); // FIXME: pass window ptr - set_action_icon(); + set_action_and_extruder_icons(); init_container(); } @@ -527,11 +568,16 @@ bool ObjectDataViewModelNode::valid() } #endif /* NDEBUG */ -void ObjectDataViewModelNode::set_action_icon() +void ObjectDataViewModelNode::set_action_and_extruder_icons() { m_action_icon_name = m_type & itObject ? "advanced_plus" : m_type & (itVolume | itLayer) ? "cog" : /*m_type & itInstance*/ "set_separate_obj"; m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr + + // set extruder bitmap + int extruder_idx = atoi(m_extruder.c_str()); + if (extruder_idx > 0) --extruder_idx; + m_extruder_bmp = get_extruder_color_icon(extruder_idx); } void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable) @@ -541,7 +587,6 @@ void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable) create_scaled_bitmap(nullptr, m_printable == piPrintable ? "eye_open.png" : "eye_closed.png"); } -Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr; void ObjectDataViewModelNode::update_settings_digest_bitmaps() { m_bmp = m_empty_bmp; @@ -607,8 +652,10 @@ bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col) m_name = data.GetText(); return true; } case colExtruder: { - const wxString & val = variant.GetString(); - m_extruder = val == "0" ? _(L("default")) : val; + DataViewBitmapText data; + data << variant; + m_extruder_bmp = data.GetBitmap(); + m_extruder = data.GetText() == "0" ? _(L("default")) : data.GetText(); return true; } case colEditing: m_action_icon << variant; @@ -1381,6 +1428,51 @@ t_layer_height_range ObjectDataViewModel::GetLayerRangeByItem(const wxDataViewIt return node->GetLayerRange(); } +bool ObjectDataViewModel::UpdateColumValues(unsigned col) +{ + switch (col) + { + case colPrint: + case colName: + case colEditing: + return true; + case colExtruder: + { + wxDataViewItemArray items; + GetAllChildren(wxDataViewItem(nullptr), items); + + if (items.IsEmpty()) return false; + + for (auto item : items) + UpdateExtruderBitmap(item); + + return true; + } + default: + printf("MyObjectTreeModel::SetValue: wrong column"); + } + return false; +} + + +void ObjectDataViewModel::UpdateExtruderBitmap(wxDataViewItem item) +{ + wxString extruder = GetExtruder(item); + if (extruder.IsEmpty()) + return; + + // set extruder bitmap + int extruder_idx = atoi(extruder.c_str()); + if (extruder_idx > 0) --extruder_idx; + + const DataViewBitmapText extruder_val(extruder, get_extruder_color_icon(extruder_idx)); + + wxVariant value; + value << extruder_val; + + SetValue(value, item, colExtruder); +} + void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx) { wxASSERT(item.IsOk()); @@ -1477,6 +1569,24 @@ wxBitmap& ObjectDataViewModel::GetBitmap(const wxDataViewItem &item) const return node->m_bmp; } +wxString ObjectDataViewModel::GetExtruder(const wxDataViewItem& item) const +{ + ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return wxEmptyString; + + return node->m_extruder; +} + +int ObjectDataViewModel::GetExtruderNumber(const wxDataViewItem& item) const +{ + ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return 0; + + return atoi(node->m_extruder.c_str()); +} + void ObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const { wxASSERT(item.IsOk()); @@ -1491,7 +1601,7 @@ void ObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &ite variant << DataViewBitmapText(node->m_name, node->m_bmp); break; case colExtruder: - variant = node->m_extruder; + variant << DataViewBitmapText(node->m_extruder, node->m_extruder_bmp); break; case colEditing: variant << node->m_action_icon; @@ -1517,6 +1627,22 @@ bool ObjectDataViewModel::SetValue(const wxVariant &variant, const int item_idx, return m_objects[item_idx]->SetValue(variant, col); } +void ObjectDataViewModel::SetExtruder(const wxString& extruder, wxDataViewItem item) +{ + DataViewBitmapText extruder_val; + extruder_val.SetText(extruder); + + // set extruder bitmap + int extruder_idx = atoi(extruder.c_str()); + if (extruder_idx > 0) --extruder_idx; + extruder_val.SetBitmap(get_extruder_color_icon(extruder_idx)); + + wxVariant value; + value << extruder_val; + + SetValue(value, item, colExtruder); +} + wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume_id, const int new_volume_id, const wxDataViewItem &parent) @@ -1969,20 +2095,22 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value } // ---------------------------------------------------------------------------- -// BitmapChoiseRenderer +// BitmapChoiceRenderer // ---------------------------------------------------------------------------- -bool BitmapChoiseRenderer::SetValue(const wxVariant& value) +bool BitmapChoiceRenderer::SetValue(const wxVariant& value) { m_value << value; return true; } -bool BitmapChoiseRenderer::GetValue(wxVariant& value) const + +bool BitmapChoiceRenderer::GetValue(wxVariant& value) const { value << m_value; return true; } -bool BitmapChoiseRenderer::Render(wxRect rect, wxDC* dc, int state) + +bool BitmapChoiceRenderer::Render(wxRect rect, wxDC* dc, int state) { int xoffset = 0; @@ -1993,69 +2121,25 @@ bool BitmapChoiseRenderer::Render(wxRect rect, wxDC* dc, int state) xoffset = icon.GetWidth() + 4; } + if (rect.height==0) + rect.height= icon.GetHeight(); RenderText(m_value.GetText(), xoffset, rect, dc, state); return true; } -wxSize BitmapChoiseRenderer::GetSize() const +wxSize BitmapChoiceRenderer::GetSize() const { - if (!m_value.GetText().empty()) - { - wxSize size = GetTextExtent(m_value.GetText()); + wxSize sz = GetTextExtent(m_value.GetText()); - if (m_value.GetBitmap().IsOk()) - size.x += m_value.GetBitmap().GetWidth() + 4; - return size; - } - return wxSize(80, 20); - - /* from wxDataViewChoiceRenderer - wxSize sz; - - for ( wxArrayString::const_iterator i = m_choices.begin(); i != m_choices.end(); ++i ) - sz.IncTo(GetTextExtent(*i)); - - // Allow some space for the right-side button, which is approximately the - // size of a scrollbar (and getting pixel-exact value would be complicated). - // Also add some whitespace between the text and the button: - sz.x += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); - sz.x += GetTextExtent("M").x; + if (m_value.GetBitmap().IsOk()) + sz.x += m_value.GetBitmap().GetWidth() + 4; return sz; - */ -} - -static void update_extruder_color_icons_in_cache() -{ - // Create the bitmap with color bars. - std::vector bmps; - std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); - - unsigned char rgb[3]; - - /* It's supposed that standard size of an icon is 36px*16px for 100% scaled display. - * So set sizes for solid_colored icons used for filament preset - * and scale them in respect to em_unit value - */ - const double em = Slic3r::GUI::wxGetApp().em_unit(); - const int icon_width = lround(3.6 * em); - const int icon_height = lround(1.6 * em); - - for (const std::string& color : colors) - { - wxBitmap* bitmap = m_bitmap_cache->find(color); - if (bitmap == nullptr) { - // Paint the color icon. - Slic3r::PresetBundle::parse_color(color, rgb); - bitmap = m_bitmap_cache->insert(color, m_bitmap_cache->mksolid(icon_width, icon_height, rgb)); - } - bmps.emplace_back(bitmap); - } } -wxWindow* BitmapChoiseRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelRect, const wxVariant& value) +wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelRect, const wxVariant& value) { wxDataViewCtrl* const dv_ctrl = GetOwner()->GetOwner(); ObjectDataViewModel* const model = dynamic_cast(dv_ctrl->GetModel()); @@ -2063,28 +2147,36 @@ wxWindow* BitmapChoiseRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelR if (!(model->GetItemType(dv_ctrl->GetSelection()) & (itVolume | itObject))) return nullptr; + std::vector icons = get_extruder_color_icons(); + if (icons.empty()) + return nullptr; + DataViewBitmapText data; data << value; -// m_was_unusable_symbol = false; - - wxPoint position = labelRect.GetPosition(); - if (data.GetBitmap().IsOk()) { - const int bmp_width = data.GetBitmap().GetWidth(); - position.x += bmp_width; - labelRect.SetWidth(labelRect.GetWidth() - bmp_width); - } - - auto c_editor = new wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, //data.GetText(), + auto c_editor = new wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, labelRect.GetTopLeft(), wxSize(labelRect.GetWidth(), -1), 0, nullptr , wxCB_READONLY); - c_editor->Move(labelRect.GetRight() - c_editor->GetRect().width, wxDefaultCoord); - c_editor->SetStringSelection(data.GetText()); + int i=0; + for (wxBitmap* bmp : icons) { + if (i==0) { + c_editor->Append(_(L("default")), *bmp); + ++i; + } + + c_editor->Append(wxString::Format("%d", i), *bmp); + ++i; + } + c_editor->SetSelection(atoi(data.GetText().c_str())); + + // to avoid event propagation to other sidebar items + c_editor->Bind(wxEVT_COMBOBOX, [](wxCommandEvent& evt) { evt.StopPropagation(); }); + return c_editor; } -bool BitmapChoiseRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) +bool BitmapChoiceRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) { wxBitmapComboBox* c = (wxBitmapComboBox*)ctrl; int selection = c->GetSelection(); diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 3d90e966c..762fd08e7 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -209,6 +209,7 @@ class ObjectDataViewModelNode int m_idx = -1; bool m_container = false; wxString m_extruder = "default"; + wxBitmap m_extruder_bmp; wxBitmap m_action_icon; PrintIndicator m_printable {piUndef}; wxBitmap m_printable_icon; @@ -224,7 +225,7 @@ public: m_type(itObject), m_extruder(extruder) { - set_action_icon(); + set_action_and_extruder_icons(); init_container(); } @@ -240,7 +241,7 @@ public: m_extruder (extruder) { m_bmp = bmp; - set_action_icon(); + set_action_and_extruder_icons(); init_container(); } @@ -356,7 +357,7 @@ public: } // Set action icons for node - void set_action_icon(); + void set_action_and_extruder_icons(); // Set printable icon for node void set_printable_icon(PrintIndicator printable); @@ -438,6 +439,8 @@ public: wxString GetName(const wxDataViewItem &item) const; wxBitmap& GetBitmap(const wxDataViewItem &item) const; + wxString GetExtruder(const wxDataViewItem &item) const; + int GetExtruderNumber(const wxDataViewItem &item) const; // helper methods to change the model @@ -454,6 +457,8 @@ public: const int item_idx, unsigned int col); + void SetExtruder(const wxString& extruder, wxDataViewItem item); + // For parent move child from cur_volume_id place to new_volume_id // Remaining items will moved up/down accordingly wxDataViewItem ReorganizeChildren( const int cur_volume_id, @@ -504,6 +509,9 @@ public: void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const; + bool UpdateColumValues(unsigned col); + void UpdateExtruderBitmap(wxDataViewItem item); + private: wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type); wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item); @@ -564,36 +572,31 @@ private: // ---------------------------------------------------------------------------- -// BitmapChoiseRenderer +// BitmapChoiceRenderer // ---------------------------------------------------------------------------- -class BitmapChoiseRenderer : public wxDataViewCustomRenderer +class BitmapChoiceRenderer : public wxDataViewCustomRenderer { public: - BitmapChoiseRenderer(wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT - - , int align = wxDVR_DEFAULT_ALIGNMENT + BitmapChoiceRenderer(wxDataViewCellMode mode = wxDATAVIEW_CELL_EDITABLE, + int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL ) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {} bool SetValue(const wxVariant& value); bool GetValue(wxVariant& value) const; -#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY - virtual wxString GetAccessibleDescription() const override; -#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING virtual bool Render(wxRect cell, wxDC* dc, int state); virtual wxSize GetSize() const; bool HasEditorCtrl() const override { return true; } - wxWindow* CreateEditorCtrl(wxWindow* parent, - wxRect labelRect, - const wxVariant& value) override; - bool GetValueFromEditorCtrl(wxWindow* ctrl, - wxVariant& value) override; + wxWindow* CreateEditorCtrl(wxWindow* parent, + wxRect labelRect, + const wxVariant& value) override; + bool GetValueFromEditorCtrl( wxWindow* ctrl, + wxVariant& value) override; private: DataViewBitmapText m_value; - wxArrayString m_choices; }; From 15902766d051315d8efe7a5e2771b28af45a69ba Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 2 Oct 2019 11:53:50 +0200 Subject: [PATCH 3/7] Workaround for extruder editing under OSX --- src/slic3r/GUI/GUI_ObjectList.cpp | 71 +++++++++++++++++++++++++++++++ src/slic3r/GUI/GUI_ObjectList.hpp | 3 ++ src/slic3r/GUI/wxExtensions.cpp | 2 +- src/slic3r/GUI/wxExtensions.hpp | 2 + 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index a59156fff..3e0d6dd8f 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -788,6 +788,9 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) const wxPoint pt = get_mouse_position_in_control(); HitTest(pt, item, col); + if (m_extruder_editor) + m_extruder_editor->Hide(); + /* Note: Under OSX right click doesn't send "selection changed" event. * It means that Selection() will be return still previously selected item. * Thus under OSX we should force UnselectAll(), when item and col are nullptr, @@ -836,6 +839,8 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) fix_through_netfabb(); } } + else if (/*wxOSX &&*/evt_context_menu && title == _("Extruder")) + extruder_editing(); #ifndef __WXMSW__ GetMainWindow()->SetToolTip(""); // hide tooltip @@ -877,6 +882,72 @@ void ObjectList::show_context_menu(const bool evt_context_menu) wxGetApp().plater()->PopupMenu(menu); } +void ObjectList::extruder_editing() +{ + wxDataViewItem item = GetSelection(); + if (!item || !(m_objects_model->GetItemType(item) & (itVolume | itObject))) + return; + + std::vector icons = get_extruder_color_icons(); + if (icons.empty()) + return; + + const int column_width = GetColumn(colExtruder)->GetWidth(); + + wxPoint pos = get_mouse_position_in_control(); + + pos.y -= 2*GetTextExtent("m").y; + + wxWindow* parent = this;//this->GetMainWindow(); + + if (!m_extruder_editor) + m_extruder_editor = new wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, + pos, wxSize(column_width, -1), + 0, nullptr, wxCB_READONLY); + else + { + m_extruder_editor->SetPosition(pos); + m_extruder_editor->Clear(); + m_extruder_editor->Show(); + } + + + int i = 0; + for (wxBitmap* bmp : icons) { + if (i == 0) { + m_extruder_editor->Append(_(L("default")), *bmp); + ++i; + } + + m_extruder_editor->Append(wxString::Format("%d", i), *bmp); + ++i; + } + m_extruder_editor->SetSelection(m_objects_model->GetExtruderNumber(item)); + + auto set_extruder = [this, item]() + { + const int selection = m_extruder_editor->GetSelection(); + if (selection >= 0) + m_objects_model->SetExtruder(m_extruder_editor->GetString(selection), item); + + m_extruder_editor->Hide(); + }; + + // to avoid event propagation to other sidebar items + m_extruder_editor->Bind(wxEVT_COMBOBOX, [set_extruder](wxCommandEvent& evt) + { + set_extruder(); + evt.StopPropagation(); + }); + + m_extruder_editor->Bind(wxEVT_KILL_FOCUS, [set_extruder](wxFocusEvent& evt) + { + set_extruder(); + evt.Skip(); + }); + +} + void ObjectList::copy() { // if (m_selection_mode & smLayer) diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index b89d8943d..ddbbd7146 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -140,6 +140,8 @@ private: DynamicPrintConfig *m_config {nullptr}; std::vector *m_objects{ nullptr }; + wxBitmapComboBox *m_extruder_editor { nullptr }; + std::vector m_bmp_vector; t_layer_config_ranges m_layer_config_ranges_cache; @@ -210,6 +212,7 @@ public: void selection_changed(); void show_context_menu(const bool evt_context_menu); + void extruder_editing(); #ifndef __WXOSX__ void key_event(wxKeyEvent& event); #endif /* __WXOSX__ */ diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index b692d1cae..855e803e3 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -449,7 +449,7 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, Slic3r::GUI::BitmapCache* m_bitmap_cache = nullptr; -static std::vector get_extruder_color_icons() +/*static*/ std::vector get_extruder_color_icons() { // Create the bitmap with color bars. std::vector bmps; diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 762fd08e7..1ba55c4b5 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -55,6 +55,8 @@ int em_unit(wxWindow* win); wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, const int px_cnt = 16, const bool is_horizontal = false, const bool grayscale = false); +std::vector get_extruder_color_icons(); + class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup { static const unsigned int DefaultWidth; From d87f2d11ae05855cd69698f1f4833e1994c84006 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 2 Oct 2019 12:17:02 +0200 Subject: [PATCH 4/7] Fix OSX build --- src/slic3r/GUI/GUI_ObjectList.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index ddbbd7146..87be25ed9 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -12,6 +12,7 @@ #include "wxExtensions.hpp" class wxBoxSizer; +class wxBitmapComboBox; class wxMenuItem; class ObjectDataViewModel; class MenuWithSeparators; From 4171a6a80d9f662537e4f955f7a55ee8d7e542a1 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 2 Oct 2019 13:05:34 +0200 Subject: [PATCH 5/7] Improvements for https://github.com/prusa3d/PrusaSlicer/commit/15902766d051315d8efe7a5e2771b28af45a69ba --- src/slic3r/GUI/GUI_ObjectList.cpp | 14 ++++++-------- src/slic3r/GUI/wxExtensions.hpp | 9 +++++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 3e0d6dd8f..f8e708200 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -839,7 +839,8 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) fix_through_netfabb(); } } - else if (/*wxOSX &&*/evt_context_menu && title == _("Extruder")) + // workaround for extruder editing under OSX + else if (wxOSX && evt_context_menu && title == _("Extruder")) extruder_editing(); #ifndef __WXMSW__ @@ -895,15 +896,12 @@ void ObjectList::extruder_editing() const int column_width = GetColumn(colExtruder)->GetWidth(); wxPoint pos = get_mouse_position_in_control(); - - pos.y -= 2*GetTextExtent("m").y; - - wxWindow* parent = this;//this->GetMainWindow(); + pos.x = GetColumn(colName)->GetWidth() + GetColumn(colPrint)->GetWidth(); +// pos.y -= 2*GetTextExtent("m").y; if (!m_extruder_editor) - m_extruder_editor = new wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, - pos, wxSize(column_width, -1), - 0, nullptr, wxCB_READONLY); + m_extruder_editor = new wxBitmapComboBox(this, wxID_ANY, wxEmptyString, pos, wxSize(column_width, -1), + 0, nullptr, wxCB_READONLY); else { m_extruder_editor->SetPosition(pos); diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 1ba55c4b5..d4d5e7998 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -580,8 +580,13 @@ private: class BitmapChoiceRenderer : public wxDataViewCustomRenderer { public: - BitmapChoiceRenderer(wxDataViewCellMode mode = wxDATAVIEW_CELL_EDITABLE, - int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL + BitmapChoiceRenderer(wxDataViewCellMode mode = +#ifdef __WXOSX__ + wxDATAVIEW_CELL_INERT +#else + wxDATAVIEW_CELL_EDITABLE +#endif + ,int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL ) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {} bool SetValue(const wxVariant& value); From 9e01740db66a822d4f9e90c39037649bd96e1093 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 2 Oct 2019 15:02:13 +0200 Subject: [PATCH 6/7] More improvements --- src/slic3r/GUI/GUI_ObjectList.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index f8e708200..88cf24509 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -896,20 +896,22 @@ void ObjectList::extruder_editing() const int column_width = GetColumn(colExtruder)->GetWidth(); wxPoint pos = get_mouse_position_in_control(); + wxSize size = wxSize(column_width, -1); pos.x = GetColumn(colName)->GetWidth() + GetColumn(colPrint)->GetWidth(); -// pos.y -= 2*GetTextExtent("m").y; + pos.y -= GetTextExtent("m").y; if (!m_extruder_editor) - m_extruder_editor = new wxBitmapComboBox(this, wxID_ANY, wxEmptyString, pos, wxSize(column_width, -1), + m_extruder_editor = new wxBitmapComboBox(this, wxID_ANY, wxEmptyString, pos, size, 0, nullptr, wxCB_READONLY); else { m_extruder_editor->SetPosition(pos); + m_extruder_editor->SetMinSize(size); + m_extruder_editor->SetSize(size); m_extruder_editor->Clear(); m_extruder_editor->Show(); } - int i = 0; for (wxBitmap* bmp : icons) { if (i == 0) { @@ -922,8 +924,11 @@ void ObjectList::extruder_editing() } m_extruder_editor->SetSelection(m_objects_model->GetExtruderNumber(item)); - auto set_extruder = [this, item]() + auto set_extruder = [this]() { + wxDataViewItem item = GetSelection(); + if (!item) return; + const int selection = m_extruder_editor->GetSelection(); if (selection >= 0) m_objects_model->SetExtruder(m_extruder_editor->GetString(selection), item); @@ -937,12 +942,12 @@ void ObjectList::extruder_editing() set_extruder(); evt.StopPropagation(); }); - + /* m_extruder_editor->Bind(wxEVT_KILL_FOCUS, [set_extruder](wxFocusEvent& evt) { set_extruder(); evt.Skip(); - }); + });*/ } From 8bc569284e35dd5a5a6d07e7e004af7e980123f9 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 2 Oct 2019 16:14:40 +0200 Subject: [PATCH 7/7] Corrected editor position and size --- src/slic3r/GUI/GUI_ObjectList.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 88cf24509..308d0672d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -893,11 +893,11 @@ void ObjectList::extruder_editing() if (icons.empty()) return; - const int column_width = GetColumn(colExtruder)->GetWidth(); + const int column_width = GetColumn(colExtruder)->GetWidth() + wxSystemSettings::GetMetric(wxSYS_VSCROLL_X) + 5; wxPoint pos = get_mouse_position_in_control(); wxSize size = wxSize(column_width, -1); - pos.x = GetColumn(colName)->GetWidth() + GetColumn(colPrint)->GetWidth(); + pos.x = GetColumn(colName)->GetWidth() + GetColumn(colPrint)->GetWidth() + 5; pos.y -= GetTextExtent("m").y; if (!m_extruder_editor) @@ -2938,6 +2938,7 @@ int ObjectList::get_selected_layers_range_idx() const void ObjectList::update_selections() { + if (m_extruder_editor) m_extruder_editor->Hide(); const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); wxDataViewItemArray sels;