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
						edc79cb922
					
				
					 47 changed files with 1617 additions and 238 deletions
				
			
		|  | @ -198,6 +198,9 @@ GLVolume::GLVolume(float r, float g, float b, float a) | |||
|     : m_offset(Vec3d::Zero()) | ||||
|     , m_rotation(Vec3d::Zero()) | ||||
|     , m_scaling_factor(Vec3d::Ones()) | ||||
| #if ENABLE_MIRROR | ||||
|     , m_mirror(Vec3d::Ones()) | ||||
| #endif // ENABLE_MIRROR
 | ||||
|     , m_world_matrix(Transform3f::Identity()) | ||||
|     , m_world_matrix_dirty(true) | ||||
|     , m_transformed_bounding_box_dirty(true) | ||||
|  | @ -324,6 +327,40 @@ void GLVolume::set_scaling_factor(const Vec3d& scaling_factor) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| const Vec3d& GLVolume::get_mirror() const | ||||
| { | ||||
|     return m_mirror; | ||||
| } | ||||
| 
 | ||||
| double GLVolume::get_mirror(Axis axis) const | ||||
| { | ||||
|     return m_mirror(axis); | ||||
| } | ||||
| 
 | ||||
| void GLVolume::set_mirror(const Vec3d& mirror) | ||||
| { | ||||
|     if (m_mirror != mirror) | ||||
|     { | ||||
|         m_mirror = mirror; | ||||
|         m_world_matrix_dirty = true; | ||||
|         m_transformed_bounding_box_dirty = true; | ||||
|         m_transformed_convex_hull_bounding_box_dirty = true; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GLVolume::set_mirror(Axis axis, double mirror) | ||||
| { | ||||
|     if (m_mirror(axis) != mirror) | ||||
|     { | ||||
|         m_mirror(axis) = mirror; | ||||
|         m_world_matrix_dirty = true; | ||||
|         m_transformed_bounding_box_dirty = true; | ||||
|         m_transformed_convex_hull_bounding_box_dirty = true; | ||||
|     } | ||||
| } | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
| void GLVolume::set_convex_hull(const TriangleMesh& convex_hull) | ||||
| { | ||||
|     m_convex_hull = &convex_hull; | ||||
|  | @ -353,7 +390,11 @@ const Transform3f& GLVolume::world_matrix() const | |||
| { | ||||
|     if (m_world_matrix_dirty) | ||||
|     { | ||||
| #if ENABLE_MIRROR | ||||
|         m_world_matrix = Geometry::assemble_transform(m_offset, m_rotation, m_scaling_factor, m_mirror).cast<float>(); | ||||
| #else | ||||
|         m_world_matrix = Geometry::assemble_transform(m_offset, m_rotation, m_scaling_factor).cast<float>(); | ||||
| #endif // ENABLE_MIRROR
 | ||||
|         m_world_matrix_dirty = false; | ||||
|     } | ||||
|     return m_world_matrix; | ||||
|  | @ -729,6 +770,9 @@ std::vector<int> GLVolumeCollection::load_object( | |||
|             v.set_offset(instance->get_offset()); | ||||
|             v.set_rotation(instance->get_rotation()); | ||||
|             v.set_scaling_factor(instance->get_scaling_factor()); | ||||
| #if ENABLE_MIRROR | ||||
|             v.set_mirror(instance->get_mirror()); | ||||
| #endif // ENABLE_MIRROR
 | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | @ -2076,6 +2120,15 @@ int _3DScene::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) | |||
|     return s_canvas_mgr.get_in_object_volume_id(canvas, scene_vol_idx); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| void _3DScene::mirror_selection(wxGLCanvas* canvas, Axis axis) | ||||
| { | ||||
|     s_canvas_mgr.mirror_selection(canvas, axis); | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
| void _3DScene::reload_scene(wxGLCanvas* canvas, bool force) | ||||
| { | ||||
|     s_canvas_mgr.reload_scene(canvas, force); | ||||
|  |  | |||
|  | @ -260,6 +260,10 @@ private: | |||
|     Vec3d                 m_rotation; | ||||
|     // Scale factor along the three axes of the volume to be rendered.
 | ||||
|     Vec3d                 m_scaling_factor; | ||||
| #if ENABLE_MIRROR | ||||
|     // Mirroring along the three axes of the volume to be rendered.
 | ||||
|     Vec3d m_mirror; | ||||
| #endif // ENABLE_MIRROR
 | ||||
|     // World matrix of the volume to be rendered.
 | ||||
|     mutable Transform3f   m_world_matrix; | ||||
|     // Whether or not is needed to recalculate the world matrix.
 | ||||
|  | @ -337,6 +341,13 @@ public: | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     void set_scaling_factor(const Vec3d& scaling_factor); | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
|     const Vec3d& get_mirror() const; | ||||
|     double get_mirror(Axis axis) const; | ||||
|     void set_mirror(const Vec3d& mirror); | ||||
|     void set_mirror(Axis axis, double mirror); | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
|     const Vec3d& get_offset() const; | ||||
|     void set_offset(const Vec3d& offset); | ||||
| 
 | ||||
|  | @ -581,6 +592,12 @@ public: | |||
|     static int get_first_volume_id(wxGLCanvas* canvas, int obj_idx); | ||||
|     static int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx); | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     static void mirror_selection(wxGLCanvas* canvas, Axis axis); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
|     static void reload_scene(wxGLCanvas* canvas, bool force); | ||||
| 
 | ||||
|     static void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors); | ||||
|  |  | |||
|  | @ -54,10 +54,13 @@ public: | |||
| 	virtual bool | ||||
| 		AcceptsFocusFromKeyboard() const { return false; } | ||||
| 
 | ||||
|     void set_as_hidden() { | ||||
|         Hide(); | ||||
|         hidden = true; | ||||
| 	} | ||||
| 
 | ||||
|     virtual bool Show(bool show = true) override { | ||||
|         if (!show) | ||||
|             hidden = true; | ||||
|         return wxButton::Show(!hidden); | ||||
|         return wxButton::Show(hidden ? false : show); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1409,14 +1409,13 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) | |||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); | ||||
| 
 | ||||
|     for (unsigned int i : m_list) | ||||
|     { | ||||
|         if (is_single_full_instance()) | ||||
|             (*m_volumes)[i]->set_rotation(rotation); | ||||
|         else | ||||
|         { | ||||
|             Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); | ||||
|             // extracts rotations from the composed transformation
 | ||||
|             Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_rotation_matrix()); | ||||
| 
 | ||||
|  | @ -1436,15 +1435,13 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) | |||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     Transform3d m = Transform3d::Identity(); | ||||
|     m.scale(scale); | ||||
| 
 | ||||
|     for (unsigned int i : m_list) | ||||
|     { | ||||
|         if (is_single_full_instance()) | ||||
|             (*m_volumes)[i]->set_scaling_factor(scale); | ||||
|         else | ||||
|         { | ||||
|             Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale); | ||||
|             Eigen::Matrix<double, 3, 3, Eigen::DontAlign> new_matrix = (m * m_cache.volumes_data[i].get_scale_matrix()).matrix().block(0, 0, 3, 3); | ||||
|             // extracts scaling factors from the composed transformation
 | ||||
|             Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); | ||||
|  | @ -1460,6 +1457,25 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) | |||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| void GLCanvas3D::Selection::mirror(Axis axis) | ||||
| { | ||||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     for (unsigned int i : m_list) | ||||
|     { | ||||
|         if (is_single_full_instance()) | ||||
|             (*m_volumes)[i]->set_mirror(axis, -(*m_volumes)[i]->get_mirror(axis)); | ||||
|     } | ||||
| 
 | ||||
|     if (m_mode == Instance) | ||||
|         _synchronize_unselected_instances(); | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
| void GLCanvas3D::Selection::render(bool show_indirect_selection) const | ||||
| { | ||||
|     if (is_empty()) | ||||
|  | @ -1783,6 +1799,9 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() | |||
|         int instance_idx = volume->instance_idx(); | ||||
|         const Vec3d& rotation = volume->get_rotation(); | ||||
|         const Vec3d& scaling_factor = volume->get_scaling_factor(); | ||||
| #if ENABLE_MIRROR | ||||
|         const Vec3d& mirror = volume->get_mirror(); | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
|         // Process unselected instances.
 | ||||
|         for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) | ||||
|  | @ -1799,6 +1818,9 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() | |||
| 
 | ||||
|             v->set_rotation(rotation); | ||||
|             v->set_scaling_factor(scaling_factor); | ||||
| #if ENABLE_MIRROR | ||||
|             v->set_mirror(mirror); | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
|             done.insert(j); | ||||
|         } | ||||
|  | @ -2674,9 +2696,11 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); | |||
| wxDEFINE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_ROTATE_OBJECT, Event<int>); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_SCALE_UNIFORMLY, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_OBJECTS, Event<int>); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); | ||||
| wxDEFINE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>); | ||||
|  | @ -3404,6 +3428,17 @@ int GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const | |||
|     return ((0 <= scene_vol_idx) && (scene_vol_idx < (int)m_volumes.volumes.size())) ? m_volumes.volumes[scene_vol_idx]->volume_idx() : -1; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| void GLCanvas3D::mirror_selection(Axis axis) | ||||
| { | ||||
|     m_selection.mirror(axis); | ||||
|     _on_mirror(); | ||||
|     wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
| void GLCanvas3D::reload_scene(bool force) | ||||
| { | ||||
|     if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr)) | ||||
|  | @ -3421,7 +3456,12 @@ void GLCanvas3D::reload_scene(bool force) | |||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     if (m_regenerate_volumes) | ||||
|     { | ||||
|         reset_volumes(); | ||||
| 
 | ||||
|         // to update the toolbar
 | ||||
|         post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); | ||||
|     } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     set_bed_shape(dynamic_cast<const ConfigOptionPoints*>(m_config->option("bed_shape"))->values); | ||||
|  | @ -3441,9 +3481,6 @@ 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(); | ||||
|  | @ -3685,24 +3722,26 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) | |||
|                 switch (keyCode) | ||||
|                 { | ||||
|                 // key +
 | ||||
|                 case 43: { post_event(Event<int>(EVT_GLCANVAS_INCREASE_OBJECTS, +1)); break; } | ||||
|                 case 43: { post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, +1)); break; } | ||||
|                 // key -
 | ||||
