diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 31825d346b..5a44ae48e1 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -23,6 +23,8 @@ #define ENABLE_MODIFIED_CAMERA_TARGET (1 && ENABLE_1_42_0) // Add Geometry::Transformation class and use it into ModelInstance, ModelVolume and GLVolume #define ENABLE_MODELVOLUME_TRANSFORM (1 && ENABLE_1_42_0) +// Gizmos always rendered on top of objects +#define ENABLE_GIZMOS_ON_TOP (1 && ENABLE_1_42_0) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index d6790abe14..45c700482e 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1885,16 +1885,6 @@ int _3DScene::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrint return s_canvas_mgr.check_volumes_outside_state(canvas, config); } -bool _3DScene::move_volume_up(wxGLCanvas* canvas, unsigned int id) -{ - return s_canvas_mgr.move_volume_up(canvas, id); -} - -bool _3DScene::move_volume_down(wxGLCanvas* canvas, unsigned int id) -{ - return s_canvas_mgr.move_volume_down(canvas, id); -} - GUI::GLCanvas3D* _3DScene::get_canvas(wxGLCanvas* canvas) { return s_canvas_mgr.get_canvas(canvas); @@ -1925,21 +1915,6 @@ void _3DScene::set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape) s_canvas_mgr.set_bed_shape(canvas, shape); } -void _3DScene::set_auto_bed_shape(wxGLCanvas* canvas) -{ - s_canvas_mgr.set_auto_bed_shape(canvas); -} - -BoundingBoxf3 _3DScene::get_volumes_bounding_box(wxGLCanvas* canvas) -{ - return s_canvas_mgr.get_volumes_bounding_box(canvas); -} - -void _3DScene::set_axes_length(wxGLCanvas* canvas, float length) -{ - s_canvas_mgr.set_axes_length(canvas, length); -} - void _3DScene::set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons) { s_canvas_mgr.set_cutting_plane(canvas, z, polygons); @@ -1960,11 +1935,6 @@ bool _3DScene::is_layers_editing_allowed(wxGLCanvas* canvas) return s_canvas_mgr.is_layers_editing_allowed(canvas); } -bool _3DScene::is_shader_enabled(wxGLCanvas* canvas) -{ - return s_canvas_mgr.is_shader_enabled(canvas); -} - bool _3DScene::is_reload_delayed(wxGLCanvas* canvas) { return s_canvas_mgr.is_reload_delayed(canvas); @@ -2117,16 +2087,6 @@ std::vector _3DScene::load_object(wxGLCanvas* canvas, const Model* model, i return s_canvas_mgr.load_object(canvas, model, obj_idx); } -int _3DScene::get_first_volume_id(wxGLCanvas* canvas, int obj_idx) -{ - return s_canvas_mgr.get_first_volume_id(canvas, obj_idx); -} - -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); -} - void _3DScene::mirror_selection(wxGLCanvas* canvas, Axis axis) { s_canvas_mgr.mirror_selection(canvas, axis); diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index e54532cd5e..5d81b57bbd 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -567,8 +567,6 @@ public: static unsigned int get_volumes_count(wxGLCanvas* canvas); static void reset_volumes(wxGLCanvas* canvas); static int check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config); - static bool move_volume_up(wxGLCanvas* canvas, unsigned int id); - static bool move_volume_down(wxGLCanvas* canvas, unsigned int id); static GUI::GLCanvas3D* get_canvas(wxGLCanvas* canvas); @@ -578,11 +576,6 @@ public: static void set_model(wxGLCanvas* canvas, Model* model); static void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape); - static void set_auto_bed_shape(wxGLCanvas* canvas); - - static BoundingBoxf3 get_volumes_bounding_box(wxGLCanvas* canvas); - - static void set_axes_length(wxGLCanvas* canvas, float length); static void set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons); @@ -590,7 +583,6 @@ public: static bool is_layers_editing_enabled(wxGLCanvas* canvas); static bool is_layers_editing_allowed(wxGLCanvas* canvas); - static bool is_shader_enabled(wxGLCanvas* canvas); static bool is_reload_delayed(wxGLCanvas* canvas); @@ -626,9 +618,6 @@ public: static std::vector load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector instance_idxs); static std::vector load_object(wxGLCanvas* canvas, const Model* model, int obj_idx); - static int get_first_volume_id(wxGLCanvas* canvas, int obj_idx); - static int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx); - static void mirror_selection(wxGLCanvas* canvas, Axis axis); static void reload_scene(wxGLCanvas* canvas, bool force); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 94b7f2b5db..68d3948bbe 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -11,22 +11,21 @@ namespace Slic3r { namespace GUI { -wxString double_to_string(double const value) +wxString double_to_string(double const value, const int max_precision /*= 4*/) { if (value - int(value) == 0) return wxString::Format(_T("%i"), int(value)); - else { - int precision = 4; - for (size_t p = 1; p < 4; p++) - { - double cur_val = pow(10, p)*value; - if (cur_val - int(cur_val) == 0) { - precision = p; - break; - } + + int precision = max_precision; + for (size_t p = 1; p < max_precision; p++) + { + double cur_val = pow(10, p)*value; + if (cur_val - int(cur_val) == 0) { + precision = p; + break; } - return wxNumberFormatter::ToString(value, precision, wxNumberFormatter::Style_None); } + return wxNumberFormatter::ToString(value, precision, wxNumberFormatter::Style_None); } void Field::PostInitialize() @@ -209,7 +208,8 @@ void TextCtrl::BUILD() { break; } - auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, (m_opt.multiline ? wxTE_MULTILINE : 0)); + const long style = m_opt.multiline ? wxTE_MULTILINE : 0 | m_process_enter ? wxTE_PROCESS_ENTER : 0; + auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, style); temp->SetToolTip(get_tooltip_text(text_value)); @@ -234,21 +234,26 @@ void TextCtrl::BUILD() { }), temp->GetId()); #endif // __WXGTK__ - temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt) - { + if (m_process_enter) { + temp->Bind(wxEVT_TEXT_ENTER, ([this](wxCommandEvent& evt) { on_change_field(); }), temp->GetId()); + } + else { + temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent& evt) + { #ifdef __WXGTK__ - if (bChangedValueEvent) + if (bChangedValueEvent) #endif //__WXGTK__ - on_change_field(); - }), temp->GetId()); + on_change_field(); + }), temp->GetId()); #ifdef __WXGTK__ - // to correct value updating on GTK we should: - // call on_change_field() on wxEVT_KEY_UP instead of wxEVT_TEXT - // and prevent value updating on wxEVT_KEY_DOWN - temp->Bind(wxEVT_KEY_DOWN, &TextCtrl::change_field_value, this); - temp->Bind(wxEVT_KEY_UP, &TextCtrl::change_field_value, this); + // to correct value updating on GTK we should: + // call on_change_field() on wxEVT_KEY_UP instead of wxEVT_TEXT + // and prevent value updating on wxEVT_KEY_DOWN + temp->Bind(wxEVT_KEY_DOWN, &TextCtrl::change_field_value, this); + temp->Bind(wxEVT_KEY_UP, &TextCtrl::change_field_value, this); #endif //__WXGTK__ + } // select all text using Ctrl+A temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event) diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 58c6afebe0..29ae6f9ce0 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -34,7 +34,7 @@ using t_kill_focus = std::function; using t_change = std::function; using t_back_to_init = std::function; -wxString double_to_string(double const value); +wxString double_to_string(double const value, const int max_precision = 4); class MyButton : public wxButton { @@ -139,9 +139,10 @@ public: /// Factory method for generating new derived classes. template - static t_field Create(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) // interface for creating shared objects + static t_field Create(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id, const bool process_enter = false)// interface for creating shared objects { auto p = Slic3r::make_unique(parent, opt, id); + p->m_process_enter = process_enter; p->PostInitialize(); return std::move(p); //!p; } @@ -221,6 +222,9 @@ protected: // current value boost::any m_value; + + //this variable shows a mode of a call of the on_change function + bool m_process_enter { false }; friend class OptionsGroup; }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3e405ffe11..c7a1bad5b8 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1464,7 +1464,9 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement) } #if !DISABLE_INSTANCES_SYNCH - if (m_mode == Volume) + if (m_mode == Instance) + _synchronize_unselected_instances(); + else if (m_mode == Volume) _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH @@ -2548,14 +2550,14 @@ bool GLCanvas3D::Gizmos::grabber_contains_mouse() const return (curr != nullptr) ? (curr->get_hover_id() != -1) : false; } -void GLCanvas3D::Gizmos::update(const Linef3& mouse_ray, const Point* mouse_pos) +void GLCanvas3D::Gizmos::update(const Linef3& mouse_ray, bool shift_down, const Point* mouse_pos) { if (!m_enabled) return; GLGizmoBase* curr = _get_current(); if (curr != nullptr) - curr->update(mouse_ray, mouse_pos); + curr->update(GLGizmoBase::UpdateData(mouse_ray, mouse_pos, shift_down)); } #if ENABLE_GIZMOS_RESET @@ -2714,8 +2716,6 @@ void GLCanvas3D::Gizmos::render_current_gizmo(const GLCanvas3D::Selection& selec if (!m_enabled) return; - ::glDisable(GL_DEPTH_TEST); - _render_current_gizmo(selection); } @@ -3305,38 +3305,6 @@ int GLCanvas3D::check_volumes_outside_state(const DynamicPrintConfig* config) co return (int)state; } -bool GLCanvas3D::move_volume_up(unsigned int id) -{ - if ((id > 0) && (id < (unsigned int)m_volumes.volumes.size())) - { - std::swap(m_volumes.volumes[id - 1], m_volumes.volumes[id]); - GLVolume &v1 = *m_volumes.volumes[id - 1]; - GLVolume &v2 = *m_volumes.volumes[id]; - std::swap(v1.object_id, v2.object_id); - std::swap(v1.volume_id, v2.volume_id); - std::swap(v1.instance_id, v2.instance_id); - return true; - } - - return false; -} - -bool GLCanvas3D::move_volume_down(unsigned int id) -{ - if ((id >= 0) && (id + 1 < (unsigned int)m_volumes.volumes.size())) - { - std::swap(m_volumes.volumes[id + 1], m_volumes.volumes[id]); - GLVolume &v1 = *m_volumes.volumes[id + 1]; - GLVolume &v2 = *m_volumes.volumes[id]; - std::swap(v1.object_id, v2.object_id); - std::swap(v1.volume_id, v2.volume_id); - std::swap(v1.instance_id, v2.instance_id); - return true; - } - - return false; -} - void GLCanvas3D::set_config(DynamicPrintConfig* config) { m_config = config; @@ -3378,26 +3346,6 @@ void GLCanvas3D::set_bed_shape(const Pointfs& shape) m_dirty = true; } -void GLCanvas3D::set_auto_bed_shape() -{ - // draw a default square bed around object center - const BoundingBoxf3& bbox = volumes_bounding_box(); - double max_size = bbox.max_size(); - const Vec3d center = bbox.center(); - - Pointfs bed_shape; - bed_shape.reserve(4); - bed_shape.emplace_back(center(0) - max_size, center(1) - max_size); - bed_shape.emplace_back(center(0) + max_size, center(1) - max_size); - bed_shape.emplace_back(center(0) + max_size, center(1) + max_size); - bed_shape.emplace_back(center(0) - max_size, center(1) + max_size); - - set_bed_shape(bed_shape); - - // Set the origin for painting of the coordinate system axes. - m_axes.origin = Vec3d(center(0), center(1), (double)GROUND_Z); -} - void GLCanvas3D::set_axes_length(float length) { m_axes.length = length; @@ -3439,11 +3387,6 @@ bool GLCanvas3D::is_layers_editing_allowed() const return m_layers_editing.is_allowed(); } -bool GLCanvas3D::is_shader_enabled() const -{ - return m_shader_enabled; -} - bool GLCanvas3D::is_reload_delayed() const { return m_reload_delayed; @@ -3639,6 +3582,7 @@ void GLCanvas3D::render() _picking_pass(); // draw scene + ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _render_background(); if (is_custom_bed) // untextured bed needs to be rendered before objects @@ -3647,8 +3591,8 @@ void GLCanvas3D::render() // disable depth testing so that axes are not covered by ground _render_axes(false); } - _render_objects(); + _render_objects(); _render_selection(); if (!is_custom_bed) // textured bed needs to be rendered after objects @@ -3719,22 +3663,6 @@ std::vector GLCanvas3D::load_support_meshes(const Model& model, int obj_idx return volumes; } -int GLCanvas3D::get_first_volume_id(int obj_idx) const -{ - for (int i = 0; i < (int)m_volumes.volumes.size(); ++i) - { - if ((m_volumes.volumes[i] != nullptr) && (m_volumes.volumes[i]->object_idx() == obj_idx)) - return i; - } - - return -1; -} - -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; -} - void GLCanvas3D::mirror_selection(Axis axis) { m_selection.mirror(axis); @@ -4312,7 +4240,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_canvas->CaptureMouse(); m_mouse.dragging = true; - m_gizmos.update(mouse_ray(pos), &pos); + m_gizmos.update(mouse_ray(pos), evt.ShiftDown(), &pos); switch (m_gizmos.get_current_type()) { @@ -4972,8 +4900,6 @@ void GLCanvas3D::_picking_pass() const void GLCanvas3D::_render_background() const { - ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - ::glPushMatrix(); ::glLoadIdentity(); ::glMatrixMode(GL_PROJECTION); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index ab051229f4..fd4fa19536 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -602,7 +602,7 @@ private: bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const; bool grabber_contains_mouse() const; - void update(const Linef3& mouse_ray, const Point* mouse_pos = nullptr); + void update(const Linef3& mouse_ray, bool shift_down, const Point* mouse_pos = nullptr); #if ENABLE_GIZMOS_RESET void process_double_click(); #endif // ENABLE_GIZMOS_RESET @@ -752,8 +752,6 @@ public: unsigned int get_volumes_count() const; void reset_volumes(); int check_volumes_outside_state(const DynamicPrintConfig* config) const; - bool move_volume_up(unsigned int id); - bool move_volume_down(unsigned int id); void set_config(DynamicPrintConfig* config); void set_print(Print* print); @@ -768,8 +766,6 @@ public: // fills the m_bed.m_grid_lines and sets m_bed.m_origin. // Sets m_bed.m_polygon to limit the object placement. void set_bed_shape(const Pointfs& shape); - // Used by ObjectCutDialog and ObjectPartsPanel to generate a rectangular ground plane to support the scene objects. - void set_auto_bed_shape(); void set_axes_length(float length); @@ -783,7 +779,6 @@ public: bool is_layers_editing_enabled() const; bool is_layers_editing_allowed() const; - bool is_shader_enabled() const; bool is_reload_delayed() const; @@ -828,9 +823,6 @@ public: // Load SLA support tree and SLA pad meshes into the scene, if available at the respective SLAPrintObject instances. std::vector load_support_meshes(const Model& model, int obj_idx); - int get_first_volume_id(int obj_idx) const; - int get_in_object_volume_id(int scene_vol_idx) const; - void mirror_selection(Axis axis); void reload_scene(bool force); @@ -941,13 +933,13 @@ private: void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data); void _update_toolpath_volumes_outside_state(); void _show_warning_texture_if_needed(); - +public: void _on_move(); void _on_rotate(); void _on_scale(); void _on_flatten(); void _on_mirror(); - +private: // generates the legend texture in dependence of the current shown view type void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors); diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 0623600413..7172195200 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -252,18 +252,6 @@ int GLCanvas3DManager::check_volumes_outside_state(wxGLCanvas* canvas, const Dyn return (it != m_canvases.end()) ? it->second->check_volumes_outside_state(config) : false; } -bool GLCanvas3DManager::move_volume_up(wxGLCanvas* canvas, unsigned int id) -{ - CanvasesMap::const_iterator it = _get_canvas(canvas); - return (it != m_canvases.end()) ? it->second->move_volume_up(id) : false; -} - -bool GLCanvas3DManager::move_volume_down(wxGLCanvas* canvas, unsigned int id) -{ - CanvasesMap::const_iterator it = _get_canvas(canvas); - return (it != m_canvases.end()) ? it->second->move_volume_down(id) : false; -} - GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas) { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -284,7 +272,6 @@ void GLCanvas3DManager::set_print(wxGLCanvas* canvas, Print* print) it->second->set_print(print); } - void GLCanvas3DManager::set_SLA_print(wxGLCanvas* canvas, SLAPrint* print) { CanvasesMap::iterator it = _get_canvas(canvas); @@ -306,26 +293,6 @@ void GLCanvas3DManager::set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape) it->second->set_bed_shape(shape); } -void GLCanvas3DManager::set_auto_bed_shape(wxGLCanvas* canvas) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->set_auto_bed_shape(); -} - -BoundingBoxf3 GLCanvas3DManager::get_volumes_bounding_box(wxGLCanvas* canvas) -{ - CanvasesMap::const_iterator it = _get_canvas(canvas); - return (it != m_canvases.end()) ? it->second->volumes_bounding_box() : BoundingBoxf3(); -} - -void GLCanvas3DManager::set_axes_length(wxGLCanvas* canvas, float length) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->set_axes_length(length); -} - void GLCanvas3DManager::set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons) { CanvasesMap::iterator it = _get_canvas(canvas); @@ -352,12 +319,6 @@ bool GLCanvas3DManager::is_layers_editing_allowed(wxGLCanvas* canvas) const return (it != m_canvases.end()) ? it->second->is_layers_editing_allowed() : false; } -bool GLCanvas3DManager::is_shader_enabled(wxGLCanvas* canvas) const -{ - CanvasesMap::const_iterator it = _get_canvas(canvas); - return (it != m_canvases.end()) ? it->second->is_shader_enabled() : false; -} - bool GLCanvas3DManager::is_reload_delayed(wxGLCanvas* canvas) const { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -538,18 +499,6 @@ std::vector GLCanvas3DManager::load_object(wxGLCanvas* canvas, const Model* return (it != m_canvases.end()) ? it->second->load_object(*model, obj_idx) : std::vector(); } -int GLCanvas3DManager::get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const -{ - CanvasesMap::const_iterator it = _get_canvas(canvas); - return (it != m_canvases.end()) ? it->second->get_first_volume_id(obj_idx) : -1; -} - -int GLCanvas3DManager::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const -{ - CanvasesMap::const_iterator it = _get_canvas(canvas); - return (it != m_canvases.end()) ? it->second->get_in_object_volume_id(scene_vol_idx) : -1; -} - void GLCanvas3DManager::mirror_selection(wxGLCanvas* canvas, Axis axis) { CanvasesMap::iterator it = _get_canvas(canvas); diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 89f0d48fc5..237d3558c4 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -89,8 +89,6 @@ public: unsigned int get_volumes_count(wxGLCanvas* canvas) const; void reset_volumes(wxGLCanvas* canvas); int check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config) const; - bool move_volume_up(wxGLCanvas* canvas, unsigned int id); - bool move_volume_down(wxGLCanvas* canvas, unsigned int id); GLCanvas3D* get_canvas(wxGLCanvas* canvas); @@ -100,11 +98,6 @@ public: void set_model(wxGLCanvas* canvas, Model* model); void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape); - void set_auto_bed_shape(wxGLCanvas* canvas); - - BoundingBoxf3 get_volumes_bounding_box(wxGLCanvas* canvas); - - void set_axes_length(wxGLCanvas* canvas, float length); void set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons); @@ -112,7 +105,6 @@ public: bool is_layers_editing_enabled(wxGLCanvas* canvas) const; bool is_layers_editing_allowed(wxGLCanvas* canvas) const; - bool is_shader_enabled(wxGLCanvas* canvas) const; bool is_reload_delayed(wxGLCanvas* canvas) const; @@ -148,9 +140,6 @@ public: std::vector load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector instance_idxs); std::vector load_object(wxGLCanvas* canvas, const Model* model, int obj_idx); - int get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const; - int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const; - void mirror_selection(wxGLCanvas* canvas, Axis axis); void reload_scene(wxGLCanvas* canvas, bool force); diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 11e7bfe230..c2e373452e 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -201,10 +201,10 @@ void GLGizmoBase::stop_dragging() on_stop_dragging(); } -void GLGizmoBase::update(const Linef3& mouse_ray, const Point* mouse_pos) +void GLGizmoBase::update(const UpdateData& data) { if (m_hover_id != -1) - on_update(mouse_ray, mouse_pos); + on_update(data); } float GLGizmoBase::picking_color_component(unsigned int id) const @@ -303,9 +303,9 @@ void GLGizmoRotate::on_start_dragging(const GLCanvas3D::Selection& selection) m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth; } -void GLGizmoRotate::on_update(const Linef3& mouse_ray, const Point* mouse_position) -{ - Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(mouse_ray)); +void GLGizmoRotate::on_update(const UpdateData& data) +{ + Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray)); Vec2d orig_dir = Vec2d::UnitX(); Vec2d new_dir = mouse_pos.normalized(); @@ -597,16 +597,13 @@ bool GLGizmoRotate3D::on_init() std::string path = resources_dir() + "/icons/overlay/"; - std::string filename = path + "rotate_off.png"; - if (!m_textures[Off].load_from_file(filename, false)) + if (!m_textures[Off].load_from_file(path + "rotate_off.png", false)) return false; - filename = path + "rotate_hover.png"; - if (!m_textures[Hover].load_from_file(filename, false)) + if (!m_textures[Hover].load_from_file(path + "rotate_hover.png", false)) return false; - filename = path + "rotate_on.png"; - if (!m_textures[On].load_from_file(filename, false)) + if (!m_textures[On].load_from_file(path + "rotate_on.png", false)) return false; return true; @@ -631,6 +628,10 @@ void GLGizmoRotate3D::on_stop_dragging() void GLGizmoRotate3D::on_render(const GLCanvas3D::Selection& selection) const { +#if ENABLE_GIZMOS_ON_TOP + ::glClear(GL_DEPTH_BUFFER_BIT); +#endif // ENABLE_GIZMOS_ON_TOP + if ((m_hover_id == -1) || (m_hover_id == 0)) m_gizmos[X].render(selection); @@ -646,6 +647,7 @@ const float GLGizmoScale3D::Offset = 5.0f; GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent) : GLGizmoBase(parent) , m_scale(Vec3d::Ones()) + , m_snap_step(0.05) , m_starting_scale(Vec3d::Ones()) { } @@ -654,16 +656,13 @@ bool GLGizmoScale3D::on_init() { std::string path = resources_dir() + "/icons/overlay/"; - std::string filename = path + "scale_off.png"; - if (!m_textures[Off].load_from_file(filename, false)) + if (!m_textures[Off].load_from_file(path + "scale_off.png", false)) return false; - filename = path + "scale_hover.png"; - if (!m_textures[Hover].load_from_file(filename, false)) + if (!m_textures[Hover].load_from_file(path + "scale_hover.png", false)) return false; - filename = path + "scale_on.png"; - if (!m_textures[On].load_from_file(filename, false)) + if (!m_textures[On].load_from_file(path + "scale_on.png", false)) return false; for (int i = 0; i < 10; ++i) @@ -698,16 +697,16 @@ void GLGizmoScale3D::on_start_dragging(const GLCanvas3D::Selection& selection) } } -void GLGizmoScale3D::on_update(const Linef3& mouse_ray, const Point* mouse_pos) +void GLGizmoScale3D::on_update(const UpdateData& data) { if ((m_hover_id == 0) || (m_hover_id == 1)) - do_scale_x(mouse_ray); + do_scale_x(data); else if ((m_hover_id == 2) || (m_hover_id == 3)) - do_scale_y(mouse_ray); + do_scale_y(data); else if ((m_hover_id == 4) || (m_hover_id == 5)) - do_scale_z(mouse_ray); + do_scale_z(data); else if (m_hover_id >= 6) - do_scale_uniform(mouse_ray); + do_scale_uniform(data); } #if ENABLE_GIZMOS_RESET @@ -749,6 +748,9 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const set_tooltip(tooltip); } +#if ENABLE_GIZMOS_ON_TOP + ::glClear(GL_DEPTH_BUFFER_BIT); +#endif // ENABLE_GIZMOS_ON_TOP ::glEnable(GL_DEPTH_TEST); BoundingBoxf3 box; @@ -933,39 +935,35 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int } } -void GLGizmoScale3D::do_scale_x(const Linef3& mouse_ray) +void GLGizmoScale3D::do_scale_x(const UpdateData& data) { - double ratio = calc_ratio(mouse_ray); - + double ratio = calc_ratio(data); if (ratio > 0.0) m_scale(0) = m_starting_scale(0) * ratio; } -void GLGizmoScale3D::do_scale_y(const Linef3& mouse_ray) +void GLGizmoScale3D::do_scale_y(const UpdateData& data) { - double ratio = calc_ratio(mouse_ray); - + double ratio = calc_ratio(data); if (ratio > 0.0) m_scale(1) = m_starting_scale(1) * ratio; } -void GLGizmoScale3D::do_scale_z(const Linef3& mouse_ray) +void GLGizmoScale3D::do_scale_z(const UpdateData& data) { - double ratio = calc_ratio(mouse_ray); - + double ratio = calc_ratio(data); if (ratio > 0.0) m_scale(2) = m_starting_scale(2) * ratio; } -void GLGizmoScale3D::do_scale_uniform(const Linef3& mouse_ray) +void GLGizmoScale3D::do_scale_uniform(const UpdateData& data) { - double ratio = calc_ratio(mouse_ray); - + double ratio = calc_ratio(data); if (ratio > 0.0) m_scale = m_starting_scale * ratio; } -double GLGizmoScale3D::calc_ratio(const Linef3& mouse_ray) const +double GLGizmoScale3D::calc_ratio(const UpdateData& data) const { double ratio = 0.0; @@ -974,21 +972,24 @@ double GLGizmoScale3D::calc_ratio(const Linef3& mouse_ray) const double len_starting_vec = starting_vec.norm(); if (len_starting_vec != 0.0) { - Vec3d mouse_dir = mouse_ray.unit_vector(); + Vec3d mouse_dir = data.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; + Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.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; + ratio = (len_starting_vec + proj) / len_starting_vec; } + if (data.shift_down) + ratio = m_snap_step * (double)std::round(ratio / m_snap_step); + return ratio; } @@ -997,6 +998,7 @@ const double GLGizmoMove3D::Offset = 10.0; GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent) : GLGizmoBase(parent) , m_displacement(Vec3d::Zero()) + , m_snap_step(1.0) , m_starting_drag_position(Vec3d::Zero()) , m_starting_box_center(Vec3d::Zero()) , m_starting_box_bottom_center(Vec3d::Zero()) @@ -1007,16 +1009,13 @@ bool GLGizmoMove3D::on_init() { std::string path = resources_dir() + "/icons/overlay/"; - std::string filename = path + "move_off.png"; - if (!m_textures[Off].load_from_file(filename, false)) + if (!m_textures[Off].load_from_file(path + "move_off.png", false)) return false; - filename = path + "move_hover.png"; - if (!m_textures[Hover].load_from_file(filename, false)) + if (!m_textures[Hover].load_from_file(path + "move_hover.png", false)) return false; - filename = path + "move_on.png"; - if (!m_textures[On].load_from_file(filename, false)) + if (!m_textures[On].load_from_file(path + "move_on.png", false)) return false; for (int i = 0; i < 3; ++i) @@ -1050,14 +1049,14 @@ void GLGizmoMove3D::on_stop_dragging() m_displacement = Vec3d::Zero(); } -void GLGizmoMove3D::on_update(const Linef3& mouse_ray, const Point* mouse_pos) +void GLGizmoMove3D::on_update(const UpdateData& data) { if (m_hover_id == 0) - m_displacement(0) = calc_projection(mouse_ray); + m_displacement(0) = calc_projection(data); else if (m_hover_id == 1) - m_displacement(1) = calc_projection(mouse_ray); + m_displacement(1) = calc_projection(data); else if (m_hover_id == 2) - m_displacement(2) = calc_projection(mouse_ray); + m_displacement(2) = calc_projection(data); } void GLGizmoMove3D::on_render(const GLCanvas3D::Selection& selection) const @@ -1072,6 +1071,9 @@ void GLGizmoMove3D::on_render(const GLCanvas3D::Selection& selection) const else if ((show_position && (m_hover_id == 2)) || m_grabbers[2].dragging) set_tooltip("Z: " + format(show_position ? position(2) : m_displacement(2), 2)); +#if ENABLE_GIZMOS_ON_TOP + ::glClear(GL_DEPTH_BUFFER_BIT); +#endif // ENABLE_GIZMOS_ON_TOP ::glEnable(GL_DEPTH_TEST); const BoundingBoxf3& box = selection.get_bounding_box(); @@ -1130,7 +1132,7 @@ void GLGizmoMove3D::on_render_for_picking(const GLCanvas3D::Selection& selection render_grabbers_for_picking(selection.get_bounding_box()); } -double GLGizmoMove3D::calc_projection(const Linef3& mouse_ray) const +double GLGizmoMove3D::calc_projection(const UpdateData& data) const { double projection = 0.0; @@ -1138,18 +1140,22 @@ double GLGizmoMove3D::calc_projection(const Linef3& mouse_ray) const double len_starting_vec = starting_vec.norm(); if (len_starting_vec != 0.0) { - Vec3d mouse_dir = mouse_ray.unit_vector(); + Vec3d mouse_dir = data.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; + Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.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()); } + + if (data.shift_down) + projection = m_snap_step * (double)std::round(projection / m_snap_step); + return projection; } @@ -1164,16 +1170,13 @@ bool GLGizmoFlatten::on_init() { std::string path = resources_dir() + "/icons/overlay/"; - std::string filename = path + "layflat_off.png"; - if (!m_textures[Off].load_from_file(filename, false)) + if (!m_textures[Off].load_from_file(path + "layflat_off.png", false)) return false; - filename = path + "layflat_hover.png"; - if (!m_textures[Hover].load_from_file(filename, false)) + if (!m_textures[Hover].load_from_file(path + "layflat_hover.png", false)) return false; - filename = path + "layflat_on.png"; - if (!m_textures[On].load_from_file(filename, false)) + if (!m_textures[On].load_from_file(path + "layflat_on.png", false)) return false; return true; @@ -1496,16 +1499,13 @@ bool GLGizmoSlaSupports::on_init() { std::string path = resources_dir() + "/icons/overlay/"; - std::string filename = path + "sla_support_points_off.png"; - if (!m_textures[Off].load_from_file(filename, false)) + if (!m_textures[Off].load_from_file(path + "sla_support_points_off.png", false)) return false; - filename = path + "sla_support_points_hover.png"; - if (!m_textures[Hover].load_from_file(filename, false)) + if (!m_textures[Hover].load_from_file(path + "sla_support_points_hover.png", false)) return false; - filename = path + "sla_support_points_on.png"; - if (!m_textures[On].load_from_file(filename, false)) + if (!m_textures[On].load_from_file(path + "sla_support_points_on.png", false)) return false; return true; @@ -1708,12 +1708,12 @@ void GLGizmoSlaSupports::delete_current_grabber(bool delete_all) } } -void GLGizmoSlaSupports::on_update(const Linef3& mouse_ray, const Point* mouse_pos) +void GLGizmoSlaSupports::on_update(const UpdateData& data) { - if (m_hover_id != -1 && mouse_pos) { + if (m_hover_id != -1 && data.mouse_pos) { Vec3f new_pos; try { - new_pos = unproject_on_mesh(Vec2d((*mouse_pos)(0), (*mouse_pos)(1))); + new_pos = unproject_on_mesh(Vec2d((*data.mouse_pos)(0), (*data.mouse_pos)(1))); m_grabbers[m_hover_id].center = new_pos.cast(); m_model_object->sla_support_points[m_hover_id] = new_pos; } diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index cefc581bd8..7156c0b02a 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -52,6 +52,17 @@ public: Num_States }; + struct UpdateData + { + const Linef3 mouse_ray; + const Point* mouse_pos; + bool shift_down; + + UpdateData(const Linef3& mouse_ray, const Point* mouse_pos = nullptr, bool shift_down = false) + : mouse_ray(mouse_ray), mouse_pos(mouse_pos), shift_down(shift_down) + {} + }; + protected: GLCanvas3D& m_parent; @@ -78,9 +89,7 @@ public: void set_group_id(int id) { m_group_id = id; } EState get_state() const { return m_state; } - void set_state(EState state) { - m_state = state; on_set_state(); - } + void set_state(EState state) { m_state = state; on_set_state(); } bool is_activable(const GLCanvas3D::Selection& selection) const { return on_is_activable(selection); } @@ -99,7 +108,7 @@ public: void stop_dragging(); bool is_dragging() const { return m_dragging; } - void update(const Linef3& mouse_ray, const Point* mouse_pos); + void update(const UpdateData& data); #if ENABLE_GIZMOS_RESET void process_double_click() { on_process_double_click(); } @@ -118,7 +127,7 @@ protected: virtual void on_disable_grabber(unsigned int id) {} virtual void on_start_dragging(const GLCanvas3D::Selection& selection) {} virtual void on_stop_dragging() {} - virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos) = 0; + virtual void on_update(const UpdateData& data) = 0; #if ENABLE_GIZMOS_RESET virtual void on_process_double_click() {} #endif // ENABLE_GIZMOS_RESET @@ -175,7 +184,7 @@ protected: virtual bool on_init(); virtual std::string on_get_name() const { return ""; } virtual void on_start_dragging(const GLCanvas3D::Selection& selection); - virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos); + virtual void on_update(const UpdateData& data); #if ENABLE_GIZMOS_RESET virtual void on_process_double_click() { m_angle = 0.0; } #endif // ENABLE_GIZMOS_RESET @@ -235,11 +244,11 @@ protected: } virtual void on_start_dragging(const GLCanvas3D::Selection& selection); virtual void on_stop_dragging(); - virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos) + virtual void on_update(const UpdateData& data) { for (GLGizmoRotate& g : m_gizmos) { - g.update(mouse_ray, mouse_pos); + g.update(data); } } #if ENABLE_GIZMOS_RESET @@ -267,6 +276,8 @@ class GLGizmoScale3D : public GLGizmoBase Vec3d m_scale; + double m_snap_step; + Vec3d m_starting_scale; Vec3d m_starting_drag_position; BoundingBoxf3 m_starting_box; @@ -274,6 +285,9 @@ class GLGizmoScale3D : public GLGizmoBase public: explicit GLGizmoScale3D(GLCanvas3D& parent); + double get_snap_step(double step) const { return m_snap_step; } + void set_snap_step(double step) { m_snap_step = step; } + const Vec3d& get_scale() const { return m_scale; } void set_scale(const Vec3d& scale) { m_starting_scale = scale; m_scale = scale; } @@ -282,7 +296,7 @@ protected: virtual std::string on_get_name() const; virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return !selection.is_wipe_tower(); } virtual void on_start_dragging(const GLCanvas3D::Selection& selection); - virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos); + virtual void on_update(const UpdateData& data); #if ENABLE_GIZMOS_RESET virtual void on_process_double_click(); #endif // ENABLE_GIZMOS_RESET @@ -292,12 +306,12 @@ protected: private: void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const; - void do_scale_x(const Linef3& mouse_ray); - void do_scale_y(const Linef3& mouse_ray); - void do_scale_z(const Linef3& mouse_ray); - void do_scale_uniform(const Linef3& mouse_ray); + void do_scale_x(const UpdateData& data); + void do_scale_y(const UpdateData& data); + void do_scale_z(const UpdateData& data); + void do_scale_uniform(const UpdateData& data); - double calc_ratio(const Linef3& mouse_ray) const; + double calc_ratio(const UpdateData& data) const; }; class GLGizmoMove3D : public GLGizmoBase @@ -305,6 +319,9 @@ class GLGizmoMove3D : public GLGizmoBase static const double Offset; Vec3d m_displacement; + + double m_snap_step; + Vec3d m_starting_drag_position; Vec3d m_starting_box_center; Vec3d m_starting_box_bottom_center; @@ -312,6 +329,9 @@ class GLGizmoMove3D : public GLGizmoBase public: explicit GLGizmoMove3D(GLCanvas3D& parent); + double get_snap_step(double step) const { return m_snap_step; } + void set_snap_step(double step) { m_snap_step = step; } + const Vec3d& get_displacement() const { return m_displacement; } protected: @@ -319,12 +339,12 @@ protected: virtual std::string on_get_name() const; virtual void on_start_dragging(const GLCanvas3D::Selection& selection); virtual void on_stop_dragging(); - virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos); + virtual void on_update(const UpdateData& data); virtual void on_render(const GLCanvas3D::Selection& selection) const; virtual void on_render_for_picking(const GLCanvas3D::Selection& selection) const; private: - double calc_projection(const Linef3& mouse_ray) const; + double calc_projection(const UpdateData& data) const; }; class GLGizmoFlatten : public GLGizmoBase @@ -366,7 +386,7 @@ protected: virtual std::string on_get_name() const; virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return (selection.is_from_single_object() && !selection.is_wipe_tower() && !selection.is_modifier()); } virtual void on_start_dragging(const GLCanvas3D::Selection& selection); - virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos) {} + virtual void on_update(const UpdateData& data) {} virtual void on_render(const GLCanvas3D::Selection& selection) const; virtual void on_render_for_picking(const GLCanvas3D::Selection& selection) const; virtual void on_set_state() @@ -404,7 +424,7 @@ public: private: bool on_init(); - void on_update(const Linef3& mouse_ray, const Point* mouse_pos); + void on_update(const UpdateData& data); virtual void on_render(const GLCanvas3D::Selection& selection) const; virtual void on_render_for_picking(const GLCanvas3D::Selection& selection) const; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1d8463e92f..a616307ba6 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1182,20 +1182,23 @@ void ObjectList::delete_from_model_and_list(const ItemType type, const int obj_i void ObjectList::delete_from_model_and_list(const std::vector& items_for_delete) { - for (auto& item : items_for_delete) + if (items_for_delete.empty()) + return; + + for (std::vector::const_reverse_iterator item = items_for_delete.rbegin(); item != items_for_delete.rend(); ++item) { - if ( !(item.type&(itObject|itVolume|itInstance)) ) + if (!(item->type&(itObject | itVolume | itInstance))) continue; - if (item.type&itObject) { - del_object(item.obj_idx); - m_objects_model->Delete(m_objects_model->GetItemById(item.obj_idx)); + if (item->type&itObject) { + del_object(item->obj_idx); + m_objects_model->Delete(m_objects_model->GetItemById(item->obj_idx)); } else { - del_subobject_from_object(item.obj_idx, item.sub_obj_idx, item.type); - if (item.type&itVolume) - m_objects_model->Delete(m_objects_model->GetItemByVolumeId(item.obj_idx, item.sub_obj_idx)); + del_subobject_from_object(item->obj_idx, item->sub_obj_idx, item->type); + if (item->type&itVolume) + m_objects_model->Delete(m_objects_model->GetItemByVolumeId(item->obj_idx, item->sub_obj_idx)); else - m_objects_model->Delete(m_objects_model->GetItemByInstanceId(item.obj_idx, item.sub_obj_idx)); + m_objects_model->Delete(m_objects_model->GetItemByInstanceId(item->obj_idx, item->sub_obj_idx)); } } part_selection_changed(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 5993eb1e11..73c0045147 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -14,13 +14,14 @@ namespace Slic3r namespace GUI { -ObjectManipulation::ObjectManipulation(wxWindow* parent): +ObjectManipulation::ObjectManipulation(wxWindow* parent) : OG_Settings(parent, true) { m_og->set_name(_(L("Object Manipulation"))); m_og->label_width = 100; m_og->set_grid_vgap(5); - + m_og->set_process_enter(); // We need to update new values only after press ENTER + m_og->m_on_change = [this](t_config_option_key opt_key, boost::any value) { if (opt_key == "scale_unit") { const wxString& selection = boost::any_cast(value); @@ -32,6 +33,18 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent): m_is_percent_scale = selection == _("%"); update_scale_values(); + return; + } + + std::string param; + std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); + + if (param == "position") { + Vec3d displacement; + displacement(0) = boost::any_cast(m_og->get_value("position_x")); + displacement(1) = boost::any_cast(m_og->get_value("position_y")); + displacement(2) = boost::any_cast(m_og->get_value("position_z")); + change_position_value(displacement); } }; @@ -50,7 +63,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent): auto line = Line{ "", "" }; def.label = ""; def.type = coString; - def.width = 55; + def.width = 50; std::vector axes{ "x", "y", "z" }; for (const auto axis : axes) { @@ -64,7 +77,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent): auto add_og_to_object_settings = [](const std::string& option_name, const std::string& sidetext) { - int def_value = 0; Line line = { _(option_name), "" }; if (option_name == "Scale") { line.near_label_widget = [](wxWindow* parent) { @@ -80,14 +92,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent): } ConfigOptionDef def; - def.type = coInt; - def.default_value = new ConfigOptionInt(def_value); - def.width = 55; + def.type = coFloat; + def.default_value = new ConfigOptionFloat(0.0); + def.width = 50; if (option_name == "Rotation") def.min = -360; - else - def.min = -1000; const std::string lower_name = boost::algorithm::to_lower_copy(option_name); @@ -241,42 +251,47 @@ void ObjectManipulation::reset_settings_value() m_og->disable(); } +wxString def_0 {"0"}; +wxString def_100 {"100"}; + void ObjectManipulation::reset_position_value() { - m_og->set_value("position_x", 0); - m_og->set_value("position_y", 0); - m_og->set_value("position_z", 0); + m_og->set_value("position_x", def_0); + m_og->set_value("position_y", def_0); + m_og->set_value("position_z", def_0); + + cache_position = { 0., 0., 0. }; } void ObjectManipulation::reset_rotation_value() { - m_og->set_value("rotation_x", 0); - m_og->set_value("rotation_y", 0); - m_og->set_value("rotation_z", 0); + m_og->set_value("rotation_x", def_0); + m_og->set_value("rotation_y", def_0); + m_og->set_value("rotation_z", def_0); } void ObjectManipulation::reset_scale_value() { m_is_percent_scale = true; m_og->set_value("scale_unit", _("%")); - m_og->set_value("scale_x", 100); - m_og->set_value("scale_y", 100); - m_og->set_value("scale_z", 100); + m_og->set_value("scale_x", def_100); + m_og->set_value("scale_y", def_100); + m_og->set_value("scale_z", def_100); } void ObjectManipulation::update_values() { int selection = ol_selection(); if (selection < 0 || wxGetApp().mainframe->m_plater->model().objects.size() <= selection) { - m_og->set_value("position_x", 0); - m_og->set_value("position_y", 0); - m_og->set_value("position_z", 0); - m_og->set_value("scale_x", 0); - m_og->set_value("scale_y", 0); - m_og->set_value("scale_z", 0); - m_og->set_value("rotation_x", 0); - m_og->set_value("rotation_y", 0); - m_og->set_value("rotation_z", 0); + m_og->set_value("position_x", def_0); + m_og->set_value("position_y", def_0); + m_og->set_value("position_z", def_0); + m_og->set_value("scale_x" , def_0); + m_og->set_value("scale_y" , def_0); + m_og->set_value("scale_z" , def_0); + m_og->set_value("rotation_x", def_0); + m_og->set_value("rotation_y", def_0); + m_og->set_value("rotation_z", def_0); m_og->disable(); return; } @@ -297,14 +312,14 @@ void ObjectManipulation::update_scale_values() auto size = objects[selection]->instance_bounding_box(0).size(); 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)); - m_og->set_value("scale_z", int(instance->get_scaling_factor(Z) * 100)); + m_og->set_value("scale_x", double_to_string(instance->get_scaling_factor(X) * 100, 2)); + m_og->set_value("scale_y", double_to_string(instance->get_scaling_factor(Y) * 100, 2)); + m_og->set_value("scale_z", double_to_string(instance->get_scaling_factor(Z) * 100, 2)); } else { - m_og->set_value("scale_x", int(instance->get_scaling_factor(X) * size(0) + 0.5)); - 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)); + m_og->set_value("scale_x", double_to_string(instance->get_scaling_factor(X) * size(0) + 0.5, 2)); + m_og->set_value("scale_y", double_to_string(instance->get_scaling_factor(Y) * size(1) + 0.5, 2)); + m_og->set_value("scale_z", double_to_string(instance->get_scaling_factor(Z) * size(2) + 0.5, 2)); } } @@ -312,16 +327,18 @@ void ObjectManipulation::update_position_values() { auto instance = wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front(); - 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))); + m_og->set_value("position_x", double_to_string(instance->get_offset(X), 2)); + m_og->set_value("position_y", double_to_string(instance->get_offset(Y), 2)); + m_og->set_value("position_z", double_to_string(instance->get_offset(Z), 2)); } void ObjectManipulation::update_position_value(const Vec3d& position) { - m_og->set_value("position_x", int(position(0))); - m_og->set_value("position_y", int(position(1))); - m_og->set_value("position_z", int(position(2))); + m_og->set_value("position_x", double_to_string(position(0), 2)); + m_og->set_value("position_y", double_to_string(position(1), 2)); + m_og->set_value("position_z", double_to_string(position(2), 2)); + + cache_position = position; } void ObjectManipulation::update_scale_value(const Vec3d& scaling_factor) @@ -334,9 +351,9 @@ void ObjectManipulation::update_scale_value(const Vec3d& scaling_factor) m_og->set_value("scale_unit", _("%")); auto scale = scaling_factor * 100.0; - m_og->set_value("scale_x", int(scale(0))); - m_og->set_value("scale_y", int(scale(1))); - m_og->set_value("scale_z", int(scale(2))); + m_og->set_value("scale_x", double_to_string(scale(0), 2)); + m_og->set_value("scale_y", double_to_string(scale(1), 2)); + m_og->set_value("scale_z", double_to_string(scale(2), 2)); } void ObjectManipulation::update_rotation_values() @@ -364,18 +381,30 @@ void ObjectManipulation::update_rotation_value(double angle, Axis axis) 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))); + m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(rotation(0)), 0), 2)); + m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(rotation(1)), 0), 2)); + m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(rotation(2)), 0), 2)); } -void ObjectManipulation::show_object_name(bool show) + +void ObjectManipulation::change_position_value(const Vec3d& position) { - wxGridSizer* grid_sizer = m_og->get_grid_sizer(); - grid_sizer->Show(static_cast(0), show); - grid_sizer->Show(static_cast(1), show); + Vec3d displacement(position - cache_position); + + auto canvas = _3DScene::get_canvas(wxGetApp().canvas3D()); + canvas->get_selection().start_dragging(); + canvas->get_selection().translate(displacement); + canvas->_on_move(); + + cache_position = position; } + +void ObjectManipulation::print_cashe_value(const std::string& label, const Vec3d& value) +{ + std::cout << label << " => " << " X:" << value(0) << " Y:" << value(1) << " Z:" << value(2) << std::endl; +} + } //namespace GUI } //namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 974af0f38f..2f016f46f3 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -17,6 +17,10 @@ class ObjectManipulation : public OG_Settings // false -> uniform scale unit bool m_is_uniform_scale = false; // It indicates if scale is uniform + Vec3d cache_position { 0., 0., 0. }; + Vec3d cache_rotation { 0., 0., 0. }; + Vec3d cache_scale { 0., 0., 0. }; + public: ObjectManipulation(wxWindow* parent); ~ObjectManipulation() {} @@ -48,8 +52,13 @@ public: void set_uniform_scaling(const bool uniform_scale) { m_is_uniform_scale = uniform_scale; } - void show_object_name(bool show); + // change values + void change_position_value(const Vec3d& position); + + +private: + void print_cashe_value(const std::string& label, const Vec3d& value); }; }} diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 445736d3e6..4d70d529e4 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -43,7 +43,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co case coPercents: case coString: case coStrings: - m_fields.emplace(id, std::move(TextCtrl::Create(parent(), opt, id))); + m_fields.emplace(id, std::move(TextCtrl::Create(parent(), opt, id, process_enter))); break; case coBool: case coBools: diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index b1c6d4b6e8..c86ad09753 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -94,6 +94,8 @@ public: wxFont label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) }; int sidetext_width{ -1 }; + bool process_enter { false }; + /// Returns a copy of the pointer of the parent wxWindow. /// Accessor function is because users are not allowed to change the parent /// but defining it as const means a lot of const_casts to deal with wx functions. @@ -148,8 +150,13 @@ public: inline void disable() { for (auto& field : m_fields) field.second->disable(); } void set_grid_vgap(int gap) { m_grid_sizer->SetVGap(gap); } - void set_show_modified_btns_val(bool show) { - m_show_modified_btns = show; + void set_show_modified_btns_val(bool show) { + m_show_modified_btns = show; + } + + // The controls inside this option group will generate the event wxEVT_TEXT_ENTER + void set_process_enter() { + process_enter = true; } OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index dcc02e56f1..2def6623cb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -692,14 +692,15 @@ void Sidebar::update_objects_list_extruder_column(int extruders_count) void Sidebar::show_info_sizer() { if (!p->plater->is_single_full_object_selection() || - m_mode < ConfigMenuModeExpert ) { + m_mode < ConfigMenuModeExpert || + p->plater->model().objects.empty()) { p->object_info->Show(false); return; } int obj_idx = p->plater->get_selected_object_idx(); - const ModelObject* model_object = (*wxGetApp().model_objects())[obj_idx]; + const ModelObject* model_object = p->plater->model().objects[obj_idx]; // hack to avoid crash when deleting the last object on the bed if (model_object->volumes.empty()) { @@ -1470,6 +1471,8 @@ void Plater::priv::remove(size_t obj_idx) void Plater::priv::delete_object_from_model(size_t obj_idx) { model.delete_object(obj_idx); + object_list_changed(); + update(); } void Plater::priv::reset()