From a123099f804e869e5e11d643a25993f15b98d33c Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Fri, 1 Mar 2019 11:00:34 +0100 Subject: [PATCH 01/11] Implemented another behavior of the "Slice Now" / "Export/Send G-code" buttons (SPE-831) --- src/slic3r/GUI/3DScene.cpp | 7 +- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 3 + src/slic3r/GUI/GLCanvas3D.cpp | 55 +++++++++---- src/slic3r/GUI/GLCanvas3D.hpp | 5 +- src/slic3r/GUI/MainFrame.cpp | 3 +- src/slic3r/GUI/Plater.cpp | 91 ++++++++++++++++++++- src/slic3r/GUI/Plater.hpp | 7 +- 7 files changed, 145 insertions(+), 26 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 88815d9a6..f88b4e73d 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -834,6 +834,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside; bool all_contained = true; + bool contained_min_one = false; + for (GLVolume* volume : this->volumes) { if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled)) @@ -843,6 +845,9 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M bool contained = print_volume.contains(bb); all_contained &= contained; + if (contained) + contained_min_one = true; + volume->is_outside = !contained; if ((state == ModelInstance::PVS_Inside) && volume->is_outside) @@ -855,7 +860,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M if (out_state != nullptr) *out_state = state; - return all_contained; + return /*all_contained*/ contained_min_one; // #ys_FIXME_delete_after_testing } void GLVolumeCollection::reset_outside_state() diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index a2299e7bf..a15d3faef 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -123,6 +123,9 @@ public: // This "finished" flag does not account for the final export of the output file (.gcode or zipped PNGs), // and it does not account for the OctoPrint scheduling. bool finished() const { return m_print->finished(); } + + // set status line + void set_status(const std::string & status_str) const { m_print->set_status(100, status_str); } private: void thread_proc(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4f456c392..b29bb16e0 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3067,7 +3067,7 @@ GLGizmoBase* GLCanvas3D::Gizmos::_get_current() const return (it != m_gizmos.end()) ? it->second : nullptr; } -const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 9, 91, 134 }; +const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 120, 120, 120 };//{ 9, 91, 134 }; const unsigned char GLCanvas3D::WarningTexture::Opacity = 255; GLCanvas3D::WarningTexture::WarningTexture() @@ -3101,16 +3101,23 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool // Look at the end of our vector and generate proper texture. std::string text; + bool red_colored = false; switch (m_warnings.back()) { case ObjectOutside : text = L("Detected object outside print volume"); break; case ToolpathOutside : text = L("Detected toolpath outside print volume"); break; case SomethingNotShown : text = L("Some objects are not visible when editing supports"); break; + case ObjectClashed: { + text = L("Detected object outside print volume\n" + "Resolve a clash to continue slicing/export process correctly"); + red_colored = true; + break; + } } - _generate(text, canvas); // GUI::GLTexture::reset() is called at the beginning of generate(...) + _generate(text, canvas, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...) } -bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanvas3D& canvas) +bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanvas3D& canvas, const bool red_colored/* = false*/) { reset(); @@ -3127,7 +3134,8 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanva // calculates texture size wxCoord w, h; - memDC.GetTextExtent(msg, &w, &h); +// memDC.GetTextExtent(msg, &w, &h); + memDC.GetMultiLineTextExtent(msg, &w, &h); int pow_of_two_size = next_highest_power_of_2(std::max<unsigned int>(w, h)); @@ -3144,8 +3152,9 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanva memDC.Clear(); // draw message - memDC.SetTextForeground(*wxWHITE); - memDC.DrawText(msg, 0, 0); + memDC.SetTextForeground(red_colored ? wxColour(255,72,65/*204,204*/) : *wxWHITE); +// memDC.DrawText(msg, 0, 0); + memDC.DrawLabel(msg, wxRect(0,0, m_original_width, m_original_height), wxALIGN_CENTER); memDC.SelectObject(wxNullBitmap); @@ -4392,23 +4401,33 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (!m_volumes.empty()) { ModelInstance::EPrintVolumeState state; - bool contained = m_volumes.check_outside_state(m_config, &state); - if (!contained) - { - _set_warning_texture(WarningTexture::ObjectOutside, true); - post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, state == ModelInstance::PVS_Fully_Outside)); - } - else - { - m_volumes.reset_outside_state(); - _set_warning_texture(WarningTexture::ObjectOutside, false); - post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, !m_model->objects.empty())); - } + const bool contained_min_one = m_volumes.check_outside_state(m_config, &state); + + _set_warning_texture(WarningTexture::ObjectClashed, state == ModelInstance::PVS_Partly_Outside); + _set_warning_texture(WarningTexture::ObjectOutside, state == ModelInstance::PVS_Fully_Outside); + + post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, + contained_min_one && !m_model->objects.empty() && state != ModelInstance::PVS_Partly_Outside)); + +// #ys_FIXME_delete_after_testing +// bool contained = m_volumes.check_outside_state(m_config, &state); +// if (!contained) +// { +// _set_warning_texture(WarningTexture::ObjectOutside, true); +// post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, state == ModelInstance::PVS_Fully_Outside)); +// } +// else +// { +// m_volumes.reset_outside_state(); +// _set_warning_texture(WarningTexture::ObjectOutside, false); +// post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, !m_model->objects.empty())); +// } } else { _set_warning_texture(WarningTexture::ObjectOutside, false); + _set_warning_texture(WarningTexture::ObjectClashed, false); post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false)); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 008e77056..614f75ac2 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -751,7 +751,8 @@ private: enum Warning { ObjectOutside, ToolpathOutside, - SomethingNotShown + SomethingNotShown, + ObjectClashed }; // Sets a warning of the given type to be active/inactive. If several warnings are active simultaneously, @@ -770,7 +771,7 @@ private: std::vector<Warning> m_warnings; // Generates the texture with given text. - bool _generate(const std::string& msg, const GLCanvas3D& canvas); + bool _generate(const std::string& msg, const GLCanvas3D& canvas, const bool red_colored = false); }; class LegendTexture : public GUI::GLTexture diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index cddf081eb..1d1982ffa 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -881,9 +881,10 @@ void MainFrame::on_config_changed(DynamicPrintConfig* config) const // Update the UI based on the current preferences. void MainFrame::update_ui_from_settings() { - bool bp_on = wxGetApp().app_config->get("background_processing") == "1"; + const bool bp_on = wxGetApp().app_config->get("background_processing") == "1"; // m_menu_item_reslice_now->Enable(!bp_on); m_plater->sidebar().show_reslice(!bp_on); + m_plater->sidebar().show_export(bp_on); m_plater->sidebar().Layout(); if (m_plater) m_plater->update_ui_from_settings(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e917269d2..784443c64 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -487,6 +487,12 @@ ConfigOptionsGroup* FreqChangedParams::get_og(const bool is_fff) // Sidebar / private +enum class ActionButtonType : int { + abReslice, + abExport, + abSendGCode +}; + struct Sidebar::priv { Plater *plater; @@ -942,8 +948,9 @@ void Sidebar::enable_buttons(bool enable) p->btn_send_gcode->Enable(enable); } -void Sidebar::show_reslice(bool show) { p->btn_reslice->Show(show); } -void Sidebar::show_send(bool show) { p->btn_send_gcode->Show(show); } +void Sidebar::show_reslice(bool show) const { p->btn_reslice->Show(show); } +void Sidebar::show_export(bool show) const { p->btn_export_gcode->Show(show); } +void Sidebar::show_send(bool show) const { p->btn_send_gcode->Show(show); } bool Sidebar::is_multifilament() { @@ -1033,6 +1040,8 @@ struct Plater::priv wxTimer background_process_timer; + std::string label_btn_export; + static const std::regex pattern_bundle; static const std::regex pattern_3mf; static const std::regex pattern_zip_amf; @@ -1122,6 +1131,7 @@ struct Plater::priv void on_3dcanvas_mouse_dragging_finished(SimpleEvent&); void update_object_menu(); + void show_action_buttons(const bool is_ready_to_slice) const; // Set the bed shape to a single closed 2D polygon(array of two element arrays), // triangulate the bed and store the triangles into m_bed.m_triangles, @@ -2093,6 +2103,31 @@ unsigned int Plater::priv::update_background_process(bool force_validation) // jinak background_process.running() -> Zobraz "Slicing ..." // jinak pokud ! background_process.empty() && ! background_process.finished() -> je neco ke slajsovani (povol tlacitko) "Slice Now" + if ((return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0) + { + const wxString invalid_str = _(L("Invalid data")); + for (auto btn : {ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport}) + sidebar->set_btn_label(btn, invalid_str); + } + else + { + if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 || + (return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 ) + background_process.set_status("Ready to slice"); + + sidebar->set_btn_label(ActionButtonType::abExport, _(label_btn_export)); + sidebar->set_btn_label(ActionButtonType::abSendGCode, _(L("Send G-code"))); + + const wxString slice_string = background_process.running() && wxGetApp().get_mode() == comSimple ? + _(L("Slicing")) + dots : _(L("Slice now")); + sidebar->set_btn_label(ActionButtonType::abReslice, slice_string); + + if (background_process.finished()) + show_action_buttons(false); + else if (!background_process.empty()) + show_action_buttons(true); + } + return return_state; } @@ -2388,6 +2423,9 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) this->update_sla_scene(); break; } + + if (wxGetApp().get_mode() == comSimple) + show_action_buttons(false); } void Plater::priv::on_layer_editing_toggled(bool enable) @@ -2755,6 +2793,37 @@ void Plater::priv::update_object_menu() #endif // ENABLE_MODE_AWARE_TOOLBAR_ITEMS } +void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const +{ + wxWindowUpdateLocker noUpdater(sidebar); + const auto prin_host_opt = config->option<ConfigOptionString>("print_host"); + const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty(); + + // when a background processing is ON, export_btn and/or send_btn are showing + if (wxGetApp().app_config->get("background_processing") == "1") + { + sidebar->show_reslice(false); + sidebar->show_export(true); + sidebar->show_send(send_gcode_shown); + } + else + { + sidebar->show_reslice(is_ready_to_slice); + sidebar->show_export(!is_ready_to_slice); + sidebar->show_send(send_gcode_shown && !is_ready_to_slice); + } +} + +void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const +{ + switch (btn_type) + { + case ActionButtonType::abReslice: p->btn_reslice->SetLabelText(label); break; + case ActionButtonType::abExport: p->btn_export_gcode->SetLabelText(label); break; + case ActionButtonType::abSendGCode: p->btn_send_gcode->SetLabelText(label); break; + } +} + // Plater / Public Plater::Plater(wxWindow *parent, MainFrame *main_frame) @@ -3081,6 +3150,22 @@ void Plater::reslice() this->p->background_process.set_task(PrintBase::TaskParams()); // Only restarts if the state is valid. this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART); + + if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0) + return; + + if (p->background_process.running()) + { + if (wxGetApp().get_mode() == comSimple) + p->sidebar->set_btn_label(ActionButtonType::abReslice, _(L("Slicing")) + dots); + else + { + p->sidebar->set_btn_label(ActionButtonType::abReslice, _(L("Slice now"))); + p->show_action_buttons(false); + } + } + else if (!p->background_process.empty() && !p->background_process.idle()) + p->show_action_buttons(true); } void Plater::reslice_SLA_supports(const ModelObject &object) @@ -3282,6 +3367,8 @@ void Plater::set_printer_technology(PrinterTechnology printer_technology) } //FIXME for SLA synchronize //p->background_process.apply(Model)! + + p->label_btn_export = printer_technology == ptFFF ? L("Export G-code") : L("Export"); // #ys_FIXME_rename } void Plater::changed_object(int obj_idx) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 4d489c82a..3370dd92f 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -38,6 +38,7 @@ class GLCanvas3D; using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>; class Plater; +enum class ActionButtonType : int; class PresetComboBox : public wxBitmapComboBox { @@ -86,8 +87,10 @@ public: void show_info_sizer(); void show_sliced_info_sizer(const bool show); void enable_buttons(bool enable); - void show_reslice(bool show); - void show_send(bool show); + void set_btn_label(const ActionButtonType btn_type, const wxString& label) const; + void show_reslice(bool show) const; + void show_export(bool show) const; + void show_send(bool show) const; bool is_multifilament(); void set_mode_value(const /*ConfigOptionMode*/int mode) { m_mode = mode; } From 84a96d3ba068fee41dde516d1ad1e50d6ede2cb6 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Fri, 1 Mar 2019 12:03:14 +0100 Subject: [PATCH 02/11] Added a tooltip for the "Slice now" button and changed its behavior according to a hold of Shift + some code refactoring --- src/slic3r/GUI/GUI_App.cpp | 15 +-------------- src/slic3r/GUI/Plater.cpp | 36 +++++++++++++++++++++++++++++++++--- src/slic3r/GUI/Plater.hpp | 7 ++++--- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index eb02d622c..5526add4d 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -525,20 +525,7 @@ void GUI_App::save_mode(const /*ConfigOptionMode*/int mode) // Update view mode according to selected menu void GUI_App::update_mode() { - wxWindowUpdateLocker noUpdates(&sidebar()); - - const ConfigOptionMode mode = wxGetApp().get_mode(); - - obj_list()->get_sizer()->Show(mode > comSimple); - sidebar().set_mode_value(mode); -// sidebar().show_buttons(mode == comExpert); - obj_list()->unselect_objects(); - obj_list()->update_selections(); - obj_list()->update_object_menu(); - - sidebar().update_mode_sizer(mode); - - sidebar().Layout(); + sidebar().update_mode(); for (auto tab : tabs_list) tab->update_visibility(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 784443c64..bfde4c5c0 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -655,7 +655,13 @@ Sidebar::Sidebar(Plater *parent) // Events p->btn_export_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(); }); - p->btn_reslice->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->reslice(); }); + p->btn_reslice->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) + { + const bool export_gcode_after_slicing = wxGetKeyState(WXK_SHIFT); + p->plater->reslice(); + if (export_gcode_after_slicing) + p->plater->export_gcode(); + }); p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); } @@ -753,9 +759,15 @@ void Sidebar::update_presets(Preset::Type preset_type) wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config); } -void Sidebar::update_mode_sizer(const Slic3r::ConfigOptionMode& mode) +void Sidebar::update_mode_sizer() const { - p->mode_sizer->SetMode(mode); + p->mode_sizer->SetMode(m_mode); +} + +void Sidebar::update_reslice_btn_tooltip() const +{ + const wxString tooltip = m_mode == comSimple ? wxEmptyString : _(L("Hold Shift to Slice & Export G-code")); + p->btn_reslice->SetToolTip(tooltip); } ObjectManipulation* Sidebar::obj_manipul() @@ -958,6 +970,24 @@ bool Sidebar::is_multifilament() } +void Sidebar::update_mode() +{ + m_mode = wxGetApp().get_mode(); + + update_reslice_btn_tooltip(); + update_mode_sizer(); + + wxWindowUpdateLocker noUpdates(this); + + p->object_list->get_sizer()->Show(m_mode > comSimple); + + p->object_list->unselect_objects(); + p->object_list->update_selections(); + p->object_list->update_object_menu(); + + Layout(); +} + std::vector<PresetComboBox*>& Sidebar::combos_filament() { return p->combos_filament; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 3370dd92f..78035d0ab 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -62,7 +62,7 @@ private: class Sidebar : public wxPanel { - /*ConfigOptionMode*/int m_mode; + ConfigOptionMode m_mode; public: Sidebar(Plater *parent); Sidebar(Sidebar &&) = delete; @@ -74,7 +74,8 @@ public: void init_filament_combo(PresetComboBox **combo, const int extr_idx); void remove_unused_filament_combos(const int current_extruder_count); void update_presets(Slic3r::Preset::Type preset_type); - void update_mode_sizer(const Slic3r::ConfigOptionMode& mode); + void update_mode_sizer() const; + void update_reslice_btn_tooltip() const; ObjectManipulation* obj_manipul(); ObjectList* obj_list(); @@ -92,7 +93,7 @@ public: void show_export(bool show) const; void show_send(bool show) const; bool is_multifilament(); - void set_mode_value(const /*ConfigOptionMode*/int mode) { m_mode = mode; } + void update_mode(); std::vector<PresetComboBox*>& combos_filament(); private: From 95ca670efbdcb6fe94cf16863dbd63f91f52ab36 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Tue, 5 Mar 2019 14:26:44 +0100 Subject: [PATCH 03/11] Fixed OSX and Linux build --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5454268bf..587c3579f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -766,7 +766,7 @@ void Sidebar::update_mode_sizer() const void Sidebar::update_reslice_btn_tooltip() const { - const wxString tooltip = m_mode == comSimple ? wxEmptyString : _(L("Hold Shift to Slice & Export G-code")); + const wxString tooltip = m_mode == comSimple ? wxString("") : _(L("Hold Shift to Slice & Export G-code")); p->btn_reslice->SetToolTip(tooltip); } From 063d812d64c43bc94baaa8751b1f673e2101e7bc Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Fri, 8 Mar 2019 15:40:28 +0100 Subject: [PATCH 04/11] Added case of a slicing cancellation --- src/slic3r/GUI/Plater.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 587c3579f..7edc2bae1 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2458,7 +2458,12 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) break; } - if (wxGetApp().get_mode() == comSimple) + if (canceled) { + if (wxGetApp().get_mode() == comSimple) + sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now"); + show_action_buttons(true); + } + else if (wxGetApp().get_mode() == comSimple) show_action_buttons(false); } From 40abbc7184e802a94be327960153a183942d0043 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Mon, 11 Mar 2019 10:23:59 +0100 Subject: [PATCH 05/11] Fixed an updating of the button's show during SLA slicing --- src/slic3r/GUI/Plater.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7edc2bae1..636b916ba 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2157,7 +2157,11 @@ unsigned int Plater::priv::update_background_process(bool force_validation) if (background_process.finished()) show_action_buttons(false); - else if (!background_process.empty()) + else if (!background_process.empty() && + !background_process.running()) /* Do not update buttons if background process is running + * This condition is important for SLA mode especially, + * when this function is called several times during calculations + * */ show_action_buttons(true); } From 75cf1cde9254eb77760b5ada94141c9e53a148b7 Mon Sep 17 00:00:00 2001 From: bubnikv <bubnikv@gmail.com> Date: Tue, 12 Mar 2019 09:41:57 +0100 Subject: [PATCH 06/11] Refactoring of the Slice / Export G-code button --- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 3 --- src/slic3r/GUI/Plater.cpp | 21 +++++++++------------ 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index a15d3faef..9ea20163d 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -124,9 +124,6 @@ public: // and it does not account for the OctoPrint scheduling. bool finished() const { return m_print->finished(); } - // set status line - void set_status(const std::string & status_str) const { m_print->set_status(100, status_str); } - private: void thread_proc(); void thread_proc_safe(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c01d89352..eac611115 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -684,9 +684,10 @@ Sidebar::Sidebar(Plater *parent) p->btn_reslice->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { const bool export_gcode_after_slicing = wxGetKeyState(WXK_SHIFT); - p->plater->reslice(); if (export_gcode_after_slicing) p->plater->export_gcode(); + else + p->plater->reslice(); }); p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); } @@ -1098,6 +1099,7 @@ struct Plater::priv wxTimer background_process_timer; std::string label_btn_export; + std::string label_btn_send; static const std::regex pattern_bundle; static const std::regex pattern_3mf; @@ -2150,28 +2152,22 @@ unsigned int Plater::priv::update_background_process(bool force_validation) wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone()); } - //FIXME update "Slice Now / Schedule background process" - //background_process.is_export_scheduled() - byl zavolan "Export G-code", background processing ma jmeno export souboru - //background_process.is_upload_scheduled() - byl zavolan "Send to OctoPrint", jeste nebylo doslajsovano (pak se preda upload fronte a background process zapomene) - //background_process.empty() - prazdna plocha - // pokud (return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0 -> doslo k chybe (gray out "Slice now") mozna "Invalid data"??? - // jinak background_process.running() -> Zobraz "Slicing ..." - // jinak pokud ! background_process.empty() && ! background_process.finished() -> je neco ke slajsovani (povol tlacitko) "Slice Now" - if ((return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0) { + // Validation of the background data failed. const wxString invalid_str = _(L("Invalid data")); for (auto btn : {ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport}) sidebar->set_btn_label(btn, invalid_str); } else { + // Background data is valid. if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 || (return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 ) - background_process.set_status("Ready to slice"); + this->statusbar()->set_status_text(L("Ready to slice")); sidebar->set_btn_label(ActionButtonType::abExport, _(label_btn_export)); - sidebar->set_btn_label(ActionButtonType::abSendGCode, _(L("Send G-code"))); + sidebar->set_btn_label(ActionButtonType::abSendGCode, _(label_btn_send)); const wxString slice_string = background_process.running() && wxGetApp().get_mode() == comSimple ? _(L("Slicing")) + dots : _(L("Slice now")); @@ -3447,7 +3443,8 @@ void Plater::set_printer_technology(PrinterTechnology printer_technology) //FIXME for SLA synchronize //p->background_process.apply(Model)! - p->label_btn_export = printer_technology == ptFFF ? L("Export G-code") : L("Export"); // #ys_FIXME_rename + p->label_btn_export = printer_technology == ptFFF ? L("Export G-code") : L("Export"); + p->label_btn_send = printer_technology == ptFFF ? L("Send G-code") : L("Send to printer"); } void Plater::changed_object(int obj_idx) From 9522cd1d4f255aac752da1640a874e2a3e04ab4e Mon Sep 17 00:00:00 2001 From: Vojtech Kral <vojtech@kral.hk> Date: Mon, 11 Mar 2019 11:49:24 +0100 Subject: [PATCH 07/11] OnInit: Move preset loading out of EVT_IDLE/once, remove temp workaround of sidebar scrollbar --- src/slic3r/GUI/GUI_App.cpp | 16 +++------------- src/slic3r/GUI/GUI_ObjectList.cpp | 5 +---- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 73ff19a9d..afbf6b568 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -167,17 +167,6 @@ bool GUI_App::OnInit() if (app_config->dirty() && app_config->get("autosave") == "1") app_config->save(); - // ! Temporary workaround for the correct behavior of the Scrolled sidebar panel - // Do this "manipulations" only once ( after (re)create of the application ) - if (sidebar().obj_list()->GetMinHeight() > 15 * wxGetApp().em_unit()) - { - wxWindowUpdateLocker noUpdates_sidebar(&sidebar()); - sidebar().obj_list()->SetMinSize(wxSize(-1, 15 * wxGetApp().em_unit())); - - // !!! to correct later layouts - update_mode(); // update view mode after fix of the object_list size - } - this->obj_manipul()->update_if_dirty(); // Preset updating & Configwizard are done after the above initializations, @@ -205,11 +194,12 @@ bool GUI_App::OnInit() } preset_updater->sync(preset_bundle); }); - - load_current_presets(); } }); + load_current_presets(); + update_mode(); // update view mode after fix of the object_list size + mainframe->Show(true); m_initialized = true; return true; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index eb3744bef..6a605a667 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -115,10 +115,7 @@ ObjectList::~ObjectList() void ObjectList::create_objects_ctrl() { - // temporary workaround for the correct behavior of the Scrolled sidebar panel: - // 1. set a height of the list to some big value - // 2. change it to the normal min value (200) after first whole App updating/layouting - SetMinSize(wxSize(-1, 3000)); // #ys_FIXME + SetMinSize(wxSize(-1, 15 * wxGetApp().em_unit())); m_sizer = new wxBoxSizer(wxVERTICAL); m_sizer->Add(this, 1, wxGROW); From 4e510dc3e71d3eb96045c90cdf944396d0ca7f61 Mon Sep 17 00:00:00 2001 From: Vojtech Kral <vojtech@kral.hk> Date: Mon, 11 Mar 2019 09:48:24 +0100 Subject: [PATCH 08/11] PostProcessor on Unix: Execute using default shell #1908 escape gcode path, collect stderr --- src/libslic3r/GCode/PostProcessor.cpp | 76 ++++++++++++++++++--------- src/slic3r/GUI/Plater.cpp | 9 ++-- 2 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/GCode/PostProcessor.cpp b/src/libslic3r/GCode/PostProcessor.cpp index e86463b84..df4acc1bf 100644 --- a/src/libslic3r/GCode/PostProcessor.cpp +++ b/src/libslic3r/GCode/PostProcessor.cpp @@ -2,6 +2,7 @@ #include <boost/algorithm/string.hpp> #include <boost/log/trivial.hpp> +#include <boost/format.hpp> #include <boost/filesystem.hpp> #ifdef WIN32 @@ -88,7 +89,7 @@ static DWORD execute_process_winapi(const std::wstring &command_line) // Run the script. If it is a perl script, run it through the bundled perl interpreter. // If it is a batch file, run it through the cmd.exe. // Otherwise run it directly. -static int run_script_win32(const std::string &script, const std::string &gcode) +static int run_script(const std::string &script, const std::string &gcode, std::string &/*std_err*/) { // Unpack the argument list provided by the user. int nArgs; @@ -132,9 +133,46 @@ static int run_script_win32(const std::string &script, const std::string &gcode) } #else - #include <sys/stat.h> //for getting filesystem UID/GID - #include <unistd.h> //for getting current UID/GID - #include <boost/process.hpp> + // POSIX + +#include <cstdlib> // getenv() +#include <sstream> +#include <boost/process.hpp> + +namespace process = boost::process; + +static int run_script(const std::string &script, const std::string &gcode, std::string &std_err) +{ + // Try to obtain user's default shell + const char *shell = ::getenv("SHELL"); + if (shell == nullptr) { shell = "sh"; } + + // Quote and escape the gcode path argument + std::string command { script }; + command.append(" '"); + for (char c : gcode) { + if (c == '\'') { command.append("'\\''"); } + else { command.push_back(c); } + } + command.push_back('\''); + + BOOST_LOG_TRIVIAL(debug) << boost::format("Executing script, shell: %1%, command: %2%") % shell % command; + + process::ipstream istd_err; + process::child child(shell, "-c", command, process::std_err > istd_err); + + std_err.clear(); + std::string line; + + while (child.running() && std::getline(istd_err, line)) { + std_err.append(line); + std_err.push_back('\n'); + } + + child.wait(); + return child.exit_code(); +} + #endif namespace Slic3r { @@ -158,27 +196,15 @@ void run_post_process_scripts(const std::string &path, const PrintConfig &config if (script.empty()) continue; BOOST_LOG_TRIVIAL(info) << "Executing script " << script << " on file " << path; -#ifdef WIN32 - int result = run_script_win32(script, gcode_file.string()); -#else - //FIXME testing existence of a script is risky, as the script line may contain the script and some additional command line parameters. - // We would have to process the script line into parameters before testing for the existence of the command, the command may be looked up - // in the PATH etc. - if (! boost::filesystem::exists(boost::filesystem::path(script))) - throw std::runtime_error(std::string("The configured post-processing script does not exist: ") + script); - struct stat info; - if (stat(script.c_str(), &info)) - throw std::runtime_error(std::string("Cannot read information for post-processing script: ") + script); - boost::filesystem::perms script_perms = boost::filesystem::status(script).permissions(); - //if UID matches, check UID perm. else if GID matches, check GID perm. Otherwise check other perm. - if (!(script_perms & ((info.st_uid == geteuid()) ? boost::filesystem::perms::owner_exe - : ((info.st_gid == getegid()) ? boost::filesystem::perms::group_exe - : boost::filesystem::perms::others_exe)))) - throw std::runtime_error(std::string("The configured post-processing script is not executable: check permissions. ") + script); - int result = boost::process::system(script, gcode_file); - if (result < 0) - BOOST_LOG_TRIVIAL(error) << "Script " << script << " on file " << path << " failed. Negative error code returned."; -#endif + + std::string std_err; + const int result = run_script(script, gcode_file.string(), std_err); + if (result != 0) { + const std::string msg = std_err.empty() ? (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%") % script % path % result).str() + : (boost::format("Post-processing script %1% on file %2% failed.\nError code: %3%\nOutput:\n%4%") % script % path % result % std_err).str(); + BOOST_LOG_TRIVIAL(error) << msg; + throw std::runtime_error(msg); + } } } } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index eac611115..aac21e7db 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2463,14 +2463,17 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) this->statusbar()->reset_cancel_callback(); this->statusbar()->stop_busy(); - bool canceled = evt.GetInt() < 0; - bool success = evt.GetInt() > 0; + const bool canceled = evt.GetInt() < 0; + const bool error = evt.GetInt() == 0; + const bool success = evt.GetInt() > 0; // Reset the "export G-code path" name, so that the automatic background processing will be enabled again. this->background_process.reset_export(); - if (! success) { + + if (error) { wxString message = evt.GetString(); if (message.IsEmpty()) message = _(L("Export failed")); + show_error(q, message); this->statusbar()->set_status_text(message); } if (canceled) From 09c9f567f23c8c9248759ee71adcb902fbbdba38 Mon Sep 17 00:00:00 2001 From: Vojtech Kral <vojtech@kral.hk> Date: Mon, 11 Mar 2019 13:59:58 +0100 Subject: [PATCH 09/11] Fix crash on exit --- src/slic3r/GUI/Tab.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0d53c3fd9..1d7a9a0c2 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -751,6 +751,10 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo void Tab::on_value_change(const std::string& opt_key, const boost::any& value) { + if (wxGetApp().plater() == nullptr) { + return; + } + const bool is_fff = supports_printer_technology(ptFFF); ConfigOptionsGroup* og_freq_chng_params = wxGetApp().sidebar().og_freq_chng_params(is_fff); if (opt_key == "fill_density" || opt_key == "pad_enable") From 077b4cbfbc73941bcd802645e7f14a7aaf657a96 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Tue, 12 Mar 2019 11:39:16 +0100 Subject: [PATCH 10/11] Fixed layout for the action buttons + Tried to use DoubleBuffered for the controls drawing on the Sidebar (under MSW only) --- src/slic3r/GUI/Plater.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index aac21e7db..2fddd4784 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -555,8 +555,6 @@ void Sidebar::priv::show_preset_comboboxes() { const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; - wxWindowUpdateLocker noUpdates_scrolled(scrolled->GetParent()); - for (size_t i = 0; i < 4; ++i) sizer_presets->Show(i, !showSLA); @@ -580,6 +578,10 @@ Sidebar::Sidebar(Plater *parent) p->scrolled = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(40 * wxGetApp().em_unit(), -1)); p->scrolled->SetScrollbars(0, 20, 1, 2); +#ifdef __WINDOWS__ + p->scrolled->SetDoubleBuffered(true); +#endif //__WINDOWS__ + // Sizer in the scrolled area auto *scrolled_sizer = new wxBoxSizer(wxVERTICAL); p->scrolled->SetSizer(scrolled_sizer); @@ -645,9 +647,7 @@ Sidebar::Sidebar(Plater *parent) p->object_settings->Hide(); p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5); - wxBitmap arrow_up(GUI::from_u8(Slic3r::var("brick_go.png")), wxBITMAP_TYPE_PNG); p->btn_send_gcode = new wxButton(this, wxID_ANY, _(L("Send to printer"))); - p->btn_send_gcode->SetBitmap(arrow_up); p->btn_send_gcode->SetFont(wxGetApp().bold_font()); p->btn_send_gcode->Hide(); @@ -757,6 +757,8 @@ void Sidebar::update_presets(Preset::Type preset_type) case Preset::TYPE_PRINTER: { + wxWindowUpdateLocker noUpdates_scrolled(p->scrolled); + // Update the print choosers to only contain the compatible presets, update the dirty flags. if (print_tech == ptFFF) preset_bundle.prints.update_platter_ui(p->combo_print); @@ -2893,6 +2895,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const sidebar->show_export(!is_ready_to_slice); sidebar->show_send(send_gcode_shown && !is_ready_to_slice); } + sidebar->Layout(); } void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const From f5b5e48ad78342bffa9b806c838f7bd038226750 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Tue, 12 Mar 2019 11:57:39 +0100 Subject: [PATCH 11/11] Added cancel mechanism to GCodeAnalyzer::calc_gcode_preview_data() --- src/libslic3r/GCode.cpp | 2 +- src/libslic3r/GCode/Analyzer.cpp | 51 ++++++++++++++++++++++++++------ src/libslic3r/GCode/Analyzer.hpp | 12 ++++---- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 2907415bf..94be37b21 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -487,7 +487,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_ // starts analyzer calculations if (m_enable_analyzer) { BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data"; - m_analyzer.calc_gcode_preview_data(*preview_data); + m_analyzer.calc_gcode_preview_data(*preview_data, [print]() { print->throw_if_canceled(); }); m_analyzer.reset(); } diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index e1fb140bb..f1f828776 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -137,22 +137,22 @@ const std::string& GCodeAnalyzer::process_gcode(const std::string& gcode) return m_process_output; } -void GCodeAnalyzer::calc_gcode_preview_data(GCodePreviewData& preview_data) +void GCodeAnalyzer::calc_gcode_preview_data(GCodePreviewData& preview_data, std::function<void()> cancel_callback) { // resets preview data preview_data.reset(); // calculates extrusion layers - _calc_gcode_preview_extrusion_layers(preview_data); + _calc_gcode_preview_extrusion_layers(preview_data, cancel_callback); // calculates travel - _calc_gcode_preview_travel(preview_data); + _calc_gcode_preview_travel(preview_data, cancel_callback); // calculates retractions - _calc_gcode_preview_retractions(preview_data); + _calc_gcode_preview_retractions(preview_data, cancel_callback); // calculates unretractions - _calc_gcode_preview_unretractions(preview_data); + _calc_gcode_preview_unretractions(preview_data, cancel_callback); } bool GCodeAnalyzer::is_valid_extrusion_role(ExtrusionRole role) @@ -676,7 +676,7 @@ bool GCodeAnalyzer::_is_valid_extrusion_role(int value) const return ((int)erNone <= value) && (value <= (int)erMixed); } -void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& preview_data) +void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& preview_data, std::function<void()> cancel_callback) { struct Helper { @@ -725,9 +725,18 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ GCodePreviewData::Range feedrate_range; GCodePreviewData::Range volumetric_rate_range; + // to avoid to call the callback too often + unsigned int cancel_callback_threshold = (unsigned int)extrude_moves->second.size() / 25; + unsigned int cancel_callback_curr = 0; + // constructs the polylines while traversing the moves for (const GCodeMove& move : extrude_moves->second) { + // to avoid to call the callback too often + cancel_callback_curr = (cancel_callback_curr + 1) % cancel_callback_threshold; + if (cancel_callback_curr == 0) + cancel_callback(); + if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm)) { // store current polyline @@ -769,7 +778,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range); } -void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data) +void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function<void()> cancel_callback) { struct Helper { @@ -797,9 +806,17 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data) GCodePreviewData::Range width_range; GCodePreviewData::Range feedrate_range; + // to avoid to call the callback too often + unsigned int cancel_callback_threshold = (unsigned int)travel_moves->second.size() / 25; + unsigned int cancel_callback_curr = 0; + // constructs the polylines while traversing the moves for (const GCodeMove& move : travel_moves->second) { + cancel_callback_curr = (cancel_callback_curr + 1) % cancel_callback_threshold; + if (cancel_callback_curr == 0) + cancel_callback(); + GCodePreviewData::Travel::EType move_type = (move.delta_extruder < 0.0f) ? GCodePreviewData::Travel::Retract : ((move.delta_extruder > 0.0f) ? GCodePreviewData::Travel::Extrude : GCodePreviewData::Travel::Move); GCodePreviewData::Travel::Polyline::EDirection move_direction = ((move.start_position.x() != move.end_position.x()) || (move.start_position.y() != move.end_position.y())) ? GCodePreviewData::Travel::Polyline::Generic : GCodePreviewData::Travel::Polyline::Vertical; @@ -840,28 +857,44 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data) preview_data.ranges.feedrate.update_from(feedrate_range); } -void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data) +void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback) { TypeToMovesMap::iterator retraction_moves = m_moves_map.find(GCodeMove::Retract); if (retraction_moves == m_moves_map.end()) return; + // to avoid to call the callback too often + unsigned int cancel_callback_threshold = (unsigned int)retraction_moves->second.size() / 25; + unsigned int cancel_callback_curr = 0; + for (const GCodeMove& move : retraction_moves->second) { + cancel_callback_curr = (cancel_callback_curr + 1) % cancel_callback_threshold; + if (cancel_callback_curr == 0) + cancel_callback(); + // store position Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height); } } -void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data) +void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback) { TypeToMovesMap::iterator unretraction_moves = m_moves_map.find(GCodeMove::Unretract); if (unretraction_moves == m_moves_map.end()) return; + // to avoid to call the callback too often + unsigned int cancel_callback_threshold = (unsigned int)unretraction_moves->second.size() / 25; + unsigned int cancel_callback_curr = 0; + for (const GCodeMove& move : unretraction_moves->second) { + cancel_callback_curr = (cancel_callback_curr + 1) % cancel_callback_threshold; + if (cancel_callback_curr == 0) + cancel_callback(); + // store position Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height); diff --git a/src/libslic3r/GCode/Analyzer.hpp b/src/libslic3r/GCode/Analyzer.hpp index c74a4558c..4c201c640 100644 --- a/src/libslic3r/GCode/Analyzer.hpp +++ b/src/libslic3r/GCode/Analyzer.hpp @@ -122,7 +122,8 @@ public: const std::string& process_gcode(const std::string& gcode); // Calculates all data needed for gcode visualization - void calc_gcode_preview_data(GCodePreviewData& preview_data); + // throws CanceledException through print->throw_if_canceled() (sent by the caller as callback). + void calc_gcode_preview_data(GCodePreviewData& preview_data, std::function<void()> cancel_callback = std::function<void()>()); // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; @@ -237,10 +238,11 @@ private: // Checks if the given int is a valid extrusion role (contained into enum ExtrusionRole) bool _is_valid_extrusion_role(int value) const; - void _calc_gcode_preview_extrusion_layers(GCodePreviewData& preview_data); - void _calc_gcode_preview_travel(GCodePreviewData& preview_data); - void _calc_gcode_preview_retractions(GCodePreviewData& preview_data); - void _calc_gcode_preview_unretractions(GCodePreviewData& preview_data); + // All the following methods throw CanceledException through print->throw_if_canceled() (sent by the caller as callback). + void _calc_gcode_preview_extrusion_layers(GCodePreviewData& preview_data, std::function<void()> cancel_callback); + void _calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function<void()> cancel_callback); + void _calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback); + void _calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback); }; } // namespace Slic3r