|                 case 45: { post_event(Event<int>(EVT_GLCANVAS_INCREASE_OBJECTS, -1)); break; } | ||||
|                 case 45: { post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, -1)); break; } | ||||
|                 // key A/a
 | ||||
|                 case 65: | ||||
|                 case 97: { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } | ||||
|                 // key B/b
 | ||||
|                 case 66: | ||||
|                 case 98: { zoom_to_bed(); break; } | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|                 // key L/l
 | ||||
|                 case 76: | ||||
|                 case 108: { post_event(Event<int>(EVT_GLCANVAS_ROTATE_OBJECT, -1)); break; } | ||||
|                 // key R/r
 | ||||
|                           // key R/r
 | ||||
|                 case 82: | ||||
|                 case 114: { post_event(Event<int>(EVT_GLCANVAS_ROTATE_OBJECT, +1)); break; } | ||||
|                 // key S/s
 | ||||
|                           // key S/s
 | ||||
|                 case 83: | ||||
|                 case 115: { post_event(SimpleEvent(EVT_GLCANVAS_SCALE_UNIFORMLY)); break; } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|                 // key Z/z
 | ||||
|                 case 90: | ||||
|                 case 122: { zoom_to_volumes(); break; } | ||||
|  | @ -3820,7 +3859,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         case Gizmos::Scale: | ||||
|         { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             m_regenerate_volumes = false; | ||||
|             m_selection.scale(m_gizmos.get_scale()); | ||||
|             _on_scale(); | ||||
| #else | ||||
|  | @ -3837,7 +3875,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         case Gizmos::Rotate: | ||||
|         { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             m_regenerate_volumes = false; | ||||
|             m_selection.rotate(m_gizmos.get_rotation()); | ||||
|             _on_rotate(); | ||||
| #else | ||||
|  | @ -3903,9 +3940,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|         } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|         else if (!m_selection.is_empty() && m_gizmos.grabber_contains_mouse()) | ||||
|         else if (evt.LeftDown() && !m_selection.is_empty() && m_gizmos.grabber_contains_mouse()) | ||||
| #else | ||||
|         else if ((selected_object_idx != -1) && m_gizmos.grabber_contains_mouse()) | ||||
|         else if (evt.LeftDown() && (selected_object_idx != -1) && m_gizmos.grabber_contains_mouse()) | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|         { | ||||
|             update_gizmos_data(); | ||||
|  | @ -3920,7 +3957,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             if (m_gizmos.get_current_type() == Gizmos::Flatten) { | ||||
|                 // Rotate the object so the normal points downward:
 | ||||
| #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); | ||||
|  | @ -3951,14 +3987,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                 if (evt.LeftDown() && (m_hover_volume_id != -1)) | ||||
|                 { | ||||
|                     if (evt.ControlDown()) | ||||
|                         m_selection.remove(m_hover_volume_id); | ||||
|                     else | ||||
|                     if (!evt.ShiftDown() || !m_selection.contains_volume(m_hover_volume_id)) | ||||
|                         m_selection.add(m_hover_volume_id, !evt.ShiftDown()); | ||||
|                     else | ||||
|                         m_selection.remove(m_hover_volume_id); | ||||
| 
 | ||||
|                     m_gizmos.update_on_off_state(m_selection); | ||||
|                     update_gizmos_data(); | ||||
|                     wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|                     post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); | ||||
|                     m_dirty = true; | ||||
|                 } | ||||
| #else | ||||
|  | @ -3983,16 +4020,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             } | ||||
| 
 | ||||
|             // propagate event through callback
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             if (m_picking_enabled && (m_hover_volume_id != -1)) | ||||
|             { | ||||
|                 int object_idx = m_selection.get_object_idx(); | ||||
|                 _on_select(m_hover_volume_id, object_idx); | ||||
|             } | ||||
| #else | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|             if (m_picking_enabled && (volume_idx != -1)) | ||||
|                 _on_select(volume_idx, selected_object_idx); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|             if (m_hover_volume_id != -1) | ||||
|  | @ -4319,10 +4350,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                 m_selection.clear(); | ||||
|                 wxGetApp().obj_manipul()->update_settings_value(m_selection); | ||||
|                 post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); | ||||
| #else | ||||
|                 deselect_volumes(); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|                 _on_select(-1, -1); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|                 update_gizmos_data(); | ||||
|             } | ||||
| #if ENABLE_GIZMOS_RESET | ||||
|  | @ -4363,7 +4395,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             case Gizmos::Scale: | ||||
|             { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                 m_regenerate_volumes = false; | ||||
|                 _on_scale(); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|                 break; | ||||
|  | @ -4371,7 +4402,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|             case Gizmos::Rotate: | ||||
|             { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|                 m_regenerate_volumes = false; | ||||
|                 _on_rotate(); | ||||
| #else | ||||
|                 post_event(Vec3dEvent(EVT_GIZMO_ROTATE, m_gizmos.get_rotation())); | ||||
|  | @ -6524,6 +6554,41 @@ void GLCanvas3D::_on_flatten() | |||
|     _on_rotate(); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| void GLCanvas3D::_on_mirror() | ||||
| { | ||||
|     if (m_model == nullptr) | ||||
|         return; | ||||
| 
 | ||||
|     std::set<std::pair<int, int>> done;  // prevent mirroring instances twice
 | ||||
| 
 | ||||
|     for (const GLVolume* v : m_volumes.volumes) | ||||
|     { | ||||
|         int object_idx = v->object_idx(); | ||||
|         if (object_idx >= 1000) | ||||
|             continue; | ||||
| 
 | ||||
|         int instance_idx = v->instance_idx(); | ||||
| 
 | ||||
|         // prevent mirroring instances twice
 | ||||
|         std::pair<int, int> done_id(object_idx, instance_idx); | ||||
|         if (done.find(done_id) != done.end()) | ||||
|             continue; | ||||
| 
 | ||||
|         done.insert(done_id); | ||||
| 
 | ||||
|         // Mirror instances.
 | ||||
|         ModelObject* model_object = m_model->objects[object_idx]; | ||||
|         if (model_object != nullptr) | ||||
|         { | ||||
|             model_object->instances[instance_idx]->set_mirror(v->get_mirror()); | ||||
|             model_object->invalidate_bounding_box(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // schedule_background_process
 | ||||
| } | ||||
| #endif // ENABLE_MIRROR
 | ||||
| #else | ||||
| void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs) | ||||
| { | ||||
|  | @ -6572,11 +6637,9 @@ void GLCanvas3D::_on_move(const std::vector<int>& volume_idxs) | |||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| void GLCanvas3D::_on_select(int volume_idx, int object_idx) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); | ||||
| #else | ||||
|     int vol_id = -1; | ||||
|     int obj_id = -1; | ||||
| 
 | ||||
|  | @ -6605,8 +6668,8 @@ void GLCanvas3D::_on_select(int volume_idx, int object_idx) | |||
| 
 | ||||
|     post_event(ObjectSelectEvent(obj_id, vol_id)); | ||||
|     wxGetApp().obj_list()->select_current_volume(obj_id, vol_id); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| std::vector<float> GLCanvas3D::_parse_colors(const std::vector<std::string>& colors) | ||||
| { | ||||
|  |  | |||
|  | @ -112,9 +112,11 @@ wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); | |||
| wxDECLARE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_ROTATE_OBJECT, Event<int>);    // data: -1 => rotate left, +1 => rotate right
 | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_SCALE_UNIFORMLY, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_OBJECTS, Event<int>); // data: +1 => increase, -1 => decrease
 | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>); // data: +1 => increase, -1 => decrease
 | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>); | ||||
|  | @ -483,6 +485,8 @@ public: | |||
|         bool is_from_single_instance() const { return get_instance_idx() != -1; } | ||||
|         bool is_from_single_object() const { return get_object_idx() != -1; } | ||||
| 
 | ||||
|         bool contains_volume(unsigned int volume_idx) const { return std::find(m_list.begin(), m_list.end(), volume_idx) != m_list.end(); } | ||||
| 
 | ||||
|         // Returns the the object id if the selection is from a single object, otherwise is -1
 | ||||
|         int get_object_idx() const; | ||||
|         // Returns the instance id if the selection is from a single object and from a single instance, otherwise is -1
 | ||||
|  | @ -499,6 +503,9 @@ public: | |||
|         void translate(const Vec3d& displacement); | ||||
|         void rotate(const Vec3d& rotation); | ||||
|         void scale(const Vec3d& scale); | ||||
| #if ENABLE_MIRROR | ||||
|         void mirror(Axis axis); | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
|         void render(bool show_indirect_selection) const; | ||||
| 
 | ||||
|  | @ -831,6 +838,12 @@ public: | |||
|     int get_first_volume_id(int obj_idx) const; | ||||
|     int get_in_object_volume_id(int scene_vol_idx) const; | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     void mirror_selection(Axis axis); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
|     void reload_scene(bool force); | ||||
| 
 | ||||
|     void load_gcode_preview(const GCodePreviewData& preview_data, const std::vector<std::string>& str_tool_colors); | ||||
|  | @ -953,10 +966,15 @@ private: | |||
|     void _on_rotate(); | ||||
|     void _on_scale(); | ||||
|     void _on_flatten(); | ||||
| #if ENABLE_MIRROR | ||||
|     void _on_mirror(); | ||||
| #endif // ENABLE_MIRROR
 | ||||
| #else | ||||
|     void _on_move(const std::vector<int>& volume_idxs); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     void _on_select(int volume_idx, int object_idx); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     // generates the legend texture in dependence of the current shown view type
 | ||||
