diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index c4bc391d1..dcb320766 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -12,6 +12,7 @@ #include "DoubleSlider.hpp" #include "GLCanvas3D.hpp" #include "GLToolbar.hpp" +#include "GUI_Preview.hpp" #include "libslic3r/Model.hpp" #if ENABLE_GCODE_VIEWER_STATISTICS #include <imgui/imgui_internal.h> @@ -279,7 +280,7 @@ void GCodeViewer::refresh(const GCodeProcessor::Result& gcode_result, const std: } // update buffers' render paths - refresh_render_paths(false); + refresh_render_paths(false, false); #if ENABLE_GCODE_VIEWER_STATISTICS m_statistics.refresh_time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time).count(); @@ -349,16 +350,16 @@ unsigned int GCodeViewer::get_options_visibility_flags() const }; unsigned int flags = 0; - flags = set_flag(flags, 0, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Travel)); - flags = set_flag(flags, 1, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Retract)); - flags = set_flag(flags, 2, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Unretract)); - flags = set_flag(flags, 3, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Tool_change)); - flags = set_flag(flags, 4, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Color_change)); - flags = set_flag(flags, 5, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print)); - flags = set_flag(flags, 6, is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode)); - flags = set_flag(flags, 7, m_shells.visible); - flags = set_flag(flags, 8, m_sequential_view.marker.is_visible()); - flags = set_flag(flags, 9, is_legend_enabled()); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Travel), is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Travel)); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Retractions), is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Retract)); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Unretractions), is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Unretract)); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::ToolChanges), is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Tool_change)); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::ColorChanges), is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Color_change)); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::PausePrints), is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print)); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::CustomGCodes), is_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode)); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Shells), m_shells.visible); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::ToolMarker), m_sequential_view.marker.is_visible()); + flags = set_flag(flags, static_cast<unsigned int>(Preview::OptionType::Legend), is_legend_enabled()); return flags; } @@ -368,23 +369,24 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags) return (flags & (1 << flag)) != 0; }; - set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Travel, is_flag_set(0)); - set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Retract, is_flag_set(1)); - set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Unretract, is_flag_set(2)); - set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Tool_change, is_flag_set(3)); - set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Color_change, is_flag_set(4)); - set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print, is_flag_set(5)); - set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode, is_flag_set(6)); - m_shells.visible = is_flag_set(7); - m_sequential_view.marker.set_visible(is_flag_set(8)); - enable_legend(is_flag_set(9)); + set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Travel, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Travel))); + set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Retract, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Retractions))); + set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Unretract, is_flag_set(static_cast<unsigned int>(Preview::OptionType::Unretractions))); + set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Tool_change, is_flag_set(static_cast<unsigned int>(Preview::OptionType::ToolChanges))); + set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Color_change, is_flag_set(static_cast<unsigned int>(Preview::OptionType::ColorChanges))); + set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Pause_Print, is_flag_set(static_cast<unsigned int>(Preview::OptionType::PausePrints))); + set_toolpath_move_type_visible(GCodeProcessor::EMoveType::Custom_GCode, is_flag_set(static_cast<unsigned int>(Preview::OptionType::CustomGCodes))); + m_shells.visible = is_flag_set(static_cast<unsigned int>(Preview::OptionType::Shells)); + m_sequential_view.marker.set_visible(is_flag_set(static_cast<unsigned int>(Preview::OptionType::ToolMarker))); + enable_legend(is_flag_set(static_cast<unsigned int>(Preview::OptionType::Legend))); } void GCodeViewer::set_layers_z_range(const std::array<double, 2>& layers_z_range) { - bool keep_sequential_current = layers_z_range[1] <= m_layers_z_range[1]; + bool keep_sequential_current_first = layers_z_range[0] >= m_layers_z_range[0]; + bool keep_sequential_current_last = layers_z_range[1] <= m_layers_z_range[1]; m_layers_z_range = layers_z_range; - refresh_render_paths(keep_sequential_current); + refresh_render_paths(keep_sequential_current_first, keep_sequential_current_last); wxGetApp().plater()->update_preview_moves_slider(); } @@ -628,7 +630,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized) } } -void GCodeViewer::refresh_render_paths(bool keep_sequential_current) const +void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const { #if ENABLE_GCODE_VIEWER_STATISTICS auto start_time = std::chrono::high_resolution_clock::now(); @@ -661,10 +663,12 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current) const m_statistics.render_paths_size = 0; #endif // ENABLE_GCODE_VIEWER_STATISTICS - m_sequential_view.first = m_vertices.vertices_count; - m_sequential_view.last = 0; - if (!keep_sequential_current) - m_sequential_view.current = m_vertices.vertices_count; + m_sequential_view.endpoints.first = m_vertices.vertices_count; + m_sequential_view.endpoints.last = 0; + if (!keep_sequential_current_first) + m_sequential_view.current.first = 0; + if (!keep_sequential_current_last) + m_sequential_view.current.last = m_vertices.vertices_count; // first pass: collect visible paths and update sequential view data std::vector<std::pair<IBuffer*, size_t>> paths; @@ -690,22 +694,23 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current) const // store valid path paths.push_back({ &buffer, i }); - m_sequential_view.first = std::min(m_sequential_view.first, path.first.s_id); - m_sequential_view.last = std::max(m_sequential_view.last, path.last.s_id); + m_sequential_view.endpoints.first = std::min(m_sequential_view.endpoints.first, path.first.s_id); + m_sequential_view.endpoints.last = std::max(m_sequential_view.endpoints.last, path.last.s_id); } } // update current sequential position - m_sequential_view.current = keep_sequential_current ? std::clamp(m_sequential_view.current, m_sequential_view.first, m_sequential_view.last) : m_sequential_view.last; + m_sequential_view.current.first = keep_sequential_current_first ? std::clamp(m_sequential_view.current.first, m_sequential_view.endpoints.first, m_sequential_view.endpoints.last) : m_sequential_view.endpoints.first; + m_sequential_view.current.last = keep_sequential_current_last ? std::clamp(m_sequential_view.current.last, m_sequential_view.endpoints.first, m_sequential_view.endpoints.last) : m_sequential_view.endpoints.last; glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vertices.vbo_id)); size_t v_size = VBuffer::vertex_size_bytes(); - glsafe(::glGetBufferSubData(GL_ARRAY_BUFFER, static_cast<GLintptr>(m_sequential_view.current * v_size), static_cast<GLsizeiptr>(v_size), static_cast<void*>(m_sequential_view.current_position.data()))); + glsafe(::glGetBufferSubData(GL_ARRAY_BUFFER, static_cast<GLintptr>(m_sequential_view.current.last * v_size), static_cast<GLsizeiptr>(v_size), static_cast<void*>(m_sequential_view.current_position.data()))); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); // second pass: filter paths by sequential data for (auto&& [buffer, id] : paths) { const Path& path = buffer->paths[id]; - if ((m_sequential_view.current < path.first.s_id) || (path.last.s_id < m_sequential_view.first)) + if ((m_sequential_view.current.last <= path.first.s_id) || (path.last.s_id <= m_sequential_view.current.first)) continue; Color color; @@ -722,8 +727,12 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current) const it->color = color; } - it->sizes.push_back(std::min(m_sequential_view.current, path.last.s_id) - path.first.s_id + 1); - it->offsets.push_back(static_cast<size_t>(path.first.i_id * sizeof(unsigned int))); + it->sizes.push_back(std::min(m_sequential_view.current.last, path.last.s_id) - std::max(m_sequential_view.current.first, path.first.s_id) + 1); + unsigned int delta_1st = 0; + if ((path.first.s_id < m_sequential_view.current.first) && (m_sequential_view.current.first <= path.last.s_id)) + delta_1st = m_sequential_view.current.first - path.first.s_id; + + it->offsets.push_back(static_cast<size_t>((path.first.i_id + delta_1st) * sizeof(unsigned int))); } #if ENABLE_GCODE_VIEWER_STATISTICS @@ -1013,7 +1022,7 @@ void GCodeViewer::render_legend() const { m_extrusions.role_visibility_flags = is_visible(role) ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role); // update buffers' render paths - refresh_render_paths(false); + refresh_render_paths(false, false); wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); wxGetApp().plater()->update_preview_bottom_toolbar(); } diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index e53bcb0c6..688f1266b 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -222,9 +222,14 @@ public: void init_shader(); }; - unsigned int first{ 0 }; - unsigned int last{ 0 }; - unsigned int current{ 0 }; + struct Endpoints + { + unsigned int first{ 0 }; + unsigned int last{ 0 }; + }; + + Endpoints endpoints; + Endpoints current; Vec3f current_position{ Vec3f::Zero() }; Marker marker; }; @@ -285,7 +290,12 @@ public: const std::vector<double>& get_layers_zs() const { return m_layers_zs; }; const SequentialView& get_sequential_view() const { return m_sequential_view; } - void update_sequential_view_current(unsigned int low, unsigned int high) { m_sequential_view.current = high; refresh_render_paths(true); } + void update_sequential_view_current(unsigned int first, unsigned int last) + { + m_sequential_view.current.first = first; + m_sequential_view.current.last = last; + refresh_render_paths(true, true); + } EViewType get_view_type() const { return m_view_type; } void set_view_type(EViewType type) { @@ -310,7 +320,7 @@ private: bool init_shaders(); void load_toolpaths(const GCodeProcessor::Result& gcode_result); void load_shells(const Print& print, bool initialized); - void refresh_render_paths(bool keep_sequential_current) const; + void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const; void render_toolpaths() const; void render_shells() const; void render_legend() const; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 714ed3c9e..65e1e5058 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -298,17 +298,17 @@ bool Preview::init(wxWindow* parent, Model* model) m_combochecklist_options = new wxComboCtrl(); m_combochecklist_options->Create(this, wxID_ANY, _L("Options"), wxDefaultPosition, wxDefaultSize, wxCB_READONLY); std::string options_items = GUI::into_u8( - _L("Travel") + "|0|" + - _L("Retractions") + "|0|" + - _L("Unretractions") + "|0|" + - _L("Tool changes") + "|0|" + - _L("Color changes") + "|0|" + - _L("Pause prints") + "|0|" + - _L("Custom GCodes") + "|0|" + - _L("Shells") + "|0|" + - _L("Tool marker") + "|1|" + - _L("Legend") + "|1" -); + get_option_type_string(OptionType::Travel) + "|0|" + + get_option_type_string(OptionType::Retractions) + "|0|" + + get_option_type_string(OptionType::Unretractions) + "|0|" + + get_option_type_string(OptionType::ToolChanges) + "|0|" + + get_option_type_string(OptionType::ColorChanges) + "|0|" + + get_option_type_string(OptionType::PausePrints) + "|0|" + + get_option_type_string(OptionType::CustomGCodes) + "|0|" + + get_option_type_string(OptionType::Shells) + "|0|" + + get_option_type_string(OptionType::ToolMarker) + "|0|" + + get_option_type_string(OptionType::Legend) + "|1" + ); Slic3r::GUI::create_combochecklist(m_combochecklist_options, GUI::into_u8(_L("Options")), options_items); #else m_checkbox_travel = new wxCheckBox(this, wxID_ANY, _(L("Travel"))); @@ -328,19 +328,19 @@ bool Preview::init(wxWindow* parent, Model* model) #endif // ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER - m_moves_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL); + m_moves_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxSize(-1, 3 * GetTextExtent("m").y), wxSL_HORIZONTAL); m_moves_slider->SetDrawMode(DoubleSlider::dmSequentialGCodeView); m_moves_slider->Bind(wxEVT_SCROLL_CHANGED, &Preview::on_moves_slider_scroll_changed, this); m_bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL); - m_bottom_toolbar_sizer->AddSpacer(10); + m_bottom_toolbar_sizer->AddSpacer(5); m_bottom_toolbar_sizer->Add(m_label_view_type, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5); - m_bottom_toolbar_sizer->Add(m_choice_view_type, 0, wxALIGN_CENTER_VERTICAL, 5); - m_bottom_toolbar_sizer->AddSpacer(10); + m_bottom_toolbar_sizer->Add(m_choice_view_type, 0, wxALIGN_CENTER_VERTICAL, 0); + m_bottom_toolbar_sizer->AddSpacer(5); m_bottom_toolbar_sizer->Add(m_label_show, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5); - m_bottom_toolbar_sizer->Add(m_combochecklist_options, 0, wxALIGN_CENTER_VERTICAL, 5); + m_bottom_toolbar_sizer->Add(m_combochecklist_options, 0, wxALIGN_CENTER_VERTICAL, 0); m_bottom_toolbar_sizer->Add(m_combochecklist_features, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5); - m_bottom_toolbar_sizer->AddSpacer(10); + m_bottom_toolbar_sizer->AddSpacer(5); m_bottom_toolbar_sizer->Add(m_moves_slider, 1, wxALL | wxEXPAND, 5); #else wxBoxSizer* bottom_sizer = new wxBoxSizer(wxHORIZONTAL); @@ -686,8 +686,27 @@ void Preview::on_combochecklist_features(wxCommandEvent& evt) #if ENABLE_GCODE_VIEWER void Preview::on_combochecklist_options(wxCommandEvent& evt) { - m_canvas->set_gcode_options_visibility_from_flags(Slic3r::GUI::combochecklist_get_flags(m_combochecklist_options)); - refresh_print(); + auto xor = [](unsigned int flags1, unsigned int flags2, unsigned int flag) { + auto is_flag_set = [](unsigned int flags, unsigned int flag) { + return (flags & (1 << flag)) != 0; + }; + return !is_flag_set(flags1, flag) != !is_flag_set(flags2, flag); + }; + + unsigned int curr_flags = m_canvas->get_gcode_options_visibility_flags(); + unsigned int new_flags = Slic3r::GUI::combochecklist_get_flags(m_combochecklist_options); + if (curr_flags == new_flags) + return; + + m_canvas->set_gcode_options_visibility_from_flags(new_flags); + + bool skip_refresh = xor(curr_flags, new_flags, static_cast<unsigned int>(OptionType::Shells)) || + xor(curr_flags, new_flags, static_cast<unsigned int>(OptionType::ToolMarker)); + + if (!skip_refresh) + refresh_print(); + else + m_canvas->set_as_dirty(); } #else void Preview::on_checkbox_travel(wxCommandEvent& evt) @@ -1082,16 +1101,16 @@ void Preview::update_layers_slider_from_canvas(wxKeyEvent& event) void Preview::update_moves_slider() { const GCodeViewer::SequentialView& view = m_canvas->get_gcode_sequential_view(); - std::vector<double> values(view.last - view.first + 1); + std::vector<double> values(view.endpoints.last - view.endpoints.first + 1); unsigned int count = 0; - for (unsigned int i = view.first; i <= view.last; ++i) + for (unsigned int i = view.endpoints.first; i <= view.endpoints.last; ++i) { values[count++] = static_cast<double>(i + 1); } m_moves_slider->SetSliderValues(values); - m_moves_slider->SetMaxValue(view.last - view.first); - m_moves_slider->SetSelectionSpan(0, view.current); + m_moves_slider->SetMaxValue(view.endpoints.last - view.endpoints.first); + m_moves_slider->SetSelectionSpan(view.current.first - view.endpoints.first, view.current.last - view.endpoints.first); } #else void Preview::update_double_slider_from_canvas(wxKeyEvent & event) @@ -1356,6 +1375,25 @@ void Preview::on_moves_slider_scroll_changed(wxCommandEvent& event) m_canvas->update_gcode_sequential_view_current(static_cast<unsigned int>(m_moves_slider->GetLowerValueD()), static_cast<unsigned int>(m_moves_slider->GetHigherValueD())); m_canvas->render(); } + +wxString Preview::get_option_type_string(OptionType type) const +{ + switch (type) + { + case OptionType::Travel: { return _L("Travel"); } + case OptionType::Retractions: { return _L("Retractions"); } + case OptionType::Unretractions: { return _L("Unretractions"); } + case OptionType::ToolChanges: { return _L("Tool changes"); } + case OptionType::ColorChanges: { return _L("Color changes"); } + case OptionType::PausePrints: { return _L("Pause prints"); } + case OptionType::CustomGCodes: { return _L("Custom GCodes"); } + case OptionType::Shells: { return _L("Shells"); } + case OptionType::ToolMarker: { return _L("Tool marker"); } + case OptionType::Legend: { return _L("Legend"); } + default: { return ""; } + } +} + #endif // ENABLE_GCODE_VIEWER } // namespace GUI diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 3f0d4b4e6..9cf694ece 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -136,6 +136,20 @@ class Preview : public wxPanel public: #if ENABLE_GCODE_VIEWER + enum class OptionType : unsigned int + { + Travel, + Retractions, + Unretractions, + ToolChanges, + ColorChanges, + PausePrints, + CustomGCodes, + Shells, + ToolMarker, + Legend + }; + Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process = []() {}); #else @@ -235,6 +249,7 @@ private: #if ENABLE_GCODE_VIEWER void on_layers_slider_scroll_changed(wxCommandEvent& event); void on_moves_slider_scroll_changed(wxCommandEvent& event); + wxString get_option_type_string(OptionType type) const; #else void on_sliders_scroll_changed(wxCommandEvent& event); #endif // ENABLE_GCODE_VIEWER