mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/Slic3r
This commit is contained in:
		
						commit
						022e325a60
					
				
					 21 changed files with 546 additions and 75 deletions
				
			
		|  | @ -721,32 +721,37 @@ int GLVolumeCollection::load_wipe_tower_preview( | |||
|     return int(this->volumes.size() - 1); | ||||
| } | ||||
| 
 | ||||
| typedef std::pair<GLVolume*, double> GLVolumeWithZ; | ||||
| typedef std::vector<GLVolumeWithZ> GLVolumesWithZList; | ||||
| static GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func) | ||||
| GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func) | ||||
| { | ||||
|     GLVolumesWithZList list; | ||||
|     GLVolumeWithIdAndZList list; | ||||
|     list.reserve(volumes.size()); | ||||
| 
 | ||||
|     for (GLVolume* volume : volumes) | ||||
|     for (unsigned int i = 0; i < (unsigned int)volumes.size(); ++i) | ||||
|     { | ||||
|         GLVolume* volume = volumes[i]; | ||||
|         bool is_transparent = (volume->render_color[3] < 1.0f); | ||||
|         if ((((type == GLVolumeCollection::Opaque) && !is_transparent) || | ||||
|              ((type == GLVolumeCollection::Transparent) && is_transparent) || | ||||
|              (type == GLVolumeCollection::All)) && | ||||
|             (! filter_func || filter_func(*volume))) | ||||
|             list.emplace_back(std::make_pair(volume, 0.0)); | ||||
|             list.emplace_back(std::make_pair(volume, std::make_pair(i, 0.0))); | ||||
|     } | ||||
| 
 | ||||
|     if ((type == GLVolumeCollection::Transparent) && (list.size() > 1)) | ||||
|     { | ||||
|         for (GLVolumeWithZ& volume : list) | ||||
|         for (GLVolumeWithIdAndZ& volume : list) | ||||
|         { | ||||
|             volume.second = volume.first->bounding_box.transformed(view_matrix * volume.first->world_matrix()).max(2); | ||||
|             volume.second.second = volume.first->bounding_box.transformed(view_matrix * volume.first->world_matrix()).max(2); | ||||
|         } | ||||
| 
 | ||||
|         std::sort(list.begin(), list.end(), | ||||
|             [](const GLVolumeWithZ& v1, const GLVolumeWithZ& v2) -> bool { return v1.second < v2.second; } | ||||
|             [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.second.second < v2.second.second; } | ||||
|         ); | ||||
|     } | ||||
|     else if ((type == GLVolumeCollection::Opaque) && (list.size() > 1)) | ||||
|     { | ||||
|         std::sort(list.begin(), list.end(), | ||||
|             [](const GLVolumeWithIdAndZ& v1, const GLVolumeWithIdAndZ& v2) -> bool { return v1.first->selected && !v2.first->selected; } | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|  | @ -788,9 +793,8 @@ void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool | |||
|     if (clipping_plane_id != -1) | ||||
|         glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)clipping_plane)); | ||||
| 
 | ||||
|     GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); | ||||
| 
 | ||||
|     for (GLVolumeWithZ& volume : to_render) { | ||||
|     GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); | ||||
|     for (GLVolumeWithIdAndZ& volume : to_render) { | ||||
|         volume.first->set_render_color(); | ||||
|         volume.first->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id); | ||||
|     } | ||||
|  | @ -819,8 +823,8 @@ void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface, | |||
|     glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); | ||||
|   | ||||
|     GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); | ||||
|     for (GLVolumeWithZ& volume : to_render) | ||||
|     GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); | ||||
|     for (GLVolumeWithIdAndZ& volume : to_render) | ||||
|     { | ||||
|         volume.first->set_render_color(); | ||||
|         volume.first->render_legacy(); | ||||
|  |  | |||
|  | @ -412,6 +412,8 @@ public: | |||
| }; | ||||
| 
 | ||||
| typedef std::vector<GLVolume*> GLVolumePtrs; | ||||
| typedef std::pair<GLVolume*, std::pair<unsigned int, double>> GLVolumeWithIdAndZ; | ||||
| typedef std::vector<GLVolumeWithIdAndZ> GLVolumeWithIdAndZList; | ||||
| 
 | ||||