|     void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors); | ||||
|  |  | |||
|  | @ -596,6 +596,17 @@ int GLCanvas3DManager::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol | |||
|     return (it != m_canvases.end()) ? it->second->get_in_object_volume_id(scene_vol_idx) : -1; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
| void GLCanvas3DManager::mirror_selection(wxGLCanvas* canvas, Axis axis) | ||||
| { | ||||
|     CanvasesMap::iterator it = _get_canvas(canvas); | ||||
|     if (it != m_canvases.end()) | ||||
|         it->second->mirror_selection(axis); | ||||
| } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
| void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force) | ||||
| { | ||||
|     CanvasesMap::iterator it = _get_canvas(canvas); | ||||
|  |  | |||
|  | @ -163,6 +163,12 @@ public: | |||
|     int get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const; | ||||
|     int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const; | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     void mirror_selection(wxGLCanvas* canvas, Axis axis); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
|     void reload_scene(wxGLCanvas* canvas, bool force); | ||||
| 
 | ||||
|     void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors); | ||||
|  |  | |||
|  | @ -868,7 +868,7 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const | |||
|     BoundingBoxf3 box; | ||||
|     Transform3d transform = Transform3d::Identity(); | ||||
|     Vec3d angles = Vec3d::Zero(); | ||||
|     Transform3d rotation = Transform3d::Identity(); | ||||
|     Transform3d offsets_transform = Transform3d::Identity(); | ||||
| 
 | ||||
|     if (selection.is_from_single_instance()) | ||||
|     { | ||||
|  | @ -880,13 +880,19 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const | |||
|         } | ||||
| 
 | ||||
|         // gets transform from first selected volume
 | ||||
|         transform = selection.get_volume(*idxs.begin())->world_matrix().cast<double>(); | ||||
|         const GLVolume* v = selection.get_volume(*idxs.begin()); | ||||
|         transform = v->world_matrix().cast<double>(); | ||||
| 
 | ||||
|         // extract angles from transform
 | ||||
|         angles = Slic3r::Geometry::extract_euler_angles(transform); | ||||
|         // gets angles from first selected volume
 | ||||
|         angles = v->get_rotation(); | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
|         // consider rotation+mirror only components of the transform for offsets
 | ||||
|         offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_mirror()); | ||||
| #else | ||||
|         // set rotation-only component of transform
 | ||||
|         rotation = Geometry::assemble_transform(Vec3d::Zero(), angles); | ||||
|         offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles); | ||||
| #endif // ENABLE_MIRROR
 | ||||
|     } | ||||
|     else | ||||
|         box = selection.get_bounding_box(); | ||||
|  | @ -898,9 +904,9 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const | |||
| 
 | ||||
|     const Vec3d& center = m_box.center(); | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     Vec3d offset_x = rotation * Vec3d((double)Offset, 0.0, 0.0); | ||||
|     Vec3d offset_y = rotation * Vec3d(0.0, (double)Offset, 0.0); | ||||
|     Vec3d offset_z = rotation * Vec3d(0.0, 0.0, (double)Offset); | ||||
|     Vec3d offset_x = offsets_transform * Vec3d((double)Offset, 0.0, 0.0); | ||||
|     Vec3d offset_y = offsets_transform * Vec3d(0.0, (double)Offset, 0.0); | ||||
|     Vec3d offset_z = offsets_transform * Vec3d(0.0, 0.0, (double)Offset); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     // x axis
 | ||||
|  | @ -1468,6 +1474,7 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const | |||
| 
 | ||||
|     ::glEnable(GL_BLEND); | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     ::glDisable(GL_CULL_FACE); | ||||
| 
 | ||||
|     for (int i=0; i<(int)m_planes.size(); ++i) { | ||||
|         if (i == m_hover_id) | ||||
|  | @ -1506,6 +1513,7 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     } | ||||
| 
 | ||||
|     ::glEnable(GL_CULL_FACE); | ||||
|     ::glDisable(GL_BLEND); | ||||
| } | ||||
| 
 | ||||
|  | @ -1516,6 +1524,7 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| { | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     ::glDisable(GL_CULL_FACE); | ||||
| 
 | ||||
|     for (unsigned int i = 0; i < m_planes.size(); ++i) | ||||
|     { | ||||
|  | @ -1546,6 +1555,8 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const | |||
|         } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     } | ||||
| 
 | ||||
|     ::glEnable(GL_CULL_FACE); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) | ||||
|  | @ -1769,9 +1780,9 @@ Vec3d GLGizmoFlatten::get_flattening_rotation() const | |||
|     // calculates the rotations in model space, taking in account the scaling factors
 | ||||
|     Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m = m_model_object->instances.front()->world_matrix(true, true).matrix().block(0, 0, 3, 3).inverse().transpose(); | ||||
|     Eigen::Quaterniond q; | ||||
|     Vec3d angles = q.setFromTwoVectors(m * m_normal, -Vec3d::UnitZ()).toRotationMatrix().eulerAngles(2, 1, 0); | ||||
|     Vec3d angles = Geometry::extract_euler_angles(q.setFromTwoVectors(m * m_normal, -Vec3d::UnitZ()).toRotationMatrix()); | ||||
|     m_normal = Vec3d::Zero(); | ||||
|     return Vec3d(angles(2), angles(1), angles(0)); | ||||
|     return angles; | ||||
| } | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
|  |  | |||
|  | @ -327,24 +327,6 @@ void GUI_App::CallAfter(std::function<void()> cb) | |||
|     callback_register.unlock(); | ||||
| } | ||||
| 
 | ||||
| wxMenuItem* GUI_App::append_submenu(wxMenu* menu, | ||||
|     wxMenu* sub_menu, | ||||
|     int id, | ||||
|     const wxString& string, | ||||
|     const wxString& description, | ||||
|     const std::string& icon) | ||||
| { | ||||
|     if (id == wxID_ANY) | ||||
|         id = wxNewId(); | ||||
|     auto item = new wxMenuItem(menu, id, string, description); | ||||
|     if (!icon.empty()) | ||||
|         item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG)); | ||||
|     item->SetSubMenu(sub_menu); | ||||
|     menu->Append(item); | ||||
| 
 | ||||
|     return item; | ||||
| } | ||||
| 
 | ||||
| void GUI_App::window_pos_save(wxTopLevelWindow* window, const std::string &name) | ||||
| { | ||||
|     if (name.empty()) { return; } | ||||
|  | @ -500,7 +482,8 @@ ConfigMenuIDs GUI_App::get_view_mode() | |||
|         return ConfigMenuModeSimple; | ||||
| 
 | ||||
|     const auto mode = app_config->get("view_mode"); | ||||
|     return mode == "expert" ? ConfigMenuModeExpert : ConfigMenuModeSimple; | ||||
|     return mode == "expert" ? ConfigMenuModeExpert :  | ||||
|            mode == "simple" ? ConfigMenuModeSimple : ConfigMenuModeMiddle; | ||||
| } | ||||
| 
 | ||||
| // Update view mode according to selected menu
 | ||||
|  | @ -518,6 +501,11 @@ void GUI_App::update_mode() | |||
| 
 | ||||
|     sidebar().Layout(); | ||||
|     mainframe->m_plater->Layout(); | ||||
| 
 | ||||
|     ConfigOptionMode opt_mode = mode == ConfigMenuModeSimple ? comSimple : | ||||
|                                 mode == ConfigMenuModeExpert ? comExpert : comMiddle; | ||||
|     for (auto tab : tabs_list) | ||||
|         tab->update_visibility(opt_mode); | ||||
| } | ||||
| 
 | ||||
