mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge branch 'dev_native' into vb_dev_native_background_processing
This commit is contained in:
		
						commit
						857863102d
					
				
					 43 changed files with 1628 additions and 1085 deletions
				
			
		|  | @ -196,13 +196,8 @@ const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f }; | |||
| 
 | ||||
| GLVolume::GLVolume(float r, float g, float b, float a) | ||||
|     : m_offset(Vec3d::Zero()) | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     , m_rotation(Vec3d::Zero()) | ||||
|     , m_scaling_factor(Vec3d::Ones()) | ||||
| #else | ||||
|     , m_rotation(0.0) | ||||
|     , m_scaling_factor(1.0) | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|     , m_world_matrix(Transform3f::Identity()) | ||||
|     , m_world_matrix_dirty(true) | ||||
|     , m_transformed_bounding_box_dirty(true) | ||||
|  | @ -262,7 +257,6 @@ void GLVolume::set_render_color() | |||
|         set_render_color(color, 4); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| const Vec3d& GLVolume::get_rotation() const | ||||
| { | ||||
|     return m_rotation; | ||||
|  | @ -295,23 +289,6 @@ void GLVolume::set_rotation(const Vec3d& rotation) | |||
|         m_transformed_convex_hull_bounding_box_dirty = true; | ||||
|     } | ||||
| } | ||||
| #else | ||||
| double GLVolume::get_rotation() const | ||||
| { | ||||
|     return m_rotation; | ||||
| } | ||||
| 
 | ||||
| void GLVolume::set_rotation(double rotation) | ||||
| { | ||||
|     if (m_rotation != rotation) | ||||
|     { | ||||
|         m_rotation = rotation; | ||||
|         m_world_matrix_dirty = true; | ||||
|         m_transformed_bounding_box_dirty = true; | ||||
|         m_transformed_convex_hull_bounding_box_dirty = true; | ||||
|     } | ||||
| } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| const Vec3d& GLVolume::get_offset() const | ||||
| { | ||||
|  | @ -329,7 +306,6 @@ void GLVolume::set_offset(const Vec3d& offset) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| const Vec3d& GLVolume::get_scaling_factor() const | ||||
| { | ||||
|  | @ -347,18 +323,6 @@ void GLVolume::set_scaling_factor(const Vec3d& scaling_factor) | |||
|         m_transformed_convex_hull_bounding_box_dirty = true; | ||||
|     } | ||||
| } | ||||
| #else | ||||
| void GLVolume::set_scaling_factor(double factor) | ||||
| { | ||||
|     if (m_scaling_factor != factor) | ||||
|     { | ||||
|         m_scaling_factor = factor; | ||||
|         m_world_matrix_dirty = true; | ||||
|         m_transformed_bounding_box_dirty = true; | ||||
|         m_transformed_convex_hull_bounding_box_dirty = true; | ||||
|     } | ||||
| } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| void GLVolume::set_convex_hull(const TriangleMesh& convex_hull) | ||||
| { | ||||
|  | @ -389,14 +353,7 @@ const Transform3f& GLVolume::world_matrix() const | |||
| { | ||||
|     if (m_world_matrix_dirty) | ||||
|     { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|         m_world_matrix = Geometry::assemble_transform(m_offset, m_rotation, m_scaling_factor).cast<float>(); | ||||
| #else | ||||
|         m_world_matrix = Transform3f::Identity(); | ||||
|         m_world_matrix.translate(m_offset.cast<float>()); | ||||
|         m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation, Vec3f::UnitZ())); | ||||
|         m_world_matrix.scale((float)m_scaling_factor); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|         m_world_matrix_dirty = false; | ||||
|     } | ||||
|     return m_world_matrix; | ||||
|  | @ -471,13 +428,7 @@ void GLVolume::render() const | |||
|     ::glCullFace(GL_BACK); | ||||
|     ::glPushMatrix(); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     ::glMultMatrixf(world_matrix().data()); | ||||
| #else | ||||
|     ::glTranslated(m_offset(0), m_offset(1), m_offset(2)); | ||||
|     ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); | ||||
|     ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|     if (this->indexed_vertex_array.indexed()) | ||||
|         this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); | ||||
|     else | ||||
|  | @ -602,13 +553,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c | |||
| 
 | ||||
|     ::glPushMatrix(); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     ::glMultMatrixf(world_matrix().data()); | ||||
| #else | ||||
|     ::glTranslated(m_offset(0), m_offset(1), m_offset(2)); | ||||
|     ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); | ||||
|     ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|     if (n_triangles > 0) | ||||
|     { | ||||
|  | @ -652,13 +597,7 @@ void GLVolume::render_legacy() const | |||
| 
 | ||||
|     ::glPushMatrix(); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     ::glMultMatrixf(world_matrix().data()); | ||||
| #else | ||||
|     ::glTranslated(m_offset(0), m_offset(1), m_offset(2)); | ||||
|     ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); | ||||
|     ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|     if (n_triangles > 0) | ||||
|         ::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, indexed_vertex_array.triangle_indices.data() + tverts_range.first); | ||||
|  | @ -787,15 +726,9 @@ std::vector<int> GLVolumeCollection::load_object( | |||
|             } | ||||
|             v.is_modifier = ! model_volume->is_model_part(); | ||||
|             v.shader_outside_printer_detection_enabled = model_volume->is_model_part(); | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|             v.set_offset(instance->get_offset()); | ||||
|             v.set_rotation(instance->get_rotation()); | ||||
|             v.set_scaling_factor(instance->get_scaling_factor()); | ||||
| #else | ||||
|             v.set_offset(Vec3d(instance->offset(0), instance->offset(1), 0.0)); | ||||
|             v.set_rotation(instance->rotation); | ||||
|             v.set_scaling_factor(instance->scaling_factor); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  |  | |||
|  | @ -256,17 +256,10 @@ public: | |||
| private: | ||||
|     // Offset of the volume to be rendered.
 | ||||
|     Vec3d                 m_offset; | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     // Rotation around three axes of the volume to be rendered.
 | ||||
|     Vec3d                 m_rotation; | ||||
|     // Scale factor along the three axes of the volume to be rendered.
 | ||||
|     Vec3d                 m_scaling_factor; | ||||
| #else | ||||
|     // Rotation around Z axis of the volume to be rendered.
 | ||||
|     double                m_rotation; | ||||
|     // Scale factor of the volume to be rendered.
 | ||||
|     double                m_scaling_factor; | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|     // World matrix of the volume to be rendered.
 | ||||
|     mutable Transform3f   m_world_matrix; | ||||
|     // Whether or not is needed to recalculate the world matrix.
 | ||||
|  | @ -336,7 +329,6 @@ public: | |||
|     // Sets render color in dependence of current state
 | ||||
|     void set_render_color(); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     const Vec3d& get_rotation() const; | ||||
|     void set_rotation(const Vec3d& rotation); | ||||
| 
 | ||||
|  | @ -344,12 +336,6 @@ public: | |||
|     const Vec3d& get_scaling_factor() const; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     void set_scaling_factor(const Vec3d& scaling_factor); | ||||
| #else | ||||
|     double get_rotation() const; | ||||
|     void set_rotation(double rotation); | ||||
| 
 | ||||
|     void set_scaling_factor(double factor); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|     const Vec3d& get_offset() const; | ||||
|     void set_offset(const Vec3d& offset); | ||||
|  |  | |||
|  | @ -610,8 +610,13 @@ void ColourPicker::BUILD() | |||
| 	if (m_opt.height >= 0) size.SetHeight(m_opt.height); | ||||
| 	if (m_opt.width >= 0) size.SetWidth(m_opt.width); | ||||
| 
 | ||||
| 	wxString clr(static_cast<const ConfigOptionStrings*>(m_opt.default_value)->get_at(m_opt_idx)); | ||||
| 	// FIXME: verify clr is valid, otherwise this causes an assert
 | ||||
| 	// Validate the color
 | ||||
| 	wxString clr_str(static_cast<const ConfigOptionStrings*>(m_opt.default_value)->get_at(m_opt_idx)); | ||||
| 	wxColour clr(clr_str); | ||||
| 	if (! clr.IsOk()) { | ||||
| 		clr = wxTransparentColour; | ||||
| 	} | ||||
| 
 | ||||
| 	auto temp = new wxColourPickerCtrl(m_parent, wxID_ANY, clr, wxDefaultPosition, size); | ||||
| 
 | ||||
| 	// 	// recast as a wxWindow to fit the calling convention
 | ||||
|  | @ -619,7 +624,7 @@ void ColourPicker::BUILD() | |||
| 
 | ||||
| 	temp->Bind(wxEVT_COLOURPICKER_CHANGED, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); | ||||
| 
 | ||||
| 	temp->SetToolTip(get_tooltip_text(clr)); | ||||
| 	temp->SetToolTip(get_tooltip_text(clr_str)); | ||||
| } | ||||
| 
 | ||||
| boost::any& ColourPicker::get_value(){ | ||||
|  |  | |||
|  | @ -1346,7 +1346,7 @@ bool GLCanvas3D::Selection::is_single_full_instance() const | |||
|     int object_idx = m_valid ? get_object_idx() : -1; | ||||
|     if (object_idx != -1) | ||||
|     { | ||||
|         if (get_instance_idx() != -1) | ||||
|         if ((object_idx != -1) && (object_idx < 1000)) | ||||
|             return m_model->objects[object_idx]->volumes.size() == m_list.size(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1653,7 +1653,7 @@ void GLCanvas3D::Selection::_calc_bounding_box() const | |||
|     { | ||||
|         for (unsigned int i : m_list) | ||||
|         { | ||||
|             m_bounding_box.merge((*m_volumes)[i]->transformed_bounding_box()); | ||||
|             m_bounding_box.merge((*m_volumes)[i]->transformed_convex_hull_bounding_box()); | ||||
|         } | ||||
|     } | ||||
|     m_bounding_box_dirty = false; | ||||
|  | @ -1702,7 +1702,7 @@ void GLCanvas3D::Selection::_render_unselected_instances() const | |||
|             if (it == boxes.end()) | ||||
|                 it = boxes.insert(InstanceToBoxMap::value_type(box_id, BoundingBoxf3())).first; | ||||
| 
 | ||||
|             it->second.merge(v->transformed_bounding_box()); | ||||
|             it->second.merge(v->transformed_convex_hull_bounding_box()); | ||||
| 
 | ||||
|             done.insert(j); | ||||
|         } | ||||
|  | @ -1830,11 +1830,6 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent) | |||
|     if (!gizmo->init()) | ||||
|         return false; | ||||
| 
 | ||||
| #if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     // temporary disable z grabber
 | ||||
|     gizmo->disable_grabber(2); | ||||
| #endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|     m_gizmos.insert(GizmosMap::value_type(Move, gizmo)); | ||||
| 
 | ||||
|     gizmo = new GLGizmoScale3D(parent); | ||||
|  | @ -1844,18 +1839,6 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent) | |||
|     if (!gizmo->init()) | ||||
|         return false; | ||||
| 
 | ||||
| #if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     // temporary disable x grabbers
 | ||||
|     gizmo->disable_grabber(0); | ||||
|     gizmo->disable_grabber(1); | ||||
|     // temporary disable y grabbers
 | ||||
|     gizmo->disable_grabber(2); | ||||
|     gizmo->disable_grabber(3); | ||||
|     // temporary disable z grabbers
 | ||||
|     gizmo->disable_grabber(4); | ||||
|     gizmo->disable_grabber(5); | ||||
| #endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|     m_gizmos.insert(GizmosMap::value_type(Scale, gizmo)); | ||||
| 
 | ||||
|     gizmo = new GLGizmoRotate3D(parent); | ||||
|  | @ -1871,12 +1854,6 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent) | |||
|         return false; | ||||
|     } | ||||
| 
 | ||||
| #if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     // temporary disable x and y grabbers
 | ||||
|     gizmo->disable_grabber(0); | ||||
|     gizmo->disable_grabber(1); | ||||
| #endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|     m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo)); | ||||
| 
 | ||||
|     gizmo = new GLGizmoFlatten(parent); | ||||
|  | @ -1916,7 +1893,7 @@ void GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Vec2 | |||
|     float cnv_h = (float)canvas.get_canvas_size().get_height(); | ||||
|     float height = _get_total_overlay_height(); | ||||
|     float top_y = 0.5f * (cnv_h - height); | ||||
|     for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) | ||||
|     for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) | ||||
|     { | ||||
|         if (it->second == nullptr) | ||||
|             continue; | ||||
|  | @ -1926,8 +1903,7 @@ void GLCanvas3D::Gizmos::update_hover_state(const GLCanvas3D& canvas, const Vec2 | |||
| 
 | ||||
|         // we currently use circular icons for gizmo, so we check the radius
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         bool no_wipe_tower = selection.is_wipe_tower() && !it->second->get_accept_wipe_tower(); | ||||
|         if (!no_wipe_tower && (it->second->get_state() != GLGizmoBase::On)) | ||||
|         if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On)) | ||||
| #else | ||||
|         if (it->second->get_state() != GLGizmoBase::On) | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|  | @ -1951,7 +1927,7 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec | |||
|     float cnv_h = (float)canvas.get_canvas_size().get_height(); | ||||
|     float height = _get_total_overlay_height(); | ||||
|     float top_y = 0.5f * (cnv_h - height); | ||||
|     for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) | ||||
|     for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) | ||||
|     { | ||||
|         if (it->second == nullptr) | ||||
|             continue; | ||||
|  | @ -1961,18 +1937,17 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec | |||
| 
 | ||||
|         // we currently use circular icons for gizmo, so we check the radius
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         bool no_wipe_tower = selection.is_wipe_tower() && !it->second->get_accept_wipe_tower(); | ||||
|         if (!no_wipe_tower && ((mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size)) | ||||
|         if (it->second->is_activable(selection) && ((mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size)) | ||||
| #else | ||||
|         if ((mouse_pos - Vec2d(OverlayOffsetX + half_tex_size, top_y + half_tex_size)).norm() < half_tex_size) | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|         { | ||||
|             if ((it->second->get_state() == GLGizmoBase::On)) | ||||
|             { | ||||
|                 it->second->set_state(GLGizmoBase::Off); | ||||
|                 it->second->set_state(GLGizmoBase::Hover); | ||||
|                 m_current = Undefined; | ||||
|             } | ||||
|             else | ||||
|             else if ((it->second->get_state() == GLGizmoBase::Hover)) | ||||
|             { | ||||
|                 it->second->set_state(GLGizmoBase::On); | ||||
|                 m_current = it->first; | ||||
|  | @ -1983,8 +1958,27 @@ void GLCanvas3D::Gizmos::update_on_off_state(const GLCanvas3D& canvas, const Vec | |||
| 
 | ||||
|         top_y += (tex_size + OverlayGapY); | ||||
|     } | ||||
| 
 | ||||
|     GizmosMap::iterator it = m_gizmos.find(m_current); | ||||
|     if ((it != m_gizmos.end()) && (it->second != nullptr) && (it->second->get_state() != GLGizmoBase::On)) | ||||
|         it->second->set_state(GLGizmoBase::On); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| void GLCanvas3D::Gizmos::update_on_off_state(const Selection& selection) | ||||
| { | ||||
|     GizmosMap::iterator it = m_gizmos.find(m_current); | ||||
|     if ((it != m_gizmos.end()) && (it->second != nullptr)) | ||||
|     { | ||||
|         if (!it->second->is_activable(selection)) | ||||
|         { | ||||
|             it->second->set_state(GLGizmoBase::Off); | ||||
|             m_current = Undefined; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| void GLCanvas3D::Gizmos::reset_all_states() | ||||
| { | ||||
|     if (!m_enabled) | ||||
|  | @ -2104,6 +2098,9 @@ bool GLCanvas3D::Gizmos::is_running() const | |||
| 
 | ||||
| bool GLCanvas3D::Gizmos::is_dragging() const | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return false; | ||||
| 
 | ||||
|     GLGizmoBase* curr = _get_current(); | ||||
|     return (curr != nullptr) ? curr->is_dragging() : false; | ||||
| } | ||||
|  | @ -2111,6 +2108,9 @@ bool GLCanvas3D::Gizmos::is_dragging() const | |||
| #if ENABLE_EXTENDED_SELECTION | ||||
| void GLCanvas3D::Gizmos::start_dragging(const GLCanvas3D::Selection& selection) | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return; | ||||
| 
 | ||||
|     GLGizmoBase* curr = _get_current(); | ||||
|     if (curr != nullptr) | ||||
|         curr->start_dragging(selection); | ||||
|  | @ -2118,6 +2118,9 @@ void GLCanvas3D::Gizmos::start_dragging(const GLCanvas3D::Selection& selection) | |||
| #else | ||||
| void GLCanvas3D::Gizmos::start_dragging(const BoundingBoxf3& box) | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return; | ||||
| 
 | ||||
|     GLGizmoBase* curr = _get_current(); | ||||
|     if (curr != nullptr) | ||||
|         curr->start_dragging(box); | ||||
|  | @ -2126,6 +2129,9 @@ void GLCanvas3D::Gizmos::start_dragging(const BoundingBoxf3& box) | |||
| 
 | ||||
| void GLCanvas3D::Gizmos::stop_dragging() | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return; | ||||
| 
 | ||||
|     GLGizmoBase* curr = _get_current(); | ||||
|     if (curr != nullptr) | ||||
|         curr->stop_dragging(); | ||||
|  | @ -2161,7 +2167,6 @@ void GLCanvas3D::Gizmos::set_position(const Vec3d& position) | |||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| Vec3d GLCanvas3D::Gizmos::get_scale() const | ||||
| { | ||||
|     if (!m_enabled) | ||||
|  | @ -2208,54 +2213,6 @@ Vec3d GLCanvas3D::Gizmos::get_flattening_rotation() const | |||
|     GizmosMap::const_iterator it = m_gizmos.find(Flatten); | ||||
|     return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_rotation() : Vec3d::Zero(); | ||||
| } | ||||
| #else | ||||
| float GLCanvas3D::Gizmos::get_scale() const | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return 1.0f; | ||||
| 
 | ||||
|     GizmosMap::const_iterator it = m_gizmos.find(Scale); | ||||
|     return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoScale3D*>(it->second)->get_scale_x() : 1.0f; | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::Gizmos::set_scale(float scale) | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return; | ||||
| 
 | ||||
|     GizmosMap::const_iterator it = m_gizmos.find(Scale); | ||||
|     if (it != m_gizmos.end()) | ||||
|         reinterpret_cast<GLGizmoScale3D*>(it->second)->set_scale(scale); | ||||
| } | ||||
| 
 | ||||
| float GLCanvas3D::Gizmos::get_angle_z() const | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return 0.0f; | ||||
| 
 | ||||
|     GizmosMap::const_iterator it = m_gizmos.find(Rotate); | ||||
|     return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoRotate3D*>(it->second)->get_angle_z() : 0.0f; | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::Gizmos::set_angle_z(float angle_z) | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return; | ||||
| 
 | ||||
|     GizmosMap::const_iterator it = m_gizmos.find(Rotate); | ||||
|     if (it != m_gizmos.end()) | ||||
|         reinterpret_cast<GLGizmoRotate3D*>(it->second)->set_angle_z(angle_z); | ||||
| } | ||||
| 
 | ||||
| Vec3d GLCanvas3D::Gizmos::get_flattening_normal() const | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return Vec3d::Zero(); | ||||
| 
 | ||||
|     GizmosMap::const_iterator it = m_gizmos.find(Flatten); | ||||
|     return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_normal() : Vec3d::Zero(); | ||||
| } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| void GLCanvas3D::Gizmos::set_flattening_data(const ModelObject* model_object) | ||||
| { | ||||
|  | @ -2704,9 +2661,15 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); | ||||
| #else | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, ObjectSelectEvent); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_DOUBLE_CLICK, SimpleEvent); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); | ||||
|  | @ -2722,8 +2685,8 @@ wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); | |||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDEFINE_EVENT(EVT_GIZMO_SCALE, Vec3dEvent); | ||||
| wxDEFINE_EVENT(EVT_GIZMO_ROTATE, Vec3dEvent); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| wxDEFINE_EVENT(EVT_GIZMO_FLATTEN, Vec3dEvent); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) | ||||
|     : m_canvas(canvas) | ||||
|  | @ -3241,7 +3204,7 @@ void GLCanvas3D::select_view(const std::string& direction) | |||
|     else if (direction == "rear") | ||||
|         dir_vec = VIEW_REAR; | ||||
| 
 | ||||
|     if ((dir_vec != nullptr) && !empty(volumes_bounding_box())) | ||||
|     if (dir_vec != nullptr) | ||||
|     { | ||||
|         m_camera.phi = dir_vec[0]; | ||||
|         m_camera.set_theta(dir_vec[1]); | ||||
|  | @ -3306,15 +3269,9 @@ void GLCanvas3D::update_gizmos_data() | |||
|             ModelInstance* model_instance = model_object->instances[0]; | ||||
|             if (model_instance != nullptr) | ||||
|             { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|                 m_gizmos.set_position(model_instance->get_offset()); | ||||
|                 m_gizmos.set_scale(model_instance->get_scaling_factor()); | ||||
|                 m_gizmos.set_rotation(model_instance->get_rotation()); | ||||
| #else | ||||
|                 m_gizmos.set_position(Vec3d(model_instance->offset(0), model_instance->offset(1), 0.0)); | ||||
|                 m_gizmos.set_scale(model_instance->scaling_factor); | ||||
|                 m_gizmos.set_angle_z(model_instance->rotation); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|                 m_gizmos.set_flattening_data(model_object); | ||||
|             } | ||||
|         } | ||||
|  | @ -3322,13 +3279,8 @@ void GLCanvas3D::update_gizmos_data() | |||
|     else | ||||
|     { | ||||
|         m_gizmos.set_position(Vec3d::Zero()); | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|         m_gizmos.set_scale(Vec3d::Ones()); | ||||
|         m_gizmos.set_rotation(Vec3d::Zero()); | ||||
| #else | ||||
|         m_gizmos.set_scale(1.0f); | ||||
|         m_gizmos.set_angle_z(0.0f); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|         m_gizmos.set_flattening_data(nullptr); | ||||
|     } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|  | @ -3489,6 +3441,9 @@ void GLCanvas3D::reload_scene(bool force) | |||
|         { | ||||
|             load_object(*m_model, obj_idx); | ||||
|         } | ||||
| 
 | ||||
|         // to update the toolbar
 | ||||
|         post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); | ||||
|     } | ||||
| 
 | ||||
|     update_gizmos_data(); | ||||
|  | @ -3846,8 +3801,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         m_mouse.position = Vec2d(-1.0, -1.0); | ||||
|         m_dirty = true; | ||||
|     } | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     else if (evt.LeftDClick() && (m_hover_volume_id != -1) && !gizmos_overlay_contains_mouse && (toolbar_contains_mouse == -1)) | ||||
|         post_event(SimpleEvent(EVT_GLCANVAS_DOUBLE_CLICK)); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     else if (evt.LeftDClick() && (toolbar_contains_mouse != -1)) | ||||
|     { | ||||
|         m_toolbar_action_running = true; | ||||
|  | @ -3862,7 +3819,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         { | ||||
|         case Gizmos::Scale: | ||||
|         { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             m_regenerate_volumes = false; | ||||
|             m_selection.scale(m_gizmos.get_scale()); | ||||
|  | @ -3870,9 +3826,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
| #else | ||||
|             post_event(Vec3dEvent(EVT_GIZMO_SCALE, m_gizmos.get_scale())); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #else | ||||
|             m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale()); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
| #else | ||||
|  | @ -3883,7 +3836,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         } | ||||
|         case Gizmos::Rotate: | ||||
|         { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             m_regenerate_volumes = false; | ||||
|             m_selection.rotate(m_gizmos.get_rotation()); | ||||
|  | @ -3891,9 +3843,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
| #else | ||||
|             post_event(Vec3dEvent(EVT_GIZMO_ROTATE, std::move(m_gizmos.get_rotation()))); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #else | ||||
|             m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
| #else | ||||
|  | @ -3969,18 +3918,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|             if (m_gizmos.get_current_type() == Gizmos::Flatten) { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|                 // Rotate the object so the normal points downward:
 | ||||
|                 post_event(Vec3dEvent(EVT_GIZMO_FLATTEN, m_gizmos.get_flattening_rotation())); | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                 m_regenerate_volumes = false; | ||||
|                 m_selection.rotate(m_gizmos.get_flattening_rotation()); | ||||
|                 _on_flatten(); | ||||
|                 wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
| #else | ||||
|                 // Rotate the object so the normal points downward:
 | ||||
|                 Vec3d normal = m_gizmos.get_flattening_normal(); | ||||
|                 if (normal(0) != 0.0 || normal(1) != 0.0 || normal(2) != 0.0) { | ||||
|                     Vec3d axis = normal(2) > 0.999 ? Vec3d::UnitX() : normal.cross(-Vec3d::UnitZ()).normalized(); | ||||
|                     float angle = acos(clamp(-1.0, 1.0, -normal(2))); | ||||
|                     m_on_gizmo_flatten_callback.call(angle, (float)axis(0), (float)axis(1), (float)axis(2)); | ||||
|                 } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|                 post_event(Vec3dEvent(EVT_GIZMO_FLATTEN, m_gizmos.get_flattening_rotation())); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|             } | ||||
| 
 | ||||
|             m_dirty = true; | ||||
|  | @ -4003,13 +3949,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|             { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                 if (m_hover_volume_id != -1) | ||||
|                 if (evt.LeftDown() && (m_hover_volume_id != -1)) | ||||
|                 { | ||||
|                     if (evt.ControlDown()) | ||||
|                         m_selection.remove(m_hover_volume_id); | ||||
|                     else | ||||
|                         m_selection.add(m_hover_volume_id, !evt.ShiftDown()); | ||||
| 
 | ||||
|                     m_gizmos.update_on_off_state(m_selection); | ||||
|                     update_gizmos_data(); | ||||
|                     wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|                     m_dirty = true; | ||||
|  | @ -4096,13 +4043,24 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|                     render(); | ||||
|                     if (m_hover_volume_id != -1) | ||||
|                     { | ||||
|                         // if right clicking on volume, propagate event through callback (shows context menu)
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                         if (m_volumes.volumes[m_hover_volume_id]->hover) | ||||
| #else | ||||
|                         if (m_volumes.volumes[volume_idx]->hover) | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|                         // if right clicking on volume, propagate event through callback (shows context menu)
 | ||||
|                         if (m_volumes.volumes[m_hover_volume_id]->hover && !m_volumes.volumes[m_hover_volume_id]->is_wipe_tower) | ||||
|                         { | ||||
|                             // forces the selection of the volume
 | ||||
|                             m_selection.add(m_hover_volume_id); | ||||
|                             m_gizmos.update_on_off_state(m_selection); | ||||
|                             update_gizmos_data(); | ||||
|                             wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|                             // forces a frame render to update the view before the context menu is shown
 | ||||
|                             render(); | ||||
|                             post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, pos.cast<double>())); | ||||
|                         } | ||||
| #else | ||||
|                         // if right clicking on volume, propagate event through callback (shows context menu)
 | ||||
|                         if (m_volumes.volumes[volume_idx]->hover) | ||||
|                             post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, pos.cast<double>())); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | @ -4215,7 +4173,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         } | ||||
|         case Gizmos::Scale: | ||||
|         { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|             // Apply new temporary scale factors
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             m_selection.scale(m_gizmos.get_scale()); | ||||
|  | @ -4228,20 +4185,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             } | ||||
|             wxGetApp().obj_manipul()->update_scale_value(scale); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #else | ||||
|             // Apply new temporary scale factor
 | ||||
