diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 24839d5e5..2a115c1fd 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1292,6 +1292,12 @@ void GLCanvas3D::set_as_dirty() m_dirty = true; } +void GLCanvas3D::set_items_show(bool show_volumes, bool show_gcode) +{ + m_show_volume = show_volumes; + m_show_gcode = show_gcode; +} + unsigned int GLCanvas3D::get_volumes_count() const { return (unsigned int)m_volumes.volumes.size(); @@ -1661,9 +1667,9 @@ void GLCanvas3D::render() // draw scene glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); _render_background(); - - _render_objects(); - if (!m_main_toolbar.is_enabled()) + if(m_show_volume) + _render_objects(); + if (m_show_gcode && !m_main_toolbar.is_enabled()) _render_gcode(); _render_sla_slices(); _render_selection(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d99e0b77a..545e05e20 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -457,7 +457,9 @@ private: int m_extra_frame_requested_delayed { std::numeric_limits::max() }; bool m_event_handlers_bound{ false }; + bool m_show_volume = true;; mutable GLVolumeCollection m_volumes; + bool m_show_gcode = true; GCodeViewer m_gcode_viewer; RenderTimer m_render_timer; @@ -552,6 +554,7 @@ public: void post_event(wxEvent &&event); void set_as_dirty(); + void set_items_show(bool show_volumes, bool show_gcode); unsigned int get_volumes_count() const; const GLVolumeCollection& get_volumes() const { return m_volumes; } diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 5799610fc..797b2ff77 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -57,6 +57,9 @@ View3D::~View3D() bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) { + name = "3D"; + title = "3D view"; + if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) return false; @@ -195,6 +198,10 @@ Preview::Preview( bool Preview::init(wxWindow* parent, Model* model) { + + name = "Preview"; + title = "Gcode Preview"; + if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) return false; @@ -921,6 +928,7 @@ void Preview::load_print_as_fff(bool keep_z_range) GCodeViewer::EViewType gcode_view_type = m_canvas->get_gcode_view_preview_type(); bool gcode_preview_data_valid = !m_gcode_result->moves.empty(); + gcode_preview_data_valid = gcode_preview_data_valid && current_force_state != ForceState::ForceExtrusions; // Collect colors per extruder. std::vector colors; std::vector color_print_values = {}; @@ -934,7 +942,6 @@ void Preview::load_print_as_fff(bool keep_z_range) } } else if (gcode_view_type == GCodeViewer::EViewType::Filament) - { const ConfigOptionStrings* extruders_opt = dynamic_cast(m_config->option("extruder_colour")); const ConfigOptionStrings* filamemts_opt = dynamic_cast(m_config->option("filament_colour")); @@ -954,7 +961,6 @@ void Preview::load_print_as_fff(bool keep_z_range) color_print_values.clear(); } else if (gcode_preview_data_valid || (gcode_view_type == GCodeViewer::EViewType::Tool)) - { colors = wxGetApp().plater()->get_extruder_colors_from_plater_config(); color_print_values.clear(); @@ -962,9 +968,15 @@ void Preview::load_print_as_fff(bool keep_z_range) if (IsShown()) { std::vector zs; + if (current_force_state == ForceState::ForceGcode) + m_canvas->set_items_show(false, true); + else if (current_force_state == ForceState::ForceExtrusions) + m_canvas->set_items_show(true, false); + else + m_canvas->set_items_show(true, true); m_canvas->set_selected_extruder(0); - if (gcode_preview_data_valid) { + if (current_force_state == ForceState::ForceGcode || (gcode_preview_data_valid && current_force_state != ForceState::ForceExtrusions)) { // Load the real G-code preview. m_canvas->load_gcode_preview(*m_gcode_result); m_canvas->refresh_gcode_preview(*m_gcode_result, colors); diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 07eb5691d..436ece776 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -39,7 +39,20 @@ class Bed3D; struct Camera; class Plater; -class View3D : public wxPanel +// ---------------------------------------------------------------------------- +// titlepanel +// ---------------------------------------------------------------------------- +class wxTitledPanel : public wxPanel +{ +public: + std::string name; + std::string title; + virtual GLCanvas3D* get_canvas3d() = 0; + virtual void set_as_dirty() = 0; + virtual void select_view(const std::string& direction) = 0; +}; + +class View3D : public wxTitledPanel { wxGLCanvas* m_canvas_widget; GLCanvas3D* m_canvas; @@ -49,12 +62,12 @@ public: virtual ~View3D(); wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } - GLCanvas3D* get_canvas3d() { return m_canvas; } + GLCanvas3D* get_canvas3d() override { return m_canvas; } - void set_as_dirty(); + void set_as_dirty() override; void bed_shape_changed(); - void select_view(const std::string& direction); + void select_view(const std::string& direction) override; void select_all(); void deselect_all(); void delete_selected(); @@ -76,7 +89,7 @@ private: bool init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process); }; -class Preview : public wxPanel +class Preview : public wxTitledPanel { wxGLCanvas* m_canvas_widget { nullptr }; GLCanvas3D* m_canvas { nullptr }; @@ -140,12 +153,18 @@ public: Legend }; + enum class ForceState : unsigned int { + NoForce, + ForceExtrusions, + ForceGcode + }; + Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodeProcessor::Result* gcode_result, std::function schedule_background_process = []() {}); virtual ~Preview(); wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } - GLCanvas3D* get_canvas3d() { return m_canvas; } + GLCanvas3D* get_canvas3d() override { return m_canvas; } void set_as_dirty(); @@ -159,6 +178,7 @@ Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSl void load_print(bool keep_z_range = false); void reload_print(bool keep_volumes = false); void refresh_print(); + void set_force_state(ForceState new_force_state = ForceState::NoForce) { current_force_state = new_force_state; } void msw_rescale(); void jump_layers_slider(wxKeyEvent& evt); @@ -180,6 +200,8 @@ Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSl void hide_layers_slider(); private: + ForceState current_force_state = ForceState::NoForce; + bool init(wxWindow* parent, Model* model); void bind_event_handlers(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 04abc8488..a7d641bf4 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -263,8 +263,14 @@ void MainFrame::update_layout() // On Linux m_plater needs to be removed from m_tabpanel before to reparent it int plater_page_id = m_tabpanel->FindPage(m_plater); - if (plater_page_id != wxNOT_FOUND) + while (plater_page_id != wxNOT_FOUND) { m_tabpanel->RemovePage(plater_page_id); + plater_page_id = m_tabpanel->FindPage(m_plater); + } + for (int i = 0; i < m_tabpanel->GetPageCount(); i++) { + m_tabpanel->SetPageImage(i, -1); + } + m_tabpanel->SetImageList(nullptr); //clear if (m_plater->GetParent() != this) m_plater->Reparent(this); @@ -286,6 +292,8 @@ void MainFrame::update_layout() m_tabpanel->Hide(); m_plater->Hide(); + m_plater->enable_view_toolbar(true); + m_plater->force_preview(Preview::ForceState::NoForce); Layout(); }; @@ -305,6 +313,8 @@ void MainFrame::update_layout() // Remove old settings if (m_layout != ESettingsLayout::Unknown) restore_to_creation(); + else //init with view_toolbar by default + m_plater->enable_view_toolbar(true); #ifdef __WXMSW__ enum class State { @@ -331,8 +341,27 @@ void MainFrame::update_layout() } case ESettingsLayout::Old: { + // don't use view_toolbar here + m_plater->enable_view_toolbar(false); m_plater->Reparent(m_tabpanel); - m_tabpanel->InsertPage(0, m_plater, _L("Plater")); + // icons for ESettingsLayout::Old + wxImageList* img_list = nullptr; + for (std::string icon_name : {"editor_menu", "layers", "preview_menu", "cog"}) { + const wxBitmap& bmp = create_scaled_bitmap(icon_name, this, 32); + if (img_list == nullptr) + img_list = new wxImageList(bmp.GetWidth(), bmp.GetHeight()); + img_list->Add(bmp); + } + m_tabpanel->AssignImageList(img_list); + m_tabpanel->InsertPage(0, m_plater, _L("3D view")); + m_tabpanel->InsertPage(1, m_plater, _L("Sliced preview")); + m_tabpanel->InsertPage(2, m_plater, _L("Gcode preview")); + m_tabpanel->SetPageImage(0, 0); + m_tabpanel->SetPageImage(1, 1); + m_tabpanel->SetPageImage(2, 2); + m_tabpanel->SetPageImage(3, 3); + m_tabpanel->SetPageImage(4, 3); + m_tabpanel->SetPageImage(5, 3); m_main_sizer->Add(m_tabpanel, 1, wxEXPAND); m_plater->Show(); m_tabpanel->Show(); @@ -538,6 +567,7 @@ void MainFrame::init_tabpanel() m_tabpanel->Hide(); m_settings_dialog.set_tabpanel(m_tabpanel); + m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxEvent&) { wxWindow* panel = m_tabpanel->GetCurrentPage(); Tab* tab = dynamic_cast(panel); @@ -547,13 +577,27 @@ void MainFrame::init_tabpanel() return; auto& tabs_list = wxGetApp().tabs_list; + int last_selected_tab = m_last_selected_tab; if (tab && std::find(tabs_list.begin(), tabs_list.end(), tab) != tabs_list.end()) { // On GTK, the wxEVT_NOTEBOOK_PAGE_CHANGED event is triggered // before the MainFrame is fully set up. tab->OnActivate(); m_last_selected_tab = m_tabpanel->GetSelection(); } - else + else if (this->m_layout == ESettingsLayout::Old) { + if (m_tabpanel->GetSelection() == 0) + this->m_plater->select_view_3D("3D"); + else if (m_tabpanel->GetSelection() == 1) { + this->m_plater->force_preview(Preview::ForceState::ForceExtrusions); + this->m_plater->select_view_3D("Preview"); + this->m_plater->refresh_print(); + } + else if (m_tabpanel->GetSelection() == 2) { + this->m_plater->force_preview(Preview::ForceState::ForceGcode); + this->m_plater->select_view_3D("Preview"); + this->m_plater->refresh_print(); + } + }else select_tab(size_t(0)); // select Plater }); @@ -565,7 +609,7 @@ void MainFrame::init_tabpanel() wxGetApp().obj_list()->create_popup_menus(); if (wxGetApp().is_editor()) - create_preset_tabs(); + create_preset_tabs(); if (m_plater) { // load initial config diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index eb8e524d8..ce92e04a6 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1634,8 +1634,8 @@ struct Plater::priv // GUI elements wxSizer* panel_sizer{ nullptr }; - wxPanel* current_panel{ nullptr }; - std::vector panels; + wxTitledPanel* current_panel{ nullptr }; + std::vector panels; Sidebar *sidebar; Bed3D bed; Camera camera; @@ -1839,7 +1839,7 @@ struct Plater::priv void reload_all_from_disk(); void fix_through_netfabb(const int obj_idx, const int vol_idx = -1); - void set_current_panel(wxPanel* panel); + void set_current_panel(wxTitledPanel* panel); void on_select_preset(wxCommandEvent&); void on_slicing_update(SlicingStatusEvent&); @@ -2142,7 +2142,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) q->SetDropTarget(new PlaterDropTarget(q)); // if my understanding is right, wxWindow takes the owenership q->Layout(); - set_current_panel(wxGetApp().is_editor() ? static_cast(view3D) : static_cast(preview)); + set_current_panel(wxGetApp().is_editor() ? static_cast(view3D) : static_cast(preview)); if (wxGetApp().is_gcode_viewer()) preview->hide_layers_slider(); @@ -2267,28 +2267,33 @@ void Plater::priv::update(unsigned int flags) void Plater::priv::select_view(const std::string& direction) { - if (current_panel == view3D) - view3D->select_view(direction); - else if (current_panel == preview) - preview->select_view(direction); + if(current_panel != nullptr) + current_panel->select_view(direction); } void Plater::priv::select_view_3D(const std::string& name) { - if (name == "3D") - set_current_panel(view3D); - else if (name == "Preview") - set_current_panel(preview); - + for (wxTitledPanel* panel : panels) { + if (panel->name == name) { + set_current_panel(panel); + break; + } + } wxGetApp().update_ui_from_settings(false); } void Plater::priv::select_next_view_3D() { - if (current_panel == view3D) - set_current_panel(preview); - else if (current_panel == preview) - set_current_panel(view3D); + for (int i = 0; i < panels.size(); i++) { + if (panels[i] == current_panel) { + if (i + 1 == panels.size()) { + set_current_panel(panels[0]); + } else { + set_current_panel(panels[i+1]); + } + return; + } + } } void Plater::priv::collapse_sidebar(bool collapse) @@ -3488,7 +3493,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = this->schedule_background_process(); } -void Plater::priv::set_current_panel(wxPanel* panel) +void Plater::priv::set_current_panel(wxTitledPanel* panel) { if (std::find(panels.begin(), panels.end(), panel) == panels.end()) return; @@ -3500,7 +3505,7 @@ void Plater::priv::set_current_panel(wxPanel* panel) if (current_panel == panel) return; - wxPanel* old_panel = current_panel; + wxTitledPanel* old_panel = current_panel; current_panel = panel; // to reduce flickering when changing view, first set as visible the new current panel for (wxPanel* p : panels) { @@ -3525,12 +3530,12 @@ void Plater::priv::set_current_panel(wxPanel* panel) panel_sizer->Layout(); + if(old_panel) + old_panel->get_canvas3d()->unbind_event_handlers(); + if (current_panel) + current_panel->get_canvas3d()->bind_event_handlers(); + if (current_panel == view3D) { - if (old_panel == preview) - preview->get_canvas3d()->unbind_event_handlers(); - - view3D->get_canvas3d()->bind_event_handlers(); - if (view3D->is_reload_delayed()) { // Delayed loading of the 3D scene. if (this->printer_technology == ptSLA) { @@ -3540,19 +3545,8 @@ void Plater::priv::set_current_panel(wxPanel* panel) } else view3D->reload_scene(true); } - - // sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) - view3D->set_as_dirty(); - view_toolbar.select_item("3D"); - if(notification_manager != nullptr) - notification_manager->set_in_preview(false); } else if (current_panel == preview) { - if (old_panel == view3D) - view3D->get_canvas3d()->unbind_event_handlers(); - - preview->get_canvas3d()->bind_event_handlers(); - // see: Plater::priv::object_list_changed() // FIXME: it may be better to have a single function making this check and let it be called wherever needed bool export_in_progress = this->background_process.is_export_scheduled(); @@ -3561,14 +3555,17 @@ void Plater::priv::set_current_panel(wxPanel* panel) this->q->reslice(); // keeps current gcode preview, if any preview->reload_print(true); - - preview->set_as_dirty(); - view_toolbar.select_item("Preview"); - if (notification_manager != nullptr) - notification_manager->set_in_preview(true); } - current_panel->SetFocusFromKbd(); + if (current_panel) { + // sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) + current_panel->set_as_dirty(); + view_toolbar.select_item(current_panel->name); + if (notification_manager != nullptr) + notification_manager->set_in_preview(current_panel == preview); + + current_panel->SetFocusFromKbd(); + } } void Plater::priv::on_select_preset(wxCommandEvent &evt) @@ -4287,7 +4284,6 @@ bool Plater::priv::init_view_toolbar() return false; view_toolbar.select_item("3D"); - view_toolbar.set_enabled(true); return true; } @@ -5221,6 +5217,11 @@ void Plater::select_view(const std::string& direction) { p->select_view(directio void Plater::select_view_3D(const std::string& name) { p->select_view_3D(name); } +void Plater::force_preview(Preview::ForceState force) { + if (p->preview) + p->preview->set_force_state(force); +} + bool Plater::is_preview_shown() const { return p->is_preview_shown(); } bool Plater::is_preview_loaded() const { return p->is_preview_loaded(); } bool Plater::is_view3D_shown() const { return p->is_view3D_shown(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 1b5e80740..398c993e9 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -14,6 +14,7 @@ #include "libslic3r/GCode/GCodeProcessor.hpp" #include "Jobs/Job.hpp" #include "Search.hpp" +#include "GUI_Preview.hpp" class wxButton; class ScalableButton; @@ -166,6 +167,7 @@ public: void stop_jobs(); void select_view(const std::string& direction); void select_view_3D(const std::string& name); + void force_preview(Preview::ForceState force); bool is_preview_shown() const; bool is_preview_loaded() const; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 0bf6b72a3..6de15c804 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -561,8 +561,8 @@ void PreferencesDialog::create_icon_size_slider() void PreferencesDialog::create_settings_mode_widget() { - wxString choices[] = { _L("Old regular layout with the tab bar"), - _L("New layout, access via settings button in the top menu"), + wxString choices[] = { _L("Regular layout with the tab bar"), + _L("Access via settings button in the top menu"), _L("Settings in non-modal window") }; auto app_config = get_app_config();