| void GUI_App::add_config_menu(wxMenuBar *menu) | ||||
|  | @ -537,6 +525,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu) | |||
|     local_menu->AppendSeparator(); | ||||
|     auto mode_menu = new wxMenu(); | ||||
|     mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeSimple, _(L("&Simple")), _(L("Simple View Mode"))); | ||||
|     mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeMiddle, _(L("&Middle")), _(L("Middle View Mode"))); | ||||
|     mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeExpert, _(L("&Expert")), _(L("Expert View Mode"))); | ||||
|     mode_menu->Check(config_id_base + get_view_mode(), true); | ||||
|     local_menu->AppendSubMenu(mode_menu, _(L("&Mode")), _(L("Slic3r View Mode"))); | ||||
|  | @ -607,8 +596,9 @@ void GUI_App::add_config_menu(wxMenuBar *menu) | |||
|         } | ||||
|     }); | ||||
|     mode_menu->Bind(wxEVT_MENU, [this, config_id_base](wxEvent& event) { | ||||
|         std::string mode = event.GetId() - config_id_base == ConfigMenuModeExpert ? | ||||
|             "expert" : "simple"; | ||||
|         int id_mode = event.GetId() - config_id_base; | ||||
|         std::string mode = id_mode == ConfigMenuModeExpert ? "expert" : | ||||
|                            id_mode == ConfigMenuModeSimple ? "simple" : "middle"; | ||||
|         app_config->set("view_mode", mode); | ||||
|         app_config->save(); | ||||
|         update_mode(); | ||||
|  |  | |||
|  | @ -51,6 +51,7 @@ enum ConfigMenuIDs { | |||
|     ConfigMenuUpdate, | ||||
|     ConfigMenuPreferences, | ||||
|     ConfigMenuModeSimple, | ||||
|     ConfigMenuModeMiddle, | ||||
|     ConfigMenuModeExpert, | ||||
|     ConfigMenuLanguage, | ||||
|     ConfigMenuFlashFirmware, | ||||
|  | @ -107,12 +108,6 @@ public: | |||
| //     void            notify(/*message*/);
 | ||||
|     void            update_ui_from_settings(); | ||||
|     void            CallAfter(std::function<void()> cb); | ||||
|     wxMenuItem*     append_submenu(wxMenu* menu, | ||||
|                                     wxMenu* sub_menu, | ||||
|                                     int id, | ||||
|                                     const wxString& string, | ||||
|                                     const wxString& description, | ||||
|                                     const std::string& icon); | ||||
| 
 | ||||
|     void            window_pos_save(wxTopLevelWindow* window, const std::string &name); | ||||
|     void            window_pos_restore(wxTopLevelWindow* window, const std::string &name); | ||||
|  |  | |||
|  | @ -868,7 +868,7 @@ void ObjectList::del_settings_from_config() | |||
| 
 | ||||
| void ObjectList::del_instances_from_object(const int obj_idx) | ||||
| { | ||||
|     auto instances = (*m_objects)[obj_idx]->instances; | ||||
|     auto& instances = (*m_objects)[obj_idx]->instances; | ||||
|     if (instances.size() <= 1) | ||||
|         return; | ||||
| 
 | ||||
|  | @ -1054,7 +1054,11 @@ void ObjectList::part_selection_changed() | |||
| 
 | ||||
|     m_selected_object_id = obj_idx; | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     wxGetApp().obj_manipul()->update_settings_value(_3DScene::get_canvas(wxGetApp().canvas3D())->get_selection()); | ||||
| #else | ||||
|     wxGetApp().obj_manipul()->update_values(); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| } | ||||
| 
 | ||||
| void ObjectList::update_manipulation_sizer(const bool is_simple_mode) | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include <wx/bitmap.h> | ||||
| #include <wx/dataview.h> | ||||
| #include <map> | ||||
| #include <vector> | ||||
| 
 | ||||
| class wxBoxSizer; | ||||
| class PrusaObjectDataViewModel; | ||||
|  |  | |||
|  | @ -221,7 +221,7 @@ void ObjectManipulation::update_settings_list() | |||
|                 if (cat.second.size() == 1 && cat.second[0] == "extruder") | ||||
|                     continue; | ||||
| 
 | ||||
|                 auto optgroup = std::make_shared<ConfigOptionsGroup>(parent, cat.first, config, false, ogDEFAULT, extra_column); | ||||
|                 auto optgroup = std::make_shared<ConfigOptionsGroup>(parent, cat.first, config, false, extra_column); | ||||
|                 optgroup->label_width = 150; | ||||
|                 optgroup->sidetext_width = 70; | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ | |||
| 
 | ||||
| #include <wx/toplevel.h> | ||||
| #include <wx/sizer.h> | ||||
| #include <wx/panel.h> | ||||
| #include <wx/checkbox.h> | ||||
| 
 | ||||
| #include "libslic3r/Config.hpp" | ||||
|  | @ -16,6 +15,30 @@ namespace Slic3r { | |||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent) | ||||
|     : wxPanel(parent, wxID_ANY) | ||||
| { | ||||
|     // WARN: wxMSW does some extra shenanigans to calc the extra control size.
 | ||||
|     // It first calls the create function with a dummy empty wxDialog parent and saves its size.
 | ||||
|     // Afterwards, the create function is called again with the real parent.
 | ||||
|     // Additionally there's no way to pass any extra data to the create function (no closure),
 | ||||
|     // which is why we have to this stuff here. Grrr!
 | ||||
|     auto *dlg = dynamic_cast<CheckboxFileDialog*>(parent); | ||||
|     const wxString checkbox_label(dlg != nullptr ? dlg->checkbox_label : wxString("String long enough to contain dlg->checkbox_label")); | ||||
| 
 | ||||
|     auto* sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|     cbox = new wxCheckBox(this, wxID_ANY, checkbox_label); | ||||
|     cbox->SetValue(true); | ||||
|     sizer->AddSpacer(5); | ||||
|     sizer->Add(this->cbox, 0, wxEXPAND | wxALL, 5); | ||||
|     SetSizer(sizer); | ||||
|     sizer->SetSizeHints(this); | ||||
| } | ||||
| 
 | ||||
| wxWindow* CheckboxFileDialog::ExtraPanel::ctor(wxWindow *parent) { | ||||
|     return new ExtraPanel(parent); | ||||
| } | ||||
| 
 | ||||
| CheckboxFileDialog::CheckboxFileDialog(wxWindow *parent, | ||||
|     const wxString &checkbox_label, | ||||
|     bool checkbox_value, | ||||
|  | @ -29,35 +52,22 @@ CheckboxFileDialog::CheckboxFileDialog(wxWindow *parent, | |||
|     const wxString &name | ||||
| ) | ||||
|     : wxFileDialog(parent, message, default_dir, default_file, wildcard, style, pos, size, name) | ||||
|     , cbox(nullptr) | ||||
|     , checkbox_label(checkbox_label) | ||||
| { | ||||
|     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); | ||||
| 
 | ||||
|         return panel; | ||||
|     }; | ||||
| 
 | ||||
|     SetExtraControlCreator(*extra_control_creator.target<ExtraControlCreatorFunction>()); | ||||
|     SetExtraControlCreator(ExtraPanel::ctor); | ||||
| } | ||||
| 
 | ||||
| bool CheckboxFileDialog::get_checkbox_value() const | ||||
| { | ||||
|     return this->cbox != nullptr ? cbox->IsChecked() : false; | ||||
|     auto *extra_panel = dynamic_cast<ExtraPanel*>(GetExtraControl()); | ||||
|     return extra_panel != nullptr ? extra_panel->cbox->GetValue() : false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| WindowMetrics WindowMetrics::from_window(wxTopLevelWindow *window) | ||||
| { | ||||
|     WindowMetrics res; | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| 
 | ||||
| #include <wx/filedlg.h> | ||||
| #include <wx/gdicmn.h> | ||||
| #include <wx/panel.h> | ||||
| 
 | ||||
| class wxCheckBox; | ||||
| class wxTopLevelWindow; | ||||
|  | @ -37,8 +38,15 @@ public: | |||
|     bool get_checkbox_value() const; | ||||
| 
 | ||||
| private: | ||||
|     std::function<wxWindow*(wxWindow*)> extra_control_creator; | ||||
|     wxCheckBox *cbox; | ||||
|     struct ExtraPanel : public wxPanel | ||||
|     { | ||||
|         wxCheckBox *cbox; | ||||
| 
 | ||||
|         ExtraPanel(wxWindow *parent); | ||||
|         static wxWindow* ctor(wxWindow *parent); | ||||
|     }; | ||||
| 
 | ||||
|     wxString checkbox_label; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -296,13 +296,13 @@ void MainFrame::init_menubar() | |||
|     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"); | ||||
|             [this](wxCommandEvent&){ m_plater->export_gcode(); }, "cog_go.png"); | ||||
|         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"); | ||||
|             [this](wxCommandEvent&){ m_plater->export_stl(); }, "brick_go.png"); | ||||
|         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"); | ||||
|             [this](wxCommandEvent&){ m_plater->export_amf(); }, "brick_go.png"); | ||||
|         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"); | ||||
|             [this](wxCommandEvent&){ m_plater->export_3mf(); }, "brick_go.png"); | ||||
|     } | ||||
| 
 | ||||
|     // Window menu
 | ||||