|             float scale_factor = m_gizmos.get_scale(); | ||||
|             for (GLVolume* v : volumes) | ||||
|             { | ||||
|                 v->set_scaling_factor((double)scale_factor); | ||||
|             } | ||||
|             wxGetApp().obj_manipul()->update_scale_values((double)scale_factor); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|             break; | ||||
|         } | ||||
|         case Gizmos::Rotate: | ||||
|         { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|             // Apply new temporary rotations
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             m_selection.rotate(m_gizmos.get_rotation()); | ||||
|  | @ -4255,15 +4202,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             } | ||||
|             wxGetApp().obj_manipul()->update_rotation_value(rotation); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #else | ||||
|             // Apply new temporary angle_z
 | ||||
|             float angle_z = m_gizmos.get_angle_z(); | ||||
|             for (GLVolume* v : volumes) | ||||
|             { | ||||
|                 v->set_rotation((double)angle_z); | ||||
|             } | ||||
|             update_rotation_value((double)angle_z, Z); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|  | @ -4280,12 +4218,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|                 bb.merge(volume->transformed_bounding_box()); | ||||
|             } | ||||
|             const Vec3d& size = bb.size(); | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|             const Vec3d& scale = m_gizmos.get_scale(); | ||||
|             post_event(Vec3dsEvent<2>(EVT_GLCANVAS_UPDATE_GEOMETRY, {size, scale})); | ||||
| #else | ||||
|             m_on_update_geometry_info_callback.call(size(0), size(1), size(2), m_gizmos.get_scale()); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|         } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|  | @ -4428,28 +4362,20 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             } | ||||
|             case Gizmos::Scale: | ||||
|             { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                 m_regenerate_volumes = false; | ||||
|                 _on_scale(); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #else | ||||
|                 m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale()); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|                 break; | ||||
|             } | ||||
|             case Gizmos::Rotate: | ||||
|             { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                 m_regenerate_volumes = false; | ||||
|                 _on_rotate(); | ||||
| #else | ||||
|                 post_event(Vec3dEvent(EVT_GIZMO_ROTATE, m_gizmos.get_rotation())); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #else | ||||
|                 m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|                 break; | ||||
|             } | ||||
|             default: | ||||
|  | @ -4651,6 +4577,7 @@ bool GLCanvas3D::_init_toolbar() | |||
|     if (!m_toolbar.add_separator()) | ||||
|         return false; | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     item.name = "settings"; | ||||
|     item.tooltip = GUI::L_str("Settings..."); | ||||
|     item.sprite_id = 8; | ||||
|  | @ -4658,6 +4585,7 @@ bool GLCanvas3D::_init_toolbar() | |||
|     item.action_event = EVT_GLTOOLBAR_SETTINGS; | ||||
|     if (!m_toolbar.add_item(item)) | ||||
|         return false; | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     item.name = "layersediting"; | ||||
|     item.tooltip = GUI::L_str("Layers editing"); | ||||
|  | @ -5135,7 +5063,7 @@ void GLCanvas3D::_render_objects() const | |||
| void GLCanvas3D::_render_selection() const | ||||
| { | ||||
|     Gizmos::EType type = m_gizmos.get_current_type(); | ||||
|     bool show_indirect_selection = m_gizmos.is_running() && ((type == Gizmos::Rotate) || (type == Gizmos::Scale)); | ||||
|     bool show_indirect_selection = m_gizmos.is_running() && ((type == Gizmos::Rotate) || (type == Gizmos::Scale) || (type == Gizmos::Flatten)); | ||||
|     m_selection.render(show_indirect_selection); | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|  | @ -6487,11 +6415,9 @@ void GLCanvas3D::_on_move() | |||
|     std::set<std::pair<int, int>> done;  // prevent moving instances twice
 | ||||
|     bool object_moved = false; | ||||
|     Vec3d wipe_tower_origin = Vec3d::Zero(); | ||||
|     const Selection::IndicesList& selection = m_selection.get_volume_idxs(); | ||||
| 
 | ||||
|     for (unsigned int i : selection) | ||||
|     for (const GLVolume* v : m_volumes.volumes) | ||||
|     { | ||||
|         const GLVolume* v = m_volumes.volumes[i]; | ||||
|         int object_idx = v->object_idx(); | ||||
|         int instance_idx = v->instance_idx(); | ||||
| 
 | ||||
|  | @ -6531,11 +6457,9 @@ void GLCanvas3D::_on_rotate() | |||
|         return; | ||||
| 
 | ||||
|     std::set<std::pair<int, int>> done;  // prevent rotating instances twice
 | ||||
|     const Selection::IndicesList& selection = m_selection.get_volume_idxs(); | ||||
| 
 | ||||
|     for (unsigned int i : selection) | ||||
|     for (const GLVolume* v : m_volumes.volumes) | ||||
|     { | ||||
|         const GLVolume* v = m_volumes.volumes[i]; | ||||
|         int object_idx = v->object_idx(); | ||||
|         if (object_idx >= 1000) | ||||
|             continue; | ||||
|  | @ -6567,18 +6491,16 @@ void GLCanvas3D::_on_scale() | |||
|         return; | ||||
| 
 | ||||
|     std::set<std::pair<int, int>> done;  // prevent scaling instances twice
 | ||||
|     const Selection::IndicesList& selection = m_selection.get_volume_idxs(); | ||||
| 
 | ||||
|     for (unsigned int i : selection) | ||||
|     for (const GLVolume* v : m_volumes.volumes) | ||||
|     { | ||||
|         const GLVolume* v = m_volumes.volumes[i]; | ||||
|         int object_idx = v->object_idx(); | ||||
|         if (object_idx >= 1000) | ||||
|             continue; | ||||
| 
 | ||||
|         int instance_idx = v->instance_idx(); | ||||
| 
 | ||||
|         // prevent rotating instances twice
 | ||||
|         // prevent scaling instances twice
 | ||||
|         std::pair<int, int> done_id(object_idx, instance_idx); | ||||
|         if (done.find(done_id) != done.end()) | ||||
|             continue; | ||||
|  | @ -6596,6 +6518,12 @@ void GLCanvas3D::_on_scale() | |||
| 
 | ||||
|     // schedule_background_process
 | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::_on_flatten() | ||||
| { | ||||
|     _on_rotate(); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs) | ||||
| { | ||||
|  | @ -6625,12 +6553,7 @@ void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs) | |||
|             ModelObject* model_object = m_model->objects[obj_idx]; | ||||
|             if (model_object != nullptr) | ||||
|             { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|                 model_object->instances[instance_idx]->set_offset(volume->get_offset()); | ||||
| #else | ||||
|                 const Vec3d& offset = volume->get_offset(); | ||||
|                 model_object->instances[instance_idx]->offset = Vec2d(offset(0), offset(1)); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|                 model_object->invalidate_bounding_box(); | ||||
|                 wxGetApp().obj_manipul()->update_position_values(); | ||||
|                 object_moved = true; | ||||
|  | @ -6652,7 +6575,7 @@ void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs) | |||
| void GLCanvas3D::_on_select(int volume_idx, int object_idx) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     post_event(ObjectSelectEvent(object_idx, -1)); | ||||
|     post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); | ||||
| #else | ||||
|     int vol_id = -1; | ||||
|     int obj_id = -1; | ||||
|  |  | |||
|  | @ -81,7 +81,9 @@ public: | |||
|     void set_bottom(float bottom); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); | ||||
| #else | ||||
| struct ObjectSelectEvent; | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, ObjectSelectEvent); | ||||
| struct ObjectSelectEvent : public ArrayEvent<ptrdiff_t, 2> | ||||
|  | @ -93,6 +95,7 @@ struct ObjectSelectEvent : public ArrayEvent<ptrdiff_t, 2> | |||
|     ptrdiff_t object_id() const { return data[0]; } | ||||
|     ptrdiff_t volume_id() const { return data[1]; } | ||||
| }; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| using Vec2dEvent = Event<Vec2d>; | ||||
| template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>; | ||||
|  | @ -102,7 +105,9 @@ template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>; | |||
| 
 | ||||
| 
 | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_DOUBLE_CLICK, SimpleEvent); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); | ||||
|  | @ -118,8 +123,8 @@ wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); | |||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDECLARE_EVENT(EVT_GIZMO_SCALE, Vec3dEvent); | ||||
| wxDECLARE_EVENT(EVT_GIZMO_ROTATE, Vec3dEvent); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| wxDECLARE_EVENT(EVT_GIZMO_FLATTEN, Vec3dEvent); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| 
 | ||||
| class GLCanvas3D | ||||
|  | @ -552,6 +557,7 @@ private: | |||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         void update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection); | ||||
|         void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection); | ||||
|         void update_on_off_state(const Selection& selection); | ||||
| #else | ||||
|         void update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos); | ||||
|         void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos); | ||||
|  | @ -589,7 +595,6 @@ private: | |||
|         void set_position(const Vec3d& position); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|         Vec3d get_scale() const; | ||||
|         void set_scale(const Vec3d& scale); | ||||
| 
 | ||||
|  | @ -597,15 +602,6 @@ private: | |||
|         void set_rotation(const Vec3d& rotation); | ||||
| 
 | ||||
|         Vec3d get_flattening_rotation() const; | ||||
| #else | ||||
|         float get_scale() const; | ||||
|         void set_scale(float scale); | ||||
| 
 | ||||
|         float get_angle_z() const; | ||||
|         void set_angle_z(float angle_z); | ||||
| 
 | ||||
|         Vec3d get_flattening_normal() const; | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|         void set_flattening_data(const ModelObject* model_object); | ||||
| 
 | ||||
|  | @ -956,6 +952,7 @@ private: | |||
|     void _on_move(); | ||||
|     void _on_rotate(); | ||||
|     void _on_scale(); | ||||
|     void _on_flatten(); | ||||
| #else | ||||
|     void _on_move(const std::vector<int>& volume_idxs); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ static const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f | |||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| // returns the intersection of the given ray with the plane parallel to plane XY and passing through the given center
 | ||||
| // coordinates are local to the plane
 | ||||
| Vec3d intersection_on_plane_xy(const Linef3& ray, const Vec3d& center) | ||||
|  | @ -105,7 +106,8 @@ unsigned int select_best_plane(const Vec3d& unit_vector, unsigned int preferred_ | |||
| 
 | ||||
|     return ret; | ||||
| } | ||||
|      | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| const float GLGizmoBase::Grabber::SizeFactor = 0.025f; | ||||
| const float GLGizmoBase::Grabber::MinHalfSize = 1.5f; | ||||
| const float GLGizmoBase::Grabber::DraggingScaleFactor = 1.25f; | ||||
|  | @ -217,9 +219,6 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent) | |||
|     : m_parent(parent) | ||||
|     , m_group_id(-1) | ||||
|     , m_state(Off) | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     , m_accept_wipe_tower(false) | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     , m_hover_id(-1) | ||||
|     , m_dragging(false) | ||||
| { | ||||
|  | @ -1065,7 +1064,11 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int | |||
| 
 | ||||
| void GLGizmoScale3D::do_scale_x(const Linef3& mouse_ray) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     double ratio = calc_ratio(mouse_ray); | ||||
| #else | ||||
|     double ratio = calc_ratio(1, mouse_ray, m_starting_box.center()); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     if (ratio > 0.0) | ||||
|         m_scale(0) = m_starting_scale(0) * ratio; | ||||
|  | @ -1073,40 +1076,70 @@ void GLGizmoScale3D::do_scale_x(const Linef3& mouse_ray) | |||
| 
 | ||||
| void GLGizmoScale3D::do_scale_y(const Linef3& mouse_ray) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     double ratio = calc_ratio(mouse_ray); | ||||
| #else | ||||
|     double ratio = calc_ratio(2, mouse_ray, m_starting_box.center()); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     if (ratio > 0.0) | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|         m_scale(1) = m_starting_scale(1) * ratio; | ||||
| #else | ||||
|         m_scale(0) = m_starting_scale(1) * ratio; | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| } | ||||
| 
 | ||||
| void GLGizmoScale3D::do_scale_z(const Linef3& mouse_ray) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     double ratio = calc_ratio(mouse_ray); | ||||
| #else | ||||
|     double ratio = calc_ratio(1, mouse_ray, m_starting_box.center()); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     if (ratio > 0.0) | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|         m_scale(2) = m_starting_scale(2) * ratio; | ||||
| #else | ||||
|         m_scale(0) = m_starting_scale(2) * ratio; // << this is temporary
 | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| } | ||||
| 
 | ||||
