diff --git a/resources/icons/add_text_modifier.svg b/resources/icons/add_text_modifier.svg new file mode 100644 index 000000000..5172668ce --- /dev/null +++ b/resources/icons/add_text_modifier.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/resources/icons/add_text_negative.svg b/resources/icons/add_text_negative.svg new file mode 100644 index 000000000..09591f34f --- /dev/null +++ b/resources/icons/add_text_negative.svg @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/resources/icons/add_text_part.svg b/resources/icons/add_text_part.svg new file mode 100644 index 000000000..9c0232873 --- /dev/null +++ b/resources/icons/add_text_part.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 3d1704f8c..7f57c923a 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -165,6 +165,14 @@ const std::vector> MenuFactory::ADD_VOLUME_M {L("Add support enforcer"), "support_enforcer"}, // ~ModelVolumeType::SUPPORT_ENFORCER }; +// Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important +const std::vector MenuFactory::TEXT_VOLUME_ICONS { +// text_volume bitmap name + {"add_text_part" }, // ~ModelVolumeType::MODEL_PART + {"add_text_negative" }, // ~ModelVolumeType::NEGATIVE_VOLUME + {"add_text_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER +}; + static Plater* plater() { return wxGetApp().plater(); @@ -440,6 +448,15 @@ std::vector MenuFactory::get_volume_bitmaps() return volume_bmps; } +std::vector MenuFactory::get_text_volume_bitmaps() +{ + std::vector volume_bmps; + volume_bmps.reserve(TEXT_VOLUME_ICONS.size()); + for (auto item : TEXT_VOLUME_ICONS) + volume_bmps.push_back(create_menu_bitmap(item)); + return volume_bmps; +} + void MenuFactory::append_menu_item_delete(wxMenu* menu) { append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"), @@ -469,8 +486,9 @@ wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType ty auto add_text = [type](wxCommandEvent &) { GLGizmosManager &mng = plater()->canvas3D()->get_gizmos_manager(); - if (mng.get_current_type() == GLGizmosManager::Emboss || - mng.open_gizmo(GLGizmosManager::Emboss)) { + if ((mng.get_current_type() == GLGizmosManager::Emboss || + mng.open_gizmo(GLGizmosManager::Emboss)) && + type != ModelVolumeType::INVALID) { GLGizmoEmboss *emboss = dynamic_cast(mng.get_current()); if (emboss != nullptr) emboss->set_volume_type(type); } @@ -478,6 +496,7 @@ wxMenu* MenuFactory::append_submenu_add_generic(wxMenu* menu, ModelVolumeType ty if (type == ModelVolumeType::MODEL_PART || type == ModelVolumeType::NEGATIVE_VOLUME + || type == ModelVolumeType::PARAMETER_MODIFIER || type == ModelVolumeType::INVALID // cannot use gizmo without selected object ) append_menu_item(sub_menu, wxID_ANY, _L("Text"), "", add_text, "", menu); @@ -991,28 +1010,52 @@ void MenuFactory::create_sla_object_menu() m_sla_object_menu.AppendSeparator(); } +void MenuFactory::append_immutable_part_menu_items(wxMenu* menu) +{ + append_menu_items_mirror(menu); + + append_menu_item(menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual parts"), + [](wxCommandEvent&) { plater()->split_volume(); }, "split_parts_SMALL", nullptr, + []() { return plater()->can_split(false); }, m_parent); + + menu->AppendSeparator(); + append_menu_item_change_type(menu); +} + +void MenuFactory::append_mutable_part_menu_items(wxMenu* menu) +{ + append_menu_item_settings(menu); + append_menu_item_change_extruder(menu); +} + void MenuFactory::create_part_menu() { wxMenu* menu = &m_part_menu; #ifdef __WXOSX__ append_menu_items_osx(menu); #endif // __WXOSX__ - append_menu_item_edit_text(menu); append_menu_item_delete(menu); append_menu_item_reload_from_disk(menu); append_menu_item_replace_with_stl(menu); append_menu_item_export_stl(menu); append_menu_item_fix_through_netfabb(menu); append_menu_item_simplify(menu); - append_menu_items_mirror(menu); - append_menu_item(menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual parts"), - [](wxCommandEvent&) { plater()->split_volume(); }, "split_parts_SMALL", nullptr, - []() { return plater()->can_split(false); }, m_parent); + append_immutable_part_menu_items(menu); +} +void MenuFactory::create_text_part_menu() +{ + wxMenu* menu = &m_text_part_menu; +#ifdef __WXOSX__ + append_menu_items_osx(menu); +#endif // __WXOSX__ + append_menu_item_edit_text(menu); menu->AppendSeparator(); - append_menu_item_change_type(menu); + append_menu_item_delete(menu); + // menu->AppendSeparator(); + append_immutable_part_menu_items(menu); } void MenuFactory::create_instance_menu() @@ -1031,6 +1074,7 @@ void MenuFactory::init(wxWindow* parent) create_object_menu(); create_sla_object_menu(); create_part_menu(); + create_text_part_menu(); create_instance_menu(); } @@ -1067,12 +1111,19 @@ wxMenu* MenuFactory::sla_object_menu() wxMenu* MenuFactory::part_menu() { append_menu_items_convert_unit(&m_part_menu, 2); - append_menu_item_settings(&m_part_menu); - append_menu_item_change_extruder(&m_part_menu); + + append_mutable_part_menu_items(&m_part_menu); return &m_part_menu; } +wxMenu* MenuFactory::text_part_menu() +{ + append_mutable_part_menu_items(&m_text_part_menu); + + return &m_text_part_menu; +} + wxMenu* MenuFactory::instance_menu() { return &m_instance_menu; diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index 726eb0931..64f92af7f 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -34,7 +34,9 @@ class MenuFactory { public: static const std::vector> ADD_VOLUME_MENU_ITEMS; + static const std::vector TEXT_VOLUME_ICONS; static std::vector get_volume_bitmaps(); + static std::vector get_text_volume_bitmaps(); MenuFactory(); ~MenuFactory() = default; @@ -52,6 +54,7 @@ public: wxMenu* object_menu(); wxMenu* sla_object_menu(); wxMenu* part_menu(); + wxMenu* text_part_menu(); wxMenu* instance_menu(); wxMenu* layer_menu(); wxMenu* multi_selection_menu(); @@ -67,6 +70,7 @@ private: MenuWithSeparators m_object_menu; MenuWithSeparators m_part_menu; + MenuWithSeparators m_text_part_menu; MenuWithSeparators m_sla_object_menu; MenuWithSeparators m_default_menu; MenuWithSeparators m_instance_menu; @@ -80,7 +84,10 @@ private: void create_common_object_menu(wxMenu *menu); void create_object_menu(); void create_sla_object_menu(); + void append_immutable_part_menu_items(wxMenu* menu); + void append_mutable_part_menu_items(wxMenu* menu); void create_part_menu(); + void create_text_part_menu(); void create_instance_menu(); wxMenu* append_submenu_add_generic(wxMenu* menu, ModelVolumeType type); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 83f9d1ec1..720915fa6 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -955,11 +955,17 @@ void ObjectList::show_context_menu(const bool evt_context_menu) const ItemType type = m_objects_model->GetItemType(item); if (!(type & (itObject | itVolume | itLayer | itInstance))) return; - - menu = type & itInstance ? plater->instance_menu() : - type & itLayer ? plater->layer_menu() : - m_objects_model->GetParent(item) != wxDataViewItem(nullptr) ? plater->part_menu() : - printer_technology() == ptFFF ? plater->object_menu() : plater->sla_object_menu(); + if (type & itVolume) { + int obj_idx, vol_idx; + get_selected_item_indexes(obj_idx, vol_idx, item); + if (obj_idx < 0 || vol_idx < 0) + return; + menu = object(obj_idx)->volumes[vol_idx]->text_configuration.has_value() ? plater->text_part_menu() : plater->part_menu(); + } + else + menu = type & itInstance ? plater->instance_menu() : + type & itLayer ? plater->layer_menu() : + printer_technology() == ptFFF ? plater->object_menu() : plater->sla_object_menu(); } else if (evt_context_menu) menu = plater->default_menu(); @@ -2026,6 +2032,7 @@ void ObjectList::split() for (const ModelVolume* volume : model_object->volumes) { const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(parent, from_u8(volume->name), volume->type(),// is_modifier() ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, + volume->text_configuration.has_value(), get_warning_icon_name(volume->mesh().stats()), volume->config.has("extruder") ? volume->config.extruder() : 0, false); @@ -2678,6 +2685,7 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed) const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(item, from_u8(volume->name), volume->type(), + volume->text_configuration.has_value(), get_warning_icon_name(volume->mesh().stats()), volume->config.has("extruder") ? volume->config.extruder() : 0, false); @@ -3782,8 +3790,13 @@ void ObjectList::change_part_type() } } - const wxString names[] = { _L("Part"), _L("Negative Volume"), _L("Modifier"), _L("Support Blocker"), _L("Support Enforcer") }; - auto new_type = ModelVolumeType(wxGetSingleChoiceIndex(_L("Type:"), _L("Select type of part"), wxArrayString(5, names), int(type))); + wxArrayString names; + for (const wxString& name : { _L("Part"), _L("Negative Volume"), _L("Modifier") }) + names.Add(name); + if (!volume->text_configuration.has_value()) + for (const wxString& name : { _L("Support Blocker"), _L("Support Enforcer") }) + names.Add(name); + auto new_type = ModelVolumeType(wxGetSingleChoiceIndex(_L("Type:"), _L("Select type of part"), names, int(type))); if (new_type == type || new_type == ModelVolumeType::INVALID) return; @@ -4333,6 +4346,7 @@ wxDataViewItemArray ObjectList::reorder_volumes_and_get_selection(int obj_idx, s for (const ModelVolume* volume : object->volumes) { wxDataViewItem vol_item = m_objects_model->AddVolumeChild(object_item, from_u8(volume->name), volume->type(), + volume->text_configuration.has_value(), get_warning_icon_name(volume->mesh().stats()), volume->config.has("extruder") ? volume->config.extruder() : 0, false); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index b034e8b2f..36c08d567 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -207,7 +207,7 @@ bool GLGizmoEmboss::on_init() std::string GLGizmoEmboss::on_get_name() const { - return (_L("Emboss")).ToUTF8().data(); + return _u8L("Emboss"); } void GLGizmoEmboss::on_render() {} @@ -409,6 +409,26 @@ bool GLGizmoEmboss::process() return add_volume(create_volume_name(), its); } +void GLGizmoEmboss::set_volume_type(ModelVolumeType volume_type) +{ + m_volume_type = volume_type; // fsFIXME - may be it's no needed + + const Selection& selection = m_parent.get_selection(); + if (selection.is_empty() || selection.get_object_idx() < 0) + return; + + m_volume->set_type(volume_type); + + ObjectList* obj_list = wxGetApp().obj_list(); + ModelVolume* volume = m_volume; // copy pointer for lambda + wxDataViewItemArray sel = obj_list->reorder_volumes_and_get_selection(selection.get_object_idx(), [volume](const ModelVolume* vol) { return vol == volume; }); + if (!sel.IsEmpty()) + obj_list->select_item(sel.front()); + + obj_list->selection_changed(); + m_parent.reload_scene(true); +} + bool GLGizmoEmboss::add_volume(const std::string &name, indexed_triangle_set &its) { if (its.indices.empty()) return false; @@ -453,32 +473,6 @@ bool GLGizmoEmboss::add_volume(const std::string &name, indexed_triangle_set &it m_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); m_volume->text_configuration = create_configuration(); - // select new added volume - ModelObject *mo = m_volume->get_object(); - // Editing object volume change its name - if (mo->volumes.size() == 1) mo->name = name; - ObjectList * obj_list = app.obj_list(); - const ModelObjectPtrs &objs = *obj_list->objects(); - auto item = find(objs.begin(), objs.end(), mo); - assert(item != objs.end()); - int object_idx = item - objs.begin(); - ModelVolume *new_volume = m_volume; // copy pointer for lambda - obj_list->select_item([new_volume, object_idx, obj_list]() { - wxDataViewItemArray items = obj_list->reorder_volumes_and_get_selection( - object_idx, [new_volume](const ModelVolume *volume) { - return volume == new_volume; - }); - if (items.IsEmpty()) return wxDataViewItem(); - return items.front(); - }); - - if (m_volume->type() == ModelVolumeType::MODEL_PART) - // update printable state on canvas - m_parent.update_instance_printable_state_for_object( - (size_t) object_idx); - - obj_list->selection_changed(); - m_parent.reload_scene(true); return true; } @@ -500,22 +494,22 @@ void GLGizmoEmboss::draw_window() #endif // ALLOW_DEBUG_MODE if (!m_font.has_value()) { - ImGui::Text(_L("Warning: No font is selected. Select correct one.").c_str()); + ImGui::Text(_u8L("Warning: No font is selected. Select correct one.").c_str()); } draw_font_list(); draw_text_input(); static bool advanced = false; - ImGui::Checkbox(_L("Advance").c_str(), &advanced); + ImGui::Checkbox(_u8L("Advance").c_str(), &advanced); if (advanced) draw_advanced(); - if (ImGui::Button(_L("Close").c_str())) close(); + if (ImGui::Button(_u8L("Close").c_str())) close(); // Option to create text volume when reselecting volumes m_imgui->disabled_begin(!m_font.has_value()); if (m_volume == nullptr) { ImGui::SameLine(); - if (ImGui::Button(_L("Generate preview").c_str())) process(); + if (ImGui::Button(_u8L("Generate preview").c_str())) process(); } m_imgui->disabled_end(); } @@ -529,18 +523,18 @@ void GLGizmoEmboss::draw_font_list() if (ImGui::BeginCombo("##font_selector", current_name.c_str())) { // first line #ifdef USE_FONT_DIALOG - if (ImGui::Button(_L("Choose font").c_str())) { + if (ImGui::Button(_u8L("Choose font").c_str())) { choose_font_by_wxdialog(); store_font_list(); ImGui::CloseCurrentPopup(); - } else if (ImGui::IsItemHovered()) ImGui::SetTooltip(_L("Choose from installed font in dialog.").c_str()); + } else if (ImGui::IsItemHovered()) ImGui::SetTooltip(_u8L("Choose from installed font in dialog.").c_str()); ImGui::SameLine(); #endif // USE_FONT_DIALOG - if (ImGui::Button(_L("Add File").c_str())) { + if (ImGui::Button(_u8L("Add File").c_str())) { choose_true_type_file(); store_font_list(); ImGui::CloseCurrentPopup(); - } else if (ImGui::IsItemHovered()) ImGui::SetTooltip(_L("add file with font(.ttf, .ttc)").c_str()); + } else if (ImGui::IsItemHovered()) ImGui::SetTooltip(_u8L("add file with font(.ttf, .ttc)").c_str()); ImGui::Separator(); @@ -626,24 +620,24 @@ void GLGizmoEmboss::draw_text_input() } void GLGizmoEmboss::draw_advanced() { - if (ImGui::InputFloat(_L("Size[in mm]").c_str(), &m_font_prop.size_in_mm)) { + if (ImGui::InputFloat(_u8L("Size[in mm]").c_str(), &m_font_prop.size_in_mm)) { if (m_font_prop.size_in_mm < 0.1) m_font_prop.size_in_mm = 10; load_imgui_font(); process(); } - if (ImGui::InputFloat(_L("Emboss[in mm]").c_str(), &m_font_prop.emboss)) process(); - if (ImGui::InputFloat(_L("Flatness").c_str(), &m_font_prop.flatness)) { + if (ImGui::InputFloat(_u8L("Emboss[in mm]").c_str(), &m_font_prop.emboss)) process(); + if (ImGui::InputFloat(_u8L("Flatness").c_str(), &m_font_prop.flatness)) { if (m_font.has_value()) m_font->cache.clear(); process(); } - if (ImGui::InputInt(_L("CharGap[in font points]").c_str(), &m_font_prop.char_gap)) + if (ImGui::InputInt(_u8L("CharGap[in font points]").c_str(), &m_font_prop.char_gap)) process(); - if (ImGui::InputInt(_L("LineGap[in font points]").c_str(), &m_font_prop.line_gap)) + if (ImGui::InputInt(_u8L("LineGap[in font points]").c_str(), &m_font_prop.line_gap)) process(); // when more collection add selector if (m_font.has_value() && m_font->count > 1) { - if (ImGui::BeginCombo(_L("Font collection").c_str(), + if (ImGui::BeginCombo(_u8L("Font collection").c_str(), std::to_string(m_font->index).c_str())) { for (unsigned int i = 0; i < m_font->count; ++i) { ImGui::PushID(1 << 10 + i); @@ -1100,7 +1094,7 @@ bool GLGizmoEmboss::draw_button(IconType icon, bool disable) if (disable) { draw_icon(icon, IconState::disabled); if (ImGui::IsItemHovered() && icon == IconType::erase) - ImGui::SetTooltip(_L("Active font can't be removed").c_str()); + ImGui::SetTooltip(_u8L("Active font can't be removed").c_str()); return false; } @@ -1110,8 +1104,8 @@ bool GLGizmoEmboss::draw_button(IconType icon, bool disable) if (ImGui::IsItemClicked()) return true; if (ImGui::IsItemHovered()) { switch (icon) { - case IconType::rename: ImGui::SetTooltip(_L("rename").c_str()); break; - case IconType::erase: ImGui::SetTooltip(_L("delete").c_str()); break; + case IconType::rename: ImGui::SetTooltip(_u8L("rename").c_str()); break; + case IconType::erase: ImGui::SetTooltip(_u8L("delete").c_str()); break; default: break; } // redraw image over previous diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index deb6d0395..c4d1adbff 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -23,7 +23,8 @@ public: GLGizmoEmboss(GLCanvas3D& parent); virtual ~GLGizmoEmboss(); - void set_volume_type(ModelVolumeType volume_type) { m_volume_type = volume_type; } + void set_volume_type(ModelVolumeType volume_type); + protected: virtual bool on_init() override; virtual std::string on_get_name() const override; diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index ed4b477b8..d8206bec0 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -56,7 +56,7 @@ const std::map INFO_ITEMS{ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const wxString& sub_obj_name, Slic3r::ModelVolumeType type, - const wxBitmap& bmp, + const bool is_text_volume, const wxString& extruder, const int idx/* = -1*/, const std::string& warning_icon_name /*= std::string*/) : @@ -64,11 +64,11 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* pare m_name(sub_obj_name), m_type(itVolume), m_volume_type(type), + m_is_text_volume(is_text_volume), m_idx(idx), m_extruder(type == Slic3r::ModelVolumeType::MODEL_PART || type == Slic3r::ModelVolumeType::PARAMETER_MODIFIER ? extruder : ""), m_warning_icon_name(warning_icon_name) { - m_bmp = bmp; set_action_and_extruder_icons(); init_container(); } @@ -324,9 +324,10 @@ ObjectDataViewModel::ObjectDataViewModel() { m_bitmap_cache = new Slic3r::GUI::BitmapCache; - m_volume_bmps = MenuFactory::get_volume_bitmaps(); - m_warning_bmp = create_scaled_bitmap(WarningIcon); - m_warning_manifold_bmp = create_scaled_bitmap(WarningManifoldIcon); + m_volume_bmps = MenuFactory::get_volume_bitmaps(); + m_text_volume_bmps = MenuFactory::get_text_volume_bitmaps(); + m_warning_bmp = create_scaled_bitmap(WarningIcon); + m_warning_manifold_bmp = create_scaled_bitmap(WarningManifoldIcon); for (auto item : INFO_ITEMS) m_info_bmps[item.first] = create_scaled_bitmap(item.second.bmp_name); @@ -366,6 +367,7 @@ wxDataViewItem ObjectDataViewModel::Add(const wxString &name, wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent_item, const wxString &name, const Slic3r::ModelVolumeType volume_type, + const bool is_text_volume /*- false*/, const std::string& warning_icon_name/* = std::string()*/, const int extruder/* = 0*/, const bool create_frst_child/* = true*/) @@ -383,8 +385,8 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent if (create_frst_child && root->m_volumes_cnt == 0) { const Slic3r::ModelVolumeType type = Slic3r::ModelVolumeType::MODEL_PART; - const auto node = new ObjectDataViewModelNode(root, root->m_name, type, GetVolumeIcon(type, root->m_warning_icon_name), extruder_str, 0, root->m_warning_icon_name); - + const auto node = new ObjectDataViewModelNode(root, root->m_name, type, root->is_text_volume(), extruder_str, 0, root->m_warning_icon_name); + SetVolumeBitmap(node); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // notify control const wxDataViewItem child((void*)node); @@ -394,7 +396,8 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent if (insert_position >= 0) insert_position++; } - const auto node = new ObjectDataViewModelNode(root, name, volume_type, GetVolumeIcon(volume_type, warning_icon_name), extruder_str, root->m_volumes_cnt, warning_icon_name); + const auto node = new ObjectDataViewModelNode(root, name, volume_type, is_text_volume, extruder_str, root->m_volumes_cnt, warning_icon_name); + SetVolumeBitmap(node); insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); // if part with errors is added, but object wasn't marked, then mark it @@ -1611,20 +1614,9 @@ void ObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item, ItemChanged(item); } -void ObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType volume_type) +void ObjectDataViewModel::SetVolumeBitmap(ObjectDataViewModelNode* node) { - if (!item.IsOk() || GetItemType(item) != itVolume) - return; - - ObjectDataViewModelNode *node = static_cast(item.GetID()); - node->SetVolumeType(volume_type); - node->SetBitmap(m_volume_bmps[int(volume_type)]); - if (volume_type != Slic3r::ModelVolumeType::MODEL_PART && volume_type != Slic3r::ModelVolumeType::PARAMETER_MODIFIER) - node->SetExtruder(""); // hide extruder - else if (node->GetExtruder().IsEmpty()) - node->SetExtruder("default"); // show extruder ans set it to default - node->UpdateExtruderAndColorIcon(); - ItemChanged(item); + node->SetBitmap(GetVolumeIcon(node, node->m_warning_icon_name)); } ModelVolumeType ObjectDataViewModel::GetVolumeType(const wxDataViewItem& item) @@ -1678,9 +1670,11 @@ wxDataViewItem ObjectDataViewModel::SetObjectPrintableState( void ObjectDataViewModel::Rescale() { - m_volume_bmps = MenuFactory::get_volume_bitmaps(); - m_warning_bmp = create_scaled_bitmap(WarningIcon); - m_warning_manifold_bmp = create_scaled_bitmap(WarningManifoldIcon); + m_volume_bmps = MenuFactory::get_volume_bitmaps(); + m_text_volume_bmps = MenuFactory::get_text_volume_bitmaps(); + + m_warning_bmp = create_scaled_bitmap(WarningIcon); + m_warning_manifold_bmp = create_scaled_bitmap(WarningManifoldIcon); wxDataViewItemArray all_items; GetAllChildren(wxDataViewItem(0), all_items); @@ -1699,7 +1693,7 @@ void ObjectDataViewModel::Rescale() if (node->m_bmp.IsOk()) node->m_bmp = GetWarningBitmap(node->m_warning_icon_name); break; case itVolume: - node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_warning_icon_name); + SetVolumeBitmap(node); break; case itLayerRoot: node->m_bmp = create_scaled_bitmap(LayerRootIcon); @@ -1713,12 +1707,13 @@ void ObjectDataViewModel::Rescale() } } -wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const std::string& warning_icon_name/* = std::string()*/) +wxBitmap ObjectDataViewModel::GetVolumeIcon(const ObjectDataViewModelNode* node, const std::string& warning_icon_name) { + const std::vector& bitmaps = node->is_text_volume() ? m_text_volume_bmps : m_volume_bmps; if (warning_icon_name.empty()) - return m_volume_bmps[static_cast(vol_type)]; + return bitmaps[node->volume_type()]; - std::string scaled_bitmap_name = warning_icon_name + std::to_string(static_cast(vol_type)); + std::string scaled_bitmap_name = warning_icon_name + std::to_string(node->volume_type()); scaled_bitmap_name += "-em" + std::to_string(wxGetApp().em_unit()) + (wxGetApp().dark_mode() ? "-dm" : "-lm"); wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name); @@ -1726,7 +1721,7 @@ wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_ty std::vector bmps; bmps.emplace_back(GetWarningBitmap(warning_icon_name)); - bmps.emplace_back(m_volume_bmps[static_cast(vol_type)]); + bmps.emplace_back(bitmaps[node->volume_type()]); bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps); } @@ -1734,6 +1729,11 @@ wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_ty return *bmp; } +wxBitmap ObjectDataViewModel::GetVolumeIcon(const ObjectDataViewModelNode* node) +{ + return GetVolumeIcon(node, node->m_warning_icon_name); +} + void ObjectDataViewModel::AddWarningIcon(const wxDataViewItem& item, const std::string& warning_icon_name) { if (!item.IsOk()) @@ -1746,7 +1746,7 @@ void ObjectDataViewModel::AddWarningIcon(const wxDataViewItem& item, const std:: } if (node->GetType() & itVolume) { - node->SetWarningBitmap(GetVolumeIcon(node->GetVolumeType(), warning_icon_name), warning_icon_name); + node->SetWarningBitmap(GetVolumeIcon(node, warning_icon_name), warning_icon_name); node->GetParent()->SetWarningBitmap(GetWarningBitmap(warning_icon_name), warning_icon_name); return; } diff --git a/src/slic3r/GUI/ObjectDataViewModel.hpp b/src/slic3r/GUI/ObjectDataViewModel.hpp index f8885b206..9fdcc81ce 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.hpp +++ b/src/slic3r/GUI/ObjectDataViewModel.hpp @@ -82,6 +82,7 @@ class ObjectDataViewModelNode std::string m_action_icon_name = ""; ModelVolumeType m_volume_type; + bool m_is_text_volume{ false }; InfoItemType m_info_item_type {InfoItemType::Undef}; public: @@ -99,7 +100,7 @@ public: ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const wxString& sub_obj_name, Slic3r::ModelVolumeType type, - const wxBitmap& bmp, + const bool is_text_volume, const wxString& extruder, const int idx = -1, const std::string& warning_icon_name = std::string()); @@ -178,7 +179,6 @@ public: } bool SetValue(const wxVariant &variant, unsigned int col); - void SetVolumeType(ModelVolumeType type) { m_volume_type = type; } void SetBitmap(const wxBitmap &icon) { m_bmp = icon; } void SetExtruder(const wxString &extruder) { m_extruder = extruder; } void SetWarningBitmap(const wxBitmap& icon, const std::string& warning_icon_name) { m_bmp = icon; m_warning_icon_name = warning_icon_name; } @@ -234,6 +234,7 @@ public: void update_settings_digest_bitmaps(); bool update_settings_digest(const std::vector& categories); int volume_type() const { return int(m_volume_type); } + bool is_text_volume() const { return m_is_text_volume; } void msw_rescale(); #ifndef NDEBUG @@ -258,6 +259,7 @@ class ObjectDataViewModel :public wxDataViewModel { std::vector m_objects; std::vector m_volume_bmps; + std::vector m_text_volume_bmps; std::map m_info_bmps; wxBitmap m_empty_bmp; wxBitmap m_warning_bmp; @@ -275,6 +277,7 @@ public: wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item, const wxString &name, const Slic3r::ModelVolumeType volume_type, + const bool is_text_volume = false, const std::string& warning_icon_name = std::string(), const int extruder = 0, const bool create_frst_child = true); @@ -374,7 +377,7 @@ public: void UpdateObjectPrintable(wxDataViewItem parent_item); void UpdateInstancesPrintable(wxDataViewItem parent_item); - void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type); + void SetVolumeBitmap(ObjectDataViewModelNode* node); ModelVolumeType GetVolumeType(const wxDataViewItem &item); wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx, int subobj_idx = -1, @@ -385,8 +388,9 @@ public: // Rescale bitmaps for existing Items void Rescale(); - wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, - const std::string& warning_icon_name = std::string()); + wxBitmap GetVolumeIcon(const ObjectDataViewModelNode* node, + const std::string& warning_icon_name); + wxBitmap GetVolumeIcon(const ObjectDataViewModelNode* node); void AddWarningIcon(const wxDataViewItem& item, const std::string& warning_name); void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); void UpdateWarningIcon(const wxDataViewItem& item, const std::string& warning_name); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 9a24d91cc..e12e55631 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4196,13 +4196,20 @@ void Plater::priv::on_right_click(RBtnEvent& evt) menu = menus.sla_object_menu(); else { const Selection& selection = get_selection(); - // show "Object menu" for each one or several FullInstance instead of FullObject - const bool is_some_full_instances = selection.is_single_full_instance() || - selection.is_single_full_object() || - selection.is_multiple_full_instance(); - const bool is_part = selection.is_single_volume() || selection.is_single_modifier(); - menu = is_some_full_instances ? menus.object_menu() : - is_part ? menus.part_menu() : menus.multi_selection_menu(); + // check if selected item is object's part + if (selection.is_single_volume() || selection.is_single_modifier()) { + int vol_idx = get_selected_volume_idx(); + if (vol_idx < 0) + return; + menu = model.objects[obj_idx]->volumes[vol_idx]->text_configuration.has_value() ? menus.text_part_menu() : menus.part_menu(); + } + else { + // show "Object menu" for each one or several FullInstance instead of FullObject + const bool is_some_full_instances = selection.is_single_full_instance() || + selection.is_single_full_object() || + selection.is_multiple_full_instance(); + menu = is_some_full_instances ? menus.object_menu() : menus.multi_selection_menu(); + } } } @@ -6841,6 +6848,7 @@ void Plater::bring_instance_forward() wxMenu* Plater::object_menu() { return p->menus.object_menu(); } wxMenu* Plater::part_menu() { return p->menus.part_menu(); } +wxMenu* Plater::text_part_menu() { return p->menus.text_part_menu(); } wxMenu* Plater::sla_object_menu() { return p->menus.sla_object_menu(); } wxMenu* Plater::default_menu() { return p->menus.default_menu(); } wxMenu* Plater::instance_menu() { return p->menus.instance_menu(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 0e9d28c1a..b790a4470 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -420,6 +420,7 @@ public: // get same Plater/ObjectList menus wxMenu* object_menu(); wxMenu* part_menu(); + wxMenu* text_part_menu(); wxMenu* sla_object_menu(); wxMenu* default_menu(); wxMenu* instance_menu();