| class GLVolumeCollection | ||||
| { | ||||
|  | @ -509,6 +511,8 @@ private: | |||
|     GLVolumeCollection& operator=(const GLVolumeCollection &); | ||||
| }; | ||||
| 
 | ||||
| GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = nullptr); | ||||
| 
 | ||||
| class GLModel | ||||
| { | ||||
| protected: | ||||
|  |  | |||
|  | @ -3232,12 +3232,37 @@ bool GLCanvas3D::_init_toolbar() | |||
|     if (!m_toolbar.add_separator()) | ||||
|         return false; | ||||
| 
 | ||||
|     item.name = "copy"; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     item.icon_filename = "copy.svg"; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     item.tooltip = GUI::L_str("Copy") + " [" + GUI::shortkey_ctrl_prefix() + "C]"; | ||||
|     item.sprite_id = 4; | ||||
|     item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); }; | ||||
|     item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_copy(); }; | ||||
|     if (!m_toolbar.add_item(item)) | ||||
|         return false; | ||||
| 
 | ||||
|     item.name = "paste"; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     item.icon_filename = "paste.svg"; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     item.tooltip = GUI::L_str("Paste") + " [" + GUI::shortkey_ctrl_prefix() + "V]"; | ||||
|     item.sprite_id = 5; | ||||
|     item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); }; | ||||
|     item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_paste(); }; | ||||
|     if (!m_toolbar.add_item(item)) | ||||
|         return false; | ||||
| 
 | ||||
|     if (!m_toolbar.add_separator()) | ||||
|         return false; | ||||
| 
 | ||||
|     item.name = "more"; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     item.icon_filename = "instance_add.svg"; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     item.tooltip = GUI::L_str("Add instance [+]"); | ||||
|     item.sprite_id = 4; | ||||
|     item.sprite_id = 6; | ||||
|     item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); }; | ||||
|     item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; | ||||
|     item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_increase_instances(); }; | ||||
|  | @ -3249,7 +3274,7 @@ bool GLCanvas3D::_init_toolbar() | |||
|     item.icon_filename = "instance_remove.svg"; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     item.tooltip = GUI::L_str("Remove instance [-]"); | ||||
|     item.sprite_id = 5; | ||||
|     item.sprite_id = 7; | ||||
|     item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); }; | ||||
|     item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; | ||||
|     item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_decrease_instances(); }; | ||||
|  | @ -3264,7 +3289,7 @@ bool GLCanvas3D::_init_toolbar() | |||
|     item.icon_filename = "split_objects.svg"; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     item.tooltip = GUI::L_str("Split to objects"); | ||||
|     item.sprite_id = 6; | ||||
|     item.sprite_id = 8; | ||||
|     item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); }; | ||||
|     item.visibility_callback = GLToolbarItem::Default_Visibility_Callback; | ||||
|     item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_split_to_objects(); }; | ||||
|  | @ -3276,7 +3301,7 @@ bool GLCanvas3D::_init_toolbar() | |||
|     item.icon_filename = "split_parts.svg"; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     item.tooltip = GUI::L_str("Split to parts"); | ||||
|     item.sprite_id = 7; | ||||
|     item.sprite_id = 9; | ||||
|     item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); }; | ||||
|     item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; | ||||
|     item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_split_to_volumes(); }; | ||||
|  | @ -3291,7 +3316,7 @@ bool GLCanvas3D::_init_toolbar() | |||
|     item.icon_filename = "layers.svg"; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     item.tooltip = GUI::L_str("Layers editing"); | ||||
|     item.sprite_id = 8; | ||||
|     item.sprite_id = 10; | ||||
|     item.is_toggable = true; | ||||
|     item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); }; | ||||
|     item.visibility_callback = [this]()->bool { return m_process->current_printer_technology() == ptFFF; }; | ||||
|  | @ -3501,7 +3526,7 @@ void GLCanvas3D::_picking_pass() const | |||
|             ::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)m_camera_clipping_plane.get_data()); | ||||
|             ::glEnable(GL_CLIP_PLANE0); | ||||
|         } | ||||
|         _render_volumes(true); | ||||
|         _render_volumes_for_picking(); | ||||
|         if (! m_use_VBOs) | ||||
|             ::glDisable(GL_CLIP_PLANE0); | ||||
| 
 | ||||