| void GLGizmoScale3D::do_scale_uniform(const Linef3& mouse_ray) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     double ratio = calc_ratio(mouse_ray); | ||||
| #else | ||||
|     Vec3d center = m_starting_box.center(); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     center(2) = m_box.min(2); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     double ratio = calc_ratio(0, mouse_ray, center); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     if (ratio > 0.0) | ||||
|         m_scale = m_starting_scale * ratio; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| double GLGizmoScale3D::calc_ratio(const Linef3& mouse_ray) const | ||||
| { | ||||
|     double ratio = 0.0; | ||||
| 
 | ||||
|     // vector from the center to the starting position
 | ||||
|     Vec3d starting_vec = m_starting_drag_position - m_starting_box.center(); | ||||
|     double len_starting_vec = starting_vec.norm(); | ||||
|     if (len_starting_vec != 0.0) | ||||
|     { | ||||
|         Vec3d mouse_dir = mouse_ray.unit_vector(); | ||||
|         // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
 | ||||
|         // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
 | ||||
|         // in our case plane normal and ray direction are the same (orthogonal view)
 | ||||
|         // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
 | ||||
|         Vec3d inters = mouse_ray.a + (m_starting_drag_position - mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; | ||||
|         // vector from the starting position to the found intersection
 | ||||
|         Vec3d inters_vec = inters - m_starting_drag_position; | ||||
| 
 | ||||
|         // finds projection of the vector along the staring direction
 | ||||
|         double proj = inters_vec.dot(starting_vec.normalized()); | ||||
| 
 | ||||
|         return (len_starting_vec + proj) / len_starting_vec; | ||||
|     } | ||||
| 
 | ||||
|     return ratio; | ||||
| } | ||||
| #else | ||||
| double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Vec3d& center) const | ||||
| { | ||||
|     double ratio = 0.0; | ||||
|  | @ -1142,6 +1175,7 @@ double GLGizmoScale3D::calc_ratio(unsigned int preferred_plane_id, const Linef3& | |||
| 
 | ||||
|     return ratio; | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| const double GLGizmoMove3D::Offset = 10.0; | ||||
| 
 | ||||
|  | @ -1179,10 +1213,6 @@ bool GLGizmoMove3D::on_init() | |||
|         m_grabbers.push_back(Grabber()); | ||||
|     } | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     m_accept_wipe_tower = true; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
|  | @ -1209,11 +1239,11 @@ void GLGizmoMove3D::on_update(const Linef3& mouse_ray) | |||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     if (m_hover_id == 0) | ||||
|         m_displacement(0) = calc_projection(X, 1, mouse_ray) - (m_starting_drag_position(0) - m_starting_box_center(0)); | ||||
|         m_displacement(0) = calc_projection(mouse_ray); | ||||
|     else if (m_hover_id == 1) | ||||
|         m_displacement(1) = calc_projection(Y, 2, mouse_ray) - (m_starting_drag_position(1) - m_starting_box_center(1)); | ||||
|         m_displacement(1) = calc_projection(mouse_ray); | ||||
|     else if (m_hover_id == 2) | ||||
|         m_displacement(2) = calc_projection(Z, 1, mouse_ray) - (m_starting_drag_position(2) - m_starting_box_bottom_center(2)); | ||||
|         m_displacement(2) = calc_projection(mouse_ray); | ||||
| #else | ||||
|     if (m_hover_id == 0) | ||||
|         m_position(0) = 2.0 * m_starting_box_center(0) + calc_projection(X, 1, mouse_ray) - m_starting_drag_position(0); | ||||
|  | @ -1315,6 +1345,30 @@ void GLGizmoMove3D::on_render_for_picking(const BoundingBoxf3& box) const | |||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| double GLGizmoMove3D::calc_projection(const Linef3& mouse_ray) const | ||||
| { | ||||
|     double projection = 0.0; | ||||
| 
 | ||||
|     Vec3d starting_vec = m_starting_drag_position - m_starting_box_center; | ||||
|     double len_starting_vec = starting_vec.norm(); | ||||
|     if (len_starting_vec != 0.0) | ||||
|     { | ||||
|         Vec3d mouse_dir = mouse_ray.unit_vector(); | ||||
|         // finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
 | ||||
|         // use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
 | ||||
|         // in our case plane normal and ray direction are the same (orthogonal view)
 | ||||
|         // when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
 | ||||
|         Vec3d inters = mouse_ray.a + (m_starting_drag_position - mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir; | ||||
|         // vector from the starting position to the found intersection
 | ||||
|         Vec3d inters_vec = inters - m_starting_drag_position; | ||||
| 
 | ||||
|         // finds projection of the vector along the staring direction
 | ||||
|         projection = inters_vec.dot(starting_vec.normalized()); | ||||
|     } | ||||
|     return projection; | ||||
| } | ||||
| #else | ||||
| double GLGizmoMove3D::calc_projection(Axis axis, unsigned int preferred_plane_id, const Linef3& mouse_ray) const | ||||
| { | ||||
|     double projection = 0.0; | ||||
|  | @ -1350,6 +1404,7 @@ double GLGizmoMove3D::calc_projection(Axis axis, unsigned int preferred_plane_id | |||
| 
 | ||||
|     return projection; | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent) | ||||
|     : GLGizmoBase(parent) | ||||
|  | @ -1420,24 +1475,35 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const | |||
|         else | ||||
|             ::glColor4f(0.9f, 0.9f, 0.9f, 0.5f); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         int instance_idx = selection.get_instance_idx(); | ||||
|         if ((instance_idx != -1) && (m_model_object != nullptr)) | ||||
|         { | ||||
|             Transform3d m = m_model_object->instances[instance_idx]->world_matrix(); | ||||
|             m.pretranslate(dragged_offset); | ||||
|             ::glPushMatrix(); | ||||
|             ::glMultMatrixd(m.data()); | ||||
|             ::glBegin(GL_POLYGON); | ||||
|             for (const Vec3d& vertex : m_planes[i].vertices) | ||||
|             { | ||||
|                 ::glVertex3dv(vertex.data()); | ||||
|             } | ||||
|             ::glEnd(); | ||||
|             ::glPopMatrix(); | ||||
|         } | ||||
| #else | ||||
|         for (const InstanceData& inst : m_instances) { | ||||
|             Transform3d m = inst.matrix; | ||||
|             m.pretranslate(dragged_offset); | ||||
|             ::glPushMatrix(); | ||||
|             ::glMultMatrixd(m.data()); | ||||
| #else | ||||
|         for (Vec2d offset : m_instances_positions) { | ||||
|             offset += to_2d(dragged_offset); | ||||
|             ::glPushMatrix(); | ||||
|             ::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|             ::glBegin(GL_POLYGON); | ||||
|             for (const Vec3d& vertex : m_planes[i].vertices) | ||||
|                 ::glVertex3dv(vertex.data()); | ||||
|             ::glEnd(); | ||||
|             ::glPopMatrix(); | ||||
|         } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     } | ||||
| 
 | ||||
|     ::glDisable(GL_BLEND); | ||||
|  | @ -1454,21 +1520,31 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const | |||
|     for (unsigned int i = 0; i < m_planes.size(); ++i) | ||||
|     { | ||||
|         ::glColor3f(1.0f, 1.0f, picking_color_component(i)); | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         int instance_idx = selection.get_instance_idx(); | ||||
|         if ((instance_idx != -1) && (m_model_object != nullptr)) | ||||
|         { | ||||
|             ::glPushMatrix(); | ||||
|             ::glMultMatrixd(m_model_object->instances[instance_idx]->world_matrix().data()); | ||||
|             ::glBegin(GL_POLYGON); | ||||
|             for (const Vec3d& vertex : m_planes[i].vertices) | ||||
|             { | ||||
|                 ::glVertex3dv(vertex.data()); | ||||
|             } | ||||
|             ::glEnd(); | ||||
|             ::glPopMatrix(); | ||||
|         } | ||||
| #else | ||||
|         for (const InstanceData& inst : m_instances) { | ||||
|             ::glPushMatrix(); | ||||
|             ::glMultMatrixd(inst.matrix.data()); | ||||
| #else | ||||
|         for (const Vec2d& offset : m_instances_positions) { | ||||
|             ::glPushMatrix(); | ||||
|             ::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|             ::glBegin(GL_POLYGON); | ||||
|             for (const Vec3d& vertex : m_planes[i].vertices) | ||||
|                 ::glVertex3dv(vertex.data()); | ||||
|             ::glEnd(); | ||||
|             ::glPopMatrix(); | ||||
|         } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1476,20 +1552,14 @@ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) | |||
| { | ||||
|     m_model_object = model_object; | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     // ...and save the updated positions of the object instances:
 | ||||
|     if (m_model_object && !m_model_object->instances.empty()) { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|         m_instances.clear(); | ||||
| #else | ||||
|         m_instances_positions.clear(); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|         for (const auto* instance : m_model_object->instances) | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|             m_instances.emplace_back(instance->world_matrix()); | ||||
| #else | ||||
|             m_instances_positions.emplace_back(instance->offset); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|     } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     if (is_plane_update_necessary()) | ||||
|         update_planes(); | ||||
|  | @ -1502,10 +1572,6 @@ void GLGizmoFlatten::update_planes() | |||
|         ch.merge(vol->get_convex_hull()); | ||||
| 
 | ||||
|     ch = ch.convex_hull_3d(); | ||||
| #if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     ch.scale(m_model_object->instances.front()->scaling_factor); | ||||
|     ch.rotate_z(m_model_object->instances.front()->rotation); | ||||
| #endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|     const Vec3d& bb_size = ch.bounding_box().size(); | ||||
|     double min_bb_face_area = std::min(bb_size(0) * bb_size(1), std::min(bb_size(0) * bb_size(2), bb_size(1) * bb_size(2))); | ||||
|  | @ -1671,10 +1737,6 @@ void GLGizmoFlatten::update_planes() | |||
|     m_source_data.bounding_boxes.clear(); | ||||
|     for (const auto& vol : m_model_object->volumes) | ||||
|         m_source_data.bounding_boxes.push_back(vol->get_convex_hull().bounding_box()); | ||||
| #if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     m_source_data.scaling_factor = m_model_object->instances.front()->scaling_factor; | ||||
|     m_source_data.rotation = m_model_object->instances.front()->rotation; | ||||
| #endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|     const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex(); | ||||
|     m_source_data.mesh_first_point = Vec3d((double)first_vertex[0], (double)first_vertex[1], (double)first_vertex[2]); | ||||
| } | ||||
|  | @ -1686,13 +1748,7 @@ bool GLGizmoFlatten::is_plane_update_necessary() const | |||
|     if (m_state != On || !m_model_object || m_model_object->instances.empty()) | ||||
|         return false; | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size()) | ||||
| #else | ||||
|     if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size() | ||||
|      || m_model_object->instances.front()->scaling_factor != m_source_data.scaling_factor | ||||
|      || m_model_object->instances.front()->rotation != m_source_data.rotation) | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|         return true; | ||||
| 
 | ||||
|     // now compare the bounding boxes:
 | ||||
|  | @ -1708,7 +1764,6 @@ bool GLGizmoFlatten::is_plane_update_necessary() const | |||
|     return false; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| Vec3d GLGizmoFlatten::get_flattening_rotation() const | ||||
| { | ||||
|     // calculates the rotations in model space, taking in account the scaling factors
 | ||||
|  | @ -1718,13 +1773,6 @@ Vec3d GLGizmoFlatten::get_flattening_rotation() const | |||
|     m_normal = Vec3d::Zero(); | ||||
|     return Vec3d(angles(2), angles(1), angles(0)); | ||||
| } | ||||
| #else | ||||
| Vec3d GLGizmoFlatten::get_flattening_normal() const { | ||||
|     Vec3d normal = m_model_object->instances.front()->world_matrix(true).matrix().block(0, 0, 3, 3).inverse() * m_normal; | ||||
|     m_normal = Vec3d::Zero(); | ||||
|     return normal.normalized(); | ||||
| } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
|  | @ -59,9 +59,6 @@ protected: | |||
| 
 | ||||
|     int m_group_id; | ||||
|     EState m_state; | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     bool m_accept_wipe_tower; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     // textures are assumed to be square and all with the same size in pixels, no internal check is done
 | ||||
|     GLTexture m_textures[Num_States]; | ||||
|     int m_hover_id; | ||||
|  | @ -84,8 +81,7 @@ public: | |||
|     void set_state(EState state) { m_state = state; on_set_state(); } | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     bool get_accept_wipe_tower() { return m_accept_wipe_tower; } | ||||
|     void set_accept_wipe_tower(bool accept) { m_accept_wipe_tower = accept; } | ||||
|     bool is_activable(const GLCanvas3D::Selection& selection) const { return on_is_activable(selection); } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     unsigned int get_texture_id() const { return m_textures[m_state].get_id(); } | ||||
|  | @ -125,6 +121,9 @@ protected: | |||
|     virtual bool on_init() = 0; | ||||
|     virtual void on_set_state() {} | ||||
|     virtual void on_set_hover_id() {} | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return true; } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     virtual void on_enable_grabber(unsigned int id) {} | ||||
|     virtual void on_disable_grabber(unsigned int id) {} | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|  | @ -230,19 +229,8 @@ class GLGizmoRotate3D : public GLGizmoBase | |||
| public: | ||||
|     explicit GLGizmoRotate3D(GLCanvas3D& parent); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); } | ||||
|     void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); } | ||||
| #else | ||||
|     double get_angle_x() const { return m_gizmos[X].get_angle(); } | ||||
|     void set_angle_x(double angle) { m_gizmos[X].set_angle(angle); } | ||||
| 
 | ||||
|     double get_angle_y() const { return m_gizmos[Y].get_angle(); } | ||||
|     void set_angle_y(double angle) { m_gizmos[Y].set_angle(angle); } | ||||
| 
 | ||||
|     double get_angle_z() const { return m_gizmos[Z].get_angle(); } | ||||
|     void set_angle_z(double angle) { m_gizmos[Z].set_angle(angle); } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| protected: | ||||
|     virtual bool on_init(); | ||||
|  | @ -260,6 +248,9 @@ protected: | |||
|             m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1); | ||||
|         } | ||||
|     } | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return !selection.is_wipe_tower(); } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     virtual void on_enable_grabber(unsigned int id) | ||||
|     { | ||||
|         if ((0 <= id) && (id < 3)) | ||||
|  | @ -329,28 +320,18 @@ class GLGizmoScale3D : public GLGizmoBase | |||
| public: | ||||
|     explicit GLGizmoScale3D(GLCanvas3D& parent); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     const Vec3d& get_scale() const { return m_scale; } | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     void set_scale(const Vec3d& scale) { m_starting_scale = scale; m_scale = scale; } | ||||
| #else | ||||
|     void set_scale(const Vec3d& scale) { m_starting_scale = scale; } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #else | ||||
|     double get_scale_x() const { return m_scale(0); } | ||||
|     void set_scale_x(double scale) { m_starting_scale(0) = scale; } | ||||
| 
 | ||||
|     double get_scale_y() const { return m_scale(1); } | ||||
|     void set_scale_y(double scale) { m_starting_scale(1) = scale; } | ||||
| 
 | ||||
|     double get_scale_z() const { return m_scale(2); } | ||||
|     void set_scale_z(double scale) { m_starting_scale(2) = scale; } | ||||
| 
 | ||||
|     void set_scale(double scale) { m_starting_scale = scale * Vec3d::Ones(); } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| protected: | ||||
|     virtual bool on_init(); | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return !selection.is_wipe_tower(); } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     virtual void on_start_dragging(const GLCanvas3D::Selection& selection); | ||||
| #else | ||||
|  | @ -376,7 +357,11 @@ private: | |||
|     void do_scale_z(const Linef3& mouse_ray); | ||||
|     void do_scale_uniform(const Linef3& mouse_ray); | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     double calc_ratio(const Linef3& mouse_ray) const; | ||||
| #else | ||||
|     double calc_ratio(unsigned int preferred_plane_id, const Linef3& mouse_ray, const Vec3d& center) const; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| }; | ||||
| 
 | ||||
| class GLGizmoMove3D : public GLGizmoBase | ||||
|  | @ -419,7 +404,11 @@ protected: | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| private: | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     double calc_projection(const Linef3& mouse_ray) const; | ||||
| #else | ||||
|     double calc_projection(Axis axis, unsigned int preferred_plane_id, const Linef3& mouse_ray) const; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| }; | ||||
| 
 | ||||
| class GLGizmoFlatten : public GLGizmoBase | ||||
|  | @ -436,10 +425,6 @@ private: | |||
|     }; | ||||
|     struct SourceDataSummary { | ||||
|         std::vector<BoundingBoxf3> bounding_boxes; // bounding boxes of convex hulls of individual volumes
 | ||||
| #if !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|         float scaling_factor; | ||||
|         float rotation; | ||||
| #endif // !ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|         Vec3d mesh_first_point; | ||||
|     }; | ||||
| 
 | ||||
|  | @ -447,16 +432,14 @@ private: | |||
|     SourceDataSummary m_source_data; | ||||
| 
 | ||||
|     std::vector<PlaneData> m_planes; | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     struct InstanceData | ||||
|     { | ||||
|         Transform3d matrix; | ||||
|         InstanceData(const Transform3d& matrix) : matrix(matrix) {} | ||||
|     }; | ||||
|     std::vector<InstanceData> m_instances; | ||||
| #else | ||||
|     std::vector<Vec2d> m_instances_positions; | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     Vec3d m_starting_center; | ||||
|     const ModelObject* m_model_object = nullptr; | ||||
| 
 | ||||
|  | @ -467,14 +450,13 @@ public: | |||
|     explicit GLGizmoFlatten(GLCanvas3D& parent); | ||||
| 
 | ||||
|     void set_flattening_data(const ModelObject* model_object); | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     Vec3d get_flattening_rotation() const; | ||||
| #else | ||||
|     Vec3d get_flattening_normal() const; | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| protected: | ||||
|     virtual bool on_init(); | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return selection.is_single_full_instance(); } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     virtual void on_start_dragging(const GLCanvas3D::Selection& selection); | ||||
| #else | ||||
|  |  | |||
|  | @ -24,7 +24,9 @@ wxDEFINE_EVENT(EVT_GLTOOLBAR_MORE, SimpleEvent); | |||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_SPLIT, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_CUT, SimpleEvent); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_SETTINGS, SimpleEvent); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDEFINE_EVENT(EVT_GLTOOLBAR_SELECTBYPARTS, SimpleEvent); | ||||
|  |  | |||
|  | @ -24,7 +24,9 @@ wxDECLARE_EVENT(EVT_GLTOOLBAR_MORE, SimpleEvent); | |||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_FEWER, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_SPLIT, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_CUT, SimpleEvent); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_SETTINGS, SimpleEvent); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_LAYERSEDITING, SimpleEvent); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDECLARE_EVENT(EVT_GLTOOLBAR_SELECTBYPARTS, SimpleEvent); | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ | |||
| 
 | ||||
| #include "Utils.hpp" | ||||
| #include "GUI.hpp" | ||||
| #include "GUI_Utils.hpp" | ||||
| #include "AppConfig.hpp" | ||||
| #include "PresetBundle.hpp" | ||||
| #include "3DScene.hpp" | ||||
|  | @ -326,25 +327,6 @@ void GUI_App::CallAfter(std::function<void()> cb) | |||
|     callback_register.unlock(); | ||||
| } | ||||
| 
 | ||||
| wxMenuItem* GUI_App::append_menu_item(  wxMenu* menu, | ||||
|                                         int id, | ||||
|                                         const wxString& string, | ||||
|                                         const wxString& description, | ||||
|                                         const std::string& icon, | ||||
|                                         std::function<void(wxCommandEvent& event)> cb, | ||||
|                                         wxItemKind kind/* = wxITEM_NORMAL*/) | ||||
| { | ||||
|     if (id == wxID_ANY) | ||||
|         id = wxNewId(); | ||||
|     auto item = new wxMenuItem(menu, id, string, description, kind); | ||||
|     if (!icon.empty()) | ||||
|         item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG)); | ||||
|     menu->Append(item); | ||||
| 
 | ||||
|     menu->Bind(wxEVT_MENU, /*[cb](wxCommandEvent& event){cb; }*/cb); | ||||
|     return item; | ||||
| } | ||||
| 
 | ||||
| wxMenuItem* GUI_App::append_submenu(wxMenu* menu, | ||||
|     wxMenu* sub_menu, | ||||
|     int id, | ||||
|  | @ -363,41 +345,43 @@ wxMenuItem* GUI_App::append_submenu(wxMenu* menu, | |||
|     return item; | ||||
| } | ||||
| 
 | ||||
| void GUI_App::save_window_pos(wxTopLevelWindow* window, const std::string& name){ | ||||
|     int x, y; | ||||
|     window->GetScreenPosition(&x, &y); | ||||
|     app_config->set(name + "_pos", wxString::Format("%d,%d", x, y).ToStdString()); | ||||
| 
 | ||||
|     window->GetSize(&x, &y); | ||||
|     app_config->set(name + "_size", wxString::Format("%d,%d", x, y).ToStdString()); | ||||
| 
 | ||||
|     app_config->set(name + "_maximized", window->IsMaximized() ? "1" : "0"); | ||||
| void GUI_App::window_pos_save(wxTopLevelWindow* window, const std::string &name) | ||||
| { | ||||
|     if (name.empty()) { return; } | ||||
|     const auto config_key = (boost::format("window_%1%") % name).str(); | ||||
| 
 | ||||
|     WindowMetrics metrics = WindowMetrics::from_window(window); | ||||
|     app_config->set(config_key, metrics.serialize()); | ||||
|     app_config->save(); | ||||
| } | ||||
| 
 | ||||
| void GUI_App::restore_window_pos(wxTopLevelWindow* window, const std::string& name) | ||||
| void GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &name) | ||||
| { | ||||
|     if (!app_config->has(name + "_pos")) | ||||
|         return; | ||||
|     if (name.empty()) { return; } | ||||
|     const auto config_key = (boost::format("window_%1%") % name).str(); | ||||
| 
 | ||||
|     std::string str = app_config->get(name + "_size"); | ||||
|     std::vector<std::string> values; | ||||
|     boost::split(values, str, boost::is_any_of(",")); | ||||
|     wxSize size = wxSize(atoi(values[0].c_str()), atoi(values[1].c_str())); | ||||
|     window->SetSize(size); | ||||
|     if (! app_config->has(config_key)) { return; } | ||||
| 
 | ||||
|     auto display = (new wxDisplay())->GetClientArea(); | ||||
|     str = app_config->get(name + "_pos"); | ||||
|     values.resize(0); | ||||
|     boost::split(values, str, boost::is_any_of(",")); | ||||
|     wxPoint pos = wxPoint(atoi(values[0].c_str()), atoi(values[1].c_str())); | ||||
|     if (pos.x + 0.5*size.GetWidth() < display.GetRight() && | ||||
|         pos.y + 0.5*size.GetHeight() < display.GetBottom()) | ||||
|         window->Move(pos); | ||||
|     auto metrics = WindowMetrics::deserialize(app_config->get(config_key)); | ||||
|     if (! metrics) { return; } | ||||
| 
 | ||||
|     if (app_config->get(name + "_maximized") == "1") | ||||
|         window->Maximize(); | ||||
|     window->SetSize(metrics->get_rect()); | ||||
|     window->Maximize(metrics->get_maximized()); | ||||
| } | ||||
| 
 | ||||
| void GUI_App::window_pos_sanitize(wxTopLevelWindow* window) | ||||
| { | ||||
|     const auto display_idx = wxDisplay::GetFromWindow(window); | ||||
|     if (display_idx == wxNOT_FOUND) { return; } | ||||
| 
 | ||||
|     const auto display = wxDisplay(display_idx).GetClientArea(); | ||||
| 
 | ||||
|     auto metrics = WindowMetrics::from_window(window); | ||||
| 
 | ||||
|     metrics.sanitize_for_display(display); | ||||
|     if (window->GetScreenRect() != metrics.get_rect()) { | ||||
|         window->SetSize(metrics.get_rect()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // select language from the list of installed languages
 | ||||
|  |  | |||
|  | @ -107,21 +107,16 @@ public: | |||
| //     void            notify(/*message*/);
 | ||||
|     void            update_ui_from_settings(); | ||||
|     void            CallAfter(std::function<void()> cb); | ||||
|     wxMenuItem*     append_menu_item(   wxMenu* menu, | ||||
|                                         int id, | ||||
|                                         const wxString& string, | ||||
|                                         const wxString& description, | ||||
|                                         const std::string& icon, | ||||
|                                         std::function<void(wxCommandEvent& event)> cb, | ||||
|                                         wxItemKind kind = wxITEM_NORMAL); | ||||
|     wxMenuItem*     append_submenu( wxMenu* menu, | ||||
|     wxMenuItem*     append_submenu(wxMenu* menu, | ||||
|                                     wxMenu* sub_menu, | ||||
|                                     int id, | ||||
|                                     const wxString& string, | ||||
|                                     const wxString& description, | ||||
|                                     const std::string& icon); | ||||
|     void            save_window_pos(wxTopLevelWindow* window, const std::string& name); | ||||
|     void            restore_window_pos(wxTopLevelWindow* window, const std::string& name); | ||||
| 
 | ||||
|     void            window_pos_save(wxTopLevelWindow* window, const std::string &name); | ||||
|     void            window_pos_restore(wxTopLevelWindow* window, const std::string &name); | ||||
|     void            window_pos_sanitize(wxTopLevelWindow* window); | ||||
| 
 | ||||
|     bool            select_language(wxArrayString & names, wxArrayLong & identifiers); | ||||
|     bool            load_language(); | ||||
|  |  | |||
|  | @ -58,7 +58,7 @@ ObjectList::ObjectList(wxWindow* parent) : | |||
|     Bind(wxEVT_CHOICE, [this](wxCommandEvent& event) { update_extruder_in_config(event.GetString()); }); | ||||
| 
 | ||||
|     GetMainWindow()->Bind(wxEVT_MOTION, [this](wxMouseEvent& event) { | ||||
|         set_tooltip_for_item(event.GetPosition()); | ||||
|         set_tooltip_for_item(/*event.GetPosition()*/get_mouse_position_in_control()); | ||||
|         event.Skip(); | ||||
|     }); | ||||
| #else | ||||
|  | @ -94,17 +94,13 @@ void ObjectList::create_objects_ctrl() | |||
|     // column 0(Icon+Text) of the view control: 
 | ||||
|     // And Icon can be consisting of several bitmaps
 | ||||
|     AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaBitmapTextRenderer(), | ||||
|         0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); | ||||
|         0, 250, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); | ||||
| 
 | ||||
|     // column 1 of the view control:
 | ||||
|     AppendTextColumn(_(L("Copy")), 1, wxDATAVIEW_CELL_INERT, 45, | ||||
|         wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); | ||||
| 
 | ||||
|     // column 2 of the view control:
 | ||||
|     AppendColumn(create_objects_list_extruder_column(4)); | ||||
| 
 | ||||
|     // column 3 of the view control:
 | ||||
|     AppendBitmapColumn(" ", 3, wxDATAVIEW_CELL_INERT, 25, | ||||
|     // column 2 of the view control:
 | ||||
|     AppendBitmapColumn(" ", 2, wxDATAVIEW_CELL_INERT, 25, | ||||
|         wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); | ||||
| } | ||||
| 
 | ||||
|  | @ -118,7 +114,7 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt) | |||
|     if (col->GetTitle() == " " && GetSelectedItemsCount()<2) | ||||
|         GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings"))); | ||||
|     else if (col->GetTitle() == _("Name") && | ||||
|         m_objects_model->GetIcon(item).GetRefData() == m_icon_manifold_warning.GetRefData()) { | ||||
|         m_objects_model->GetBitmap(item).GetRefData() == m_bmp_manifold_warning.GetRefData()) { | ||||
|         int obj_idx = m_objects_model->GetIdByItem(item); | ||||
|         auto& stats = (*m_objects)[obj_idx]->volumes[0]->mesh.stl.stats; | ||||
|         int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + | ||||
|  | @ -178,7 +174,7 @@ wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_ | |||
|         choices.Add(wxString::Format("%d", i)); | ||||
|     wxDataViewChoiceRenderer *c = | ||||
|         new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL); | ||||
|     wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 2, 60, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); | ||||
|     wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 1, 80, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); | ||||
|     return column; | ||||
| } | ||||
| 
 | ||||