|  |  | |||
|  | @ -97,8 +97,8 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co | |||
| void OptionsGroup::add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& field) | ||||
| { | ||||
| 	if (!m_show_modified_btns) { | ||||
| 		field->m_Undo_btn->Hide(); | ||||
| 		field->m_Undo_to_sys_btn->Hide(); | ||||
|         field->m_Undo_btn->set_as_hidden(); | ||||
| 		field->m_Undo_to_sys_btn->set_as_hidden(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -123,6 +123,10 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/* | |||
| 	for (auto opt : option_set)  | ||||
| 		m_options.emplace(opt.opt_id, opt); | ||||
| 
 | ||||
|     // add mode value for current line to m_options_mode
 | ||||
|     if (!option_set.empty()) | ||||
|         m_options_mode.push_back(option_set[0].opt.mode); | ||||
| 
 | ||||
| 	// if we have a single option with no label, no sidetext just add it directly to sizer
 | ||||
| 	if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width && | ||||
| 		option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr &&  | ||||
|  | @ -156,16 +160,8 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/* | |||
| #endif /* __WXGTK__ */ | ||||
| 
 | ||||
| 	// if we have an extra column, build it
 | ||||
| 	if (extra_column) { | ||||
| 		if (extra_column) { | ||||
| 			grid_sizer->Add(extra_column(parent(), line), 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 3); | ||||
| 		} | ||||
| 		else { | ||||
| 			// if the callback provides no sizer for the extra cell, put a spacer
 | ||||
| 			grid_sizer->AddSpacer(1); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (extra_column) | ||||
| 		grid_sizer->Add(extra_column(parent(), line), 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 3); | ||||
| 
 | ||||
|     // Build a label if we have it
 | ||||
| 	wxStaticText* label=nullptr; | ||||
|  | @ -182,16 +178,14 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/* | |||
|         label->SetFont(label_font); | ||||
|         label->Wrap(label_width); // avoid a Linux/GTK bug
 | ||||
|         if (!line.near_label_widget) | ||||
| 		    grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) |  | ||||
| 						    (m_flag == ogSIDE_OPTIONS_VERTICAL ? wxTOP : wxALIGN_CENTER_VERTICAL), 5); | ||||
| 		    grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5); | ||||
|         else { | ||||
|             // If we're here, we have some widget near the label
 | ||||
|             // so we need a horizontal sizer to arrange these things
 | ||||
|             auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|             grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); | ||||
|             sizer->Add(line.near_label_widget(parent()), 0, wxRIGHT, 7); | ||||
|             sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | | ||||
|                 (m_flag == ogSIDE_OPTIONS_VERTICAL ? wxTOP : wxALIGN_CENTER_VERTICAL), 5); | ||||
|             sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5); | ||||
|         } | ||||
| 		if (line.label_tooltip.compare("") != 0) | ||||
| 			label->SetToolTip(line.label_tooltip); | ||||
|  | @ -208,7 +202,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/* | |||
| 	 | ||||
| 	// If we're here, we have more than one option or a single option with sidetext
 | ||||
|     // so we need a horizontal sizer to arrange these things
 | ||||
| 	auto sizer = new wxBoxSizer(m_flag == ogSIDE_OPTIONS_VERTICAL ? wxVERTICAL : wxHORIZONTAL); | ||||
| 	auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 	grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1); | ||||
| 	// If we have a single option with no sidetext just add it directly to the grid sizer
 | ||||
| 	if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 && | ||||
|  | @ -227,14 +221,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/* | |||
| 
 | ||||
|     for (auto opt : option_set) { | ||||
| 		ConfigOptionDef option = opt.opt; | ||||
| 		wxSizer* sizer_tmp; | ||||
| 		if (m_flag == ogSIDE_OPTIONS_VERTICAL){ | ||||
| 			auto sz = new wxFlexGridSizer(1, 3, 2, 2); | ||||
| 			sz->RemoveGrowableCol(2); | ||||
| 			sizer_tmp = sz; | ||||
| 		} | ||||
|     	else | ||||
|     		sizer_tmp = sizer; | ||||
| 		wxSizer* sizer_tmp = sizer; | ||||
| 		// add label if any
 | ||||
| 		if (option.label != "") { | ||||
| 			wxString str_label = _(option.label); | ||||
|  | @ -260,7 +247,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/* | |||
| 			auto sidetext = new wxStaticText(	parent(), wxID_ANY, _(option.sidetext), wxDefaultPosition,  | ||||
| 												wxSize(sidetext_width, -1)/*wxDefaultSize*/, wxALIGN_LEFT); | ||||
| 			sidetext->SetFont(sidetext_font); | ||||
| 			sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, m_flag == ogSIDE_OPTIONS_VERTICAL ? 0 : 4); | ||||
| 			sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); | ||||
| 			field->set_side_text_ptr(sidetext); | ||||
| 		} | ||||
| 
 | ||||
|  | @ -269,13 +256,10 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/* | |||
| 			sizer_tmp->Add(opt.side_widget(parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1);	//! requires verification
 | ||||
| 		} | ||||
| 
 | ||||
| 		if (opt.opt_id != option_set.back().opt_id && m_flag != ogSIDE_OPTIONS_VERTICAL) //! istead of (opt != option_set.back())
 | ||||
| 		if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back())
 | ||||
| 		{ | ||||
| 			sizer_tmp->AddSpacer(6); | ||||
| 	    } | ||||
| 
 | ||||
| 		if (m_flag == ogSIDE_OPTIONS_VERTICAL) | ||||
| 			sizer->Add(sizer_tmp, 0, wxALIGN_RIGHT|wxALL, 0); | ||||
| 	} | ||||
| 	// add extra sizers if any
 | ||||
| 	for (auto extra_widget : line.get_extra_widgets()) { | ||||
|  | @ -403,6 +387,39 @@ void ConfigOptionsGroup::reload_config(){ | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) { | ||||
|     if (m_options_mode.empty()) | ||||
|         return true; | ||||
|     if (m_grid_sizer->GetEffectiveRowsCount() != m_options_mode.size() && | ||||
|         m_options_mode.size() == 1) | ||||
|         return m_options_mode[0] <= mode; | ||||
| 
 | ||||
|     sizer->ShowItems(true); | ||||
| #ifdef __WXGTK__ | ||||
|     m_panel->Show(true); | ||||
|     m_grid_sizer->Show(true); | ||||
| #endif /* __WXGTK__ */ | ||||
| 
 | ||||
|     int coef = 0; | ||||
|     int hidden_row_cnt = 0; | ||||
|     const int cols = m_grid_sizer->GetCols(); | ||||
|     for (auto opt_mode : m_options_mode) { | ||||
| 		const bool show = opt_mode <= mode; | ||||
|         if (!show) { | ||||
|             hidden_row_cnt++; | ||||
|             for (int i = 0; i < cols; ++i) | ||||
|                 m_grid_sizer->Show(coef + i, show); | ||||
|         } | ||||
|         coef+= cols; | ||||
| 	} | ||||
| 
 | ||||
|     if (hidden_row_cnt == m_options_mode.size()) { | ||||
|         sizer->ShowItems(false); | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_index, bool deserialize){ | ||||
| 
 | ||||
| 	if (deserialize) { | ||||
|  |  | |||
|  | @ -27,11 +27,6 @@ | |||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| enum ogDrawFlag{ | ||||
| 	ogDEFAULT, | ||||
| 	ogSIDE_OPTIONS_VERTICAL | ||||
| }; | ||||
| 
 | ||||
| /// Widget type describes a function object that returns a wxWindow (our widget) and accepts a wxWidget (parent window).
 | ||||
| using widget_t = std::function<wxSizer*(wxWindow*)>;//!std::function<wxWindow*(wxWindow*)>;
 | ||||
| 
 | ||||
|  | @ -151,7 +146,6 @@ public: | |||
| 
 | ||||
| 	inline void		enable() { for (auto& field : m_fields) field.second->enable(); } | ||||
|     inline void		disable() { for (auto& field : m_fields) field.second->disable(); } | ||||
| 	void			set_flag(ogDrawFlag flag) { m_flag = flag; } | ||||
| 	void			set_grid_vgap(int gap) { m_grid_sizer->SetVGap(gap); } | ||||
| 
 | ||||
| 	void set_show_modified_btns_val(bool show) { | ||||
|  | @ -159,9 +153,10 @@ public: | |||
|     } | ||||
| 
 | ||||
| 	OptionsGroup(	wxWindow* _parent, const wxString& title, bool is_tab_opt = false,  | ||||
| 					ogDrawFlag flag = ogDEFAULT, column_t extra_clmn = nullptr) : | ||||
| 					m_parent(_parent), title(title), m_show_modified_btns(is_tab_opt), | ||||
| 					staticbox(title!=""), m_flag(flag), extra_column(extra_clmn){ | ||||
| 					column_t extra_clmn = nullptr) : | ||||
| 					m_parent(_parent), title(title),  | ||||
|                     m_show_modified_btns(is_tab_opt), | ||||
| 					staticbox(title!=""), extra_column(extra_clmn){ | ||||
|         if (staticbox) { | ||||
|             stb = new wxStaticBox(_parent, wxID_ANY, title); | ||||
|             stb->SetFont(wxGetApp().bold_font()); | ||||
|  | @ -172,7 +167,7 @@ public: | |||
|         if (extra_column != nullptr) num_columns++; | ||||
|         m_grid_sizer = new wxFlexGridSizer(0, num_columns, 1,0); | ||||
|         static_cast<wxFlexGridSizer*>(m_grid_sizer)->SetFlexibleDirection(wxBOTH/*wxHORIZONTAL*/); | ||||
|         static_cast<wxFlexGridSizer*>(m_grid_sizer)->AddGrowableCol(label_width != 0); | ||||
|         static_cast<wxFlexGridSizer*>(m_grid_sizer)->AddGrowableCol(label_width == 0 ? 0 : !extra_column ? 1 : 2 ); | ||||
| #ifdef __WXGTK__ | ||||
|         m_panel = new wxPanel( _parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); | ||||
|         sizer->Fit(m_panel); | ||||
|  | @ -187,6 +182,7 @@ public: | |||
| protected: | ||||
| 	std::map<t_config_option_key, Option>	m_options; | ||||
|     wxWindow*				m_parent {nullptr}; | ||||
|     std::vector<ConfigOptionMode>           m_options_mode; | ||||
| 
 | ||||
|     /// Field list, contains unique_ptrs of the derived type.
 | ||||
|     /// using types that need to know what it is beyond the public interface 
 | ||||
|  | @ -197,8 +193,6 @@ protected: | |||
| 	// "true" if option is created in preset tabs
 | ||||
| 	bool					m_show_modified_btns{ false }; | ||||
| 
 | ||||
| 	ogDrawFlag				m_flag{ ogDEFAULT }; | ||||
| 
 | ||||
| 	// This panel is needed for correct showing of the ToolTips for Button, StaticText and CheckBox
 | ||||
| 	// Tooltips on GTK doesn't work inside wxStaticBoxSizer unless you insert a panel 
 | ||||
| 	// inside it before you insert the other controls.
 | ||||
|  | @ -223,8 +217,8 @@ protected: | |||
| class ConfigOptionsGroup: public OptionsGroup { | ||||
| public: | ||||
| 	ConfigOptionsGroup(	wxWindow* parent, const wxString& title, DynamicPrintConfig* _config = nullptr,  | ||||
| 						bool is_tab_opt = false, ogDrawFlag flag = ogDEFAULT, column_t extra_clmn = nullptr) : | ||||
| 		OptionsGroup(parent, title, is_tab_opt, flag, extra_clmn), m_config(_config) {} | ||||
| 						bool is_tab_opt = false, column_t extra_clmn = nullptr) : | ||||
| 		OptionsGroup(parent, title, is_tab_opt, extra_clmn), m_config(_config) {} | ||||
| 
 | ||||
|     /// reference to libslic3r config, non-owning pointer (?).
 | ||||
|     DynamicPrintConfig*		m_config {nullptr}; | ||||
|  | @ -252,6 +246,8 @@ public: | |||
| 	void		back_to_config_value(const DynamicPrintConfig& config, const std::string& opt_key); | ||||
| 	void		on_kill_focus() override{ reload_config();} | ||||
| 	void		reload_config(); | ||||
|     // return value shows visibility : false => all options are hidden
 | ||||
|     bool        update_visibility(ConfigOptionMode mode); | ||||
| 	boost::any	config_value(const std::string& opt_key, int opt_index, bool deserialize); | ||||
| 	// return option value from config 
 | ||||
| 	boost::any	get_config_value(const DynamicPrintConfig& config, const std::string& opt_key, int opt_index = -1); | ||||
|  |  | |||
|  | @ -701,7 +701,7 @@ private: | |||
|     static const std::regex pattern_drop; | ||||
| }; | ||||
| 
 | ||||
| const std::regex PlaterDropTarget::pattern_drop("[.](stl|obj|amf|3mf|prusa)$", std::regex::icase); | ||||
| const std::regex PlaterDropTarget::pattern_drop(".*[.](stl|obj|amf|3mf|prusa)", std::regex::icase); | ||||
| 
 | ||||
| bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames) | ||||
| { | ||||
|  | @ -783,13 +783,19 @@ struct Plater::priv | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     void selection_changed(); | ||||
|     void object_list_changed(); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     void select_view(); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     void remove(size_t obj_idx); | ||||
|     void reset(); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     void rotate(); | ||||
|     void mirror(const Axis &axis); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     void mirror(Axis axis); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     void scale(); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     void arrange(); | ||||
|     void split_object(); | ||||
|     void schedule_background_process(); | ||||
|  | @ -844,12 +850,17 @@ private: | |||
|     bool can_split_object() const; | ||||
|     bool can_cut_object() const; | ||||
|     bool layers_height_allowed() const; | ||||
|     bool can_delete_all() const; | ||||
|     bool can_arrange() const; | ||||
| #if ENABLE_MIRROR | ||||
|     bool can_mirror() const; | ||||
| #endif // ENABLE_MIRROR
 | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| }; | ||||
| 
 | ||||
| const std::regex Plater::priv::pattern_bundle("[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)$", std::regex::icase); | ||||
| const std::regex Plater::priv::pattern_3mf("[.]3mf$", std::regex::icase); | ||||
| const std::regex Plater::priv::pattern_zip_amf("[.]zip[.]amf$", std::regex::icase); | ||||
| const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase); | ||||
| const std::regex Plater::priv::pattern_3mf(".*3mf", std::regex::icase); | ||||
| const std::regex Plater::priv::pattern_zip_amf(".*[.]zip[.]amf", std::regex::icase); | ||||
| 
 | ||||
| Plater::priv::priv(Plater *q, MainFrame *main_frame) : | ||||
|     q(q), | ||||
|  | @ -925,9 +936,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : | |||
|     canvas3D->Bind(EVT_GLCANVAS_MODEL_UPDATE, &priv::on_model_update, this); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [q](SimpleEvent&) { q->remove_selected(); }); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); }); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     canvas3D->Bind(EVT_GLCANVAS_ROTATE_OBJECT, [this](Event<int> &evt) { /*TODO: call rotate */ }); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, [this](SimpleEvent&) { scale(); }); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_INCREASE_OBJECTS, [q](Event<int> &evt) { evt.data == 1 ? q->increase() : q->decrease(); }); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|     canvas3D->Bind(EVT_GLCANVAS_INCREASE_INSTANCES, [q](Event<int> &evt) { evt.data == 1 ? q->increase_instances() : q->decrease_instances(); }); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); }); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this); | ||||
|     canvas3D->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, &priv::on_enable_action_buttons, this); | ||||
|  | @ -937,8 +950,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : | |||
|     canvas3D->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); } ); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_DELETE_ALL, [this](SimpleEvent&) { reset(); }); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_ARRANGE, [this](SimpleEvent&) { arrange(); }); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_MORE, [q](SimpleEvent&) { q->increase(); }); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_FEWER, [q](SimpleEvent&) { q->decrease(); }); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_MORE, [q](SimpleEvent&) { q->increase_instances(); }); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_FEWER, [q](SimpleEvent&) { q->decrease_instances(); }); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_SPLIT, &priv::on_action_split, this); | ||||
|     canvas3D->Bind(EVT_GLTOOLBAR_CUT, &priv::on_action_cut, this); | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|  | @ -1092,6 +1105,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path> &input_ | |||
|                 // $self->async_apply_config;
 | ||||