|  | @ -3702,13 +3727,10 @@ void GLCanvas3D::_render_legend_texture() const | |||
|     m_legend_texture.render(*this); | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::_render_volumes(bool fake_colors) const | ||||
| void GLCanvas3D::_render_volumes_for_picking() const | ||||
| { | ||||
|     static const GLfloat INV_255 = 1.0f / 255.0f; | ||||
| 
 | ||||
|     if (!fake_colors) | ||||
|         glsafe(::glEnable(GL_LIGHTING)); | ||||
| 
 | ||||
|     // do not cull backfaces to show broken geometry, if any
 | ||||
|     glsafe(::glDisable(GL_CULL_FACE)); | ||||
| 
 | ||||
|  | @ -3718,27 +3740,31 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const | |||
|     glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); | ||||
| 
 | ||||
|     unsigned int volume_id = 0; | ||||
|     for (GLVolume* vol : m_volumes.volumes) | ||||
|     const Transform3d& view_matrix = m_camera.get_view_matrix(); | ||||
|     GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Opaque, view_matrix); | ||||
|     for (const GLVolumeWithIdAndZ& volume : to_render) | ||||
|     { | ||||
|         if (fake_colors) | ||||
|         { | ||||
|             // Object picking mode. Render the object with a color encoding the object index.
 | ||||
|             unsigned int r = (volume_id & 0x000000FF) >> 0; | ||||
|             unsigned int g = (volume_id & 0x0000FF00) >> 8; | ||||
|             unsigned int b = (volume_id & 0x00FF0000) >> 16; | ||||
|             glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             vol->set_render_color(); | ||||
|             glsafe(::glColor4fv(vol->render_color)); | ||||
|         } | ||||
|         // Object picking mode. Render the object with a color encoding the object index.
 | ||||
|         unsigned int r = (volume.second.first & 0x000000FF) >> 0; | ||||
|         unsigned int g = (volume.second.first & 0x0000FF00) >> 8; | ||||
|         unsigned int b = (volume.second.first & 0x00FF0000) >> 16; | ||||
|         glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); | ||||
| 
 | ||||
|         if ((!fake_colors || !vol->disabled) && (vol->composite_id.volume_id >= 0 || m_render_sla_auxiliaries)) | ||||
|             vol->render(); | ||||
|         if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) | ||||
|             volume.first->render(); | ||||
|     } | ||||
| 
 | ||||
|         ++volume_id; | ||||
|     to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Transparent, view_matrix); | ||||
|     for (const GLVolumeWithIdAndZ& volume : to_render) | ||||
|     { | ||||
|         // Object picking mode. Render the object with a color encoding the object index.
 | ||||
|         unsigned int r = (volume.second.first & 0x000000FF) >> 0; | ||||
|         unsigned int g = (volume.second.first & 0x0000FF00) >> 8; | ||||
|         unsigned int b = (volume.second.first & 0x00FF0000) >> 16; | ||||
|         glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); | ||||
| 
 | ||||
|         if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) | ||||
|             volume.first->render(); | ||||
|     } | ||||
| 
 | ||||
|     glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); | ||||
|  | @ -3746,9 +3772,6 @@ void GLCanvas3D::_render_volumes(bool fake_colors) const | |||
|     glsafe(::glDisable(GL_BLEND)); | ||||
| 
 | ||||
|     glsafe(::glEnable(GL_CULL_FACE)); | ||||
| 
 | ||||
|     if (!fake_colors) | ||||
|         glsafe(::glDisable(GL_LIGHTING)); | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::_render_current_gizmo() const | ||||
|  | @ -4026,15 +4049,9 @@ void GLCanvas3D::_update_volumes_hover_state() const | |||
|         return; | ||||
| 
 | ||||
|     GLVolume* volume = m_volumes.volumes[m_hover_volume_id]; | ||||
| 
 | ||||