|  | @ -188,17 +184,17 @@ void ObjectList::update_objects_list_extruder_column(int extruders_count) | |||
|     if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) | ||||
|         extruders_count = 1; | ||||
| 
 | ||||
|     // delete old 3rd column
 | ||||
|     DeleteColumn(GetColumn(2)); | ||||
|     // delete old 2nd column
 | ||||
|     DeleteColumn(GetColumn(1)); | ||||
|     // insert new created 3rd column
 | ||||
|     InsertColumn(2, create_objects_list_extruder_column(extruders_count)); | ||||
|     InsertColumn(1, create_objects_list_extruder_column(extruders_count)); | ||||
|     // set show/hide for this column 
 | ||||
|     set_extruder_column_hidden(extruders_count <= 1); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::set_extruder_column_hidden(bool hide) | ||||
| { | ||||
|     GetColumn(2)->SetHidden(hide); | ||||
|     GetColumn(1)->SetHidden(hide); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::update_extruder_in_config(const wxString& selection) | ||||
|  | @ -214,11 +210,11 @@ void ObjectList::update_extruder_in_config(const wxString& selection) | |||
| } | ||||
| 
 | ||||
| void ObjectList::init_icons(){ | ||||
|     m_icon_modifiermesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     m_icon_solidmesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     m_bmp_modifiermesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     m_bmp_solidmesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 
 | ||||
|     // init icon for manifold warning
 | ||||
|     m_icon_manifold_warning = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     m_bmp_manifold_warning = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 
 | ||||
|     // init bitmap for "Split to sub-objects" context menu
 | ||||
|     m_bmp_split = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("split.png")), wxBITMAP_TYPE_PNG); | ||||
|  | @ -268,7 +264,7 @@ void ObjectList::context_menu() | |||
|         show_context_menu(); | ||||
| 
 | ||||
|         else if (title == _("Name") && pt.x >15 && | ||||
|                     m_objects_model->GetIcon(item).GetRefData() == m_icon_manifold_warning.GetRefData()) | ||||
|                     m_objects_model->GetBitmap(item).GetRefData() == m_bmp_manifold_warning.GetRefData()) | ||||
|         { | ||||
|             if (is_windows10()) | ||||
|                 /*fix_through_netfabb()*/;// #ys_FIXME
 | ||||
|  | @ -283,7 +279,7 @@ void ObjectList::show_context_menu() | |||
|     const auto item = GetSelection(); | ||||
|     if (item) | ||||
|     { | ||||
|         if (m_objects_model->IsSettingsItem(item)) | ||||
|         if (!(m_objects_model->GetItemType(item) & (itObject | itVolume))) | ||||
|             return; | ||||
|         const auto menu = m_objects_model->GetParent(item) == wxDataViewItem(0) ? | ||||
|             create_add_part_popupmenu() : | ||||
|  | @ -313,10 +309,10 @@ void ObjectList::key_event(wxKeyEvent& event) | |||
| 
 | ||||
| void ObjectList::item_value_change(wxDataViewEvent& event) | ||||
| { | ||||
|     if (event.GetColumn() == 2) | ||||
|     if (event.GetColumn() == 1) | ||||
|     { | ||||
|         wxVariant variant; | ||||
|         m_objects_model->GetValue(variant, event.GetItem(), 2); | ||||
|         m_objects_model->GetValue(variant, event.GetItem(), 1); | ||||
| #ifdef __WXOSX__ | ||||
|         m_selected_extruder = variant.GetString(); | ||||
| #else // --> for Linux
 | ||||
|  | @ -325,14 +321,20 @@ void ObjectList::item_value_change(wxDataViewEvent& event) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| struct draging_item_data | ||||
| { | ||||
|     int obj_idx; | ||||
|     int vol_idx; | ||||
| }; | ||||
| 
 | ||||
| void ObjectList::on_begin_drag(wxDataViewEvent &event) | ||||
| { | ||||
|     wxDataViewItem item(event.GetItem()); | ||||
| 
 | ||||
|     // only allow drags for item, not containers
 | ||||
|     if (multiple_selection() || | ||||
|         m_objects_model->GetParent(item) == wxDataViewItem(0) ||  | ||||
|         m_objects_model->IsSettingsItem(item) ) { | ||||
|         m_objects_model->GetParent(item) == wxDataViewItem(0) || | ||||
|         m_objects_model->GetItemType(item) != itVolume ) { | ||||
|         event.Veto(); | ||||
|         return; | ||||
|     } | ||||
|  | @ -356,7 +358,7 @@ void ObjectList::on_drop_possible(wxDataViewEvent &event) | |||
| 
 | ||||
|     // only allow drags for item or background, not containers
 | ||||
|     if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) || | ||||
|         event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->IsSettingsItem(item)) | ||||
|         event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->GetItemType(item) != itVolume) | ||||
|         event.Veto(); | ||||
| } | ||||
| 
 | ||||
|  | @ -366,7 +368,7 @@ void ObjectList::on_drop(wxDataViewEvent &event) | |||
| 
 | ||||
|     // only allow drops for item, not containers
 | ||||
|     if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) || | ||||
|         event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->IsSettingsItem(item)) { | ||||
|         event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->GetItemType(item) != itVolume) { | ||||
|         event.Veto(); | ||||
|         return; | ||||
|     } | ||||
|  | @ -495,7 +497,7 @@ void ObjectList::get_settings_choice(wxMenu *menu, int id, bool is_part) | |||
|     // Add settings item for object
 | ||||