|             } else { | ||||
|                 model = Slic3r::Model::read_from_file(path.string(), nullptr, false); | ||||
|                 for (auto obj : model.objects) | ||||
|                     if (obj->name.empty()) | ||||
|                         obj->name = fs::path(obj->input_file).filename().string(); | ||||
|             } | ||||
|         } | ||||
|         catch (const std::runtime_error &e) { | ||||
|  | @ -1139,7 +1155,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path> &input_ | |||
|             new_model->convert_multipart_object(nozzle_dmrs->values.size()); | ||||
|         } | ||||
| 
 | ||||
|         auto loaded_idxs = load_model_objects(model.objects); | ||||
|         auto loaded_idxs = load_model_objects(new_model->objects); | ||||
|         obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end()); | ||||
|     } | ||||
| 
 | ||||
|  | @ -1159,7 +1175,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode | |||
|     bool scaled_down = false; | ||||
|     std::vector<size_t> obj_idxs; | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     unsigned int obj_count = 0; | ||||
|     unsigned int obj_count = model.objects.size(); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     for (ModelObject *model_object : model_objects) { | ||||
|  | @ -1238,7 +1254,8 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType | |||
|         case FT_STL: | ||||
|         case FT_AMF: | ||||
|         case FT_3MF: | ||||
|             wildcard = file_wildcards[FT_STL]; | ||||
|         case FT_GCODE: | ||||
|             wildcard = file_wildcards[file_type]; | ||||
|         break; | ||||
| 
 | ||||
|         default: | ||||
|  | @ -1342,7 +1359,7 @@ void Plater::priv::selection_changed() | |||
|     _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); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "layersediting", have_sel && config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D)); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|  | @ -1421,25 +1438,31 @@ 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(); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "deleteall", can_delete_all()); | ||||
|     _3DScene::enable_toolbar_item(canvas3D, "arrange", can_arrange()); | ||||
| #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); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     const bool export_in_progress = !(export_gcode_output_file.empty() && send_gcode_file.empty()); | ||||
|     // XXX: is this right?
 | ||||
|     const bool model_fits = _3DScene::check_volumes_outside_state(canvas3D, config) == ModelInstance::PVS_Inside; | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits); | ||||
| #else | ||||
|     sidebar->enable_buttons(have_objects && !export_in_progress && model_fits); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| } | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| void Plater::priv::select_view() | ||||
| { | ||||
|     // TODO
 | ||||
| } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| void Plater::priv::remove(size_t obj_idx) | ||||
| { | ||||
|  | @ -1448,6 +1471,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 (_3DScene::is_layers_editing_enabled(canvas3D)) | ||||
|         _3DScene::enable_layers_editing(canvas3D, false); | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     objects.erase(objects.begin() + obj_idx); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|  | @ -1471,6 +1497,9 @@ void Plater::priv::reset() | |||
|     // Prevent toolpaths preview from rendering while we modify the Print object
 | ||||
|     preview->set_enabled(false); | ||||
| 
 | ||||
|     if (_3DScene::is_layers_editing_enabled(canvas3D)) | ||||
|         _3DScene::enable_layers_editing(canvas3D, false); | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|     objects.clear(); | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
|  | @ -1487,13 +1516,20 @@ void Plater::priv::reset() | |||
|     update(); | ||||
| } | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| void Plater::priv::rotate() | ||||
| { | ||||
|     // TODO
 | ||||
| } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| void Plater::priv::mirror(const Axis &axis) | ||||
| void Plater::priv::mirror(Axis axis) | ||||
| { | ||||
| #if ENABLE_MIRROR | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     _3DScene::mirror_selection(canvas3D, axis); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| #else | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     if (obj_idx == -1) | ||||
|  | @ -1526,12 +1562,15 @@ void Plater::priv::mirror(const Axis &axis) | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
|     selection_changed(); | ||||
|     update(); | ||||
| #endif // ENABLE_MIRROR
 | ||||
| } | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
| void Plater::priv::scale() | ||||
| { | ||||
|     // TODO
 | ||||
| } | ||||
| #endif // !ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| void Plater::priv::arrange() | ||||
| { | ||||
|  | @ -1547,7 +1586,45 @@ void Plater::priv::arrange() | |||
| 
 | ||||
| void Plater::priv::split_object() | ||||
| { | ||||
|     // TODO
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     if (obj_idx == -1) | ||||
|         return; | ||||
| 
 | ||||
|     // we clone model object because split_object() adds the split volumes
 | ||||
|     // into the same model object, thus causing duplicates when we call load_model_objects()
 | ||||
|     Model new_model = model; | ||||
|     ModelObject* current_model_object = new_model.objects[obj_idx]; | ||||
| 
 | ||||
|     if (current_model_object->volumes.size() > 1) | ||||
|     { | ||||
|         Slic3r::GUI::warning_catcher(q, _(L("The selected object can't be split because it contains more than one volume/material."))); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| //    $self->stop_background_process;
 | ||||
| 
 | ||||
|     ModelObjectPtrs new_objects; | ||||
|     current_model_object->split(&new_objects); | ||||
|     if (new_objects.size() == 1) | ||||
|     { | ||||
|         Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part."))); | ||||
| //        $self->schedule_background_process;
 | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         for (ModelObject* m : new_objects) | ||||
|         { | ||||
|             m->center_around_origin(); | ||||
|         } | ||||
| 
 | ||||
|         remove(obj_idx); | ||||
| 
 | ||||
|         // load all model objects at once, otherwise the plate would be rearranged after each one
 | ||||
|         // causing original positions not to be kept
 | ||||
|         load_model_objects(new_objects); | ||||
|     } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::schedule_background_process() | ||||
|  | @ -1821,7 +1898,7 @@ void Plater::priv::on_action_add(SimpleEvent&) | |||
| 
 | ||||
| void Plater::priv::on_action_split(SimpleEvent&) | ||||
| { | ||||
|     // TODO
 | ||||
|     split_object(); | ||||
| } | ||||
| 
 | ||||
| void Plater::priv::on_action_cut(SimpleEvent&) | ||||
|  | @ -1838,7 +1915,10 @@ void Plater::priv::on_action_settings(SimpleEvent&) | |||
| 
 | ||||
| void Plater::priv::on_action_layersediting(SimpleEvent&) | ||||
| { | ||||
|     // TODO
 | ||||
|     bool enable = !_3DScene::is_layers_editing_enabled(canvas3D); | ||||
|     _3DScene::enable_layers_editing(canvas3D, enable); | ||||
|     if (enable && !_3DScene::is_layers_editing_enabled(canvas3D)) | ||||
|         _3DScene::enable_toolbar_item(canvas3D, "layersediting", false); | ||||
| } | ||||
| 
 | ||||
| #if !ENABLE_EXTENDED_SELECTION | ||||
|  | @ -1958,17 +2038,41 @@ 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"); | ||||
|         [this](wxCommandEvent&){ q->increase_instances(); }, "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"); | ||||
|         [this](wxCommandEvent&){ q->decrease_instances(); }, "delete.png"); | ||||
| 
 | ||||
|     object_menu.AppendSeparator(); | ||||
|      | ||||
| #if ENABLE_MIRROR | ||||
|     wxMenu* mirror_menu = new wxMenu(); | ||||
|     if (mirror_menu == nullptr) | ||||
|         return false; | ||||
| 
 | ||||
|     append_menu_item(mirror_menu, wxID_ANY, _(L("Along X axis")), _(L("Mirror the selected object along the X axis")), | ||||
|         [this](wxCommandEvent&){ mirror(X); }, "bullet_red.png", &object_menu); | ||||
|     append_menu_item(mirror_menu, wxID_ANY, _(L("Along Y axis")), _(L("Mirror the selected object along the Y axis")), | ||||
|         [this](wxCommandEvent&){ mirror(Y); }, "bullet_green.png", &object_menu); | ||||
|     append_menu_item(mirror_menu, wxID_ANY, _(L("Along Z axis")), _(L("Mirror the selected object along the Z axis")), | ||||
|         [this](wxCommandEvent&){ mirror(Z); }, "bullet_blue.png", &object_menu); | ||||
| 
 | ||||
|     wxMenuItem* item_mirror = append_submenu(&object_menu, mirror_menu, wxID_ANY, _(L("Mirror")), _(L("Mirror the selected object"))); | ||||
| #endif // ENABLE_MIRROR
 | ||||
| 
 | ||||
|     wxMenuItem* item_split = append_menu_item(&object_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object into individual parts")), | ||||
|         [this](wxCommandEvent&){ split_object(); }, "shape_ungroup.png"); | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     // ui updates needs to be binded to the parent panel
 | ||||
|     if (q != nullptr) | ||||
|     { | ||||
| #if ENABLE_MIRROR | ||||
|         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_mirror()); }, item_mirror->GetId()); | ||||
| #endif // ENABLE_MIRROR
 | ||||