|     switch (m_selection.get_mode()) | ||||
|     { | ||||
|     case Selection::Volume: | ||||
|     { | ||||
|     if (volume->is_modifier) | ||||
|         volume->hover = true; | ||||
|         break; | ||||
|     } | ||||
|     case Selection::Instance: | ||||
|     else | ||||
|     { | ||||
|         int object_idx = volume->object_idx(); | ||||
|         int instance_idx = volume->instance_idx(); | ||||
|  | @ -4044,9 +4061,6 @@ void GLCanvas3D::_update_volumes_hover_state() const | |||
|             if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) | ||||
|                 v->hover = true; | ||||
|         } | ||||
| 
 | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -609,7 +609,7 @@ private: | |||
| #endif // ENABLE_RENDER_SELECTION_CENTER
 | ||||
|     void _render_warning_texture() const; | ||||
|     void _render_legend_texture() const; | ||||
|     void _render_volumes(bool fake_colors) const; | ||||
|     void _render_volumes_for_picking() const; | ||||
|     void _render_current_gizmo() const; | ||||
|     void _render_gizmos_overlay() const; | ||||
|     void _render_toolbar() const; | ||||
|  |  | |||
|  | @ -21,6 +21,8 @@ wxDEFINE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent); | |||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE_ALL, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_ARRANGE, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_COPY, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_PASTE, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_MORE, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); | ||||
|  |  | |||
|  | @ -20,6 +20,8 @@ wxDECLARE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent); | |||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_DELETE_ALL, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_ARRANGE, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_COPY, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_PASTE, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_MORE, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_SPLIT_OBJECTS, SimpleEvent); | ||||
|  |  | |||
|  | @ -439,6 +439,66 @@ void ObjectList::selection_changed() | |||
|     part_selection_changed(); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes) | ||||
| { | ||||
|     if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx)) | ||||
|         return; | ||||
| 
 | ||||
|     if (volumes.empty()) | ||||
|         return; | ||||
| 
 | ||||
|     ModelObject& model_object = *(*m_objects)[obj_idx]; | ||||
|     const auto object_item = m_objects_model->GetItemById(obj_idx); | ||||
| 
 | ||||
|     wxDataViewItemArray items; | ||||
| 
 | ||||
|     for (const ModelVolume* volume : volumes) | ||||
|     { | ||||
|         auto vol_item = m_objects_model->AddVolumeChild(object_item, volume->name, volume->type(), | ||||
|             volume->config.has("extruder") ? volume->config.option<ConfigOptionInt>("extruder")->value : 0); | ||||
|         auto opt_keys = volume->config.keys(); | ||||
|         if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder"))) | ||||
|             select_item(m_objects_model->AddSettingsChild(vol_item)); | ||||
| 
 | ||||
|         items.Add(vol_item); | ||||
|     } | ||||
| 
 | ||||
|     m_parts_changed = true; | ||||
|     parts_changed(obj_idx); | ||||
| 
 | ||||
|     if (items.size() > 1) | ||||
|     { | ||||
|         m_selection_mode = smVolume; | ||||
|         m_last_selected_item = wxDataViewItem(0); | ||||
|     } | ||||
| 
 | ||||
|     select_items(items); | ||||
| #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
 | ||||
|     selection_changed(); | ||||
| #endif //no __WXOSX__ //__WXMSW__
 | ||||
| } | ||||
| 
 | ||||
| void ObjectList::paste_objects_into_list(const std::vector<size_t>& object_idxs) | ||||
| { | ||||
|     if (object_idxs.empty()) | ||||
|         return; | ||||
| 
 | ||||
|     wxDataViewItemArray items; | ||||
|     for (const size_t object : object_idxs) | ||||
|     { | ||||
|         add_object_to_list(object); | ||||
|         m_parts_changed = true; | ||||
|         parts_changed(object); | ||||
| 
 | ||||
|         items.Add(m_objects_model->GetItemById(object)); | ||||
|     } | ||||
| 
 | ||||
|     select_items(items); | ||||
| #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
 | ||||
|     selection_changed(); | ||||
| #endif //no __WXOSX__ //__WXMSW__
 | ||||
| } | ||||
| 
 | ||||