|     const auto item = GetSelection(); | ||||
|     if (item) { | ||||
|         const auto settings_item = m_objects_model->HasSettings(item); | ||||
|         const auto settings_item = m_objects_model->GetSettingsItem(item); | ||||
|         select_item(settings_item ? settings_item : | ||||
|             m_objects_model->AddSettingsChild(item)); | ||||
| #ifndef __WXOSX__ | ||||
|  | @ -547,7 +549,7 @@ wxMenu* ObjectList::create_add_part_popupmenu() | |||
|     int i = 0; | ||||
|     for (auto& item : menu_items) { | ||||
|         auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item)); | ||||
|         menu_item->SetBitmap(i == 0 ? m_icon_solidmesh : m_icon_modifiermesh); | ||||
|         menu_item->SetBitmap(i == 0 ? m_bmp_solidmesh : m_bmp_modifiermesh); | ||||
|         if (item == "Add generic") | ||||
|             menu_item_add_generic(menu_item, config_id_base + i); | ||||
|         menu->Append(menu_item); | ||||
|  | @ -666,8 +668,8 @@ void ObjectList::load_subobject(bool is_modifier /*= false*/, bool is_lambda/* = | |||
|     parts_changed(obj_idx); | ||||
| 
 | ||||
|     for (int i = 0; i < part_names.size(); ++i) { | ||||
|         const wxDataViewItem sel_item = m_objects_model->AddChild(item, part_names.Item(i), | ||||
|             is_modifier ? m_icon_modifiermesh : m_icon_solidmesh); | ||||
|         const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), | ||||
|             is_modifier ? m_bmp_modifiermesh : m_bmp_solidmesh); | ||||
| 
 | ||||
|         if (i == part_names.size() - 1) | ||||
|             select_item(sel_item); | ||||
|  | @ -816,8 +818,8 @@ void ObjectList::load_lambda(const std::string& type_name) | |||
|     m_parts_changed = true; | ||||
|     parts_changed(m_selected_object_id); | ||||
| 
 | ||||
|     select_item(m_objects_model->AddChild(GetSelection(), | ||||
|         name, m_icon_modifiermesh)); | ||||
|     select_item(m_objects_model->AddVolumeChild(GetSelection(), | ||||
|         name, m_bmp_modifiermesh)); | ||||
| #ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
 | ||||
|     selection_changed(); | ||||
| #endif //no __WXOSX__ //__WXMSW__
 | ||||
|  | @ -830,15 +832,20 @@ void ObjectList::del_subobject_item(wxDataViewItem& item) | |||
| { | ||||
|     if (!item) return; | ||||
| 
 | ||||
|     int obj_idx, vol_idx; | ||||
|     m_objects_model->GetObjectAndVolumeIdsByItem(item, obj_idx, vol_idx); | ||||
|     int obj_idx, idx; | ||||
|     ItemType type; | ||||
| 
 | ||||
|     if (vol_idx == -1) | ||||
|     m_objects_model->GetItemInfo(item, type, obj_idx, idx); | ||||
|     if (type == itUndef) | ||||
|         return; | ||||
| 
 | ||||
|     if (vol_idx == -2) | ||||
|     if (type == itSettings) | ||||
|         del_settings_from_config(); | ||||
|     else if (!del_subobject_from_object(obj_idx, vol_idx)) | ||||
|     else if (type == itInstanceRoot && obj_idx != -1) | ||||
|         del_instances_from_object(obj_idx); | ||||
|     else if (idx == -1) | ||||
|         return; | ||||
|     else if (!del_subobject_from_object(obj_idx, idx, type)) | ||||
|         return; | ||||
| 
 | ||||
|     m_objects_model->Delete(item); | ||||
|  | @ -859,21 +866,48 @@ void ObjectList::del_settings_from_config() | |||
|         m_config->set_key_value("extruder", new ConfigOptionInt(extruder)); | ||||
| } | ||||
| 
 | ||||
| bool ObjectList::del_subobject_from_object(const int obj_idx, const int vol_idx) | ||||
| void ObjectList::del_instances_from_object(const int obj_idx) | ||||
| { | ||||
|     const auto volume = (*m_objects)[obj_idx]->volumes[vol_idx]; | ||||
|     auto instances = (*m_objects)[obj_idx]->instances; | ||||
|     if (instances.size() <= 1) | ||||
|         return; | ||||
| 
 | ||||
|     // if user is deleting the last solid part, throw error
 | ||||
|     int solid_cnt = 0; | ||||
|     for (auto vol : (*m_objects)[obj_idx]->volumes) | ||||
|         if (vol->is_model_part()) | ||||
|             ++solid_cnt; | ||||
|     if (volume->is_model_part() && solid_cnt == 1) { | ||||
|         Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from this object."))); | ||||
|         return false; | ||||
|     while ( instances.size()> 1) | ||||
|         instances.pop_back(); | ||||
| 
 | ||||
|     (*m_objects)[obj_idx]->invalidate_bounding_box(); // ? #ys_FIXME
 | ||||
| 
 | ||||
|     m_parts_changed = true; | ||||
|     parts_changed(obj_idx); | ||||
| } | ||||
| 
 | ||||
| bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type) | ||||
| { | ||||
|     if (type == itVolume) { | ||||
|         const auto volume = (*m_objects)[obj_idx]->volumes[idx]; | ||||
| 
 | ||||
|         // if user is deleting the last solid part, throw error
 | ||||
|         int solid_cnt = 0; | ||||
|         for (auto vol : (*m_objects)[obj_idx]->volumes) | ||||
|             if (vol->is_model_part()) | ||||
|                 ++solid_cnt; | ||||
|         if (volume->is_model_part() && solid_cnt == 1) { | ||||
|             Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from object."))); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         (*m_objects)[obj_idx]->delete_volume(idx); | ||||
|     } | ||||
|     else if (type == itInstance) { | ||||
|         if ((*m_objects)[obj_idx]->instances.size() == 1) { | ||||
|             Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last intance from object."))); | ||||
|             return false; | ||||
|         } | ||||
|         (*m_objects)[obj_idx]->delete_instance(idx); | ||||
|     } | ||||
|     else | ||||
|         return false; | ||||
| 
 | ||||
|     (*m_objects)[obj_idx]->delete_volume(vol_idx); | ||||
|     m_parts_changed = true; | ||||
|     parts_changed(obj_idx); | ||||
| 
 | ||||
|  | @ -901,8 +935,8 @@ void ObjectList::split(const bool split_part) | |||
|         m_objects_model->DeleteChildren(parent); | ||||
| 
 | ||||
|         for (auto id = 0; id < model_object->volumes.size(); id++) | ||||
|             m_objects_model->AddChild(parent, model_object->volumes[id]->name, | ||||
|             model_object->volumes[id]->is_modifier() ? m_icon_modifiermesh : m_icon_solidmesh, | ||||
|             m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name, | ||||
|             model_object->volumes[id]->is_modifier() ? m_bmp_modifiermesh : m_bmp_solidmesh, | ||||
|             model_object->volumes[id]->config.has("extruder") ? | ||||
|             model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0, | ||||
|             false); | ||||
|  | @ -911,8 +945,8 @@ void ObjectList::split(const bool split_part) | |||
|     } | ||||
|     else { | ||||
|         for (auto id = 0; id < model_object->volumes.size(); id++) | ||||
|             m_objects_model->AddChild(item, model_object->volumes[id]->name, | ||||
|             m_icon_solidmesh, | ||||
|             m_objects_model->AddVolumeChild(item, model_object->volumes[id]->name, | ||||
|             m_bmp_solidmesh, | ||||
|             model_object->volumes[id]->config.has("extruder") ? | ||||
|             model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0, | ||||
|             false); | ||||
|  | @ -1001,7 +1035,7 @@ void ObjectList::part_selection_changed() | |||
|                     m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config; | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|             else if (m_objects_model->GetItemType(item) == itVolume){ | ||||
|                 og_name = _(L("Part manipulation")); | ||||
|                 is_part = true; | ||||
|                 const auto volume_id = m_objects_model->GetVolumeIdByItem(item); | ||||
|  | @ -1038,7 +1072,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) | |||
| { | ||||
|     auto model_object = (*m_objects)[obj_idx]; | ||||
|     wxString item_name = model_object->name; | ||||
|     auto item = m_objects_model->Add(item_name, model_object->instances.size()); | ||||
|     auto item = m_objects_model->Add(item_name); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     /*Select*/select_item(item); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|  | @ -1049,15 +1083,15 @@ void ObjectList::add_object_to_list(size_t obj_idx) | |||
|         stats.facets_added + stats.facets_reversed + stats.backwards_edges; | ||||
|     if (errors > 0)		{ | ||||
|         wxVariant variant; | ||||
|         variant << PrusaDataViewBitmapText(item_name, m_icon_manifold_warning); | ||||
|         variant << PrusaDataViewBitmapText(item_name, m_bmp_manifold_warning); | ||||
|         m_objects_model->SetValue(variant, item, 0); | ||||
|     } | ||||
| 
 | ||||
|     if (model_object->volumes.size() > 1) { | ||||
|         for (auto id = 0; id < model_object->volumes.size(); id++) | ||||
|             m_objects_model->AddChild(item, | ||||
|             m_objects_model->AddVolumeChild(item, | ||||
|             model_object->volumes[id]->name, | ||||
|             m_icon_solidmesh, | ||||
|             m_bmp_solidmesh, | ||||
|             model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value, | ||||
|             false); | ||||
|         Expand(item); | ||||
|  | @ -1095,10 +1129,14 @@ void ObjectList::delete_all_objects_from_list() | |||
|     part_selection_changed(); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::set_object_count(int idx, int count) | ||||
| void ObjectList::increase_object_instances(const size_t obj_idx, const size_t num) | ||||
| { | ||||
|     m_objects_model->SetValue(wxString::Format("%d", count), idx, 1); | ||||
|     Refresh(); | ||||
|     select_item(m_objects_model->AddInstanceChild(m_objects_model->GetItemById(obj_idx), num)); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::decrease_object_instances(const size_t obj_idx, const size_t num) | ||||
| { | ||||
|     select_item(m_objects_model->DeleteLastInstance(m_objects_model->GetItemById(obj_idx), num)); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::unselect_objects() | ||||
|  | @ -1191,22 +1229,28 @@ void ObjectList::update_selections_on_canvas() | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto add_to_selection = [this](wxDataViewItem& item, GLCanvas3D::Selection& selection, bool as_single_selection) | ||||
|     auto add_to_selection = [this](const wxDataViewItem& item, GLCanvas3D::Selection& selection, bool as_single_selection) | ||||
|     {         | ||||
|         if (m_objects_model->GetParent(item) == wxDataViewItem(0)){ | ||||
|             selection.add_object(m_objects_model->GetIdByItem(item), as_single_selection); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         auto parent = m_objects_model->GetParent(item); | ||||
|         const int obj_idx = m_objects_model->GetIdByItem(parent); | ||||
|         const int vol_idx = m_objects_model->GetVolumeIdByItem(item); | ||||
|         selection.add_volume(obj_idx, vol_idx, as_single_selection);         | ||||
|         if (m_objects_model->GetItemType(item) == itVolume) { | ||||
|             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item)); | ||||
|             const int vol_idx = m_objects_model->GetVolumeIdByItem(item); | ||||
|             selection.add_volume(obj_idx, vol_idx, as_single_selection); | ||||
|         } | ||||
|         else if (m_objects_model->GetItemType(item) == itInstance) { | ||||
|             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); | ||||
|             const int inst_idx = m_objects_model->GetInstanceIdByItem(item); | ||||
|             selection.add_instance(obj_idx, inst_idx, as_single_selection); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     if (sel_cnt == 1) { | ||||
|         wxDataViewItem item = GetSelection(); | ||||
|         if (m_objects_model->IsSettingsItem(item)) | ||||
|         if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) | ||||
|             add_to_selection(m_objects_model->GetParent(item), selection, true); | ||||
|         else | ||||
|             add_to_selection(item, selection, true); | ||||
|  |  | |||
|  | @ -22,9 +22,9 @@ class ObjectList : public wxDataViewCtrl | |||
| 
 | ||||
|     DynamicPrintConfig  *m_default_config {nullptr}; | ||||
| 
 | ||||
|     wxBitmap	m_icon_modifiermesh; | ||||
|     wxBitmap	m_icon_solidmesh; | ||||
|     wxBitmap	m_icon_manifold_warning; | ||||
|     wxBitmap	m_bmp_modifiermesh; | ||||
|     wxBitmap	m_bmp_solidmesh; | ||||
|     wxBitmap	m_bmp_manifold_warning; | ||||
|     wxBitmap	m_bmp_cog; | ||||
|     wxBitmap	m_bmp_split; | ||||
| 
 | ||||
|  | @ -87,7 +87,8 @@ public: | |||
|     void                load_lambda(const std::string& type_name); | ||||
|     void                del_subobject_item(wxDataViewItem& item); | ||||
|     void                del_settings_from_config(); | ||||
|     bool                del_subobject_from_object(const int obj_idx, const int vol_idx); | ||||
|     void                del_instances_from_object(const int obj_idx); | ||||
|     bool                del_subobject_from_object(const int obj_idx, const int idx, const int type); | ||||
|     void                split(const bool split_part); | ||||
|     bool                get_volume_by_item(const bool split_part, const wxDataViewItem& item, ModelVolume*& volume); | ||||
|     bool                is_splittable_object(const bool split_part); | ||||
|  | @ -111,8 +112,10 @@ public: | |||
|     void delete_volume_from_list(const size_t obj_idx, const size_t vol_idx); | ||||
|     // Delete all objects from the list
 | ||||
|     void delete_all_objects_from_list(); | ||||
|     // Set count of object on c++ side
 | ||||
|     void set_object_count(int idx, int count); | ||||
|     // Increase instances count
 | ||||
|     void increase_object_instances(const size_t obj_idx, const size_t num); | ||||
|     // Decrease instances count
 | ||||
|     void decrease_object_instances(const size_t obj_idx, const size_t num); | ||||
| 
 | ||||
|     // #ys_FIXME_to_delete
 | ||||
|     // Unselect all objects in the list on c++ side
 | ||||
|  |  | |||
|  | @ -375,7 +375,6 @@ void ObjectManipulation::update_scale_values() | |||
|     auto instance = objects[selection]->instances.front(); | ||||
|     auto size = objects[selection]->instance_bounding_box(0).size(); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     if (m_is_percent_scale) { | ||||
|         m_og->set_value("scale_x", int(instance->get_scaling_factor(X) * 100)); | ||||
|         m_og->set_value("scale_y", int(instance->get_scaling_factor(Y) * 100)); | ||||
|  | @ -386,34 +385,15 @@ void ObjectManipulation::update_scale_values() | |||
|         m_og->set_value("scale_y", int(instance->get_scaling_factor(Y) * size(1) + 0.5)); | ||||
|         m_og->set_value("scale_z", int(instance->get_scaling_factor(Z) * size(2) + 0.5)); | ||||
|     } | ||||
| #else | ||||
|     if (m_is_percent_scale) { | ||||
|         auto scale = instance->scaling_factor * 100.0; | ||||
|         m_og->set_value("scale_x", int(scale)); | ||||
|         m_og->set_value("scale_y", int(scale)); | ||||
|         m_og->set_value("scale_z", int(scale)); | ||||
|     } | ||||
|     else { | ||||
|         m_og->set_value("scale_x", int(instance->scaling_factor * size(0) + 0.5)); | ||||
|         m_og->set_value("scale_y", int(instance->scaling_factor * size(1) + 0.5)); | ||||
|         m_og->set_value("scale_z", int(instance->scaling_factor * size(2) + 0.5)); | ||||
|     } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| } | ||||
| 
 | ||||
| void ObjectManipulation::update_position_values() | ||||
| { | ||||
|     auto instance = wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front(); | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     m_og->set_value("position_x", int(instance->get_offset(X))); | ||||
|     m_og->set_value("position_y", int(instance->get_offset(Y))); | ||||
|     m_og->set_value("position_z", int(instance->get_offset(Z))); | ||||
| #else | ||||
|     m_og->set_value("position_x", int(instance->offset(0))); | ||||
|     m_og->set_value("position_y", int(instance->offset(1))); | ||||
|     m_og->set_value("position_z", 0); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| } | ||||
| 
 | ||||
| void ObjectManipulation::update_position_value(const Vec3d& position) | ||||
|  | @ -423,7 +403,6 @@ void ObjectManipulation::update_position_value(const Vec3d& position) | |||
|     m_og->set_value("position_z", int(position(2))); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| void ObjectManipulation::update_scale_value(const Vec3d& scaling_factor) | ||||
| { | ||||
|     // this is temporary
 | ||||
|  | @ -438,33 +417,10 @@ void ObjectManipulation::update_scale_value(const Vec3d& scaling_factor) | |||
|     m_og->set_value("scale_y", int(scale(1))); | ||||
|     m_og->set_value("scale_z", int(scale(2))); | ||||
| } | ||||
| #else | ||||
| void ObjectManipulation::update_scale_values(double scaling_factor) | ||||
| { | ||||
|     // this is temporary
 | ||||
|     // to be able to update the values as size
 | ||||
|     // we need to store somewhere the original size
 | ||||
|     // or have it passed as parameter
 | ||||
|     if (!m_is_percent_scale) | ||||
|         m_og->set_value("scale_unit", _("%")); | ||||
| 
 | ||||
|     auto scale = scaling_factor * 100.0; | ||||
|     m_og->set_value("scale_x", int(scale)); | ||||
|     m_og->set_value("scale_y", int(scale)); | ||||
|     m_og->set_value("scale_z", int(scale)); | ||||
| } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| void ObjectManipulation::update_rotation_values() | ||||
| { | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     update_rotation_value(wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front()->get_rotation()); | ||||
| #else | ||||
|     auto instance = wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front(); | ||||
|     m_og->set_value("rotation_x", 0); | ||||
|     m_og->set_value("rotation_y", 0); | ||||
|     m_og->set_value("rotation_z", int(Geometry::rad2deg(instance->rotation))); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| } | ||||
| 
 | ||||
| void ObjectManipulation::update_rotation_value(double angle, Axis axis) | ||||
|  | @ -485,14 +441,12 @@ void ObjectManipulation::update_rotation_value(double angle, Axis axis) | |||
|     m_og->set_value(axis_str, round_nearest(int(Geometry::rad2deg(angle)), 0)); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
| void ObjectManipulation::update_rotation_value(const Vec3d& rotation) | ||||
| { | ||||
|     m_og->set_value("rotation_x", int(round_nearest(Geometry::rad2deg(rotation(0)), 0))); | ||||
|     m_og->set_value("rotation_y", int(round_nearest(Geometry::rad2deg(rotation(1)), 0))); | ||||
|     m_og->set_value("rotation_z", int(round_nearest(Geometry::rad2deg(rotation(2)), 0))); | ||||
| } | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
| void ObjectManipulation::show_object_name(bool show) | ||||
| { | ||||
|  |  | |||
|  | @ -61,18 +61,12 @@ public: | |||
|     void update_position_value(const Vec3d& position); | ||||
|     // update scale values after scale unit changing or "gizmos"
 | ||||
|     void update_scale_values(); | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     void update_scale_value(const Vec3d& scaling_factor); | ||||
| #else | ||||
|     void update_scale_values(double scaling_factor); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
|     // update rotation values object selection changing
 | ||||
|     void update_rotation_values(); | ||||
|     // update rotation value after "gizmos"
 | ||||
|     void update_rotation_value(double angle, Axis axis); | ||||
| #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM | ||||
|     void update_rotation_value(const Vec3d& rotation); | ||||
| #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM
 | ||||
| 
 | ||||
|     void set_uniform_scaling(const bool uniform_scale) { m_is_uniform_scale = uniform_scale; } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,16 +1,23 @@ | |||
| #include "GUI_Utils.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/format.hpp> | ||||
| 
 | ||||
| #include <wx/toplevel.h> | ||||
| #include <wx/sizer.h> | ||||
| #include <wx/panel.h> | ||||
| #include <wx/checkbox.h> | ||||
| 
 | ||||
| #include "libslic3r/Config.hpp" | ||||
| 
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| CheckboxFileDialog::CheckboxFileDialog(wxWindow *parent, | ||||
| 	const wxString &checkbox_label, | ||||
|     const wxString &checkbox_label, | ||||
|     bool checkbox_value, | ||||
|     const wxString &message, | ||||
|     const wxString &default_dir, | ||||
|  | @ -24,31 +31,87 @@ CheckboxFileDialog::CheckboxFileDialog(wxWindow *parent, | |||
|     : wxFileDialog(parent, message, default_dir, default_file, wildcard, style, pos, size, name) | ||||
|     , cbox(nullptr) | ||||
| { | ||||
| 	if (checkbox_label.IsEmpty()) { | ||||
| 		return; | ||||
| 	} | ||||
|     if (checkbox_label.IsEmpty()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| 	extra_control_creator = [this, checkbox_label](wxWindow *parent) -> wxWindow* { | ||||
| 		wxPanel* panel = new wxPanel(parent, -1); | ||||
| 	    wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 	    this->cbox = new wxCheckBox(panel, wxID_HIGHEST + 1, checkbox_label); | ||||
| 	    this->cbox->SetValue(true); | ||||
| 	    sizer->AddSpacer(5); | ||||
| 	    sizer->Add(this->cbox, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); | ||||
| 	    panel->SetSizer(sizer); | ||||
| 	    sizer->SetSizeHints(panel); | ||||
|     extra_control_creator = [this, checkbox_label](wxWindow *parent) -> wxWindow* { | ||||
|         wxPanel* panel = new wxPanel(parent, -1); | ||||
|         wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|         this->cbox = new wxCheckBox(panel, wxID_HIGHEST + 1, checkbox_label); | ||||
|         this->cbox->SetValue(true); | ||||
|         sizer->AddSpacer(5); | ||||
|         sizer->Add(this->cbox, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5); | ||||
|         panel->SetSizer(sizer); | ||||
|         sizer->SetSizeHints(panel); | ||||
| 
 | ||||
| 	    return panel; | ||||
| 	}; | ||||
|         return panel; | ||||
|     }; | ||||
| 
 | ||||
|     SetExtraControlCreator(*extra_control_creator.target<ExtraControlCreatorFunction>()); | ||||
| } | ||||
| 
 | ||||
| bool CheckboxFileDialog::get_checkbox_value() const | ||||
| { | ||||
| 	return this->cbox != nullptr ? cbox->IsChecked() : false; | ||||
|     return this->cbox != nullptr ? cbox->IsChecked() : false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| WindowMetrics WindowMetrics::from_window(wxTopLevelWindow *window) | ||||
| { | ||||
|     WindowMetrics res; | ||||
|     res.rect = window->GetScreenRect(); | ||||
|     res.maximized = window->IsMaximized(); | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| boost::optional<WindowMetrics> WindowMetrics::deserialize(const std::string &str) | ||||
| { | ||||
|     std::vector<std::string> metrics_str; | ||||
|     metrics_str.reserve(5); | ||||
| 
 | ||||
|     if (!unescape_strings_cstyle(str, metrics_str) || metrics_str.size() != 5) { | ||||
|         return boost::none; | ||||
|     } | ||||
| 
 | ||||
|     int metrics[5]; | ||||
|     try { | ||||
|         for (size_t i = 0; i < 5; i++) { | ||||
|             metrics[i] = boost::lexical_cast<int>(metrics_str[i]); | ||||
|         } | ||||
|     } catch(const boost::bad_lexical_cast &) { | ||||
|         return boost::none; | ||||
|     } | ||||
| 
 | ||||
|     if ((metrics[4] & ~1) != 0) {    // Checks if the maximized flag is 1 or 0
 | ||||
|         metrics[4] = 0; | ||||
|     } | ||||
| 
 | ||||
|     WindowMetrics res; | ||||
|     res.rect = wxRect(metrics[0], metrics[1], metrics[2], metrics[3]); | ||||
|     res.maximized = metrics[4]; | ||||
| 
 | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| void WindowMetrics::sanitize_for_display(const wxRect &screen_rect) | ||||
| { | ||||
|     rect = rect.Intersect(screen_rect); | ||||
| } | ||||
| 
 | ||||
| std::string WindowMetrics::serialize() | ||||
| { | ||||
|     return (boost::format("%1%; %2%; %3%; %4%; %5%") | ||||
|         % rect.GetX() | ||||
|         % rect.GetY() | ||||
|         % rect.GetWidth() | ||||
|         % rect.GetHeight() | ||||
|         % static_cast<int>(maximized) | ||||
|     ).str(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -2,10 +2,16 @@ | |||
| #define slic3r_GUI_Utils_hpp_ | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <string> | ||||
| 
 | ||||
| #include <boost/optional.hpp> | ||||
| 
 | ||||
| #include <wx/filedlg.h> | ||||
| #include <wx/gdicmn.h> | ||||
| 
 | ||||
| class wxCheckBox; | ||||
| class wxTopLevelWindow; | ||||
| class wxRect; | ||||
| 
 | ||||
| 
 | ||||
| namespace Slic3r { | ||||
|  | @ -36,6 +42,25 @@ private: | |||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class WindowMetrics | ||||
| { | ||||
| private: | ||||
|     wxRect rect; | ||||
|     bool maximized; | ||||
| 
 | ||||
|     WindowMetrics() : maximized(false) {} | ||||
| public: | ||||
|     static WindowMetrics from_window(wxTopLevelWindow *window); | ||||
|     static boost::optional<WindowMetrics> deserialize(const std::string &str); | ||||
| 
 | ||||
|     wxRect get_rect() const { return rect; } | ||||
|     bool get_maximized() const { return maximized; } | ||||
| 
 | ||||
|     void sanitize_for_display(const wxRect &screen_rect); | ||||
|     std::string serialize(); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| }} | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ | |||
| #include "Print.hpp" | ||||
| #include "Polygon.hpp" | ||||
| #include "AppConfig.hpp" | ||||
| #include "wxExtensions.hpp" | ||||
| 
 | ||||
| #include <fstream> | ||||
| #include "GUI_App.hpp" | ||||
|  | @ -77,8 +78,6 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL | |||
|     Fit(); | ||||
|     SetMinSize(wxSize(760, 490)); | ||||
|     SetSize(GetMinSize()); | ||||
|     wxGetApp().restore_window_pos(this, "main_frame"); | ||||
|     Show(); | ||||
|     Layout(); | ||||
| 
 | ||||
|     // declare events
 | ||||
|  | @ -88,7 +87,7 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL | |||
|             return; | ||||
|         } | ||||
|         // save window size
 | ||||
|         wxGetApp().save_window_pos(this, "main_frame"); | ||||
|         wxGetApp().window_pos_save(this, "mainframe"); | ||||
|         // Save the slic3r.ini.Usually the ini file is saved from "on idle" callback,
 | ||||
|         // but in rare cases it may not have been called yet.
 | ||||
|         wxGetApp().app_config->save(); | ||||
|  | @ -100,6 +99,17 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL | |||
|         event.Skip(); | ||||
|     }); | ||||
| 
 | ||||
|     // NB: Restoring the window position is done in a two-phase manner here,
 | ||||
|     // first the saved position is restored as-is and validation is done after the window is shown
 | ||||
|     // and initial round of events is complete, because on some platforms that is the only way
 | ||||
|     // to get an accurate window position & size.
 | ||||
|     wxGetApp().window_pos_restore(this, "mainframe"); | ||||
|     Bind(wxEVT_SHOW, [this](wxShowEvent&) { | ||||
|         CallAfter([this]() { | ||||
|             wxGetApp().window_pos_sanitize(this); | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     update_ui_from_settings(); | ||||
|     return; | ||||
| } | ||||
|  | @ -237,10 +247,8 @@ void MainFrame::init_menubar() | |||
|     // File menu
 | ||||
|     wxMenu* fileMenu = new wxMenu; | ||||
|     { | ||||
|         wxGetApp().append_menu_item(fileMenu, wxID_ANY, _(L("Open STL/OBJ/AMF/3MF…\tCtrl+O")), _(L("Open a model")),  | ||||
|             "", [](wxCommandEvent&){ | ||||
| //             if (m_plater) m_plater->add();
 | ||||
|         }); //'brick_add.png');
 | ||||
|         append_menu_item(fileMenu, wxID_ANY, _(L("Open STL/OBJ/AMF/3MF…\tCtrl+O")), _(L("Open a model")), | ||||
|                         [this](wxCommandEvent&) { if (m_plater) m_plater->add(); }, "brick_add.png"); | ||||
|         append_menu_item(fileMenu, wxID_ANY, _(L("&Load Config…\tCtrl+L")), _(L("Load exported configuration file")),  | ||||
|                         [this](wxCommandEvent&){ load_config_file(); }, "plugin_add.png"); | ||||
|         append_menu_item(fileMenu, wxID_ANY, _(L("&Export Config…\tCtrl+E")), _(L("Export current configuration to file")),  | ||||
|  | @ -285,19 +293,16 @@ void MainFrame::init_menubar() | |||
|     } | ||||
| 
 | ||||
|     // Plater menu
 | ||||
|     if(m_plater) { | ||||
|         auto plater_menu = new wxMenu(); | ||||
|         append_menu_item(plater_menu, wxID_ANY, L("Export G-code..."), L("Export current plate as G-code"),  | ||||
|     if (m_plater) { | ||||
|         m_plater_menu = new wxMenu(); | ||||
|         append_menu_item(m_plater_menu, wxID_ANY, _(L("Export G-code...")), _(L("Export current plate as G-code")), | ||||
|             [this](wxCommandEvent&){ /*m_plater->export_gcode(); */}, "cog_go.png"); | ||||
|         append_menu_item(plater_menu, wxID_ANY, L("Export plate as STL..."), L("Export current plate as STL"),  | ||||
|         append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as STL...")), _(L("Export current plate as STL")), | ||||
|             [this](wxCommandEvent&){ /*m_plater->export_stl(); */}, "brick_go.png"); | ||||
|         append_menu_item(plater_menu, wxID_ANY, L("Export plate as AMF..."), L("Export current plate as AMF"),  | ||||
|         append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as AMF...")), _(L("Export current plate as AMF")), | ||||
|             [this](wxCommandEvent&){ /*m_plater->export_amf();*/ }, "brick_go.png"); | ||||
|         append_menu_item(plater_menu, wxID_ANY, L("Export plate as 3MF..."), L("Export current plate as 3MF"),  | ||||
|         append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as 3MF...")), _(L("Export current plate as 3MF")), | ||||
|             [this](wxCommandEvent&){ /*m_plater->export_3mf(); */}, "brick_go.png"); | ||||
| 
 | ||||
| //         m_object_menu = m_plater->object_menu;
 | ||||
|         on_plater_selection_changed(false); | ||||
|     } | ||||
| 
 | ||||
|     // Window menu
 | ||||
|  | @ -323,23 +328,14 @@ void MainFrame::init_menubar() | |||
|     // View menu
 | ||||
|     if (m_plater) { | ||||
|         m_viewMenu = new wxMenu(); | ||||
| // \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators,
 | ||||
|         // as the simple numeric accelerators spoil all numeric data entry.
 | ||||
|         // The camera control accelerators are captured by 3DScene Perl module instead.
 | ||||
|         auto accel = [](const wxString& st1, const wxString& st2) { | ||||
| //             if ($^O eq "MSWin32")
 | ||||
| //                 return st1 + "\t\xA0" + st2;
 | ||||
| //             else
 | ||||
|                 return st1;  | ||||
|         }; | ||||
| 
 | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Iso")), "0"),     L("Iso View"),   [this](wxCommandEvent&){ select_view("iso"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Top")), "1"),     L("Top View"),   [this](wxCommandEvent&){ select_view("top"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Bottom")), "2"),  L("Bottom View"),[this](wxCommandEvent&){ select_view("bottom"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Front")), "3"),   L("Front View"), [this](wxCommandEvent&){ select_view("front"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Rear")), "4"),    L("Rear View"),  [this](wxCommandEvent&){ select_view("rear"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Left")), "5"),    L("Left View"),  [this](wxCommandEvent&){ select_view("left"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Right")), "6"),   L("Right View"), [this](wxCommandEvent&){ select_view("right"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, _(L("Iso\t0")), _(L("Iso View")), [this](wxCommandEvent&){ select_view("iso"); }); | ||||
|         m_viewMenu->AppendSeparator(); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, _(L("Top\t1")), _(L("Top View")), [this](wxCommandEvent&){ select_view("top"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, _(L("Bottom\t2")), _(L("Bottom View")), [this](wxCommandEvent&){ select_view("bottom"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, _(L("Front\t3")), _(L("Front View")), [this](wxCommandEvent&){ select_view("front"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, _(L("Rear\t4")), _(L("Rear View")), [this](wxCommandEvent&){ select_view("rear"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, _(L("Left\t5")), _(L("Left View")), [this](wxCommandEvent&){ select_view("left"); }); | ||||
|         append_menu_item(m_viewMenu, wxID_ANY, _(L("Right\t6")), _(L("Right View")), [this](wxCommandEvent&){ select_view("right"); }); | ||||
|     } | ||||
| 
 | ||||
|     // Help menu
 | ||||
|  | @ -375,7 +371,6 @@ void MainFrame::init_menubar() | |||
|         auto menubar = new wxMenuBar(); | ||||
|         menubar->Append(fileMenu, L("&File")); | ||||
|         if (m_plater_menu) menubar->Append(m_plater_menu, L("&Plater")) ; | ||||
|         if (m_object_menu) menubar->Append(m_object_menu, L("&Object")) ; | ||||
|         menubar->Append(windowMenu, L("&Window")); | ||||
|         if (m_viewMenu) menubar->Append(m_viewMenu, L("&View")); | ||||
|         // Add additional menus from C++
 | ||||
|  | @ -385,15 +380,6 @@ void MainFrame::init_menubar() | |||
|     } | ||||
| } | ||||
| 
 | ||||
| // Selection of a 3D object changed on the platter.
 | ||||
| void MainFrame::on_plater_selection_changed(const bool have_selection) | ||||
| { | ||||
|     if (!m_object_menu) return; | ||||
|      | ||||
|     for (auto item : m_object_menu->GetMenuItems()) | ||||
|         m_object_menu->Enable(item->GetId(), have_selection); | ||||
| } | ||||
| 
 | ||||
| void MainFrame::slice_to_png(){ | ||||
| //     m_plater->stop_background_process();
 | ||||
| //     m_plater->async_apply_config();
 | ||||
|  | @ -707,24 +693,8 @@ void MainFrame::select_tab(size_t tab) const | |||
| // Set a camera direction, zoom to all objects.
 | ||||
| void MainFrame::select_view(const std::string& direction) | ||||
| { | ||||
| //    if (m_plater)
 | ||||
| //        m_plater->select_view(direction);
 | ||||
| } | ||||
| 
 | ||||
| wxMenuItem* MainFrame::append_menu_item(wxMenu* menu,  | ||||
|                                         int id,  | ||||
|                                         const wxString& string, | ||||
|                                         const wxString& description, | ||||
|                                         std::function<void(wxCommandEvent& event)> cb,  | ||||
|                                         const std::string& icon /*= ""*/) | ||||
| { | ||||
|     if (id == wxID_ANY) | ||||
|         id = wxNewId(); | ||||
|     auto item = menu->Append(id, string, description); | ||||
|     if (!icon.empty()) | ||||
|         item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG)); | ||||
|     menu->Bind(wxEVT_MENU, /*[cb](wxCommandEvent& event){cb; }*/cb); | ||||
|     return item; | ||||
|      if (m_plater) | ||||
|          m_plater->select_view(direction); | ||||
| } | ||||
| 
 | ||||
| void MainFrame::on_presets_changed(SimpleEvent &event) | ||||
|  |  | |||
|  | @ -30,11 +30,11 @@ class Tab; | |||
| 
 | ||||
| enum QuickSlice | ||||
| { | ||||
|     qsUndef, | ||||
|     qsReslice, | ||||
|     qsSaveAs, | ||||
|     qsExportSVG, | ||||
|     qsExportPNG | ||||
|     qsUndef = 0, | ||||
|     qsReslice = 1, | ||||
|     qsSaveAs = 2, | ||||
|     qsExportSVG = 4, | ||||
|     qsExportPNG = 8 | ||||
| }; | ||||
| 
 | ||||
| struct PresetTab { | ||||
|  | @ -57,17 +57,9 @@ class MainFrame : public wxFrame | |||
|     AppController*                  m_appController { nullptr }; | ||||
|     std::map<std::string, Tab*>     m_options_tabs; | ||||
| 
 | ||||
|     wxMenuItem* append_menu_item(wxMenu* menu, | ||||
|                                  int id, | ||||
|                                  const wxString& string, | ||||
|                                  const wxString& description, | ||||
|                                  std::function<void(wxCommandEvent& event)> cb, | ||||
|                                  const std::string& icon = ""); | ||||
| 
 | ||||
|     wxMenuItem* m_menu_item_reslice_now { nullptr }; | ||||
|     wxMenu*     m_plater_menu { nullptr }; | ||||
|     wxMenu*     m_object_menu { nullptr }; | ||||
|     wxMenu*     m_viewMenu { nullptr }; | ||||
|     wxMenu*     m_viewMenu{ nullptr }; | ||||
| 
 | ||||
|     std::string     get_base_name(const wxString full_name) const ; | ||||
|     std::string     get_dir_name(const wxString full_name) const ; | ||||
|  | @ -93,7 +85,6 @@ public: | |||
|     bool        is_loaded() const { return m_loaded; } | ||||
|     bool        is_last_input_file() const  { return !m_qs_last_input_file.IsEmpty(); } | ||||
| 
 | ||||
|     void        on_plater_selection_changed(const bool have_selection); | ||||
|     void        slice_to_png(); | ||||
|     void        quick_slice(const int qs = qsUndef); | ||||
|     void        reslice_now(); | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ | |||
| #include "GUI_ObjectList.hpp" | ||||
| #include "GUI_ObjectManipulation.hpp" | ||||
| #include "GUI_Utils.hpp" | ||||
| #include "wxExtensions.hpp" | ||||
| #include "MainFrame.hpp" | ||||
| #include "3DScene.hpp" | ||||
| #include "GLCanvas3D.hpp" | ||||
|  | @ -673,7 +674,7 @@ std::vector<PresetComboBox*>& Sidebar::combos_filament() | |||
|     return p->combos_filament; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| // Plater::Object
 | ||||
| 
 | ||||
| struct PlaterObject | ||||
|  | @ -683,6 +684,7 @@ struct PlaterObject | |||
| 
 | ||||
|     PlaterObject(std::string name) : name(std::move(name)), selected(false) {} | ||||
| }; | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| // Plater::DropTarget
 | ||||
| 
 | ||||
|  | @ -727,12 +729,17 @@ struct Plater::priv | |||
|     Plater *q; | ||||
|     MainFrame *main_frame; | ||||
| 
 | ||||
|     // Object popup menu
 | ||||
|     wxMenu object_menu; | ||||
| 
 | ||||
|     // Data
 | ||||
|     Slic3r::DynamicPrintConfig *config; | ||||
|     Slic3r::Print print; | ||||
|     Slic3r::Model model; | ||||
|     Slic3r::GCodePreviewData gcode_preview_data; | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     std::vector<PlaterObject> objects; | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     fs::path export_gcode_output_file; | ||||
|     fs::path send_gcode_file; | ||||
|  | @ -755,6 +762,7 @@ struct Plater::priv | |||
|     std::vector<int> collect_selections(); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     void update(bool force_autocenter = false); | ||||
|     void select_view(const std::string& direction); | ||||
|     void update_ui_from_settings(); | ||||
|     ProgressStatusBar* statusbar(); | ||||
|     std::string get_config(const std::string &key) const; | ||||
|  | @ -764,9 +772,15 @@ struct Plater::priv | |||
|     std::vector<size_t> load_model_objects(const ModelObjectPtrs &model_objects); | ||||
|     std::unique_ptr<CheckboxFileDialog> get_export_file(GUI::FileType file_type); | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     const GLCanvas3D::Selection& get_selection() const; | ||||
|     GLCanvas3D::Selection& get_selection(); | ||||
|     int get_selected_object_idx() const; | ||||
| #else | ||||
|     void select_object(optional<size_t> obj_idx); | ||||
|     void select_object_from_cpp(); | ||||
|     optional<size_t> selected_object() const; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     void selection_changed(); | ||||
|     void object_list_changed(); | ||||
|     void select_view(); | ||||
|  | @ -797,20 +811,40 @@ struct Plater::priv | |||
|     void on_action_add(SimpleEvent&); | ||||
|     void on_action_split(SimpleEvent&); | ||||
|     void on_action_cut(SimpleEvent&); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     void on_action_settings(SimpleEvent&); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     void on_action_layersediting(SimpleEvent&); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     void on_action_selectbyparts(SimpleEvent&); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     void on_object_select(SimpleEvent&); | ||||
| #else | ||||
|     void on_object_select(ObjectSelectEvent&); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     void on_viewport_changed(SimpleEvent&); | ||||
|     void on_right_click(Vec2dEvent&); | ||||
|     void on_model_update(SimpleEvent&); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     void on_scale_uniformly(SimpleEvent&); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     void on_wipetower_moved(Vec3dEvent&); | ||||
|     void on_enable_action_buttons(Event<bool>&); | ||||
|     void on_update_geometry(Vec3dsEvent<2>&); | ||||
| 
 | ||||
| private: | ||||
|     bool init_object_menu(); | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     bool can_delete_object() const; | ||||
|     bool can_increase_instances() const; | ||||
|     bool can_decrease_instances() const; | ||||
|     bool can_split_object() const; | ||||
|     bool can_cut_object() const; | ||||
|     bool layers_height_allowed() const; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| }; | ||||
| 
 | ||||
| const std::regex Plater::priv::pattern_bundle("[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)$", std::regex::icase); | ||||
|  | @ -871,6 +905,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : | |||
|     hsizer->Add(sidebar, 0, wxEXPAND | wxLEFT | wxRIGHT, 0); | ||||
|     q->SetSizer(hsizer); | ||||
| 
 | ||||
|     init_object_menu(); | ||||
| 
 | ||||
|     // Events:
 | ||||
| 
 | ||||
|     // Notebook page change event
 | ||||
|  | @ -882,7 +918,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : | |||
|     // 3DScene events:
 | ||||
|     canvas3D->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_VIEWPORT_CHANGED, &priv::on_viewport_changed, this); | ||||
|     // canvas3D->Bind(EVT_GLCANVAS_DOUBLE_CLICK, [](SimpleEvent&) { });  // XXX: remove?
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     canvas3D->Bind(EVT_GLCANVAS_DOUBLE_CLICK, [](SimpleEvent&) {});  // XXX: remove?
 | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     canvas3D->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_MODEL_UPDATE, &priv::on_model_update, this); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [q](SimpleEvent&) { q->remove_selected(); }); | ||||
|  | @ -903,7 +941,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : | |||
|     canvas3D->Bind(EVT_GLTOOLBAR_FEWER, [q](SimpleEvent&) { q->decrease(); }); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_SPLIT, &priv::on_action_split, this); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_CUT, &priv::on_action_cut, this); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_SETTINGS, &priv::on_action_settings, this); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_SELECTBYPARTS, &priv::on_action_selectbyparts, this); | ||||
|  | @ -958,6 +998,19 @@ void Plater::priv::update(bool force_autocenter) | |||
|     schedule_background_process(); | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::select_view(const std::string& direction) | ||||
| { | ||||
|     int page_id = notebook->GetSelection(); | ||||
|     if (page_id != wxNOT_FOUND) | ||||
|     { | ||||
|         const wxString& page_text = notebook->GetPageText(page_id); | ||||
|         if (page_text == _(L("3D"))) | ||||
|             _3DScene::select_view(canvas3D, direction); | ||||
|         else if (page_text == _(L("Preview"))) | ||||
|             preview->select_view(direction); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::update_ui_from_settings() | ||||
| { | ||||
|     // TODO: (?)
 | ||||
|  | @ -1105,12 +1158,19 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode | |||
|     bool need_arrange = false; | ||||
|     bool scaled_down = false; | ||||
|     std::vector<size_t> obj_idxs; | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     unsigned int obj_count = 0; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     for (ModelObject *model_object : model_objects) { | ||||
|         auto *object = model.add_object(*model_object); | ||||
|         std::string object_name = object->name.empty() ? fs::path(object->input_file).filename().string() : object->name; | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         obj_idxs.push_back(obj_count++); | ||||
| #else | ||||
|         objects.emplace_back(std::move(object_name)); | ||||
|         obj_idxs.push_back(objects.size() - 1); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|         if (model_object->instances.empty()) { | ||||
|             // if object has no defined position(s) we need to rearrange everything after loading
 | ||||
|  | @ -1218,6 +1278,23 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType | |||
|     return dlg; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| const GLCanvas3D::Selection& Plater::priv::get_selection() const | ||||
| { | ||||
|     return _3DScene::get_canvas(canvas3D)->get_selection(); | ||||
| } | ||||
| 
 | ||||
| GLCanvas3D::Selection& Plater::priv::get_selection() | ||||
| { | ||||
|     return _3DScene::get_canvas(canvas3D)->get_selection(); | ||||
| } | ||||
| 
 | ||||
| int Plater::priv::get_selected_object_idx() const | ||||
| { | ||||
|     int idx = get_selection().get_object_idx(); | ||||
|     return ((0 <= idx) && (idx < 1000)) ? idx : -1; | ||||
| } | ||||
| #else | ||||
| void Plater::priv::select_object(optional<size_t> obj_idx) | ||||
| { | ||||
|     for (auto &obj : objects) { | ||||
|  | @ -1244,40 +1321,43 @@ optional<size_t> Plater::priv::selected_object() const | |||
| 
 | ||||
|     return boost::none; | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| void Plater::priv::selection_changed() | ||||
| { | ||||
|     // TODO
 | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     const auto obj_idx = selected_object(); | ||||
|     const bool have_sel = !!obj_idx; | ||||
|     const bool layers_height_allowed = config->opt<ConfigOptionBool>("variable_layer_height")->value; | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     wxWindowUpdateLocker freeze_guard(sidebar); | ||||
| 
 | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "delete", have_sel); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "more", have_sel); | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "delete", can_delete_object()); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "more", can_increase_instances()); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "fewer", can_decrease_instances()); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "split", can_split_object()); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "cut", can_cut_object()); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "layersediting", layers_height_allowed()); | ||||
| #else | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "fewer", have_sel); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "split", have_sel); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "cut", have_sel); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "settings", have_sel); | ||||
| 
 | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "layersediting", layers_height_allowed); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     bool have_sel = (obj_idx != -1); | ||||
| #else | ||||
|     bool can_select_by_parts = false; | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     if (have_sel) { | ||||
|         const auto *model_object = model.objects[*obj_idx]; | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|         // XXX: ?
 | ||||
|         can_select_by_parts = *obj_idx < 1000 && model_object->volumes.size() > 1; | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|         _3DScene::enable_toolbar_item(canvas3D, "fewer", model_object->instances.size() > 1); | ||||
|     } | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     if (can_select_by_parts) { | ||||
|         // first disable to let the item in the toolbar to switch to the unpressed state   // XXX: ?
 | ||||
|         _3DScene::enable_toolbar_item(canvas3D, "selectbyparts", false); | ||||
|  | @ -1286,15 +1366,19 @@ void Plater::priv::selection_changed() | |||
|         _3DScene::enable_toolbar_item(canvas3D, "selectbyparts", false); | ||||
|         _3DScene::set_select_by(canvas3D, "object"); | ||||
|     } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     wxWindowUpdateLocker freeze_guard(sidebar); | ||||
|     if (have_sel) { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         const ModelObject* model_object = model.objects[obj_idx]; | ||||
| #else | ||||
|         const auto *model_object = model.objects[*obj_idx]; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|         // FIXME print_info runs model fixing in two rounds, it is very slow, it should not be performed here!
 | ||||
|         // # $model_object->print_info;
 | ||||
| 
 | ||||
|         // my $model_instance = $model_object->instances->[0];
 | ||||
|         const auto *model_instance = model_object->instances[0]; | ||||
|         const ModelInstance* model_instance = !model_object->instances.empty() ? model_object->instances.front() : nullptr; | ||||
|         // TODO
 | ||||
|         // $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", @{$model_object->instance_bounding_box(0)->size}));
 | ||||
|         // $self->{object_info_materials}->SetLabel($model_object->materials_count);
 | ||||
|  | @ -1336,7 +1420,11 @@ void Plater::priv::selection_changed() | |||
| void Plater::priv::object_list_changed() | ||||
| { | ||||
|     // Enable/disable buttons depending on whether there are any objects on the platter.
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     const bool have_objects = !model.objects.empty(); | ||||
| #else | ||||
|     const bool have_objects = !objects.empty(); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "deleteall", have_objects); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "arrange", have_objects); | ||||
|  | @ -1360,7 +1448,9 @@ void Plater::priv::remove(size_t obj_idx) | |||
|     // Prevent toolpaths preview from rendering while we modify the Print object
 | ||||
|     preview->set_enabled(false); | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     objects.erase(objects.begin() + obj_idx); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     model.delete_object(obj_idx); | ||||
|     print.delete_object(obj_idx); | ||||
|     // Delete object from Sidebar list
 | ||||
|  | @ -1368,7 +1458,9 @@ void Plater::priv::remove(size_t obj_idx) | |||
| 
 | ||||
|     object_list_changed(); | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     select_object(boost::none); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     update(); | ||||
| } | ||||
| 
 | ||||
|  | @ -1379,7 +1471,9 @@ void Plater::priv::reset() | |||
|     // Prevent toolpaths preview from rendering while we modify the Print object
 | ||||
|     preview->set_enabled(false); | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     objects.clear(); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     model.clear_objects(); | ||||
|     print.clear_objects(); | ||||
| 
 | ||||
|  | @ -1387,7 +1481,9 @@ void Plater::priv::reset() | |||
|     sidebar->obj_list()->delete_all_objects_from_list(); | ||||
|     object_list_changed(); | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     select_object(boost::none); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     update(); | ||||
| } | ||||
| 
 | ||||
|  | @ -1398,11 +1494,20 @@ void Plater::priv::rotate() | |||
| 
 | ||||
| void Plater::priv::mirror(const Axis &axis) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     if (obj_idx == -1) | ||||
|         return; | ||||
| 
 | ||||
|     ModelObject* model_object = model.objects[obj_idx]; | ||||
|     ModelInstance* model_instance = model_object->instances.front(); | ||||
| #else | ||||
|     const auto obj_idx = selected_object(); | ||||
|     if (! obj_idx) { return; } | ||||
| 
 | ||||
|     auto *model_object = model.objects[*obj_idx]; | ||||
|     auto *model_instance = model_object->instances[0]; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     // XXX: ?
 | ||||
|     // # apply Z rotation before mirroring
 | ||||
|  | @ -1414,7 +1519,11 @@ void Plater::priv::mirror(const Axis &axis) | |||
|     model_object->mirror(axis); | ||||
| 
 | ||||
|     // $self->stop_background_process;  // TODO
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     print.add_model_object(model_object, obj_idx); | ||||
| #else | ||||
|     print.add_model_object(model_object, *obj_idx); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     selection_changed(); | ||||
|     update(); | ||||
| } | ||||
|  | @ -1595,14 +1704,8 @@ void Plater::priv::on_layer_editing_toggled(bool enable) | |||
| 
 | ||||
| void Plater::priv::on_action_add(SimpleEvent&) | ||||
| { | ||||
|     wxArrayString input_files; | ||||
|     wxGetApp().open_model(q, input_files); | ||||
| 
 | ||||
|     std::vector<fs::path> input_paths; | ||||
|     for (const auto &file : input_files) { | ||||
|         input_paths.push_back(file.wx_str()); | ||||
|     } | ||||
|     load_files(input_paths); | ||||
|     if (q != nullptr) | ||||
|         q->add(); | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::on_action_split(SimpleEvent&) | ||||
|  | @ -1615,10 +1718,12 @@ void Plater::priv::on_action_cut(SimpleEvent&) | |||
|     // TODO
 | ||||
| } | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| void Plater::priv::on_action_settings(SimpleEvent&) | ||||
| { | ||||
|     // TODO
 | ||||
| } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| void Plater::priv::on_action_layersediting(SimpleEvent&) | ||||
| { | ||||
|  | @ -1632,6 +1737,14 @@ void Plater::priv::on_action_selectbyparts(SimpleEvent&) | |||
| } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| void Plater::priv::on_object_select(SimpleEvent& evt) | ||||
| { | ||||
|     selection_changed(); | ||||
|     item_changed_selection(); | ||||
|     wxGetApp().obj_list()->update_selections(); | ||||
| } | ||||
| #else | ||||
| void Plater::priv::on_object_select(ObjectSelectEvent &evt) | ||||
| { | ||||
|     const auto obj_idx = evt.object_id(); | ||||
|  | @ -1642,10 +1755,8 @@ void Plater::priv::on_object_select(ObjectSelectEvent &evt) | |||
|         select_object(obj_idx); | ||||
|         item_changed_selection(); | ||||
|     } | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     wxGetApp().obj_list()->update_selections(); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| void Plater::priv::on_viewport_changed(SimpleEvent& evt) | ||||
| { | ||||
|  | @ -1656,9 +1767,18 @@ void Plater::priv::on_viewport_changed(SimpleEvent& evt) | |||
|         preview->set_viewport_from_scene(canvas3D); | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::on_right_click(Vec2dEvent&) | ||||
| void Plater::priv::on_right_click(Vec2dEvent& evt) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     if (obj_idx == -1) | ||||
|         return; | ||||
| 
 | ||||
|     if (q != nullptr) | ||||
|         q->PopupMenu(&object_menu, (int)evt.data.x(), (int)evt.data.y()); | ||||
| #else | ||||
|     // TODO
 | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::on_model_update(SimpleEvent&) | ||||
|  | @ -1666,6 +1786,7 @@ void Plater::priv::on_model_update(SimpleEvent&) | |||
|     // TODO
 | ||||
| } | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| void Plater::priv::on_scale_uniformly(SimpleEvent&) | ||||
| { | ||||
| //     my ($scale) = @_;
 | ||||
|  | @ -1701,6 +1822,7 @@ void Plater::priv::on_scale_uniformly(SimpleEvent&) | |||
|      | ||||
|     this->schedule_background_process(); | ||||
| } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| void Plater::priv::on_wipetower_moved(Vec3dEvent &evt) | ||||
| { | ||||
|  | @ -1720,6 +1842,64 @@ void Plater::priv::on_update_geometry(Vec3dsEvent<2>&) | |||
|     // TODO
 | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::init_object_menu() | ||||
| { | ||||
|     wxMenuItem* item_delete = append_menu_item(&object_menu, wxID_ANY, _(L("Delete\tDel")), _(L("Remove the selected object")), | ||||
|         [this](wxCommandEvent&){ q->remove_selected(); }, "brick_delete.png"); | ||||
|     wxMenuItem* item_increase = append_menu_item(&object_menu, wxID_ANY, _(L("Increase copies\t+")), _(L("Place one more copy of the selected object")), | ||||
|         [this](wxCommandEvent&){ q->increase(); }, "add.png"); | ||||
|     wxMenuItem* item_decrease = append_menu_item(&object_menu, wxID_ANY, _(L("Decrease copies\t-")), _(L("Remove one copy of the selected object")), | ||||
|         [this](wxCommandEvent&){ q->decrease(); }, "delete.png"); | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     // ui updates needs to be binded to the parent panel
 | ||||
|     if (q != nullptr) | ||||
|     { | ||||
|         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete_object()); }, item_delete->GetId()); | ||||
|         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_increase_instances()); }, item_increase->GetId()); | ||||
|         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_decrease_instances()); }, item_decrease->GetId()); | ||||
|     } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| bool Plater::priv::can_delete_object() const | ||||
| { | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()); | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::can_increase_instances() const | ||||
| { | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()); | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::can_decrease_instances() const | ||||
| { | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1); | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::can_split_object() const | ||||
| { | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()); | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::can_cut_object() const | ||||
| { | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()); | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::layers_height_allowed() const | ||||
| { | ||||
|     return config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D); | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| // Plater / Public
 | ||||