|         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()); | ||||
|         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split_object()); }, item_split->GetId()); | ||||
|     } | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|  | @ -1997,7 +2101,7 @@ bool Plater::priv::can_decrease_instances() const | |||
| bool Plater::priv::can_split_object() const | ||||
| { | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && !model.objects[obj_idx]->is_multiparts(); | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::can_cut_object() const | ||||
|  | @ -2008,8 +2112,26 @@ bool Plater::priv::can_cut_object() const | |||
| 
 | ||||
| bool Plater::priv::layers_height_allowed() const | ||||
| { | ||||
|     return config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D); | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D); | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::can_delete_all() const | ||||
| { | ||||
|     return !model.objects.empty(); | ||||
| } | ||||
| 
 | ||||
| bool Plater::priv::can_arrange() const | ||||
| { | ||||
|     return !model.objects.empty(); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_MIRROR | ||||
| bool Plater::priv::can_mirror() const | ||||
| { | ||||
|     return get_selection().is_from_single_instance(); | ||||
| } | ||||
| #endif // ENABLE_MIRROR
 | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
| // Plater / Public
 | ||||
|  | @ -2063,7 +2185,7 @@ void Plater::remove_selected() | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| } | ||||
| 
 | ||||
| void Plater::increase(size_t num) | ||||
| void Plater::increase_instances(size_t num) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = p->get_selected_object_idx(); | ||||
|  | @ -2105,12 +2227,16 @@ void Plater::increase(size_t num) | |||
|         p->update(); | ||||
|     } | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     p->selection_changed(); | ||||
| 
 | ||||
|     this->p->schedule_background_process(); | ||||
| } | ||||
| 
 | ||||
| void Plater::decrease(size_t num) | ||||
| void Plater::decrease_instances(size_t num) | ||||
| { | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     int obj_idx = p->get_selected_object_idx(); | ||||
|  | @ -2148,6 +2274,12 @@ void Plater::decrease(size_t num) | |||
|     } | ||||
| 
 | ||||
|     p->update(); | ||||
| 
 | ||||
| #if ENABLE_EXTENDED_SELECTION | ||||
|     if (!model_object->instances.empty()) | ||||
|         p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1); | ||||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     p->selection_changed(); | ||||
| 
 | ||||
|     // $self->schedule_background_process;
 | ||||
|  | @ -2169,11 +2301,10 @@ void Plater::set_number_of_copies(size_t num) | |||
| #endif // ENABLE_EXTENDED_SELECTION
 | ||||
| 
 | ||||
|     int diff = (int)num - (int)model_object->instances.size(); | ||||
|     if (diff > 0) { | ||||
|         increase(diff); | ||||
|     } else if (diff < 0) { | ||||
|         decrease(-diff); | ||||
|     } | ||||
|     if (diff > 0) | ||||
|         increase_instances(diff); | ||||
|     else if (diff < 0) | ||||
|         decrease_instances(-diff); | ||||
| } | ||||
| 
 | ||||
| fs::path Plater::export_gcode(const fs::path &output_path) | ||||
|  |  | |||
|  | @ -113,8 +113,8 @@ public: | |||
| 
 | ||||
|     void remove(size_t obj_idx); | ||||
|     void remove_selected(); | ||||
|     void increase(size_t num = 1); | ||||
|     void decrease(size_t num = 1); | ||||
|     void increase_instances(size_t num = 1); | ||||
|     void decrease_instances(size_t num = 1); | ||||
|     void set_number_of_copies(size_t num); | ||||
| 
 | ||||
|     // Note: empty path means "use the default"
 | ||||