| void ObjectList::OnChar(wxKeyEvent& event) | ||||
| { | ||||
|     if (event.GetKeyCode() == WXK_BACK){ | ||||
|  | @ -1576,11 +1636,11 @@ void ObjectList::split() | |||
| 
 | ||||
|     for (auto id = 0; id < model_object->volumes.size(); id++) { | ||||
|         const auto vol_item = m_objects_model->AddVolumeChild(parent, from_u8(model_object->volumes[id]->name), | ||||
|                                             model_object->volumes[id]->is_modifier() ?  | ||||
|                                                 ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, | ||||
|                                             model_object->volumes[id]->config.has("extruder") ? | ||||
|                                                 model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0, | ||||
|                                             false); | ||||
|             model_object->volumes[id]->is_modifier() ? | ||||
|             ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART, | ||||
|             model_object->volumes[id]->config.has("extruder") ? | ||||
|             model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0, | ||||
|             false); | ||||
|         // add settings to the part, if it has those
 | ||||
|         auto opt_keys = model_object->volumes[id]->config.keys(); | ||||
|         if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { | ||||
|  | @ -2135,6 +2195,7 @@ void ObjectList::update_selections_on_canvas() | |||
|         add_to_selection(item, selection, instance_idx, false); | ||||
| 
 | ||||
|     wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); | ||||
|     wxGetApp().plater()->canvas3D()->render(); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::select_item(const wxDataViewItem& item) | ||||
|  |  | |||
|  | @ -31,6 +31,8 @@ typedef std::map<std::string, std::vector<std::string>> FreqSettingsBundle; | |||
| //				  category ->		vector 			 ( option	;  label )
 | ||||
| typedef std::map< std::string, std::vector< std::pair<std::string, std::string> > > settings_menu_hierarchy; | ||||
| 
 | ||||
| typedef std::vector<ModelVolume*> ModelVolumePtrs; | ||||
| 
 | ||||
| namespace GUI { | ||||
| 
 | ||||
| wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent); | ||||
|  | @ -285,6 +287,10 @@ public: | |||
|     void rename_item(); | ||||
|     void fix_through_netfabb() const; | ||||
|     void update_item_error_icon(const int obj_idx, int vol_idx) const ; | ||||
| 
 | ||||
|     void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes); | ||||
|     void paste_objects_into_list(const std::vector<size_t>& object_idxs); | ||||
| 
 | ||||
| private: | ||||
|     void OnChar(wxKeyEvent& event); | ||||
|     void OnContextMenu(wxDataViewEvent &event); | ||||
|  |  | |||
|  | @ -375,13 +375,22 @@ void MainFrame::init_menubar() | |||
|             [this](wxCommandEvent&) { m_plater->select_all(); }, ""); | ||||
|         editMenu->AppendSeparator(); | ||||
|         wxMenuItem* item_delete_sel = append_menu_item(editMenu, wxID_ANY, _(L("&Delete selected")) + sep + hotkey_delete, _(L("Deletes the current selection")), | ||||
|             [this](wxCommandEvent&) { m_plater->remove_selected(); }, ""); | ||||
|             [this](wxCommandEvent&) { m_plater->remove_selected(); }, "remove_menu"); | ||||
|         wxMenuItem* item_delete_all = append_menu_item(editMenu, wxID_ANY, _(L("Delete &all")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + hotkey_delete, _(L("Deletes all objects")), | ||||
|             [this](wxCommandEvent&) { m_plater->reset(); }, ""); | ||||
|             [this](wxCommandEvent&) { m_plater->reset(); }, "delete_all_menu"); | ||||
| 
 | ||||
|         editMenu->AppendSeparator(); | ||||
| 
 | ||||
|         wxMenuItem* item_copy = append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + "\tCtrl+C", _(L("Copy selection to clipboard")), | ||||
|             [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); }, "copy_menu"); | ||||
|         wxMenuItem* item_paste = append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + "\tCtrl+V", _(L("Paste clipboard")), | ||||
|             [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, "paste_menu"); | ||||
| 
 | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_select()); }, item_select_all->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete()); }, item_delete_sel->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete_all()); }, item_delete_all->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater->can_copy()); }, item_copy->GetId()); | ||||
|         Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_plater->can_paste()); }, item_paste->GetId()); | ||||
|     } | ||||
| 
 | ||||
|     // Window menu
 | ||||
|  |  | |||
|  | @ -1405,6 +1405,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) | |||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); }); | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE_ALL, [this](SimpleEvent&) { reset(); }); | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_ARRANGE, [this](SimpleEvent&) { arrange(); }); | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_COPY, [q](SimpleEvent&) { q->copy_selection_to_clipboard(); }); | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_PASTE, [q](SimpleEvent&) { q->paste_from_clipboard(); }); | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_MORE, [q](SimpleEvent&) { q->increase_instances(); }); | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_FEWER, [q](SimpleEvent&) { q->decrease_instances(); }); | ||||
|     view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this); | ||||
|  | @ -3699,6 +3701,34 @@ void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) | |||
| 
 | ||||
| void Plater::update_object_menu() { p->update_object_menu(); } | ||||
| 
 | ||||
| void Plater::copy_selection_to_clipboard() | ||||
| { | ||||
|     p->view3D->get_canvas3d()->get_selection().copy_to_clipboard(); | ||||
| } | ||||
| 
 | ||||
| void Plater::paste_from_clipboard() | ||||
| { | ||||
|     p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); | ||||
| } | ||||
| 
 | ||||
| bool Plater::can_paste_from_clipboard() const | ||||
| { | ||||
|     const Selection& selection = p->view3D->get_canvas3d()->get_selection(); | ||||
|     const Selection::Clipboard& clipboard = selection.get_clipboard(); | ||||
|     Selection::EMode mode = clipboard.get_mode(); | ||||
| 
 | ||||
|     if (clipboard.is_empty()) | ||||
|         return false; | ||||
| 
 | ||||
|     if ((mode == Selection::Volume) && !selection.is_from_single_instance()) | ||||
|         return false; | ||||
| 
 | ||||
|     if ((mode == Selection::Instance) && (selection.get_mode() != Selection::Instance)) | ||||
|         return false; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool Plater::can_delete() const { return p->can_delete(); } | ||||
| bool Plater::can_delete_all() const { return p->can_delete_all(); } | ||||
| bool Plater::can_increase_instances() const { return p->can_increase_instances(); } | ||||
|  | @ -3707,5 +3737,7 @@ bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); } | |||
| bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); } | ||||
| bool Plater::can_arrange() const { return p->can_arrange(); } | ||||
| bool Plater::can_layers_editing() const { return p->can_layers_editing(); } | ||||
| bool Plater::can_copy() const { return !is_selection_empty(); } | ||||
| bool Plater::can_paste() const { return can_paste_from_clipboard(); } | ||||
| 
 | ||||
| }}    // namespace Slic3r::GUI
 | ||||
|  |  | |||
|  | @ -182,6 +182,10 @@ public: | |||
|     PrinterTechnology   printer_technology() const; | ||||
|     void                set_printer_technology(PrinterTechnology printer_technology); | ||||
| 
 | ||||
|     void copy_selection_to_clipboard(); | ||||
|     void paste_from_clipboard(); | ||||
|     bool can_paste_from_clipboard() const; | ||||
| 
 | ||||
|     bool can_delete() const; | ||||
|     bool can_delete_all() const; | ||||
|     bool can_increase_instances() const; | ||||
|  | @ -190,6 +194,8 @@ public: | |||
|     bool can_split_to_volumes() const; | ||||
|     bool can_arrange() const; | ||||
|     bool can_layers_editing() const; | ||||
|     bool can_copy() const; | ||||
|     bool can_paste() const; | ||||
| 
 | ||||
| private: | ||||
|     struct priv; | ||||
|  |  | |||
|  | @ -1022,6 +1022,70 @@ bool Selection::requires_local_axes() const | |||
|     return (m_mode == Volume) && is_from_single_instance(); | ||||
| } | ||||
| 
 | ||||