| 
 | ||||
|  | @ -1738,37 +1918,75 @@ Sidebar& Plater::sidebar() { return *p->sidebar; } | |||
| Model& Plater::model()  { return p->model; } | ||||
| Print& Plater::print()  { return p->print; } | ||||
| 
 | ||||
| void Plater::add() | ||||
| { | ||||
|     wxArrayString input_files; | ||||
|     wxGetApp().open_model(this, input_files); | ||||
| 
 | ||||
|     std::vector<fs::path> input_paths; | ||||
|     for (const auto &file : input_files) { | ||||
|         input_paths.push_back(file.wx_str()); | ||||
|     } | ||||
|     load_files(input_paths); | ||||
| } | ||||
| 
 | ||||
| void Plater::load_files(const std::vector<fs::path> &input_files) { p->load_files(input_files); } | ||||
| 
 | ||||
| void Plater::update(bool force_autocenter) { p->update(force_autocenter); } | ||||
| 
 | ||||
| void Plater::select_view(const std::string& direction) { p->select_view(direction); } | ||||
| 
 | ||||
| void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } | ||||
| 
 | ||||
| void Plater::remove_selected() | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = p->get_selected_object_idx(); | ||||
|     if (obj_idx != -1) | ||||
|         remove((size_t)obj_idx); | ||||
| #else | ||||
|     const auto selected = p->selected_object(); | ||||
|     if (selected) { | ||||
|         remove(*selected); | ||||
|     } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| } | ||||
| 
 | ||||
| void Plater::increase(size_t num) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = p->get_selected_object_idx(); | ||||
|     if (obj_idx == -1) | ||||
|         return; | ||||
| 
 | ||||
|     ModelObject* model_object = p->model.objects[obj_idx]; | ||||
|     ModelInstance* model_instance = model_object->instances.back(); | ||||
| #else | ||||
|     const auto obj_idx = p->selected_object(); | ||||
|     if (! obj_idx) { return; } | ||||
| 
 | ||||
|     auto *model_object = p->model.objects[*obj_idx]; | ||||
|     auto *model_instance = model_object->instances[model_object->instances.size() - 1]; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     // $self->stop_background_process;
 | ||||
| 
 | ||||