|  |  | |||
|  | @ -476,14 +476,14 @@ 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)) | ||||
|     if (!cur_item || !m_treectrl->IsVisible(cur_item)) | ||||
|         return; | ||||
| 	auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection()); | ||||
| 	while (cur_item){ | ||||
| 		auto title = m_treectrl->GetItemText(cur_item); | ||||
| 		for (auto page : m_pages) | ||||
| 		{ | ||||
| 			if (page->title() != title) | ||||
| 			if (page->title() != title)  | ||||
| 				continue; | ||||
| 			bool sys_page = true; | ||||
| 			bool modified_page = false; | ||||
|  | @ -632,6 +632,25 @@ void Tab::reload_config(){ | |||
|  	Thaw(); | ||||
| } | ||||
| 
 | ||||
| void Tab::update_visibility(ConfigOptionMode mode) | ||||
| { | ||||
|     Freeze(); | ||||
| 
 | ||||
| 	for (auto page : m_pages) | ||||
|         page->update_visibility(mode); | ||||
|     update_page_tree_visibility(); | ||||
| 
 | ||||
|     m_hsizer->Layout(); | ||||
|     Refresh(); | ||||
| 
 | ||||
| 	Thaw(); | ||||
| 
 | ||||
|     // to update tree items color
 | ||||
|     wxTheApp->CallAfter([this]() { | ||||
|         update_changed_tree_ui(); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| Field* Tab::get_field(const t_config_option_key& opt_key, int opt_index/* = -1*/) const | ||||
| { | ||||
| 	Field* field = nullptr; | ||||
|  | @ -1021,7 +1040,7 @@ void TabPrint::build() | |||
| 
 | ||||
| 	page = add_options_page(_(L("Dependencies")), "wrench.png"); | ||||
| 		optgroup = page->new_optgroup(_(L("Profile dependencies"))); | ||||
| 		line = { _(L("Compatible printers")), "" }; | ||||
|         line = optgroup->create_single_option_line("compatible_printers");//{ _(L("Compatible printers")), "" };
 | ||||
| 		line.widget = [this](wxWindow* parent){ | ||||
| 			return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); | ||||
| 		}; | ||||
|  | @ -1347,7 +1366,7 @@ void TabFilament::build() | |||
|         optgroup->append_single_option_line("filament_cooling_final_speed"); | ||||
|         optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower"); | ||||
| 
 | ||||
|         line = { _(L("Ramming")), "" }; | ||||
|         line = optgroup->create_single_option_line("filament_ramming_parameters");// { _(L("Ramming")), "" };
 | ||||
|         line.widget = [this](wxWindow* parent){ | ||||
| 			auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); | ||||
|             auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|  | @ -1387,7 +1406,7 @@ void TabFilament::build() | |||
| 
 | ||||
| 	page = add_options_page(_(L("Dependencies")), "wrench.png"); | ||||
| 		optgroup = page->new_optgroup(_(L("Profile dependencies"))); | ||||
| 		line = { _(L("Compatible printers")), "" }; | ||||
|         line = optgroup->create_single_option_line("compatible_printers");//{ _(L("Compatible printers")), "" };
 | ||||
| 		line.widget = [this](wxWindow* parent){ | ||||
| 			return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); | ||||
| 		}; | ||||
|  | @ -1482,7 +1501,7 @@ void TabPrinter::build_fff() | |||
| 	auto page = add_options_page(_(L("General")), "printer_empty.png"); | ||||
| 		auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); | ||||
| 
 | ||||
| 		Line line{ _(L("Bed shape")), "" }; | ||||
|         Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" };
 | ||||
| 		line.widget = [this](wxWindow* parent){ | ||||
| 			auto btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
|             btn->SetFont(wxGetApp().small_font()); | ||||
|  | @ -1514,6 +1533,7 @@ void TabPrinter::build_fff() | |||
| 			def.label = L("Extruders"); | ||||
| 			def.tooltip = L("Number of extruders of the printer."); | ||||
| 			def.min = 1; | ||||
|             def.mode = comExpert; | ||||
| 		Option option(def, "extruders_count"); | ||||
| 		optgroup->append_single_option_line(option); | ||||
| 		optgroup->append_single_option_line("single_extruder_multi_material"); | ||||
|  | @ -1767,7 +1787,7 @@ void TabPrinter::build_sla() | |||
|     auto page = add_options_page(_(L("General")), "printer_empty.png"); | ||||
|     auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); | ||||
| 
 | ||||
|     Line line{ _(L("Bed shape")), "" }; | ||||
|     Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" };
 | ||||
|     line.widget = [this](wxWindow* parent){ | ||||
|         auto btn = new wxButton(parent, wxID_ANY, _(L(" Set ")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
|         //			btn->SetFont(Slic3r::GUI::small_font);
 | ||||
|  | @ -2255,6 +2275,33 @@ void Tab::rebuild_page_tree(bool tree_sel_change_event /*= false*/) | |||
| 	Thaw(); | ||||
| } | ||||
| 
 | ||||
| void Tab::update_page_tree_visibility() | ||||
| { | ||||
|     const auto sel_item = m_treectrl->GetSelection(); | ||||
|     const auto selected = sel_item ? m_treectrl->GetItemText(sel_item) : ""; | ||||
|     const auto rootItem = m_treectrl->GetRootItem(); | ||||
| 
 | ||||
|     auto have_selection = 0; | ||||
|     m_treectrl->DeleteChildren(rootItem); | ||||
|     for (auto p : m_pages) | ||||
|     { | ||||
|         if (!p->get_show()) | ||||
|             continue; | ||||
|         auto itemId = m_treectrl->AppendItem(rootItem, p->title(), p->iconID()); | ||||
|         m_treectrl->SetItemTextColour(itemId, p->get_item_colour()); | ||||
|         if (p->title() == selected) { | ||||
|             m_treectrl->SelectItem(itemId); | ||||
|             have_selection = 1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!have_selection) { | ||||
|         // this is triggered on first load, so we don't disable the sel change event
 | ||||
|         m_treectrl->SelectItem(m_treectrl->GetFirstVisibleItem());//! (treectrl->GetFirstChild(rootItem));
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Called by the UI combo box when the user switches profiles.
 | ||||
| // Select a preset by a name.If !defined(name), then the default preset is selected.
 | ||||
| // If the current profile is modified, user is asked to save the changes.
 | ||||
|  | @ -2379,10 +2426,13 @@ void Tab::OnTreeSelChange(wxTreeEvent& event) | |||
| 	wxWindowUpdateLocker noUpdates(this); | ||||
| #endif | ||||
| 
 | ||||
|     if (m_pages.empty()) | ||||
|         return; | ||||
| 
 | ||||
| 	Page* page = nullptr; | ||||
|     const auto sel_item = m_treectrl->GetSelection(); | ||||
|     const auto selection = sel_item ? m_treectrl->GetItemText(sel_item) : ""; | ||||
| 	for (auto p : m_pages) | ||||
|     for (auto p : m_pages) | ||||
| 		if (p->title() == selection) | ||||
| 		{ | ||||
| 			page = p.get(); | ||||
|  | @ -2681,6 +2731,15 @@ void Page::reload_config() | |||
| 		group->reload_config(); | ||||
| } | ||||
| 
 | ||||
| void Page::update_visibility(ConfigOptionMode mode) | ||||
| { | ||||
|     bool ret_val = false; | ||||
|     for (auto group : m_optgroups) | ||||
|         ret_val = group->update_visibility(mode) || ret_val; | ||||
| 
 | ||||
|     m_show = ret_val; | ||||
| } | ||||
| 
 | ||||
| Field* Page::get_field(const t_config_option_key& opt_key, int opt_index /*= -1*/) const | ||||
| { | ||||
| 	Field* field = nullptr; | ||||
|  | @ -2704,8 +2763,22 @@ bool Page::set_value(const t_config_option_key& opt_key, const boost::any& value | |||
| // package Slic3r::GUI::Tab::Page;
 | ||||
| ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_label_width /*= -1*/) | ||||
| { | ||||
|     auto extra_column = [](wxWindow* parent, const Line& line) | ||||
|     { | ||||
|         std::string bmp_name; | ||||
|         if (line.get_options().size() == 0) | ||||
|             bmp_name = "error.png"; | ||||
|         else { | ||||
|             auto mode = line.get_options()[0].opt.mode;  //we assume that we have one option per line
 | ||||
|             bmp_name = mode == comExpert ? "mode_expert_.png" : | ||||
|                        mode == comMiddle ? "mode_middle_.png" : "mode_simple_.png"; | ||||
|         }                                | ||||
|         auto bmp = new wxStaticBitmap(parent, wxID_ANY, wxBitmap(from_u8(var(bmp_name)), wxBITMAP_TYPE_PNG)); | ||||
|         return bmp; | ||||
|     }; | ||||
| 
 | ||||
| 	//! config_ have to be "right"
 | ||||
| 	ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(this, title, m_config, true); | ||||
| 	ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(this, title, m_config, true, extra_column); | ||||
| 	if (noncommon_label_width >= 0) | ||||
| 		optgroup->label_width = noncommon_label_width; | ||||
| 
 | ||||
|  | @ -2844,7 +2917,7 @@ void TabSLAMaterial::build() | |||
| 
 | ||||
|     page = add_options_page(_(L("Dependencies")), "wrench.png"); | ||||
|     optgroup = page->new_optgroup(_(L("Profile dependencies"))); | ||||
|     auto line = Line { _(L("Compatible printers")), "" }; | ||||
|     Line line = optgroup->create_single_option_line("compatible_printers");//Line { _(L("Compatible printers")), "" };
 | ||||
|     line.widget = [this](wxWindow* parent){ | ||||
|         return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn); | ||||
|     }; | ||||
|  |  | |||
|  | @ -47,6 +47,7 @@ class Page : public wxScrolledWindow | |||
| 	wxString		m_title; | ||||
| 	size_t			m_iconID; | ||||
| 	wxBoxSizer*		m_vsizer; | ||||
|     bool            m_show = true; | ||||
| public: | ||||
| 	Page(wxWindow* parent, const wxString title, const int iconID) : | ||||
| 			m_parent(parent), | ||||
|  | @ -73,6 +74,7 @@ public: | |||
| 	size_t		iconID() const { return m_iconID; } | ||||
| 	void		set_config(DynamicPrintConfig* config_in) { m_config = config_in; } | ||||
| 	void		reload_config(); | ||||
|     void        update_visibility(ConfigOptionMode mode); | ||||
| 	Field*		get_field(const t_config_option_key& opt_key, int opt_index = -1) const; | ||||
| 	bool		set_value(const t_config_option_key& opt_key, const boost::any& value); | ||||
| 	ConfigOptionsGroupShp	new_optgroup(const wxString& title, int noncommon_label_width = -1); | ||||
|  | @ -88,6 +90,7 @@ public: | |||
| 	const wxColour	get_item_colour() { | ||||
| 			return *m_item_color; | ||||
| 	} | ||||
|     bool get_show() const { return m_show; } | ||||
| 
 | ||||
| protected: | ||||
| 	// Color of TreeCtrlItem. The wxColour will be updated only if the new wxColour pointer differs from the currently rendered one.
 | ||||
|  | @ -214,6 +217,7 @@ public: | |||
| 	void		create_preset_tab(); | ||||
| 	void		load_current_preset(); | ||||
| 	void        rebuild_page_tree(bool tree_sel_change_event = false); | ||||
| 	void        update_page_tree_visibility(); | ||||
| 	void		select_preset(std::string preset_name = ""); | ||||
| 	bool		may_discard_current_dirty_preset(PresetCollection* presets = nullptr, const std::string& new_printer_name = ""); | ||||
| 	wxSizer*	compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn); | ||||
|  | @ -249,6 +253,7 @@ public: | |||
| 	void			update_tab_ui(); | ||||
| 	void			load_config(const DynamicPrintConfig& config); | ||||
| 	virtual void	reload_config(); | ||||
|     void            update_visibility(ConfigOptionMode mode); | ||||
| 	Field*			get_field(const t_config_option_key& opt_key, int opt_index = -1) const; | ||||
| 	bool			set_value(const t_config_option_key& opt_key, const boost::any& value); | ||||
| 	wxSizer*		description_line_widget(wxWindow* parent, ogStaticText** StaticText); | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ | |||
| #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) | ||||
|     std::function<void(wxCommandEvent& event)> cb, const std::string& icon, wxEvtHandler* event_handler) | ||||
| { | ||||
|     if (id == wxID_ANY) | ||||
|         id = wxNewId(); | ||||
|  | @ -20,7 +20,26 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const | |||
|     if (!icon.empty()) | ||||
|         item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG)); | ||||
| 
 | ||||
|     menu->Bind(wxEVT_MENU, cb, id); | ||||
|     if (event_handler != nullptr) | ||||
|         event_handler->Bind(wxEVT_MENU, cb, id); | ||||
|     else | ||||
|         menu->Bind(wxEVT_MENU, cb, id); | ||||
| 
 | ||||
|     return item; | ||||
| } | ||||
| 
 | ||||
| wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, const std::string& icon) | ||||
| { | ||||
|     if (id == wxID_ANY) | ||||
|         id = wxNewId(); | ||||
| 
 | ||||
|     wxMenuItem* item = new wxMenuItem(menu, id, string, description); | ||||
|     if (!icon.empty()) | ||||
|         item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG)); | ||||
| 
 | ||||
|     item->SetSubMenu(sub_menu); | ||||
|     menu->Append(item); | ||||
| 
 | ||||
|     return item; | ||||
| } | ||||
| 
 | ||||
|  | @ -770,7 +789,7 @@ void PrusaObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& | |||
|     type = itUndef; | ||||
| 
 | ||||
|     PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID(); | ||||
|     if (!node || node->GetIdx() < 0 && node->GetType() != itObject)  | ||||
|     if (!node || node->GetIdx() < 0 && !(node->GetType() & (itObject|itSettings|itInstanceRoot)))  | ||||
|         return; | ||||
| 
 | ||||
|     idx = node->GetIdx(); | ||||
|  |  | |||
|  | @ -12,9 +12,12 @@ | |||
| 
 | ||||
| #include <vector> | ||||
| #include <set> | ||||
| #include <functional> | ||||
| 
 | ||||
| wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, | ||||
|     std::function<void(wxCommandEvent& event)> cb, const std::string& icon = ""); | ||||
|     std::function<void(wxCommandEvent& event)> cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr); | ||||
| 
 | ||||
| wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, const std::string& icon = ""); | ||||
| 
 | ||||
| class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup | ||||
| { | ||||
|  | @ -259,7 +262,10 @@ public: | |||
|             m_name = "Settings to modified"; | ||||
|         } | ||||
|         else if (type == itInstanceRoot) { | ||||
|             m_name = "Instances";             | ||||
|             m_name = "Instances";  | ||||
| #ifdef __WXGTK__ | ||||
|             m_container = true; | ||||
| #endif  //__WXGTK__
 | ||||
|         } | ||||
|         else if (type == itInstance) { | ||||
|             m_idx = parent->GetChildCount(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv