From 7580de9da5eb8157332487246122aa763d2cc7c2 Mon Sep 17 00:00:00 2001 From: remi durand Date: Sat, 27 Mar 2021 23:52:58 +0100 Subject: [PATCH] Add a gui option to have plater tabs in the top tab bar also add icons to tabs --- resources/icons/printer_cog.svg | 114 +++++++++ resources/icons/spool_cog.svg | 121 +++++++++ src/libslic3r/AppConfig.cpp | 3 + src/slic3r/GUI/Field.cpp | 22 +- src/slic3r/GUI/GLCanvas3D.cpp | 28 ++- src/slic3r/GUI/GLCanvas3D.hpp | 3 + src/slic3r/GUI/GUI_App.cpp | 6 +- src/slic3r/GUI/GUI_Preview.cpp | 34 ++- src/slic3r/GUI/GUI_Preview.hpp | 38 ++- src/slic3r/GUI/KBShortcutsDialog.cpp | 12 +- src/slic3r/GUI/MainFrame.cpp | 319 ++++++++++++++++++++---- src/slic3r/GUI/MainFrame.hpp | 31 ++- src/slic3r/GUI/Plater.cpp | 109 ++++---- src/slic3r/GUI/Plater.hpp | 3 + src/slic3r/GUI/Preferences.cpp | 34 ++- src/slic3r/GUI/PresetComboBoxes.cpp | 2 +- src/slic3r/GUI/UnsavedChangesDialog.cpp | 2 +- 17 files changed, 731 insertions(+), 150 deletions(-) create mode 100644 resources/icons/printer_cog.svg create mode 100644 resources/icons/spool_cog.svg diff --git a/resources/icons/printer_cog.svg b/resources/icons/printer_cog.svg new file mode 100644 index 000000000..5e8230fd4 --- /dev/null +++ b/resources/icons/printer_cog.svg @@ -0,0 +1,114 @@ + + + +image/svg+xml + + + + + + + + + + \ No newline at end of file diff --git a/resources/icons/spool_cog.svg b/resources/icons/spool_cog.svg new file mode 100644 index 000000000..fa5823588 --- /dev/null +++ b/resources/icons/spool_cog.svg @@ -0,0 +1,121 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index e7012ed0a..9b9bf4788 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -63,6 +63,9 @@ void AppConfig::set_defaults() if (get("freecad_path").empty()) set("freecad_path", "."); + if (get("tab_icon_size").empty()) + set("tab_icon_size", "32"); + if (get("color_very_dark").empty()) set("color_very_dark", "0047c7"); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 86c7e4a5d..81e4b1034 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -112,16 +112,18 @@ void Field::PostInitialize() BUILD(); // For the mode, when settings are in non-modal dialog, neither dialog nor tabpanel doesn't receive wxEVT_KEY_UP event, when some field is selected. - // So, like a workaround check wxEVT_KEY_UP event for the Filed and switch between tabs if Ctrl+(1-4) was pressed + // So, like a workaround check wxEVT_KEY_UP event for the Filed and switch between tabs if Ctrl+(1-6) was pressed if (getWindow()) getWindow()->Bind(wxEVT_KEY_UP, [](wxKeyEvent& evt) { if ((evt.GetModifiers() & wxMOD_CONTROL) != 0) { - int tab_id = -1; - switch (evt.GetKeyCode()) { - case '1': { tab_id = 0; break; } - case '2': { tab_id = 1; break; } - case '3': { tab_id = 2; break; } - case '4': { tab_id = 3; break; } + MainFrame::ETabType tab_id = MainFrame::ETabType::Any; + switch (evt.GetKeyCode()) { + case '1': { tab_id = MainFrame::ETabType::Plater3D; break; } + case '2': { tab_id = MainFrame::ETabType::PlaterPreview; break; } + case '3': { tab_id = MainFrame::ETabType::PlaterGcode; break; } + case '4': { tab_id = MainFrame::ETabType::PrintSettings; break; } + case '5': { tab_id = MainFrame::ETabType::FilamentSettings; break; } + case '6': { tab_id = MainFrame::ETabType::PrintSettings; break; } #ifdef __APPLE__ case 'f': #else /* __APPLE__ */ @@ -130,9 +132,11 @@ void Field::PostInitialize() case 'F': { wxGetApp().plater()->search(false); break; } default: break; } - if (tab_id >= 0) + if (tab_id < MainFrame::ETabType::Any) wxGetApp().mainframe->select_tab(tab_id); - if (tab_id > 0) + if (wxGetApp().mainframe->get_layout() == MainFrame::ESettingsLayout::Tabs + || wxGetApp().mainframe->get_layout() == MainFrame::ESettingsLayout::Old + || tab_id >= MainFrame::ETabType::PrintSettings) // tab panel should be focused for correct navigation between tabs wxGetApp().tab_panel()->SetFocus(); } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 24839d5e5..b4040ee86 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_objects, bool show_gcode) +{ + m_show_objects = show_objects; + 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_objects) + _render_objects(); + if (m_show_gcode && !m_main_toolbar.is_enabled()) _render_gcode(); _render_sla_slices(); _render_selection(); @@ -3867,9 +3873,9 @@ void GLCanvas3D::msw_rescale() void GLCanvas3D::update_tooltip_for_settings_item_in_main_toolbar() { std::string new_tooltip = _u8L("Switch to Settings") + - "\n" + "[" + GUI::shortkey_ctrl_prefix() + "2] - " + _u8L("Print Settings Tab") + - "\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (m_process->current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) + - "\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Printer Settings Tab") ; + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Print Settings Tab") + + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "5] - " + (m_process->current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) + + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "6] - " + _u8L("Printer Settings Tab") ; m_main_toolbar.set_tooltip(get_main_toolbar_item_id("settings"), new_tooltip); } @@ -4607,14 +4613,14 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "settings"; item.icon_filename = "settings.svg"; - item.tooltip = _u8L("Switch to Settings") + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "2] - " + _u8L("Print Settings Tab") + - "\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (m_process->current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) + - "\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Printer Settings Tab") ; + item.tooltip = _u8L("Switch to Settings") + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Print Settings Tab") + + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "5] - " + (m_process->current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) + + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "6] - " + _u8L("Printer Settings Tab") ; item.sprite_id = 10; item.enabling_callback = GLToolbarItem::Default_Enabling_Callback; item.visibility_callback = [this]() { return (wxGetApp().app_config->get("new_settings_layout_mode") == "1" || wxGetApp().app_config->get("dlg_settings_layout_mode") == "1"); }; - item.left.action_callback = [this]() { wxGetApp().mainframe->select_tab(); }; + item.left.action_callback = [this]() { wxGetApp().mainframe->select_tab(MainFrame::ETabType::LastSettings); }; if (!m_main_toolbar.add_item(item)) return false; @@ -5756,8 +5762,8 @@ void GLCanvas3D::_load_print_toolpaths() GLVolume &vol = *volume; volume = m_volumes.new_toolpath_volume(vol.color); reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized); + } } -} volume->indexed_vertex_array.finalize_geometry(m_initialized); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d99e0b77a..d26a6c459 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_objects = 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_objects, bool show_gcode); unsigned int get_volumes_count() const; const GLVolumeCollection& get_volumes() const { return m_volumes; } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index b46d7b8ef..78358c6fc 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -905,7 +905,7 @@ bool GUI_App::on_init_inner() mainframe = new MainFrame(); // hide settings tabs after first Layout if (is_editor()) - mainframe->select_tab(size_t(0)); + mainframe->select_tab(MainFrame::ETabType::LastPlater); sidebar().obj_list()->init_objects(); // propagate model objects to object list // update_mode(); // !!! do that later @@ -1173,7 +1173,7 @@ void GUI_App::recreate_GUI(const wxString& msg_name) mainframe = new MainFrame(); if (is_editor()) // hide settings tabs after first Layout - mainframe->select_tab(size_t(0)); + mainframe->select_tab(MainFrame::ETabType::LastPlater); // Propagate model objects to object list. sidebar().obj_list()->init_objects(); SetTopWindow(mainframe); @@ -1806,7 +1806,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu) // hide full main_sizer for mainFrame mainframe->GetSizer()->Show(false); mainframe->update_layout(); - mainframe->select_tab(size_t(0)); + mainframe->select_tab(MainFrame::ETabType::LastPlater); } break; } diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 5799610fc..4e874a1b2 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; @@ -489,6 +496,22 @@ void Preview::hide_layers_slider() Layout(); } +bool Preview::can_display_gcode() +{ + return !m_gcode_result->moves.empty(); +} + +bool Preview::can_display_volume() +{ + const Print* print = m_canvas->fff_print(); + if (print == nullptr) + return false; + + if (!print->is_step_done(psSkirt) || !print->is_step_done(psBrim)) + return false; + return true; +} + void Preview::on_size(wxSizeEvent& evt) { evt.Skip(); @@ -921,6 +944,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 +958,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 +977,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 +984,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..eeae2d243 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,8 @@ 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; } + ForceState get_force_state() { return current_force_state; } void msw_rescale(); void jump_layers_slider(wxKeyEvent& evt); @@ -179,7 +200,12 @@ Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSl #endif // ENABLE_ARROW_KEYS_WITH_SLIDERS void hide_layers_slider(); + bool can_display_gcode(); + bool can_display_volume(); + private: + ForceState current_force_state = ForceState::NoForce; + bool init(wxWindow* parent, Model* model); void bind_event_handlers(); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 178e0003a..aafc3ff20 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -97,12 +97,12 @@ void KBShortcutsDialog::fill_shortcuts() #endif // __APPLE__ { ctrl + "F", L("Search") }, // Window - { ctrl + "1", L("Select Plater Tab") }, - { ctrl + "2", L("Select Print Settings Tab") }, - { ctrl + "3", L("Select Filament Settings Tab") }, - { ctrl + "4", L("Select Printer Settings Tab") }, - { ctrl + "5", L("Switch to 3D") }, - { ctrl + "6", L("Switch to Preview") }, + { ctrl + "1", L("Select 3d editor Tab") }, + { ctrl + "2", L("Select Layer Preview Tab") }, + { ctrl + "3", L("Select Gcode preview Tab") }, + { ctrl + "4", L("Select Print Settings Tab") }, + { ctrl + "5", L("Select Filament Settings Tab") }, + { ctrl + "6", L("Select Printer Settings Tab") }, { ctrl + "J", L("Print host upload queue") }, { ctrl + "Shift+" + "I", L("Open new instance") }, // View diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 04abc8488..2476be380 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -262,6 +262,8 @@ void MainFrame::update_layout() }; // On Linux m_plater needs to be removed from m_tabpanel before to reparent it + //clear if previous was old + m_tabpanel_stop_event = true; int plater_page_id = m_tabpanel->FindPage(m_plater); if (plater_page_id != wxNOT_FOUND) m_tabpanel->RemovePage(plater_page_id); @@ -269,15 +271,33 @@ void MainFrame::update_layout() if (m_plater->GetParent() != this) m_plater->Reparent(this); + for (int i = 0; i < m_tabpanel->GetPageCount(); i++) { + m_tabpanel->SetPageImage(i, -1); + } + m_tabpanel->SetImageList(nullptr); //clear + + if (m_tabpanel->GetParent() != this) m_tabpanel->Reparent(this); + //clear if previous was hidden plater_page_id = (m_plater_page != nullptr) ? m_tabpanel->FindPage(m_plater_page) : wxNOT_FOUND; if (plater_page_id != wxNOT_FOUND) { m_tabpanel->DeletePage(plater_page_id); m_plater_page = nullptr; } + //clear if previous was tabs + for (int i = 0; i < m_tabpanel->GetPageCount(); i++) + if (m_tabpanel->GetPage(i)->GetChildren().empty() && m_tabpanel->GetPage(i)->GetSizer()->GetItemCount() > 0) { + clean_sizer(m_tabpanel->GetPage(i)->GetSizer()); + } + if (m_tabpanel->GetPage(0)->GetChildren().size() == 0 && m_tabpanel->GetPage(1)->GetChildren().size() == 0 && m_tabpanel->GetPage(2)->GetChildren().size() == 0) { + m_tabpanel->DeletePage(2); + m_tabpanel->DeletePage(1); + m_tabpanel->DeletePage(0); + } + clean_sizer(m_main_sizer); clean_sizer(m_settings_dialog.GetSizer()); @@ -285,15 +305,19 @@ void MainFrame::update_layout() m_settings_dialog.Close(); m_tabpanel->Hide(); + m_tabpanel_stop_event = false; m_plater->Hide(); + m_plater->enable_view_toolbar(true); + m_plater->set_force_preview(Preview::ForceState::NoForce); Layout(); }; ESettingsLayout layout = wxGetApp().is_gcode_viewer() ? ESettingsLayout::GCodeViewer : - (wxGetApp().app_config->get("old_settings_layout_mode") == "1" ? ESettingsLayout::Old : - wxGetApp().app_config->get("new_settings_layout_mode") == "1" ? ESettingsLayout::New : - wxGetApp().app_config->get("dlg_settings_layout_mode") == "1" ? ESettingsLayout::Dlg : ESettingsLayout::Old); + (wxGetApp().app_config->get("old_settings_layout_mode") == "1" ? ESettingsLayout::Old : + wxGetApp().app_config->get("tab_settings_layout_mode") == "1" ? ESettingsLayout::Tabs : + wxGetApp().app_config->get("new_settings_layout_mode") == "1" ? ESettingsLayout::Hidden : + wxGetApp().app_config->get("dlg_settings_layout_mode") == "1" ? ESettingsLayout::Dlg : ESettingsLayout::Tabs); if (m_layout == layout) return; @@ -305,6 +329,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 { @@ -319,8 +345,11 @@ void MainFrame::update_layout() m_layout = layout; + m_layerpreview_menu_item->Enable(m_layout == ESettingsLayout::Tabs || m_layout == ESettingsLayout::Old); + // From the very beginning the Print settings should be selected - m_last_selected_tab = m_layout == ESettingsLayout::Dlg ? 0 : 1; + m_last_selected_setting_tab = 0; + m_last_selected_plater_tab = 999; // Set new settings switch (m_layout) @@ -328,17 +357,92 @@ void MainFrame::update_layout() case ESettingsLayout::Unknown: { break; - } - case ESettingsLayout::Old: + }case ESettingsLayout::Old: { + // don't use view_toolbar here + m_plater->enable_view_toolbar(false); + //layout m_plater->Reparent(m_tabpanel); m_tabpanel->InsertPage(0, m_plater, _L("Plater")); m_main_sizer->Add(m_tabpanel, 1, wxEXPAND); + // icons for ESettingsLayout::Old + wxImageList* img_list = nullptr; + int icon_size = 0; + try { + icon_size = atoi(wxGetApp().app_config->get("tab_icon_size").c_str()); + } + catch (std::exception e) {} + if (icon_size >= 8) { + std::initializer_list icon_list = { "plater", "cog", "spool_cog", "printer_cog" }; + if (icon_size < 16) + icon_list = { "plater", "cog", "spool", "printer" }; + for (std::string icon_name : icon_list) { + const wxBitmap& bmp = create_scaled_bitmap(icon_name, this, icon_size); + if (img_list == nullptr) + img_list = new wxImageList(bmp.GetWidth(), bmp.GetHeight()); + img_list->Add(bmp); + } + } + m_tabpanel->AssignImageList(img_list); + if (icon_size >= 8) + { + m_tabpanel->SetPageImage(0, 0); + m_tabpanel->SetPageImage(1, 1); + m_tabpanel->SetPageImage(2, 2); + m_tabpanel->SetPageImage(3, 3); + } + // show + m_plater->Show(); + m_tabpanel->Show(); + break; + } + case ESettingsLayout::Tabs: + { + // don't use view_toolbar here + m_plater->enable_view_toolbar(false); + // icons for ESettingsLayout::Tabs + wxImageList* img_list = nullptr; + int icon_size = 0; + try { + icon_size = atoi(wxGetApp().app_config->get("tab_icon_size").c_str()); + } + catch (std::exception e) {} + if (icon_size >= 8) { + std::initializer_list icon_list = { "editor_menu", "layers", "preview_menu", "cog", "spool_cog", "printer_cog" }; + if (icon_size < 16) + icon_list = { "editor_menu", "layers", "preview_menu", "cog", "spool", "printer" }; + for (std::string icon_name : icon_list) { + const wxBitmap& bmp = create_scaled_bitmap(icon_name, this, icon_size); + 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, new wxPanel(m_tabpanel), _L("3D view")); + m_tabpanel->InsertPage(1, new wxPanel(m_tabpanel), _L("Sliced preview")); + m_tabpanel->InsertPage(2, new wxPanel(m_tabpanel), _L("Gcode preview")); + m_tabpanel->GetPage(0)->SetSizer(new wxBoxSizer(wxVERTICAL)); + m_tabpanel->GetPage(1)->SetSizer(new wxBoxSizer(wxVERTICAL)); + m_tabpanel->GetPage(2)->SetSizer(new wxBoxSizer(wxVERTICAL)); + if (icon_size >= 8) + { + m_tabpanel->SetPageImage(0, 0); + m_tabpanel->SetPageImage(1, 1); + m_tabpanel->SetPageImage(2, 2); + m_tabpanel->SetPageImage(3, 3); + m_tabpanel->SetPageImage(4, 4); + m_tabpanel->SetPageImage(5, 5); + } + m_plater->Reparent(m_tabpanel->GetPage(0)); + m_tabpanel->GetPage(0)->GetSizer()->Add(m_plater, 1, wxEXPAND); + m_tabpanel->ChangeSelection(0); + m_main_sizer->Add(m_tabpanel, 1, wxEXPAND); m_plater->Show(); m_tabpanel->Show(); break; } - case ESettingsLayout::New: + case ESettingsLayout::Hidden: { m_main_sizer->Add(m_plater, 1, wxEXPAND); m_tabpanel->Hide(); @@ -404,7 +508,7 @@ void MainFrame::update_layout() // // So, if we haven't possibility to set MinSize() for the MainFrame, // // set the MinSize() as a half of regular for the m_plater and m_tabpanel, when settings layout is in slNew mode // // Otherwise, MainFrame will be maximized by height -// if (m_layout == ESettingsLayout::New) { +// if (m_layout == ESettingsLayout::Hidden) { // wxSize size = wxGetApp().get_min_size(); // size.SetHeight(int(0.5 * size.GetHeight())); // m_plater->SetMinSize(size); @@ -413,7 +517,7 @@ void MainFrame::update_layout() //#endif #ifdef __APPLE__ - m_plater->sidebar().change_top_border_for_mode_sizer(m_layout != ESettingsLayout::Old); + m_plater->sidebar().change_top_border_for_mode_sizer(m_layout != ESettingsLayout::Tabs && m_layout != ESettingsLayout::Old); #endif Layout(); @@ -538,7 +642,10 @@ void MainFrame::init_tabpanel() m_tabpanel->Hide(); m_settings_dialog.set_tabpanel(m_tabpanel); + m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxEvent&) { + if (m_tabpanel_stop_event) + return; wxWindow* panel = m_tabpanel->GetCurrentPage(); Tab* tab = dynamic_cast(panel); @@ -546,15 +653,79 @@ void MainFrame::init_tabpanel() if (panel == nullptr || (tab != nullptr && !tab->supports_printer_technology(m_plater->printer_technology()))) return; - auto& tabs_list = wxGetApp().tabs_list; + std::vector& tabs_list = wxGetApp().tabs_list; + int last_selected_plater_tab = m_last_selected_plater_tab; + int last_selected_setting_tab = m_last_selected_setting_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(); + if (this->m_layout == ESettingsLayout::Tabs) + last_selected_setting_tab = m_tabpanel->GetSelection() - 3; + if (this->m_layout == ESettingsLayout::Dlg) + last_selected_setting_tab = m_tabpanel->GetSelection(); + else + last_selected_setting_tab = m_tabpanel->GetSelection() - 1; + } + else if (this->m_layout == ESettingsLayout::Tabs) { + if (last_selected_plater_tab == m_tabpanel->GetSelection()) { + std::cout << "Page changed to the same one (" << m_last_selected_plater_tab << ") no need to do anything\n"; + return; + } + bool need_freeze = !this->IsFrozen(); + if(need_freeze) Freeze(); + std::cout << "I switched to tab " << m_tabpanel->GetSelection() << " and so i need to change the panel position & content\n"; + size_t new_tab = m_tabpanel->GetSelection(); + + size_t max = 0; + for (int i = 0; i < 3; i++) + max = std::max(max, m_tabpanel->GetPage(i)->GetSizer()->GetItemCount()); + std::cout << " 1 - hide & clear the sizers: " << max << "->"; + for(int i=0;i<3;i++) + m_tabpanel->GetPage(i)->GetSizer()->Clear(); + max = 0; + for (int i = 0; i < 3; i++) + max = std::max(max, m_tabpanel->GetPage(i)->GetSizer()->GetItemCount()); + std::cout << max << "\n"; + + m_plater->Reparent(m_tabpanel->GetCurrentPage()); + std::cout << " 2 - change parent from tab " << m_last_selected_plater_tab << " to tab " << m_tabpanel->GetSelection() << "\n"; + if (m_tabpanel->GetSelection() == 0) + this->m_plater->select_view_3D("3D"); + else if (m_tabpanel->GetSelection() == 1) { + if (this->m_plater->get_force_preview() != Preview::ForceState::ForceExtrusions) { + this->m_plater->set_force_preview(Preview::ForceState::ForceExtrusions); + this->m_plater->select_view_3D("Preview"); + this->m_plater->refresh_print(); + }else + this->m_plater->select_view_3D("Preview"); + } + else if (m_tabpanel->GetSelection() == 2) { + if (this->m_plater->get_force_preview() != Preview::ForceState::ForceGcode) { + this->m_plater->set_force_preview(Preview::ForceState::ForceGcode); + this->m_plater->select_view_3D("Preview"); + this->m_plater->refresh_print(); + }else + this->m_plater->select_view_3D("Preview"); + } + std::cout << " 3 - redraw\n"; + std::cout << " 4 - add to new sizer: " << m_tabpanel->GetCurrentPage()->GetSizer()->GetItemCount() << "->"; + m_tabpanel->GetCurrentPage()->GetSizer()->Add(m_plater, 1, wxEXPAND); + std::cout << m_tabpanel->GetCurrentPage()->GetSizer()->GetItemCount() << "\n"; + m_plater->Show(); + std::cout << "End of change for the panel position & content, tab is "<< m_tabpanel->GetSelection() <<"\n"; + m_last_selected_plater_tab = m_tabpanel->GetSelection(); + + if (need_freeze) Thaw(); +#ifdef __APPLE__ + m_tabpanel->ChangeSelection(new_tab); + m_tabpanel->Refresh(); + std::cout << "Macos: force tab selection to "<< new_tab <<" : " << m_tabpanel->GetSelection() << "\n"; +#endif + } else { + select_tab(MainFrame::ETabType::LastPlater); // select Plater + m_last_selected_plater_tab = 999; } - else - select_tab(size_t(0)); // select Plater }); m_plater = new Plater(this, this); @@ -565,7 +736,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 @@ -666,7 +837,7 @@ bool MainFrame::is_active_and_shown_tab(Tab* tab) if (m_layout == ESettingsLayout::Dlg) return m_settings_dialog.IsShown(); - if (m_layout == ESettingsLayout::New) + if (m_layout == ESettingsLayout::Hidden) return m_main_sizer->IsShown(m_tabpanel); return true; @@ -767,9 +938,10 @@ bool MainFrame::can_change_view() const switch (m_layout) { default: { return false; } - case ESettingsLayout::New: { return m_plater->IsShown(); } + case ESettingsLayout::Hidden: { return m_plater->IsShown(); } case ESettingsLayout::Dlg: { return true; } - case ESettingsLayout::Old: { + case ESettingsLayout::Old: + case ESettingsLayout::Tabs: { int page_id = m_tabpanel->GetSelection(); return page_id != wxNOT_FOUND && dynamic_cast(m_tabpanel->GetPage((size_t)page_id)) != nullptr; } @@ -1177,31 +1349,28 @@ void MainFrame::init_menubar_as_editor() auto windowMenu = new wxMenu(); { if (m_plater) { - append_menu_item(windowMenu, wxID_HIGHEST + 1, _L("&Plater Tab") + "\tCtrl+1", _L("Show the plater"), - [this](wxCommandEvent&) { select_tab(size_t(0)); }, "plater", nullptr, + append_menu_item(windowMenu, wxID_HIGHEST + 1, _L("3D &Plater Tab") + "\tCtrl+1", _L("Show the editor of the input models"), + [this](wxCommandEvent&) { select_tab(ETabType::Plater3D); }, "editor_menu", nullptr, + []() {return true; }, this); + m_layerpreview_menu_item = append_menu_item(windowMenu, wxID_HIGHEST + 2, _L("Layer previe&w Tab") + "\tCtrl+2", _L("Show the layers from the slicing process"), + [this](wxCommandEvent&) { select_tab(ETabType::PlaterPreview); }, "layers", nullptr, + []() {return true; }, this); + append_menu_item(windowMenu, wxID_HIGHEST + 3, _L("GCode Pre&view Tab") + "\tCtrl+3", _L("Show the preview of the gcode output"), + [this](wxCommandEvent&) { select_tab(ETabType::PlaterGcode); }, "preview_menu", nullptr, []() {return true; }, this); windowMenu->AppendSeparator(); } - append_menu_item(windowMenu, wxID_HIGHEST + 2, _L("P&rint Settings Tab") + "\tCtrl+2", _L("Show the print settings"), - [this/*, tab_offset*/](wxCommandEvent&) { select_tab(1); }, "cog", nullptr, + append_menu_item(windowMenu, wxID_HIGHEST + 4, _L("P&rint Settings Tab") + "\tCtrl+4", _L("Show the print settings"), + [this/*, tab_offset*/](wxCommandEvent&) { select_tab(ETabType::PrintSettings); }, "cog", nullptr, []() {return true; }, this); - wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 3, _L("&Filament Settings Tab") + "\tCtrl+3", _L("Show the filament settings"), - [this/*, tab_offset*/](wxCommandEvent&) { select_tab(2); }, "spool", nullptr, + wxMenuItem* item_material_tab = append_menu_item(windowMenu, wxID_HIGHEST + 5, _L("&Filament Settings Tab") + "\tCtrl+5", _L("Show the filament settings"), + [this/*, tab_offset*/](wxCommandEvent&) { select_tab(ETabType::FilamentSettings); }, "spool", nullptr, []() {return true; }, this); m_changeable_menu_items.push_back(item_material_tab); - wxMenuItem* item_printer_tab = append_menu_item(windowMenu, wxID_HIGHEST + 4, _L("Print&er Settings Tab") + "\tCtrl+4", _L("Show the printer settings"), - [this/*, tab_offset*/](wxCommandEvent&) { select_tab(3); }, "printer", nullptr, + wxMenuItem* item_printer_tab = append_menu_item(windowMenu, wxID_HIGHEST + 6, _L("Print&er Settings Tab") + "\tCtrl+6", _L("Show the printer settings"), + [this/*, tab_offset*/](wxCommandEvent&) { select_tab(ETabType::PrinterSettings); }, "printer", nullptr, []() {return true; }, this); m_changeable_menu_items.push_back(item_printer_tab); - if (m_plater) { - windowMenu->AppendSeparator(); - append_menu_item(windowMenu, wxID_HIGHEST + 5, _L("3&D") + "\tCtrl+5", _L("Show the 3D editing view"), - [this](wxCommandEvent&) { m_plater->select_view_3D("3D"); }, "editor_menu", nullptr, - [this](){return can_change_view(); }, this); - append_menu_item(windowMenu, wxID_HIGHEST + 6, _L("Pre&view") + "\tCtrl+6", _L("Show the 3D slices preview"), - [this](wxCommandEvent&) { m_plater->select_view_3D("Preview"); }, "preview_menu", nullptr, - [this](){return can_change_view(); }, this); - } windowMenu->AppendSeparator(); append_menu_item(windowMenu, wxID_ANY, _L("Print &Host Upload Queue") + "\tCtrl+J", _L("Display the Print Host Upload Queue window"), @@ -1689,13 +1858,16 @@ void MainFrame::select_tab(Tab* tab) { if (!tab) return; - int page_idx = m_tabpanel->FindPage(tab); - if (page_idx != wxNOT_FOUND && m_layout == ESettingsLayout::Dlg) - page_idx++; - select_tab(size_t(page_idx)); + std::vector& tabs_list = wxGetApp().tabs_list; + std::vector::iterator it_tab = std::find(tabs_list.begin(), tabs_list.end(), tab); + if (it_tab != tabs_list.end()) { + select_tab((ETabType)((uint8_t)ETabType::PrintSettings + uint8_t(it_tab - tabs_list.begin()))); + } + + select_tab(ETabType::LastSettings); } -void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) +void MainFrame::select_tab(ETabType tab /* = Any*/, bool keep_tab_type) { bool tabpanel_was_hidden = false; @@ -1703,7 +1875,26 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) // We should select/activate tab before its showing to avoid an UI-flickering auto select = [this, tab](bool was_hidden) { // when tab == -1, it means we should show the last selected tab - size_t new_selection = tab == (size_t)(-1) ? m_last_selected_tab : (m_layout == ESettingsLayout::Dlg && tab != 0) ? tab - 1 : tab; + size_t new_selection = 0; + if (tab <= ETabType::LastPlater) { + //select plater + new_selection = (uint8_t)tab; + if (tab == ETabType::LastPlater) + new_selection = m_last_selected_plater_tab > 2 ? 0 : m_last_selected_plater_tab; + if (m_layout != ESettingsLayout::Tabs) + new_selection = 0; + + } else if (tab <= ETabType::LastSettings) { + //select setting + new_selection = (uint8_t)tab - (uint8_t)ETabType::PrintSettings; + if (tab == ETabType::LastSettings) + new_selection = m_last_selected_setting_tab > 2 ? 0 : m_last_selected_setting_tab; + //push to the correct position + if (m_layout == ESettingsLayout::Tabs) + new_selection = m_last_selected_setting_tab + 3; + else if (m_layout != ESettingsLayout::Dlg) + new_selection = new_selection + 1; + } if (m_tabpanel->GetSelection() != (int)new_selection) m_tabpanel->SetSelection(new_selection); @@ -1714,8 +1905,20 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) } }; + if (m_layout != ESettingsLayout::Tabs) { + if (tab == ETabType::Plater3D || (tab == ETabType::LastPlater && m_last_selected_plater_tab == 0)) { + m_plater->select_view_3D("3D"); + } else if (tab == ETabType::PlaterPreview || (tab == ETabType::LastPlater && m_last_selected_plater_tab == 1)) { + m_plater->select_view_3D("Preview"); + } else if (tab == ETabType::PlaterGcode || (tab == ETabType::LastPlater && m_last_selected_plater_tab == 2)) { + m_plater->select_view_3D("Preview"); + } + } + if (m_layout == ESettingsLayout::Dlg) { - if (tab==0) { + if (keep_tab_type) + return; + if (tab <= ETabType::LastPlater) { if (m_settings_dialog.IsShown()) this->SetFocus(); // plater should be focused for correct navigation inside search window @@ -1746,21 +1949,35 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) } #endif } - else if (m_layout == ESettingsLayout::New) { - m_main_sizer->Show(m_plater, tab == 0); + else if (m_layout == ESettingsLayout::Hidden) { + if (keep_tab_type && m_tabpanel->GetSelection()>0) + return; + m_main_sizer->Show(m_plater, tab <= ETabType::LastPlater); tabpanel_was_hidden = !m_main_sizer->IsShown(m_tabpanel); select(tabpanel_was_hidden); - m_main_sizer->Show(m_tabpanel, tab != 0); + m_main_sizer->Show(m_tabpanel, tab > ETabType::LastPlater); // plater should be focused for correct navigation inside search window - if (tab == 0 && m_plater->canvas3D()->is_search_pressed()) + if (tab <= ETabType::LastPlater && m_plater->canvas3D()->is_search_pressed()) m_plater->SetFocus(); Layout(); } + else if (m_layout == ESettingsLayout::Old) { + if (keep_tab_type && m_tabpanel->GetSelection() > 0) + return; + else + select(false); + } + else if (m_layout == ESettingsLayout::Tabs) { + if (keep_tab_type && ( (m_tabpanel->GetSelection() >=3 && tab <= ETabType::LastPlater) || (m_tabpanel->GetSelection() < 3 && tab > ETabType::LastPlater))) + return; + else + select(false); + } else select(false); - // When we run application in ESettingsLayout::New or ESettingsLayout::Dlg mode, tabpanel is hidden from the very beginning + // When we run application in ESettingsLayout::Hidden or ESettingsLayout::Dlg mode, tabpanel is hidden from the very beginning // and as a result Tab::update_changed_tree_ui() function couldn't update m_is_nonsys_values values, // which are used for update TreeCtrl and "revert_buttons". // So, force the call of this function for Tabs, if tab panel was hidden @@ -1918,10 +2135,12 @@ SettingsDialog::SettingsDialog(MainFrame* mainframe) auto key_up_handker = [this](wxKeyEvent& evt) { if ((evt.GetModifiers() & wxMOD_CONTROL) != 0) { switch (evt.GetKeyCode()) { - case '1': { m_main_frame->select_tab(size_t(0)); break; } - case '2': { m_main_frame->select_tab(1); break; } - case '3': { m_main_frame->select_tab(2); break; } - case '4': { m_main_frame->select_tab(3); break; } + case '1': { m_main_frame->select_tab(MainFrame::ETabType::Plater3D); break; } + case '2': { m_main_frame->select_tab(MainFrame::ETabType::Plater3D); break; } + case '3': { m_main_frame->select_tab(MainFrame::ETabType::PlaterGcode); break; } + case '4': { m_main_frame->select_tab(MainFrame::ETabType::PrintSettings); break; } + case '5': { m_main_frame->select_tab(MainFrame::ETabType::FilamentSettings); break; } + case '6': { m_main_frame->select_tab(MainFrame::ETabType::PrinterSettings); break; } #ifdef __APPLE__ case 'f': #else /* __APPLE__ */ diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 9504376b4..45813c1ed 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -81,7 +81,8 @@ class MainFrame : public DPIFrame - size_t m_last_selected_tab; + size_t m_last_selected_plater_tab; + size_t m_last_selected_setting_tab; std::string get_base_name(const wxString &full_name, const char *extension = nullptr) const; std::string get_dir_name(const wxString &full_name) const; @@ -117,17 +118,36 @@ class MainFrame : public DPIFrame // vector of a MenuBar items changeable in respect to printer technology std::vector m_changeable_menu_items; + wxMenuItem* m_layerpreview_menu_item; wxFileHistory m_recent_projects; +public: + enum class ESettingsLayout { Unknown, Old, - New, + Tabs, + Hidden, Dlg, GCodeViewer }; + + enum class ETabType : uint8_t + { + Plater3D, + PlaterPreview, + PlaterGcode, + LastPlater, + PrintSettings, + FilamentSettings, + PrinterSettings, + LastSettings, + Any + }; + +private: ESettingsLayout m_layout{ ESettingsLayout::Unknown }; @@ -136,6 +156,7 @@ protected: virtual void on_sys_color_changed() override; public: + MainFrame(); ~MainFrame() = default; @@ -162,7 +183,7 @@ public: void update_ui_from_settings(bool apply_free_camera_correction = true); bool is_loaded() const { return m_loaded; } bool is_last_input_file() const { return !m_qs_last_input_file.IsEmpty(); } - bool is_dlg_layout() const { return m_layout == ESettingsLayout::Dlg; } + ESettingsLayout get_layout() const { return m_layout; } void quick_slice(const int qs = qsUndef); void reslice_now(); @@ -177,8 +198,9 @@ public: void load_config(const DynamicPrintConfig& config); // Select tab in m_tabpanel // When tab == -1, will be selected last selected tab + // 0 = a plater tab, 1 = print setting, 2 = filament settign, 3 = printer setting void select_tab(Tab* tab); - void select_tab(size_t tab = size_t(-1)); + void select_tab(ETabType tab = ETabType::Any, bool keep_tab_type = false); void select_view(const std::string& direction); // Propagate changed configuration from the Tab to the Plater and save changes to the AppConfig void on_config_changed(DynamicPrintConfig* cfg) const ; @@ -189,6 +211,7 @@ public: Plater* m_plater { nullptr }; wxNotebook* m_tabpanel { nullptr }; + bool m_tabpanel_stop_event = false; SettingsDialog m_settings_dialog; wxWindow* m_plater_page{ nullptr }; wxProgressDialog* m_progress_dialog { nullptr }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index eb8e524d8..b933a5748 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -799,7 +799,6 @@ Sidebar::Sidebar(Plater *parent) p->plater->export_gcode(true); else p->plater->reslice(); - p->plater->select_view_3D("Preview"); }); p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); // p->btn_eject_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); }); @@ -993,7 +992,7 @@ void Sidebar::jump_to_option(size_t selected) wxGetApp().get_tab(opt.type)->activate_option(boost::nowide::narrow(opt.opt_key), boost::nowide::narrow(opt.category)); // Switch to the Settings NotePad -// wxGetApp().mainframe->select_tab(); +// wxGetApp().mainframe->select_tab(MainFrame::ETabType::LastSettings); } ObjectManipulation* Sidebar::obj_manipul() @@ -1634,8 +1633,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; @@ -1651,6 +1650,7 @@ struct Plater::priv BackgroundSlicingProcess background_process; bool suppressed_backround_processing_update { false }; + std::function process_done_callback = [](int) {}; // Jobs defined inside the group class will be managed so that only one can // run at a time. Also, the background process will be stopped if a job is @@ -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) @@ -3089,6 +3094,16 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool show_action_buttons(true); } + //update tab if needed + if (invalidated != Print::ApplyStatus::APPLY_STATUS_UNCHANGED) + { + if (this->preview->can_display_gcode()) + main_frame->select_tab(MainFrame::ETabType::PlaterGcode, true); + else if (this->preview->can_display_volume()) + main_frame->select_tab(MainFrame::ETabType::PlaterPreview, true); + else + main_frame->select_tab(MainFrame::ETabType::Plater3D, true); + } return return_state; } @@ -3488,7 +3503,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 +3515,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 +3540,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 +3555,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 +3565,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) @@ -3701,6 +3708,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) void Plater::priv::on_slicing_completed(wxCommandEvent & evt) { notification_manager->push_slicing_complete_notification(evt.GetInt(), is_sidebar_collapsed()); + main_frame->select_tab(MainFrame::ETabType::PlaterPreview); switch (this->printer_technology) { case ptFFF: this->update_fff_scene(); @@ -3780,6 +3788,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) this->background_process.stop(); this->statusbar()->reset_cancel_callback(); this->statusbar()->stop_busy(); + main_frame->select_tab(MainFrame::ETabType::PlaterGcode); // Reset the "export G-code path" name, so that the automatic background processing will be enabled again. this->background_process.reset_export(); @@ -4272,7 +4281,7 @@ bool Plater::priv::init_view_toolbar() item.name = "3D"; item.icon_filename = "editor.svg"; - item.tooltip = _utf8(L("3D editor view")) + " [" + GUI::shortkey_ctrl_prefix() + "5]"; + item.tooltip = _utf8(L("3D editor view")) + " [" + GUI::shortkey_ctrl_prefix() + "1]"; item.sprite_id = 0; item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); }; if (!view_toolbar.add_item(item)) @@ -4280,14 +4289,13 @@ bool Plater::priv::init_view_toolbar() item.name = "Preview"; item.icon_filename = "preview.svg"; - item.tooltip = _utf8(L("Preview")) + " [" + GUI::shortkey_ctrl_prefix() + "6]"; + item.tooltip = _utf8(L("Preview")) + " [" + GUI::shortkey_ctrl_prefix() + "3]"; item.sprite_id = 1; item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); }; if (!view_toolbar.add_item(item)) return false; view_toolbar.select_item("3D"); - view_toolbar.set_enabled(true); return true; } @@ -5221,6 +5229,15 @@ 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::set_force_preview(Preview::ForceState force) { + if (p->preview) + p->preview->set_force_state(force); +} + +Preview::ForceState Plater::get_force_preview() { + return p->preview->get_force_state(); +} + 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..87fe4e2d1 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,8 @@ public: void stop_jobs(); void select_view(const std::string& direction); void select_view_3D(const std::string& name); + void set_force_preview(Preview::ForceState force); + Preview::ForceState get_force_preview(); 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 021155cd5..2f1ed4523 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -304,6 +304,8 @@ void PreferencesDialog::build() m_values[opt_key] = boost::any_cast(value) ? "1" : ""; else if (opt_key.find("color") != std::string::npos) m_values[opt_key] = boost::any_cast(value); + else if (opt_key.find("tab_icon_size") != std::string::npos) + m_values[opt_key] = std::to_string(boost::any_cast(value)); else m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; @@ -345,6 +347,15 @@ void PreferencesDialog::build() def.set_default_value(new ConfigOptionBool{ app_config->get("use_custom_toolbar_size") == "1" }); option = Option(def, "use_custom_toolbar_size"); m_optgroup_gui->append_single_option_line(option); + + def.label = L("Tab icon size"); + def.type = coInt; + def.tooltip = std::string(L("Size of the tab icons, in pixels. Set to 0 to remove icons.")) + + std::string(L("\nYou have to restart the application before any change will be taken into account.")); + def.set_default_value(new ConfigOptionInt{ atoi(app_config->get("tab_icon_size").c_str()) }); + option = Option(def, "tab_icon_size"); + option.opt.width = 6; + m_optgroup_gui->append_single_option_line(option); } @@ -469,7 +480,7 @@ void PreferencesDialog::accept() if (it != m_values.end() && app_config->get(key) != it->second) { m_settings_layout_changed = true; break; - } + } } for (const std::string& key : {"default_action_on_close_application", "default_action_on_select_preset"}) { @@ -574,27 +585,30 @@ 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("Old PrusaSlicer layout"), + _L("Access via settings button in the top menu"), _L("Settings in non-modal window") }; auto app_config = get_app_config(); - int selection = app_config->get("old_settings_layout_mode") == "1" ? 0 : - app_config->get("new_settings_layout_mode") == "1" ? 1 : - app_config->get("dlg_settings_layout_mode") == "1" ? 2 : 0; + int selection = app_config->get("tab_settings_layout_mode") == "1" ? 0 : + app_config->get("old_settings_layout_mode") == "1" ? 1 : + app_config->get("new_settings_layout_mode") == "1" ? 2 : + app_config->get("dlg_settings_layout_mode") == "1" ? 3 : 1; wxWindow* parent = m_optgroup_gui->parent(); m_layout_mode_box = new wxRadioBox(parent, wxID_ANY, _L("Layout Options"), wxDefaultPosition, wxDefaultSize, - WXSIZEOF(choices), choices, 3, wxRA_SPECIFY_ROWS); + WXSIZEOF(choices), choices, 4, wxRA_SPECIFY_ROWS); m_layout_mode_box->SetFont(wxGetApp().normal_font()); m_layout_mode_box->SetSelection(selection); m_layout_mode_box->Bind(wxEVT_RADIOBOX, [this](wxCommandEvent& e) { int selection = e.GetSelection(); - m_values["old_settings_layout_mode"] = boost::any_cast(selection == 0) ? "1" : "0"; - m_values["new_settings_layout_mode"] = boost::any_cast(selection == 1) ? "1" : "0"; - m_values["dlg_settings_layout_mode"] = boost::any_cast(selection == 2) ? "1" : "0"; + m_values["tab_settings_layout_mode"] = boost::any_cast(selection == 0) ? "1" : "0"; + m_values["old_settings_layout_mode"] = boost::any_cast(selection == 1) ? "1" : "0"; + m_values["new_settings_layout_mode"] = boost::any_cast(selection == 2) ? "1" : "0"; + m_values["dlg_settings_layout_mode"] = boost::any_cast(selection == 3) ? "1" : "0"; }); auto sizer = new wxBoxSizer(wxHORIZONTAL); diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 8dd35a591..d42853dfd 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -696,7 +696,7 @@ bool PlaterPresetComboBox::switch_to_tab() wxGetApp().tab_panel()->SetSelection(page_id); // Switch to Settings NotePad - wxGetApp().mainframe->select_tab(); + wxGetApp().mainframe->select_tab(MainFrame::ETabType::LastSettings); return true; } diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index a8a2381bb..95de1b44f 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -559,7 +559,7 @@ UnsavedChangesDialog::UnsavedChangesDialog(Preset::Type type, PresetCollection* const std::string& def_action = wxGetApp().app_config->get(m_app_config_key); if (def_action == "none") { - if (wxGetApp().mainframe->is_dlg_layout() && wxGetApp().mainframe->m_settings_dialog.HasFocus()) + if (wxGetApp().mainframe->get_layout() == MainFrame::ESettingsLayout::Dlg && wxGetApp().mainframe->m_settings_dialog.HasFocus()) this->SetPosition(wxGetApp().mainframe->m_settings_dialog.GetPosition()); this->CenterOnScreen(); }