|     float offset = 10.0; | ||||
|     for (size_t i = 0; i < num; i++, offset += 10.0) { | ||||
|         Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0); | ||||
|         auto *new_instance = model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation()); | ||||
|         model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation()); | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); | ||||
| #else | ||||
|         p->print.get_object(*obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     } | ||||
| 
 | ||||
|     sidebar().obj_list()->set_object_count(*obj_idx, model_object->instances.size()); | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     sidebar().obj_list()->increase_object_instances(obj_idx, num); | ||||
| #else | ||||
|     sidebar().obj_list()->increase_object_instances(*obj_idx, num); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     if (p->get_config("autocenter") == "1") { | ||||
|         p->arrange(); | ||||
|  | @ -1783,31 +2001,63 @@ void Plater::increase(size_t num) | |||
| 
 | ||||
| void Plater::decrease(size_t num) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = p->get_selected_object_idx(); | ||||
|     if (obj_idx == -1) | ||||
|         return; | ||||
| 
 | ||||
|     ModelObject* model_object = p->model.objects[obj_idx]; | ||||
| #else | ||||
|     const auto obj_idx = p->selected_object(); | ||||
|     if (! obj_idx) { return; } | ||||
| 
 | ||||
|     auto *model_object = p->model.objects[*obj_idx]; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     if (model_object->instances.size() > num) { | ||||
|         for (size_t i = 0; i < num; i++) { | ||||
|             model_object->delete_last_instance(); | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             p->print.get_object(obj_idx)->delete_last_copy(); | ||||
| #else | ||||
|             p->print.get_object(*obj_idx)->delete_last_copy(); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|         } | ||||
|         sidebar().obj_list()->set_object_count(*obj_idx, model_object->instances.size()); | ||||
|     } else { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         sidebar().obj_list()->decrease_object_instances(obj_idx, num); | ||||
| #else | ||||
|         sidebar().obj_list()->decrease_object_instances(*obj_idx, num); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     } | ||||
|     else { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         remove(obj_idx); | ||||
| #else | ||||
|         remove(*obj_idx); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     } | ||||
| 
 | ||||
|     p->update(); | ||||
|     p->selection_changed(); | ||||
| 
 | ||||
|     // $self->schedule_background_process;
 | ||||
| } | ||||
| 
 | ||||
| void Plater::set_number_of_copies(size_t num) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = p->get_selected_object_idx(); | ||||
|     if (obj_idx == -1) | ||||
|         return; | ||||
| 
 | ||||
|     ModelObject* model_object = p->model.objects[obj_idx]; | ||||
| #else | ||||
|     const auto obj_idx = p->selected_object(); | ||||
|     if (! obj_idx) { return; } | ||||
| 
 | ||||
|     auto *model_object = p->model.objects[*obj_idx]; | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     auto diff = (ptrdiff_t)num - (ptrdiff_t)model_object->instances.size(); | ||||
|     int diff = (int)num - (int)model_object->instances.size(); | ||||
|     if (diff > 0) { | ||||
|         increase(diff); | ||||
|     } else if (diff < 0) { | ||||
|  | @ -1817,7 +2067,11 @@ void Plater::set_number_of_copies(size_t num) | |||
| 
 | ||||
| fs::path Plater::export_gcode(const fs::path &output_path) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     if (p->model.objects.empty()) { return ""; } | ||||
| #else | ||||
|     if (p->objects.empty()) { return ""; } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     if (! p->export_gcode_output_file.empty()) { | ||||
|         GUI::show_error(this, _(L("Another export job is currently running."))); | ||||
|  | @ -1870,7 +2124,11 @@ fs::path Plater::export_gcode(const fs::path &output_path) | |||
| 
 | ||||
| void Plater::export_stl() | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| #else | ||||
|     if (p->objects.empty()) { return; } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     auto dialog = p->get_export_file(FT_STL); | ||||
|     if (! dialog) { return; } | ||||
|  | @ -1885,7 +2143,11 @@ void Plater::export_stl() | |||
| 
 | ||||
| void Plater::export_amf() | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| #else | ||||
|     if (p->objects.empty()) { return; } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     auto dialog = p->get_export_file(FT_AMF); | ||||
|     if (! dialog) { return; } | ||||
|  | @ -1904,7 +2166,11 @@ void Plater::export_amf() | |||
| 
 | ||||
| void Plater::export_3mf() | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| #else | ||||
|     if (p->objects.empty()) { return; } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     auto dialog = p->get_export_file(FT_3MF); | ||||
|     if (! dialog) { return; } | ||||
|  | @ -2039,6 +2305,7 @@ void Plater::changed_object_settings(int obj_idx) | |||
|         _3DScene::set_objects_selections(p->canvas3D, selections); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|         _3DScene::reload_scene(p->canvas3D, false); | ||||
|         _3DScene::zoom_to_volumes(p->canvas3D); | ||||
|     } | ||||
|     else { | ||||
|         this->p->schedule_background_process(); | ||||
|  |  | |||
|  | @ -104,9 +104,13 @@ public: | |||
|     Model& model(); | ||||
|     Print& print(); | ||||
| 
 | ||||
|     void add(); | ||||
| 
 | ||||
|     void load_files(const std::vector<boost::filesystem::path> &input_files); | ||||
| 
 | ||||
|     void update(bool force_autocenter = false); | ||||
|     void select_view(const std::string& direction); | ||||
| 
 | ||||
|     void remove(size_t obj_idx); | ||||
|     void remove_selected(); | ||||
|     void increase(size_t num = 1); | ||||
|  |  | |||
|  | @ -476,6 +476,8 @@ void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool | |||
| void Tab::update_changed_tree_ui() | ||||
| { | ||||
| 	auto cur_item = m_treectrl->GetFirstVisibleItem(); | ||||
|     if (!m_treectrl->IsVisible(cur_item)) | ||||
|         return; | ||||
| 	auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); | ||||
| 	while (cur_item){ | ||||
| 		auto title = m_treectrl->GetItemText(cur_item); | ||||
|  | @ -1843,7 +1845,7 @@ void TabPrinter::extruders_count_changed(size_t extruders_count){ | |||
|     if (!wxGetApp().mainframe) | ||||
|         return; | ||||
| 	on_value_change("extruders_count", extruders_count); | ||||
|     wxGetApp().mainframe->m_plater->sidebar().update_objects_list_extruder_column(extruders_count); | ||||
|     wxGetApp().sidebar().update_objects_list_extruder_column(extruders_count); | ||||
| } | ||||
| 
 | ||||
| void TabPrinter::append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key) | ||||
|  |  | |||
|  | @ -10,6 +10,20 @@ | |||
| #include "GUI_App.hpp" | ||||
| #include "GUI_ObjectList.hpp" | ||||
| 
 | ||||
| wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, | ||||
|     std::function<void(wxCommandEvent& event)> cb, const std::string& icon) | ||||
| { | ||||
|     if (id == wxID_ANY) | ||||
|         id = wxNewId(); | ||||
| 
 | ||||
|     wxMenuItem* item = menu->Append(id, string, description); | ||||
|     if (!icon.empty()) | ||||
|         item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG)); | ||||
| 
 | ||||
|     menu->Bind(wxEVT_MENU, cb, id); | ||||
|     return item; | ||||
| } | ||||
| 
 | ||||
| const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200; | ||||
| const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200; | ||||
| const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18; | ||||
|  | @ -362,12 +376,13 @@ void  PrusaObjectDataViewModelNode::set_part_action_icon() { | |||
| Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr; | ||||
| bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std::string>& categories) | ||||
| { | ||||
|     if (m_type != "settings" || m_opt_categories == categories) | ||||
|     if (m_type != itSettings || m_opt_categories == categories) | ||||
|         return false; | ||||
| 
 | ||||
|     m_opt_categories = categories; | ||||
|     m_name = wxEmptyString; | ||||
|     m_icon = m_empty_icon; | ||||
| //     m_icon = m_empty_icon;
 | ||||
|     m_bmp = m_empty_bmp; | ||||
| 
 | ||||
|     std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;//Slic3r::GUI::get_category_icon();
 | ||||
| 
 | ||||
|  | @ -417,18 +432,7 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name) | |||
| 	return child; | ||||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name, const int instances_count/*, int scale*/) | ||||
| { | ||||
| 	auto root = new PrusaObjectDataViewModelNode(name, instances_count); | ||||
| 	m_objects.push_back(root); | ||||
| 	// notify control
 | ||||
| 	wxDataViewItem child((void*)root); | ||||
| 	wxDataViewItem parent((void*)NULL); | ||||
| 	ItemAdded(parent, child); | ||||
| 	return child; | ||||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_item, | ||||
| wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &parent_item, | ||||
| 													const wxString &name, | ||||
|                                                     const wxBitmap& icon, | ||||
|                                                     const int extruder/* = 0*/, | ||||
|  | @ -439,25 +443,25 @@ wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_ | |||
| 
 | ||||
|     const wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder); | ||||
| 
 | ||||
|     if (create_frst_child && (root->GetChildren().Count() == 0 ||  | ||||
|                              (root->GetChildren().Count() == 1 && root->GetNthChild(0)->m_type == "settings"))) | ||||
|     if (create_frst_child && root->m_volumes_cnt == 0) | ||||
| 	{ | ||||
| 		const auto icon_solid_mesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG); | ||||
| 		const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, icon_solid_mesh, extruder_str, 0); | ||||
| 		const auto bmp_solid_mesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG); | ||||
| 		const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, bmp_solid_mesh, extruder_str, 0); | ||||
| 		root->Append(node); | ||||
| 		// notify control
 | ||||
| 		const wxDataViewItem child((void*)node); | ||||
| 		ItemAdded(parent_item, child); | ||||
| 
 | ||||
|         root->m_volumes_cnt++; | ||||
| 	} | ||||
| 
 | ||||
|     const auto volume_id =  root->GetChildCount() > 0 && root->GetNthChild(0)->m_type == "settings" ? | ||||
|                             root->GetChildCount() - 1 : root->GetChildCount(); | ||||
| 
 | ||||
| 	const auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, volume_id); | ||||
|     const auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, root->m_volumes_cnt); | ||||
| 	root->Append(node); | ||||
| 	// notify control
 | ||||
| 	const wxDataViewItem child((void*)node); | ||||
| 	ItemAdded(parent_item, child); | ||||
|     ItemAdded(parent_item, child); | ||||
|     root->m_volumes_cnt++; | ||||
| 
 | ||||
| 	return child; | ||||
| } | ||||
| 
 | ||||
|  | @ -466,7 +470,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddSettingsChild(const wxDataViewItem & | |||
|     PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID(); | ||||
|     if (!root) return wxDataViewItem(0); | ||||
| 
 | ||||
|     const auto node = new PrusaObjectDataViewModelNode(root); | ||||
|     const auto node = new PrusaObjectDataViewModelNode(root, itSettings); | ||||
|     root->Insert(node, 0); | ||||
|     // notify control
 | ||||
|     const wxDataViewItem child((void*)node); | ||||
|  | @ -474,6 +478,55 @@ wxDataViewItem PrusaObjectDataViewModel::AddSettingsChild(const wxDataViewItem & | |||
|     return child; | ||||
| } | ||||
| 
 | ||||
| int get_istances_root_idx(PrusaObjectDataViewModelNode *parent_node) | ||||
| { | ||||
|     int inst_root_id = -1; | ||||
|     int stop_search_i = parent_node->GetChildCount(); | ||||
|     if (stop_search_i > 2) stop_search_i = 2; | ||||
|     for (int i = 0; i < stop_search_i; ++i) | ||||
|         if (parent_node->GetNthChild(i)->m_type & itInstanceRoot) { | ||||
|             inst_root_id = i; | ||||
|             break; | ||||
|         } | ||||
|     return inst_root_id; | ||||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num) | ||||
| { | ||||
|     PrusaObjectDataViewModelNode *parent_node = (PrusaObjectDataViewModelNode*)parent_item.GetID(); | ||||
|     if (!parent_node) return wxDataViewItem(0); | ||||
| 
 | ||||
|     // Check and create/get instances root node
 | ||||
|     const int inst_root_id = get_istances_root_idx(parent_node); | ||||
| 
 | ||||
|     PrusaObjectDataViewModelNode *inst_root_node = inst_root_id < 0 ?  | ||||
|                                                    new PrusaObjectDataViewModelNode(parent_node, itInstanceRoot) : | ||||
|                                                    parent_node->GetNthChild(inst_root_id); | ||||
|     const wxDataViewItem inst_root_item((void*)inst_root_node); | ||||
| 
 | ||||
|     if (inst_root_id < 0) { | ||||
|         const unsigned insert_pos = parent_node->GetChildCount() == 0 || parent_node->GetNthChild(0)->m_type != itSettings ? 0 : 1; | ||||
|         parent_node->Insert(inst_root_node, insert_pos); | ||||
|         // notify control
 | ||||
|         ItemAdded(parent_item, inst_root_item); | ||||
|         num++; | ||||
|     } | ||||
| 
 | ||||
|     // Add instance nodes
 | ||||
|     PrusaObjectDataViewModelNode *instance_node = nullptr;     | ||||
|     size_t counter = 0; | ||||
|     while (counter < num){ | ||||
|         instance_node = new PrusaObjectDataViewModelNode(inst_root_node, itInstance); | ||||
|         inst_root_node->Append(instance_node); | ||||
|         // notify control
 | ||||
|         const wxDataViewItem instance_item((void*)instance_node); | ||||
|         ItemAdded(inst_root_item, instance_item); | ||||
|         ++counter; | ||||
|     } | ||||
| 
 | ||||
|     return wxDataViewItem((void*)instance_node); | ||||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item) | ||||
| { | ||||
| 	auto ret_item = wxDataViewItem(0); | ||||
|  | @ -489,21 +542,45 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item) | |||
| 	//       thus removing the node from it doesn't result in freeing it
 | ||||
| 	if (node_parent){ | ||||
| 		auto id = node_parent->GetChildren().Index(node); | ||||
| 		auto v_id = node->GetVolumeId(); | ||||
|         auto idx = node->GetIdx(); | ||||
| 		node_parent->GetChildren().Remove(node); | ||||
| 		if (id > 0){  | ||||
| 			if(id == node_parent->GetChildCount()) id--; | ||||
| 			ret_item = wxDataViewItem(node_parent->GetChildren().Item(id)); | ||||
| 		} | ||||
| 
 | ||||
| 		//update volume_id value for remaining child-nodes
 | ||||
| 		//update idx value for remaining child-nodes
 | ||||
| 		auto children = node_parent->GetChildren(); | ||||
|         for (size_t i = 0; i < node_parent->GetChildCount() && v_id>=0; i++) | ||||
|         for (size_t i = 0; i < node_parent->GetChildCount() && idx>=0; i++) | ||||
| 		{ | ||||
| 			auto volume_id = children[i]->GetVolumeId(); | ||||
| 			if (volume_id > v_id) | ||||
| 				children[i]->SetVolumeId(volume_id-1); | ||||
|             auto cur_idx = children[i]->GetIdx(); | ||||
| 			if (cur_idx > idx) | ||||
| 				children[i]->SetIdx(cur_idx-1); | ||||
| 		} | ||||
| 
 | ||||
|         // if there is last instance item, delete both of it and instance root item
 | ||||
|         if (node_parent->GetChildCount() == 1 && node_parent->GetNthChild(0)->m_type == itInstance) | ||||
|         { | ||||
|             delete node; | ||||
|             ItemDeleted(parent, item); | ||||
| 
 | ||||
|             PrusaObjectDataViewModelNode *last_instance_node = node_parent->GetNthChild(0); | ||||
|             node_parent->GetChildren().Remove(last_instance_node); | ||||
|             delete last_instance_node; | ||||
|             ItemDeleted(parent, wxDataViewItem(last_instance_node)); | ||||
| 
 | ||||
|             PrusaObjectDataViewModelNode *obj_node = node_parent->GetParent(); | ||||
|             obj_node->GetChildren().Remove(node_parent); | ||||
|             delete node_parent; | ||||
|             ret_item = wxDataViewItem(obj_node); | ||||
|             ItemDeleted(ret_item, wxDataViewItem(node_parent)); | ||||
| 
 | ||||
| #ifndef __WXGTK__ | ||||
|             if (obj_node->GetChildCount() == 0) | ||||
|                 obj_node->m_container = false; | ||||
| #endif //__WXGTK__
 | ||||
|             return ret_item; | ||||
|         } | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
|  | @ -533,6 +610,54 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item) | |||
| 	return ret_item; | ||||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &parent_item, size_t num) | ||||
| { | ||||
|     auto ret_item = wxDataViewItem(0); | ||||
|     PrusaObjectDataViewModelNode *parent_node = (PrusaObjectDataViewModelNode*)parent_item.GetID(); | ||||
|     if (!parent_node) return ret_item; | ||||
| 
 | ||||
|     const int inst_root_id = get_istances_root_idx(parent_node); | ||||
|     if (inst_root_id < 0) return ret_item; | ||||
| 
 | ||||
|     wxDataViewItemArray items; | ||||
|     PrusaObjectDataViewModelNode *inst_root_node = parent_node->GetNthChild(inst_root_id); | ||||
|     const wxDataViewItem inst_root_item((void*)inst_root_node); | ||||
| 
 | ||||
|     const int inst_cnt = inst_root_node->GetChildCount(); | ||||
|     const bool delete_inst_root_item = inst_cnt - num < 2 ? true : false; | ||||
| 
 | ||||
|     int stop = delete_inst_root_item ? 0 : inst_cnt - num; | ||||
|     for (int i = inst_cnt - 1; i >= stop;--i) { | ||||
|         PrusaObjectDataViewModelNode *last_instance_node = inst_root_node->GetNthChild(i); | ||||
|         inst_root_node->GetChildren().Remove(last_instance_node); | ||||
|         delete last_instance_node; | ||||
|         ItemDeleted(inst_root_item, wxDataViewItem(last_instance_node)); | ||||
|     } | ||||
| 
 | ||||
| //     for (int i = delete_inst_root_item ? 0 : inst_cnt - num; i < inst_cnt; ++i)
 | ||||
| //         items.Add(wxDataViewItem(inst_root_node->GetNthChild(i)));
 | ||||
| // 
 | ||||
| //     if (delete_inst_root_item)
 | ||||
| //         inst_root_node->GetChildren().RemoveAt(0, inst_cnt);
 | ||||
| //     else {
 | ||||
| //         ret_item = wxDataViewItem(inst_root_node->GetNthChild(inst_cnt - num - 1));
 | ||||
| //         inst_root_node->GetChildren().RemoveAt(inst_cnt - num, num);
 | ||||
| //     }
 | ||||
| 
 | ||||
| //     ItemsDeleted(inst_root_item, items);
 | ||||
|     if (delete_inst_root_item) { | ||||
|         ret_item = parent_item; | ||||
|         parent_node->GetChildren().Remove(inst_root_node); | ||||
|         ItemDeleted(parent_item, inst_root_item); | ||||
| #ifndef __WXGTK__ | ||||
|         if (parent_node->GetChildCount() == 0) | ||||
|             parent_node->m_container = false; | ||||
| #endif //__WXGTK__
 | ||||
|     } | ||||
| 
 | ||||
|     return ret_item; | ||||
| } | ||||
| 
 | ||||
| void PrusaObjectDataViewModel::DeleteAll() | ||||
| { | ||||
| 	while (!m_objects.empty()) | ||||
|  | @ -592,7 +717,7 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volu | |||
| 
 | ||||
|     auto parent = m_objects[obj_idx]; | ||||
|     if (parent->GetChildCount() == 0 || | ||||
|         (parent->GetChildCount() == 1 && parent->GetNthChild(0)->m_volume_id == -2)) { | ||||
|         (parent->GetChildCount() == 1 && parent->GetNthChild(0)->GetType() & itSettings )) { | ||||
|         if (volume_idx == 0) | ||||
|             return GetItemById(obj_idx); | ||||
| 
 | ||||
|  | @ -601,13 +726,13 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volu | |||
|     } | ||||
| 
 | ||||
|     for (size_t i = 0; i < parent->GetChildCount(); i++) | ||||
|         if (parent->GetNthChild(i)->m_volume_id == volume_idx) | ||||
|         if (parent->GetNthChild(i)->m_idx == volume_idx && parent->GetNthChild(0)->GetType() & itVolume) | ||||
|             return wxDataViewItem(parent->GetNthChild(i)); | ||||
| 
 | ||||
|     return wxDataViewItem(0); | ||||
| } | ||||
| 
 | ||||
| int PrusaObjectDataViewModel::GetIdByItem(wxDataViewItem& item) | ||||
| int PrusaObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) | ||||
| { | ||||
| 	wxASSERT(item.IsOk()); | ||||
| 
 | ||||
|  | @ -619,31 +744,49 @@ int PrusaObjectDataViewModel::GetIdByItem(wxDataViewItem& item) | |||
| 	return it - m_objects.begin(); | ||||
| } | ||||
| 
 | ||||
| int PrusaObjectDataViewModel::GetVolumeIdByItem(const wxDataViewItem& item) | ||||
| int PrusaObjectDataViewModel::GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const | ||||
| { | ||||
| 	wxASSERT(item.IsOk()); | ||||
| 
 | ||||
| 	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
| 	if (!node)      // happens if item.IsOk()==false
 | ||||
| 	if (!node || node->m_type != type) | ||||
| 		return -1; | ||||
| 	return node->GetVolumeId(); | ||||
| 	return node->GetIdx(); | ||||
| } | ||||
| 
 | ||||
| void PrusaObjectDataViewModel::GetObjectAndVolumeIdsByItem(const wxDataViewItem& item, int& obj_idx, int& vol_idx) | ||||
| int PrusaObjectDataViewModel::GetVolumeIdByItem(const wxDataViewItem& item) const | ||||
| { | ||||
|     return GetIdByItemAndType(item, itVolume); | ||||
| } | ||||
| 
 | ||||
| int PrusaObjectDataViewModel::GetInstanceIdByItem(const wxDataViewItem& item) const  | ||||
| { | ||||
|     return GetIdByItemAndType(item, itInstance); | ||||
| } | ||||
| 
 | ||||
| void PrusaObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx) | ||||
| { | ||||
|     wxASSERT(item.IsOk()); | ||||
|     obj_idx = vol_idx = -1; | ||||
|     type = itUndef; | ||||
| 
 | ||||
|     PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
|     if (!node) return; | ||||
|     vol_idx = node->GetVolumeId(); | ||||
|     if (!node || node->GetIdx() < 0 && node->GetType() != itObject)  | ||||
|         return; | ||||
| 
 | ||||
|     idx = node->GetIdx(); | ||||
|     type = node->GetType(); | ||||
| 
 | ||||
|     PrusaObjectDataViewModelNode *parent_node = node->GetParent(); | ||||
|     if (!parent_node) return; | ||||
|     if (type == itInstance) | ||||
|         parent_node = node->GetParent()->GetParent(); | ||||
|     if (!parent_node || parent_node->m_type != itObject) { type = itUndef; return; } | ||||
| 
 | ||||
|     auto it = find(m_objects.begin(), m_objects.end(), parent_node); | ||||
|     if (it != m_objects.end()) | ||||
|         obj_idx = it - m_objects.begin(); | ||||
|     else | ||||
|         type = itUndef; | ||||
| } | ||||
| 
 | ||||
| wxString PrusaObjectDataViewModel::GetName(const wxDataViewItem &item) const | ||||
|  | @ -655,21 +798,6 @@ wxString PrusaObjectDataViewModel::GetName(const wxDataViewItem &item) const | |||
| 	return node->m_name; | ||||
| } | ||||
| 
 | ||||
| wxString PrusaObjectDataViewModel::GetCopy(const wxDataViewItem &item) const | ||||
| { | ||||
| 	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
| 	if (!node)      // happens if item.IsOk()==false
 | ||||
| 		return wxEmptyString; | ||||
| 
 | ||||
| 	return node->m_copy; | ||||
| } | ||||
| 
 | ||||
| wxIcon& PrusaObjectDataViewModel::GetIcon(const wxDataViewItem &item) const | ||||
| { | ||||
|     PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
|     return node->m_icon; | ||||
| } | ||||
| 
 | ||||
| wxBitmap& PrusaObjectDataViewModel::GetBitmap(const wxDataViewItem &item) const | ||||
| { | ||||
|     PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
|  | @ -683,16 +811,13 @@ void PrusaObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem | |||
| 	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
| 	switch (col) | ||||
| 	{ | ||||
| 	case 0:{ | ||||
| 	case 0: | ||||
|         variant << PrusaDataViewBitmapText(node->m_name, node->m_bmp); | ||||
| 		break;} | ||||
| 	case 1: | ||||
| 		variant = node->m_copy; | ||||
| 		break; | ||||
| 	case 2: | ||||
| 	case 1: | ||||
| 		variant = node->m_extruder; | ||||
| 		break; | ||||
| 	case 3: | ||||
| 	case 2: | ||||
| 		variant << node->m_action_icon; | ||||
| 		break; | ||||
| 	default: | ||||
|  | @ -715,7 +840,7 @@ bool PrusaObjectDataViewModel::SetValue(const wxVariant &variant, const int item | |||
| 
 | ||||
| 	return m_objects[item_idx]->SetValue(variant, col); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::MoveChildUp(const wxDataViewItem &item) | ||||
| { | ||||
| 	auto ret_item = wxDataViewItem(0); | ||||
|  | @ -763,7 +888,7 @@ wxDataViewItem PrusaObjectDataViewModel::MoveChildDown(const wxDataViewItem &ite | |||
| 		ret_item = wxDataViewItem(node_parent->GetNthChild(node_parent->GetChildCount()-1)); | ||||
| 	return ret_item; | ||||
| } | ||||
| 
 | ||||
| */ | ||||
| wxDataViewItem PrusaObjectDataViewModel::ReorganizeChildren(int current_volume_id, int new_volume_id, const wxDataViewItem &parent) | ||||
| { | ||||
|     auto ret_item = wxDataViewItem(0); | ||||
|  | @ -774,14 +899,14 @@ wxDataViewItem PrusaObjectDataViewModel::ReorganizeChildren(int current_volume_i | |||
|     if (!node_parent)      // happens if item.IsOk()==false
 | ||||
|         return ret_item; | ||||
| 
 | ||||
|     const size_t shift = node_parent->GetChildren().Item(0)->m_type == "settings" ? 1 : 0; | ||||
|     const size_t shift = node_parent->GetChildren().Item(0)->m_type == itSettings ? 1 : 0; | ||||
| 
 | ||||
|     PrusaObjectDataViewModelNode *deleted_node = node_parent->GetNthChild(current_volume_id+shift); | ||||
|     node_parent->GetChildren().Remove(deleted_node); | ||||
|     ItemDeleted(parent, wxDataViewItem(deleted_node)); | ||||
|     node_parent->Insert(deleted_node, new_volume_id+shift); | ||||
|     ItemAdded(parent, wxDataViewItem(deleted_node)); | ||||
|     const auto settings_item = HasSettings(wxDataViewItem(deleted_node)); | ||||
|     const auto settings_item = GetSettingsItem(wxDataViewItem(deleted_node)); | ||||
|     if (settings_item) | ||||
|         ItemAdded(wxDataViewItem(deleted_node), settings_item); | ||||
| 
 | ||||
|  | @ -790,7 +915,7 @@ wxDataViewItem PrusaObjectDataViewModel::ReorganizeChildren(int current_volume_i | |||
|     int id_frst = current_volume_id < new_volume_id ? current_volume_id : new_volume_id; | ||||
|     int id_last = current_volume_id > new_volume_id ? current_volume_id : new_volume_id; | ||||
|     for (int id = id_frst; id <= id_last; ++id) | ||||
|         children[id+shift]->SetVolumeId(id); | ||||
|         children[id+shift]->SetIdx(id); | ||||
| 
 | ||||
|     return wxDataViewItem(node_parent->GetNthChild(new_volume_id+shift)); | ||||
| } | ||||
|  | @ -813,12 +938,32 @@ wxDataViewItem PrusaObjectDataViewModel::GetParent(const wxDataViewItem &item) c | |||
| 	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
| 
 | ||||
| 	// objects nodes has no parent too
 | ||||
| 	if (find(m_objects.begin(), m_objects.end(),node) != m_objects.end()) | ||||
|     if (node->m_type == itObject) | ||||
| 		return wxDataViewItem(0); | ||||
| 
 | ||||
| 	return wxDataViewItem((void*)node->GetParent()); | ||||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::GetTopParent(const wxDataViewItem &item) const | ||||
| { | ||||
| 	// the invisible root node has no parent
 | ||||
| 	if (!item.IsOk()) | ||||
| 		return wxDataViewItem(0); | ||||
| 
 | ||||
| 	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
|     if (node->m_type == itObject) | ||||
|         return item; | ||||
| 
 | ||||
|     PrusaObjectDataViewModelNode *parent_node = node->GetParent(); | ||||
|     while (parent_node->m_type != itObject) | ||||
|     { | ||||
|         node = parent_node; | ||||
|         parent_node = node->GetParent(); | ||||
|     } | ||||
| 
 | ||||
|     return wxDataViewItem((void*)parent_node); | ||||
| } | ||||
| 
 | ||||
| bool PrusaObjectDataViewModel::IsContainer(const wxDataViewItem &item) const | ||||
| { | ||||
| 	// the invisible root node can have children
 | ||||
|  | @ -854,7 +999,15 @@ unsigned int PrusaObjectDataViewModel::GetChildren(const wxDataViewItem &parent, | |||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::HasSettings(const wxDataViewItem &item) const | ||||
| ItemType PrusaObjectDataViewModel::GetItemType(const wxDataViewItem &item) const  | ||||
| { | ||||
|     if (!item.IsOk()) | ||||
|         return itUndef; | ||||
|     PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
|     return node->m_type; | ||||
| } | ||||
| 
 | ||||
| wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const | ||||
| { | ||||
|     if (!item.IsOk()) | ||||
|         return wxDataViewItem(0); | ||||
|  | @ -863,9 +1016,8 @@ wxDataViewItem PrusaObjectDataViewModel::HasSettings(const wxDataViewItem &item) | |||
|     if (node->GetChildCount() == 0) | ||||
|         return wxDataViewItem(0); | ||||
| 
 | ||||
|     auto& children = node->GetChildren(); | ||||
|     if (children[0]->m_type == "settings") | ||||
|         return wxDataViewItem((void*)children[0]);; | ||||
|     if (node->GetNthChild(0)->m_type == itSettings) | ||||
|         return wxDataViewItem((void*)node->GetNthChild(0)); | ||||
| 
 | ||||
|     return wxDataViewItem(0); | ||||
| } | ||||
|  | @ -875,7 +1027,7 @@ bool PrusaObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const | |||
|     if (!item.IsOk()) | ||||
|         return false; | ||||
|     PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
|     return node->m_type == "settings"; | ||||
|     return node->m_type == itSettings; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,6 +13,9 @@ | |||
| #include <vector> | ||||
| #include <set> | ||||
| 
 | ||||
| wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, | ||||
|     std::function<void(wxCommandEvent& event)> cb, const std::string& icon = ""); | ||||
| 
 | ||||
| class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup | ||||
| { | ||||
|     static const unsigned int DefaultWidth; | ||||
|  | @ -166,7 +169,7 @@ public: | |||
| 
 | ||||
|     void SetText(const wxString &text)      { m_text = text; } | ||||
|     wxString GetText() const                { return m_text; } | ||||
|     void SetBitmap(const wxIcon &icon)      { m_bmp = icon; } | ||||
|     void SetBitmap(const wxBitmap &bmp)      { m_bmp = bmp; } | ||||
|     const wxBitmap &GetBitmap() const       { return m_bmp; } | ||||
| 
 | ||||
|     bool IsSameAs(const PrusaDataViewBitmapText& other) const { | ||||
|  | @ -194,6 +197,15 @@ DECLARE_VARIANT_OBJECT(PrusaDataViewBitmapText) | |||
| // PrusaObjectDataViewModelNode: a node inside PrusaObjectDataViewModel
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| enum ItemType{ | ||||
|     itUndef = 0, | ||||
|     itObject = 1, | ||||
|     itVolume = 2, | ||||
|     itInstanceRoot = 4, | ||||
|     itInstance = 8, | ||||
|     itSettings = 16 | ||||
| }; | ||||
| 
 | ||||
| class PrusaObjectDataViewModelNode; | ||||
| WX_DEFINE_ARRAY_PTR(PrusaObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray); | ||||
| 
 | ||||
|  | @ -201,16 +213,14 @@ class PrusaObjectDataViewModelNode | |||
| { | ||||
| 	PrusaObjectDataViewModelNode*	m_parent; | ||||
| 	MyObjectTreeModelNodePtrArray   m_children; | ||||
|     wxIcon                          m_empty_icon; | ||||
|     wxBitmap                        m_empty_bmp; | ||||
|     size_t                          m_volumes_cnt = 0; | ||||
|     std::vector< std::string >      m_opt_categories; | ||||
| public: | ||||
| 	PrusaObjectDataViewModelNode(const wxString &name, const int instances_count=1) { | ||||
| 	PrusaObjectDataViewModelNode(const wxString &name) { | ||||
| 		m_parent	= NULL; | ||||
| 		m_name		= name; | ||||
| 		m_copy		= wxString::Format("%d", instances_count); | ||||
| 		m_type		= "object"; | ||||
| 		m_volume_id	= -1; | ||||
| 		m_type		= itObject; | ||||
| #ifdef __WXGTK__ | ||||
|         // it's necessary on GTK because of control have to know if this item will be container
 | ||||
|         // in another case you couldn't to add subitem for this item
 | ||||
|  | @ -224,13 +234,12 @@ public: | |||
| 									const wxString& sub_obj_name,  | ||||
| 									const wxBitmap& bmp,  | ||||
|                                     const wxString& extruder,  | ||||
| 									const int volume_id=-1) { | ||||
|                                     const int idx = -1 ) { | ||||
| 		m_parent	= parent; | ||||
| 		m_name		= sub_obj_name; | ||||
| 		m_copy		= wxEmptyString; | ||||
| 		m_bmp		= bmp; | ||||
| 		m_type		= "volume"; | ||||
| 		m_volume_id = volume_id; | ||||
| 		m_type		= itVolume; | ||||
|         m_idx       = idx; | ||||
|         m_extruder = extruder; | ||||
| #ifdef __WXGTK__ | ||||
|         // it's necessary on GTK because of control have to know if this item will be container
 | ||||
|  | @ -241,12 +250,22 @@ public: | |||
| 		set_part_action_icon(); | ||||
|     } | ||||
| 
 | ||||
|     PrusaObjectDataViewModelNode(   PrusaObjectDataViewModelNode* parent) : | ||||
|     PrusaObjectDataViewModelNode(   PrusaObjectDataViewModelNode* parent, const ItemType type) : | ||||
|                                     m_parent(parent), | ||||
|                                     m_name("Settings to modified"), | ||||
|                                     m_copy(wxEmptyString), | ||||
|                                     m_type("settings"), | ||||
|                                     m_extruder(wxEmptyString) {} | ||||
|                                     m_type(type), | ||||
|                                     m_extruder(wxEmptyString) | ||||
| 	{ | ||||
|         if (type == itSettings) { | ||||
|             m_name = "Settings to modified"; | ||||
|         } | ||||
|         else if (type == itInstanceRoot) { | ||||
|             m_name = "Instances";             | ||||
|         } | ||||
|         else if (type == itInstance) { | ||||
|             m_idx = parent->GetChildCount(); | ||||
|             m_name = wxString::Format("Instance_%d", m_idx+1); | ||||
|         } | ||||
| 	} | ||||
| 
 | ||||
| 	~PrusaObjectDataViewModelNode() | ||||
| 	{ | ||||
|  | @ -260,11 +279,9 @@ public: | |||
| 	} | ||||
| 	 | ||||
| 	wxString				m_name; | ||||
| 	wxIcon&					m_icon = m_empty_icon; | ||||
|     wxBitmap&               m_bmp = m_empty_bmp; | ||||
| 	wxString				m_copy; | ||||
| 	std::string				m_type; | ||||
| 	int						m_volume_id = -2; | ||||
|     ItemType				m_type; | ||||
|     int                     m_idx = -1; | ||||
| 	bool					m_container = false; | ||||
| 	wxString				m_extruder = "default"; | ||||
| 	wxBitmap				m_action_icon; | ||||
|  | @ -328,12 +345,9 @@ public: | |||
| 			m_name = data.GetText(); | ||||
| 			return true;} | ||||
| 		case 1: | ||||
| 			m_copy = variant.GetString(); | ||||
| 			return true; | ||||
| 		case 2: | ||||
| 			m_extruder = variant.GetString(); | ||||
| 			return true; | ||||
| 		case 3: | ||||
| 		case 2: | ||||
| 			m_action_icon << variant; | ||||
| 			return true; | ||||
| 		default: | ||||
|  | @ -341,28 +355,25 @@ public: | |||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 	void SetIcon(const wxIcon &icon) | ||||
| 	{ | ||||
| 		m_icon = icon; | ||||
| 	} | ||||
| 
 | ||||
| 	void SetBitmap(const wxBitmap &icon) | ||||
| 	{ | ||||
| 		m_bmp = icon; | ||||
| 	} | ||||
| 	 | ||||
| 	void SetType(const std::string& type){ | ||||
| 		m_type = type; | ||||
| 	}	 | ||||
| 	const std::string& GetType(){ | ||||
| 		return m_type; | ||||
| 
 | ||||
|     ItemType GetType() const { | ||||
|         return m_type; | ||||
|     } | ||||
| 
 | ||||
| 	void SetIdx(const int& idx) { | ||||
| 		m_idx = idx; | ||||
|         // update name if this node is instance
 | ||||
|         if (m_type == itInstance) | ||||
|             m_name = wxString::Format("Instance_%d", m_idx + 1); | ||||
| 	} | ||||
| 
 | ||||
| 	void SetVolumeId(const int& volume_id){ | ||||
| 		m_volume_id = volume_id; | ||||
| 	} | ||||
| 	const int& GetVolumeId(){ | ||||
| 		return m_volume_id; | ||||
| 	int GetIdx() const { | ||||
| 		return m_idx; | ||||
| 	} | ||||
| 
 | ||||
| 	// use this function only for childrens
 | ||||
|  | @ -370,9 +381,10 @@ public: | |||
| 	{ | ||||
| 		// ! Don't overwrite other values because of equality of this values for all children --
 | ||||
| 		m_name = from_node.m_name; | ||||
| 		m_icon = from_node.m_icon; | ||||
| 		m_volume_id = from_node.m_volume_id; | ||||
| 		m_extruder = from_node.m_extruder; | ||||
|         m_bmp = from_node.m_bmp; | ||||
|         m_idx = from_node.m_idx; | ||||
|         m_extruder = from_node.m_extruder; | ||||
|         m_type = from_node.m_type; | ||||
| 	} | ||||
| 
 | ||||
| 	bool SwapChildrens(int frst_id, int scnd_id) { | ||||
|  | @ -384,8 +396,8 @@ public: | |||
| 		PrusaObjectDataViewModelNode new_scnd = *GetNthChild(frst_id); | ||||
| 		PrusaObjectDataViewModelNode new_frst = *GetNthChild(scnd_id); | ||||
| 
 | ||||
| 		new_scnd.m_volume_id = m_children.Item(scnd_id)->m_volume_id; | ||||
| 		new_frst.m_volume_id = m_children.Item(frst_id)->m_volume_id; | ||||
|         new_scnd.m_idx = m_children.Item(scnd_id)->m_idx; | ||||
|         new_frst.m_idx = m_children.Item(frst_id)->m_idx; | ||||
| 
 | ||||
| 		m_children.Item(frst_id)->AssignAllVal(new_frst); | ||||
| 		m_children.Item(scnd_id)->AssignAllVal(new_scnd); | ||||
|  | @ -396,6 +408,8 @@ public: | |||
| 	void set_object_action_icon(); | ||||
| 	void set_part_action_icon(); | ||||
|     bool update_settings_digest(const std::vector<std::string>& categories); | ||||
| private: | ||||
|     friend class PrusaObjectDataViewModel; | ||||
| }; | ||||
| 
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
|  | @ -410,28 +424,29 @@ public: | |||
|     ~PrusaObjectDataViewModel(); | ||||
| 
 | ||||
| 	wxDataViewItem Add(const wxString &name); | ||||
| 	wxDataViewItem Add(const wxString &name, const int instances_count); | ||||
| 	wxDataViewItem AddChild(const wxDataViewItem &parent_item,  | ||||
| 	wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item,  | ||||
| 							const wxString &name,  | ||||
|                             const wxBitmap& icon, | ||||
|                             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); | ||||
| 	void DeleteAll(); | ||||
|     void DeleteChildren(wxDataViewItem& parent); | ||||
| 	wxDataViewItem GetItemById(int obj_idx); | ||||
| 	wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); | ||||
| 	int GetIdByItem(wxDataViewItem& item); | ||||
| 	int GetVolumeIdByItem(const wxDataViewItem& item); | ||||
|     void GetObjectAndVolumeIdsByItem(const wxDataViewItem& item, int& obj_idx, int& vol_idx); | ||||
| 	int GetIdByItem(const wxDataViewItem& item); | ||||
|     int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; | ||||
|     int GetVolumeIdByItem(const wxDataViewItem& item) const; | ||||
|     int GetInstanceIdByItem(const wxDataViewItem& item) const; | ||||
|     void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx); | ||||
|     bool IsEmpty() { return m_objects.empty(); } | ||||
| 
 | ||||
| 	// helper method for wxLog
 | ||||
| 
 | ||||
| 	wxString GetName(const wxDataViewItem &item) const; | ||||
| 	wxString GetCopy(const wxDataViewItem &item) const; | ||||
| 	wxIcon&  GetIcon(const wxDataViewItem &item) const; | ||||
|     wxBitmap& GetBitmap(const wxDataViewItem &item) const; | ||||
| 
 | ||||
| 	// helper methods to change the model
 | ||||
|  | @ -445,8 +460,8 @@ public: | |||
| 		const wxDataViewItem &item, unsigned int col) override; | ||||
| 	bool SetValue(const wxVariant &variant, const int item_idx, unsigned int col); | ||||
| 
 | ||||
| 	wxDataViewItem MoveChildUp(const wxDataViewItem &item); | ||||
| 	wxDataViewItem MoveChildDown(const wxDataViewItem &item); | ||||
| // 	wxDataViewItem MoveChildUp(const wxDataViewItem &item);
 | ||||
| // 	wxDataViewItem MoveChildDown(const wxDataViewItem &item);
 | ||||
|     // For parent move child from cur_volume_id place to new_volume_id 
 | ||||
|     // Remaining items will moved up/down accordingly
 | ||||
|     wxDataViewItem ReorganizeChildren(int cur_volume_id,  | ||||
|  | @ -456,6 +471,8 @@ public: | |||
| 	virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override; | ||||
| 
 | ||||
| 	virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override; | ||||
|     // get object item
 | ||||
|     wxDataViewItem GetTopParent(const wxDataViewItem &item) const; | ||||
| 	virtual bool IsContainer(const wxDataViewItem &item) const override; | ||||
| 	virtual unsigned int GetChildren(const wxDataViewItem &parent, | ||||
| 		wxDataViewItemArray &array) const override; | ||||
|  | @ -464,7 +481,8 @@ public: | |||
| 	// In our case it is an item with all columns 
 | ||||
| 	virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override {	return true; } | ||||
| 
 | ||||
|     wxDataViewItem    HasSettings(const wxDataViewItem &item) const; | ||||
|     ItemType GetItemType(const wxDataViewItem &item) const ; | ||||
|     wxDataViewItem    GetSettingsItem(const wxDataViewItem &item) const; | ||||
|     bool    IsSettingsItem(const wxDataViewItem &item) const; | ||||
|     void    UpdateSettingsDigest(const wxDataViewItem &item, const std::vector<std::string>& categories); | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv