Make the Design tab sidebar dockable and collapsible like Prepare's

The sidebar can move to either side, float, be resized, and collapse with
the canvas button or Shift+Tab. Its layout is remembered separately from
Prepare's, starts where Prepare's sidebar is, and View > Reset Window
Layout resets both tabs.
This commit is contained in:
SoftFever
2026-10-03 19:05:53 +08:00
parent a9c8721380
commit d47fb804c3
17 changed files with 420 additions and 164 deletions
+20 -101
View File
@@ -191,6 +191,7 @@
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
#include "AuiMgr.hpp"
#include "AuiPaneLayout.hpp"
#include "GUI_Utils.hpp"
#include "GUI_Factories.hpp"
@@ -7111,28 +7112,6 @@ enum ExportingStatus{
EXPORTING_TO_LOCAL
};
// TODO: listen on dark ui change
class FloatFrame : public wxAuiFloatingFrame
{
public:
FloatFrame(wxWindow* parent, wxAuiManager* ownerMgr, const wxAuiPaneInfo& pane) : wxAuiFloatingFrame(parent, ownerMgr, pane)
{
wxGetApp().UpdateFrameDarkUI(this);
}
};
class AuiMgr : public wxAuiManager
{
public:
AuiMgr() : wxAuiManager(){}
virtual wxAuiFloatingFrame* CreateFloatingFrame(wxWindow* parent, const wxAuiPaneInfo& p) override
{
return new FloatFrame(parent, this, p);
}
};
// Plater / private
struct Plater::priv
{
@@ -7616,7 +7595,6 @@ struct Plater::priv
//BBS: change dark/light mode
void on_change_color_mode(SimpleEvent& evt);
void on_apple_change_color_mode(wxSysColourChangedEvent& evt);
void apply_color_mode();
void on_update_geometry(Vec3dsEvent<2>&);
void on_3dcanvas_mouse_dragging_started(SimpleEvent&);
void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
@@ -7829,20 +7807,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
{
m_is_dark = wxGetApp().app_config->get("dark_color_mode") == "1";
#ifdef __WXGTK__
const bool disable_wayland_floating = Slic3r::GUI::is_running_on_wayland();
#endif
m_aui_mgr.SetManagedWindow(q);
m_aui_mgr.SetDockSizeConstraint(1, 1);
#ifdef __WXGTK__
if (disable_wayland_floating)
m_aui_mgr.SetFlags(m_aui_mgr.GetFlags() & ~wxAUI_MGR_ALLOW_FLOATING);
#endif
//m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, 0);
//m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_SASH_SIZE, 2);
m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_CAPTION_SIZE, 18);
m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_GRADIENT_TYPE, wxAUI_GRADIENT_NONE);
m_aui_mgr.init(q);
this->q->SetFont(Slic3r::GUI::wxGetApp().normal_font());
@@ -7925,13 +7890,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
update();
// Orca: Make sidebar dockable
m_aui_mgr.AddPane(sidebar, wxAuiPaneInfo()
.Name("sidebar")
.Left()
.CloseButton(false)
.TopDockable(false)
.BottomDockable(false)
.BestSize(wxSize(39 * wxGetApp().em_unit(), 90 * wxGetApp().em_unit())));
m_aui_mgr.AddPane(sidebar, AuiMgr::sidebar_pane_info());
// UV editor pane for GLGizmoTextureDisplacement's LSCM unwrap preview - a resizable/dockable
// sibling of "sidebar"/"main" like everything else registered on this same AUI manager, not a
@@ -7983,8 +7942,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
if (!layout.empty()) {
bool removed_floating_state = false;
#ifdef __WXGTK__
if (disable_wayland_floating)
layout = sanitize_window_layout_for_wayland(layout, &removed_floating_state);
layout = sanitize_window_layout_for_wayland(layout, &removed_floating_state);
#endif
if (!m_aui_mgr.LoadPerspective(layout, false)) {
@@ -8006,12 +7964,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// Keep tracking the current sidebar size, by storing it using `best_size`, which will be stored
// in the config and re-applied when the app is opened again.
this->sidebar->Bind(wxEVT_IDLE, [&sidebar](wxIdleEvent& e) {
if (sidebar.IsShown() && sidebar.IsDocked() && sidebar.rect.GetWidth() > 0) {
sidebar.BestSize(sidebar.rect.GetWidth(), sidebar.best_size.GetHeight());
}
e.Skip();
});
m_aui_mgr.track_docked_size(this->sidebar);
// Hide sidebar initially, will re-show it after initialization when we got proper window size
sidebar.Hide();
@@ -8236,8 +8189,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
q->SetDropTarget(new PlaterDropTarget(*main_frame, *q)); // if my understanding is right, wxWindow takes the owenership
q->Layout();
apply_color_mode();
set_current_panel(wxGetApp().is_editor() ? static_cast<wxPanel*>(view3D) : static_cast<wxPanel*>(preview));
// updates camera type from .ini file
@@ -8716,18 +8667,7 @@ void Plater::priv::add_dock_pane(wxWindow* window, const std::string& name, cons
info.Show(dock_pane_visible(dock_pane, info));
m_aui_mgr.AddPane(window, info);
// wxAUI does not record a dragged sash in best_size, so track the docked size like the sidebar
// does, for the saved layout.
window->Bind(wxEVT_IDLE, [this, window](wxIdleEvent& evt) {
wxAuiPaneInfo& pane = m_aui_mgr.GetPane(window);
if (pane.IsOk() && pane.IsShown() && pane.IsDocked() && pane.rect.GetWidth() > 0 && pane.rect.GetHeight() > 0) {
const bool horizontal = pane.dock_direction == wxAUI_DOCK_TOP || pane.dock_direction == wxAUI_DOCK_BOTTOM;
pane.BestSize(horizontal ? pane.best_size.GetWidth() : pane.rect.GetWidth(),
horizontal ? pane.rect.GetHeight() : pane.best_size.GetHeight());
}
evt.Skip();
});
m_aui_mgr.track_docked_size(window);
m_aui_mgr.Update();
}
@@ -13908,7 +13848,7 @@ void Plater::priv::on_apple_change_color_mode(wxSysColourChangedEvent& evt) {
assemble_view->get_canvas3d()->on_change_color_mode(m_is_dark);
}
apply_color_mode();
m_aui_mgr.apply_color_mode();
}
void Plater::priv::on_change_color_mode(SimpleEvent& evt) {
@@ -13919,19 +13859,7 @@ void Plater::priv::on_change_color_mode(SimpleEvent& evt) {
assemble_view->get_canvas3d()->on_change_color_mode(m_is_dark);
if (m_send_to_sdcard_dlg) m_send_to_sdcard_dlg->on_change_color_mode();
apply_color_mode();
}
void Plater::priv::apply_color_mode()
{
const bool is_dark = wxGetApp().dark_mode();
wxColour orca_color = wxColour(59, 68, 70);//wxColour(ColorRGBA::ORCA().r_uchar(), ColorRGBA::ORCA().g_uchar(), ColorRGBA::ORCA().b_uchar());
orca_color = is_dark ? StateColor::darkModeColorFor(orca_color) : StateColor::lightModeColorFor(orca_color);
wxColour sash_color = is_dark ? wxColour(38, 46, 48) : wxColour(206, 206, 206);
m_aui_mgr.GetArtProvider()->SetColour(wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR, sash_color);
m_aui_mgr.GetArtProvider()->SetColour(wxAUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR, *wxWHITE);
m_aui_mgr.GetArtProvider()->SetColour(wxAUI_DOCKART_SASH_COLOUR, sash_color);
m_aui_mgr.GetArtProvider()->SetColour(wxAUI_DOCKART_BORDER_COLOUR, is_dark ? *wxBLACK : wxColour(165, 165, 165));
m_aui_mgr.apply_color_mode();
}
static void get_position(wxWindowBase* child, wxWindowBase* until_parent, int& x, int& y) {
@@ -14592,26 +14520,9 @@ bool Plater::priv::init_collapse_toolbar()
if (!collapse_toolbar.init(background_data))
return false;
collapse_toolbar.set_layout_type(GLToolbar::Layout::Vertical);
collapse_toolbar.set_horizontal_orientation(GLToolbar::Layout::HO_Right);
collapse_toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Top);
collapse_toolbar.set_border(4.0f);
collapse_toolbar.set_separator_size(4);
collapse_toolbar.set_gap_size(2);
collapse_toolbar.del_all_item();
GLToolbarItem::Data item;
item.name = "collapse_sidebar";
// set collapse svg name
item.icon_filename = "collapse.svg";
item.sprite_id = 0;
item.left.action_callback = []() {
wxGetApp().plater()->collapse_sidebar(!wxGetApp().plater()->is_sidebar_collapsed());
};
if (!collapse_toolbar.add_item(item))
if (!setup_collapse_toolbar(collapse_toolbar, []() {
wxGetApp().plater()->collapse_sidebar(!wxGetApp().plater()->is_sidebar_collapsed());
}))
return false;
// Now "collapse" sidebar to current state. This is done so the tooltip
@@ -18481,7 +18392,15 @@ bool Plater::is_sidebar_collapsed() const { return p->sidebar_layout.is_collapse
void Plater::collapse_sidebar(bool collapse) { p->collapse_sidebar(collapse); }
Sidebar::DockingState Plater::get_sidebar_docking_state() const { return p->get_sidebar_docking_state(); }
void Plater::reset_window_layout() { p->reset_window_layout(); }
void Plater::reset_window_layout()
{
p->reset_window_layout();
#ifdef SLIC3R_CAD
// The Design tab docks its own sidebar.
if (DesignPanel* design = DesignPanel::if_built())
design->reset_window_layout();
#endif
}
void Plater::add_dock_pane(wxWindow* window, const std::string& name, const wxString& caption, const std::string& dock,
const wxSize& size, std::function<void()> on_close)