| void Selection::copy_to_clipboard() | ||||
| { | ||||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     m_clipboard.reset(); | ||||
| 
 | ||||
|     for (const ObjectIdxsToInstanceIdxsMap::value_type& object : m_cache.content) | ||||
|     { | ||||
|         ModelObject* src_object = m_model->objects[object.first]; | ||||
|         ModelObject* dst_object = m_clipboard.add_object(); | ||||
|         dst_object->name = src_object->name; | ||||
|         dst_object->input_file = src_object->input_file; | ||||
|         dst_object->config = src_object->config; | ||||
| 
 | ||||
|         for (int i : object.second) | ||||
|         { | ||||
|             dst_object->add_instance(*src_object->instances[i]); | ||||
|         } | ||||
| 
 | ||||
|         for (unsigned int i : m_list) | ||||
|         { | ||||
|             const GLVolume* volume = (*m_volumes)[i]; | ||||
|             if ((volume->object_idx() == object.first) && (volume->instance_idx() == *object.second.begin())) | ||||
|             { | ||||
|                 int volume_idx = volume->volume_idx(); | ||||
|                 if ((0 <= volume_idx) && (volume_idx < (int)src_object->volumes.size())) | ||||
|                 { | ||||
|                     ModelVolume* src_volume = src_object->volumes[volume_idx]; | ||||
|                     ModelVolume* dst_volume = dst_object->add_volume(*src_volume); | ||||
|                     dst_volume->set_new_unique_id(); | ||||
|                     dst_volume->config = src_volume->config; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     m_clipboard.set_mode(m_mode); | ||||
| } | ||||
| 
 | ||||
| void Selection::paste_from_clipboard() | ||||
| { | ||||
|     if (!m_valid || m_clipboard.is_empty()) | ||||
|         return; | ||||
| 
 | ||||
|     switch (m_clipboard.get_mode()) | ||||
|     { | ||||
|     case Volume: | ||||
|     { | ||||
|         if (is_from_single_instance()) | ||||
|             paste_volumes_from_clipboard(); | ||||
| 
 | ||||
|         break; | ||||
|     } | ||||
|     case Instance: | ||||
|     { | ||||
|         if (m_mode == Instance) | ||||
|             paste_objects_from_clipboard(); | ||||
| 
 | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::update_valid() | ||||
| { | ||||
|     m_valid = (m_volumes != nullptr) && (m_model != nullptr); | ||||
|  | @ -1697,5 +1761,43 @@ bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const | |||
|     return count == (unsigned int)m_model->objects[object_idx]->volumes.size(); | ||||
| } | ||||
| 
 | ||||
| void Selection::paste_volumes_from_clipboard() | ||||
| { | ||||
|     int obj_idx = get_object_idx(); | ||||
|     if ((obj_idx < 0) || ((int)m_model->objects.size() <= obj_idx)) | ||||
|         return; | ||||
| 
 | ||||
|     ModelObject* src_object = m_clipboard.get_object(0); | ||||
|     if (src_object != nullptr) | ||||
|     { | ||||
|         ModelObject* dst_object = m_model->objects[obj_idx]; | ||||
| 
 | ||||
|         ModelVolumePtrs volumes; | ||||
|         for (ModelVolume* src_volume : src_object->volumes) | ||||
|         { | ||||
|             ModelVolume* dst_volume = dst_object->add_volume(*src_volume); | ||||
|             dst_volume->config = src_volume->config; | ||||
|             dst_volume->set_new_unique_id(); | ||||
|             dst_volume->translate(10.0, 10.0, 0.0); | ||||
|             volumes.push_back(dst_volume); | ||||
|         } | ||||
|         wxGetApp().obj_list()->paste_volumes_into_list(obj_idx, volumes); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::paste_objects_from_clipboard() | ||||
| { | ||||
|     std::vector<size_t> object_idxs; | ||||
|     const ModelObjectPtrs& src_objects = m_clipboard.get_objects(); | ||||
|     for (const ModelObject* src_object : src_objects) | ||||
|     { | ||||
|         ModelObject* dst_object = m_model->add_object(*src_object); | ||||
|         dst_object->translate(10.0, 10.0, 0.0); | ||||
|         object_idxs.push_back(m_model->objects.size() - 1); | ||||
|     } | ||||
| 
 | ||||
|     wxGetApp().obj_list()->paste_objects_into_list(object_idxs); | ||||
| } | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
|  | @ -138,6 +138,23 @@ public: | |||
|     typedef std::set<int> InstanceIdxsList; | ||||
|     typedef std::map<int, InstanceIdxsList> ObjectIdxsToInstanceIdxsMap; | ||||
| 
 | ||||
|     class Clipboard | ||||
|     { | ||||
|         Model m_model; | ||||
|         Selection::EMode m_mode; | ||||
| 
 | ||||
|     public: | ||||
|         void reset() { m_model.clear_objects(); } | ||||
|         bool is_empty() const { return m_model.objects.empty(); } | ||||
| 
 | ||||
|         ModelObject* add_object() { return m_model.add_object(); } | ||||
|         ModelObject* get_object(unsigned int id) { return (id < (unsigned int)m_model.objects.size()) ? m_model.objects[id] : nullptr; } | ||||
|         const ModelObjectPtrs& get_objects() const { return m_model.objects; } | ||||
| 
 | ||||
|         Selection::EMode get_mode() const { return m_mode; } | ||||
|         void set_mode(Selection::EMode mode) { m_mode = mode; } | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     struct Cache | ||||
|     { | ||||
|  | @ -163,6 +180,7 @@ private: | |||
|     // set of indices to m_volumes
 | ||||
|     IndicesList m_list; | ||||
|     Cache m_cache; | ||||
|     Clipboard m_clipboard; | ||||
|     mutable BoundingBoxf3 m_bounding_box; | ||||
|     mutable bool m_bounding_box_dirty; | ||||
| 
 | ||||
|  | @ -267,6 +285,11 @@ public: | |||
| 
 | ||||
|     bool requires_local_axes() const; | ||||
| 
 | ||||
|     void copy_to_clipboard(); | ||||
|     void paste_from_clipboard(); | ||||
| 
 | ||||
|     const Clipboard& get_clipboard() const { return m_clipboard; } | ||||
| 
 | ||||
| private: | ||||
|     void update_valid(); | ||||
|     void update_type(); | ||||
|  | @ -301,6 +324,9 @@ private: | |||
|     void synchronize_unselected_volumes(); | ||||
|     void ensure_on_bed(); | ||||
|     bool is_from_fully_selected_instance(unsigned int volume_idx) const; | ||||
| 
 | ||||
|     void paste_volumes_from_clipboard(); | ||||
|     void paste_objects_from_clipboard(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
|  |  | |||
|  | @ -529,10 +529,10 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name, const int ext | |||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &parent_item, | ||||
| 													const wxString &name, | ||||
|                                                     const Slic3r::ModelVolumeType volume_type, | ||||
|                                                     const int extruder/* = 0*/, | ||||
|                                                     const bool create_frst_child/* = true*/) | ||||
|     const wxString &name, | ||||
|     const Slic3r::ModelVolumeType volume_type, | ||||
|     const int extruder/* = 0*/, | ||||
|     const bool create_frst_child/* = true*/) | ||||
| { | ||||
| 	PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID(); | ||||
| 	if (!root) return wxDataViewItem(0); | ||||
|  | @ -545,7 +545,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &pa | |||
|         insert_position = -1; | ||||
| 
 | ||||
|     if (create_frst_child && root->m_volumes_cnt == 0) | ||||
| 	{ | ||||
|     { | ||||
| 		const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, *m_volume_bmps[0], extruder_str, 0); | ||||
|         insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position); | ||||
| 		// notify control
 | ||||
|  |  | |||
|  | @ -454,12 +454,12 @@ public: | |||
|     ~PrusaObjectDataViewModel(); | ||||
| 
 | ||||
| 	wxDataViewItem Add(const wxString &name, const int extruder); | ||||
| 	wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item,  | ||||
| 							const wxString &name,  | ||||
|                             const Slic3r::ModelVolumeType volume_type, | ||||
|                             const int extruder = 0, | ||||
|                             const bool create_frst_child = true); | ||||
| 	wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); | ||||
|     wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item, | ||||
|         const wxString &name, | ||||
|         const Slic3r::ModelVolumeType volume_type, | ||||
|         const int extruder = 0, | ||||
|         const bool create_frst_child = true); | ||||
|     wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); | ||||
|     wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); | ||||
| 	wxDataViewItem Delete(const wxDataViewItem &item); | ||||
| 	wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv