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
@@ -617,8 +617,10 @@ Spacing constants come from `SidebarProps` (`Plater.hpp`): `TitlebarMargin()`, `
### Docking
`Plater::priv` owns `AuiMgr m_aui_mgr` (a `wxAuiManager` subclass whose `CreateFloatingFrame` returns a
themed `FloatFrame : wxAuiFloatingFrame`), managing the plater. Panes: `"sidebar"` (left, no close
Docks are `AuiMgr`s (`AuiMgr.hpp`), a `wxAuiManager` subclass carrying Orca's dock art, theme and
Wayland rule (`references/webview-gl-aui-media.md`). `Plater::priv` owns `m_aui_mgr`, managing the
plater; the Design tab owns its own for its sidebar (`DesignPanel::m_aui`, layout in
`design_window_layout`). Plater panes: `"sidebar"` (left, no close
button, not top/bottom dockable), `"main"` (`CenterPane()`, the `panel_3d`), `"uv_editor"` (right,
hidden until the texture-displacement gizmo shows it), plus dynamic dock panes. The default perspective
is saved right after `AddPane`; the app-config `window_layout` is applied with
@@ -953,11 +953,12 @@ widgets beside the canvas (a sibling, not a child over it), or in a popup.
- `wxAuiNotebook` (not used by Orca): page indices are logical; use `GetPagePosition()` for on-screen
order (`docs/changes.txt:121-126`); the default tab art changed (`35-37`).
**OrcaSlicer.** `Plater::priv` owns `AuiMgr m_aui_mgr`, a `wxAuiManager` whose `CreateFloatingFrame`
returns `FloatFrame : wxAuiFloatingFrame` (applies `UpdateFrameDarkUI`).
- Setup: `SetManagedWindow(q)` (the Plater), `SetDockSizeConstraint(1, 1)`; on Wayland clears
`wxAUI_MGR_ALLOW_FLOATING` (`disable_wayland_floating`); dock-art metrics set here, colours in the
dark-mode update (`Plater::priv::apply_color_mode`).
**OrcaSlicer.** Orca's docks use `AuiMgr` (`AuiMgr.hpp`), a `wxAuiManager` whose `CreateFloatingFrame`
returns a `wxAuiFloatingFrame` that applies `UpdateFrameDarkUI`. `init(window)` calls
`SetManagedWindow(window)` and `SetDockSizeConstraint(1, 1)`, clears `wxAUI_MGR_ALLOW_FLOATING` on
Wayland and sets the dock-art metrics and colours; `apply_color_mode()` re-colours captions, sashes and
borders and is called from the owner's theme-switch handler. `Plater::priv::m_aui_mgr` manages the
Plater (Prepare and Preview); `DesignPanel::m_aui` manages the Design tab's body below its toolbar.
- Panes: `"sidebar"` (left, no close button, not top/bottom dockable, `BestSize` in em units),
`"uv_editor"` (right, hidden; forced hidden again after a layout load), `"main"`
(`CenterPane().PaneBorder(false)`, holding `panel_3d` with View3D, Preview and AssembleView in one
@@ -966,8 +967,8 @@ returns `FloatFrame : wxAuiFloatingFrame` (applies `UpdateFrameDarkUI`).
`window_layout` app-config string goes through `sanitize_window_layout_for_wayland` (strips
floating/floatable bits on Wayland) and `LoadPerspective(layout, false)`, falling back to the default
on failure; then one `Update()`. `Plater::priv::reset` saves `SavePerspective()` back to
`window_layout`. An idle handler copies the docked sidebar width into `BestSize` (wxAUI does not record
a dragged sash there), so the width persists. `Plater::priv::reset_window_layout` is the model for
`window_layout`. `AuiMgr::track_docked_size` copies a docked pane's size into `BestSize` on idle
(wxAUI does not record a dragged sash there), so the width persists. `Plater::priv::reset_window_layout` is the model for
re-establishing panes after a load: it loads the default perspective, then re-shows each plugin pane
the perspective does not list.
- Plugin panes: `Plater::add_dock_pane(window, name, caption, dock, size, on_close)` (window must be a
@@ -977,13 +978,27 @@ returns `FloatFrame : wxAuiFloatingFrame` (applies `UpdateFrameDarkUI`).
`Destroy()`s without running `on_close`; `show_dock_pane` toggles and updates. Pane names come from
`plugin_pane_name` (`DockPanel.cpp`), which replaces `|`, `;`, `=`, `\` — the perspective-string
delimiters.
- Other pages: a page outside the Plater docks through its own `AuiMgr` member, since the Plater's
manages only the Plater. Its managed window is a body panel below the page's toolbar; a sidebar
takes `AuiMgr::sidebar_pane_info()`; the layout has its own app-config key, is reset from
`Plater::reset_window_layout`, and is saved by a `shutdown()` called from `MainFrame::shutdown`,
which also detaches a floating pane (Lifetime below). Where floating is disabled it forces
`Dock().Floatable(false)` after loading, as plugin panes do. `DesignPanel` is the model
(`docs/HLSD/design-tab.md`). A `GLCanvas3D` beside such a sidebar gets that sidebar's collapse
button with `set_collapse_toolbar`; without it the canvas falls back to the Plater's button, which
collapses Prepare's sidebar.
- Lifetime: no explicit `UnInit`. `m_aui_mgr` is a `Plater::priv` member, so it is destroyed in
`~Plater`, before `~wxWindow` destroys the Plater's children (`wxWindowBase::DestroyChildren`,
`src/common/wincmn.cpp:586-609`); a floating frame is such a child (`CreateFloatingFrame(m_frame, …)`,
`src/aui/framemanager.cpp:3151`), so a pane still floating at that point outlives the manager [source].
Plugin panes are removed earlier (`MainFrame::shutdown` → `Plater::remove_dock_panes`). The sidebar
`GetPane()` reference captured by the idle lambda is safe across `AddPane`; never `DetachPane` a pane
whose reference is captured.
Plugin panes are removed earlier (`MainFrame::shutdown` → `Plater::remove_dock_panes`). A handler
that can outlive its pane looks the pane up when it runs, as `track_docked_size` does: an idle
handler bound on the pane's window outlives the `DetachPane` in `DesignPanel::shutdown`. Never detach
a pane whose `GetPane()` reference is captured (Pane references above). `DesignPanel::shutdown` is
the model for a member manager: it detaches a
floating sidebar, which `Destroy()`s the frame into the pending-delete list, and the main frame's
deletion deletes pending top-level children before its own children (`~wxTopLevelWindowBase`,
`src/common/toplvcmn.cpp:67-93`), while the panel and its manager are still alive [source].
**Pitfalls.**
- **Rule:** Call `Update()` once after a batch of `AddPane`/`wxAuiPaneInfo` changes.
@@ -198,7 +198,7 @@ change, its line, and what it means for Orca.
| `wxAuiGenericTabArt` subclasses (also via `wxAuiMSWTabArt`) override `DrawPageTab()`/`GetPageTabSize()` instead of `DrawTab()`/`GetTabSize()`; direct `wxAuiTabArt` subclasses still work | :115-120 | none: no Orca tab art |
| `wxAuiNotebook` page index is logical (reorder-independent); `GetPagePosition()` gives the screen position | :122-126 | none; index math under `wxAUI_NB_TAB_MOVE` is what breaks |
| `wxListbook`/`wxChoicebook` interpret mnemonics in page titles "just as the other wx*book classes already did" | :128-130 | Orca uses neither (`BedShapeDialog` uses `wxSimplebook` + a combo); every book interprets `&` (`interface/wx/bookctrl.h:141-147`) → rule 11 |
| `wxAUI_MGR_HINT_FADE` is not in the default `wxAuiManager` style | :132-133 | Plater's `AuiMgr` keeps the default flags (minus `wxAUI_MGR_ALLOW_FLOATING` on Wayland, `Plater::priv::priv`), so the docking hint no longer fades; add the flag if wanted |
| `wxAUI_MGR_HINT_FADE` is not in the default `wxAuiManager` style | :132-133 | Orca's `AuiMgr` keeps the default flags (minus `wxAUI_MGR_ALLOW_FLOATING` on Wayland, `AuiMgr::init`), so the docking hint no longer fades; add the flag if wanted |
| `wxPrintDialogData::SetAllPages(false)`/`SetSelection(false)` changed meaning | :135-137 | none |
| `wxGetTranslation()` returns `wxString` by value | :139-142 | pitfall below |
| `wxWindow::Raise()` no longer shows a hidden window on any port | :144-146 | pitfall below; ba867cc534 |
+8
View File
@@ -204,6 +204,14 @@ The tab is a page of Orca's main window and answers to the same settings as Prep
- **Undo.** The tab keeps its own history (the recipe is not part of Prepare's snapshots), but
it has no Undo/Redo of its own: the top bar, `Ctrl+Z` and Edit drive it while the tab is
shown, greyed to what an undo would actually do.
- **Docking.** The sidebar docks like Prepare's — either side, floating, resized, or collapsed
with the canvas's collapse button or `Shift+Tab` — through its own AUI manager under the
toolbar, because Prepare's manages the Plater and the Plater is not on this page. The button is
the canvas's own toolbar rather than Prepare's, which collapses Prepare's sidebar. The layout,
collapse included, is kept apart from Prepare's (`design_window_layout`) and starts where
Prepare's sidebar is, at its width, so the canvas edge holds still across the tab switch until
the user moves one of them. A floating sidebar is a top-level window, so it is hidden with the
tab rather than left over the other pages, and View > Reset Window Layout resets both tabs.
## The offer is generated, not hand-written
+2
View File
@@ -147,6 +147,8 @@ set(SLIC3R_GUI_SOURCES
GUI/WebPanel.hpp
GUI/Widgets/WebHosting.cpp
GUI/Widgets/WebHosting.hpp
GUI/AuiMgr.cpp
GUI/AuiMgr.hpp
GUI/AuiPaneLayout.cpp
GUI/AuiPaneLayout.hpp
GUI/DragCanvas.cpp
+80
View File
@@ -0,0 +1,80 @@
#include "AuiMgr.hpp"
#include "GUI_App.hpp"
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
#include <wx/aui/dockart.h>
#include <wx/aui/floatpane.h>
namespace Slic3r { namespace GUI {
namespace {
// 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);
}
};
} // namespace
void AuiMgr::init(wxWindow* window)
{
SetManagedWindow(window);
SetDockSizeConstraint(1, 1);
#ifdef __WXGTK__
// Floating and its docking hints need global pointer positions and window moves, which Wayland does not provide.
if (is_running_on_wayland())
SetFlags(GetFlags() & ~wxAUI_MGR_ALLOW_FLOATING);
#endif
GetArtProvider()->SetMetric(wxAUI_DOCKART_CAPTION_SIZE, 18);
GetArtProvider()->SetMetric(wxAUI_DOCKART_GRADIENT_TYPE, wxAUI_GRADIENT_NONE);
apply_color_mode();
}
void AuiMgr::apply_color_mode()
{
const bool is_dark = wxGetApp().dark_mode();
const wxColour sash_color = is_dark ? wxColour(38, 46, 48) : wxColour(206, 206, 206);
GetArtProvider()->SetColour(wxAUI_DOCKART_INACTIVE_CAPTION_COLOUR, sash_color);
GetArtProvider()->SetColour(wxAUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR, *wxWHITE);
GetArtProvider()->SetColour(wxAUI_DOCKART_SASH_COLOUR, sash_color);
GetArtProvider()->SetColour(wxAUI_DOCKART_BORDER_COLOUR, is_dark ? *wxBLACK : wxColour(165, 165, 165));
}
void AuiMgr::track_docked_size(wxWindow* window)
{
window->Bind(wxEVT_IDLE, [this, window](wxIdleEvent& evt) {
wxAuiPaneInfo& pane = 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();
});
}
wxAuiPaneInfo AuiMgr::sidebar_pane_info()
{
return wxAuiPaneInfo()
.Name("sidebar")
.Left()
.CloseButton(false)
.TopDockable(false)
.BottomDockable(false)
.BestSize(wxSize(39 * wxGetApp().em_unit(), 90 * wxGetApp().em_unit()));
}
wxAuiFloatingFrame* AuiMgr::CreateFloatingFrame(wxWindow* parent, const wxAuiPaneInfo& pane)
{
return new FloatFrame(parent, this, pane);
}
}} // namespace Slic3r::GUI
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include <wx/aui/framemanager.h>
namespace Slic3r { namespace GUI {
// The wxAuiManager behind Orca's docked sidebars: Orca's caption and sash art in both themes,
// floating frames that follow the app theme, and no floating on Wayland.
class AuiMgr : public wxAuiManager
{
public:
// Manages `window`, whose own wxEVT_SIZE handlers must Skip().
void init(wxWindow* window);
// Captions, sashes and borders in the current theme.
void apply_color_mode();
// Keeps the docked size of `window`'s pane in its best_size, which re-docking and a saved layout
// use: wxAUI does not record a dragged sash there.
void track_docked_size(wxWindow* window);
// A tab's sidebar pane: docked left by default, movable to the right or floating, no close button.
static wxAuiPaneInfo sidebar_pane_info();
wxAuiFloatingFrame* CreateFloatingFrame(wxWindow* parent, const wxAuiPaneInfo& pane) override;
};
}} // namespace Slic3r::GUI
+15
View File
@@ -570,6 +570,21 @@ void DesignCanvas::set_show_bed(bool b)
request_repaint();
}
void DesignCanvas::set_sidebar_collapse(std::function<CollapseSide()> side, std::function<void()> toggle)
{
if (!m_canvas || !m_canvas_widget || !setup_collapse_toolbar(m_collapse_toolbar, toggle))
return;
m_canvas->set_collapse_toolbar(&m_collapse_toolbar, std::move(side));
m_canvas->enable_collapse_toolbar(true);
// Shift+Tab: the canvas posts this for its sidebar, as Prepare's canvases do.
m_canvas_widget->Bind(EVT_GLCANVAS_COLLAPSE_SIDEBAR, [toggle](SimpleEvent&) { toggle(); });
}
void DesignCanvas::set_sidebar_collapse_tooltip(const std::string& tooltip)
{
m_collapse_toolbar.set_tooltip(m_collapse_toolbar.get_item_id("collapse_sidebar"), tooltip);
}
bool DesignCanvas::is_sketching() const { return m_sketch_tool.is_active(); }
void DesignCanvas::cancel_sketch()
+6
View File
@@ -17,6 +17,7 @@
#include "slic3r/GUI/3DBed.hpp"
#include "slic3r/GUI/Camera.hpp"
#include "slic3r/GUI/GLToolbar.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/CAD/SketchEngine.hpp"
#include "slic3r/GUI/CAD/DesignSketchTool.hpp"
@@ -87,6 +88,10 @@ public:
void unbind_canvas_event_handlers(); // app close / language switch, from the plater's teardown
void reset_canvas_volumes();
void set_show_bed(bool b); // view option: draw the printer bed + plate grid, or not
// The sidebar's collapse button, as Prepare's: drawn on the edge `side` reports, it runs
// `toggle` on a click and on Shift+Tab. Set before the first paint.
void set_sidebar_collapse(std::function<CollapseSide()> side, std::function<void()> toggle);
void set_sidebar_collapse_tooltip(const std::string& tooltip);
// N: look straight down the sketch plane's normal, keeping the current zoom. A sketch drawn
// at an angle is a sketch drawn wrong, and no amount of orbiting by hand lands exactly square.
bool view_normal_to_sketch();
@@ -368,6 +373,7 @@ private:
wxGLCanvas* m_canvas_widget{nullptr};
GLCanvas3D* m_canvas{nullptr};
int m_sw_gl{-1}; // -1 unknown, 0 hardware GL, 1 software GL
GLToolbar m_collapse_toolbar{GLToolbar::Normal, "Collapse"};
std::function<void(const wxPoint&)> m_on_context_menu;
bool m_ctx_bound{false}; // bind the RIGHT_UP handler once, however often the cb is set
+109 -21
View File
@@ -104,6 +104,7 @@
#include "libslic3r/BuildVolume.hpp"
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include "slic3r/GUI/Shortcuts.hpp"
// English-only pin for the Design tab (see design-ux-contract): one lever
// de-translates this whole TU so our strings never half-translate against the host's
@@ -357,10 +358,12 @@ DesignPanel::DesignPanel(wxWindow* parent)
// Left column: a slim feature-tree + docked tool-dialog column. All form
// controls are parented to m_form so it can scroll independently of the
// live GL viewport. The tool buttons live in the top toolbar (built below).
m_form = new wxScrolledWindow(this, wxID_ANY);
auto* body_panel = new wxPanel(this, wxID_ANY); // below the toolbar, managed by m_aui
m_form = new wxScrolledWindow(body_panel, wxID_ANY);
// Explicit token background in both themes, so a theme switch can move it (an inherited
// colour stays whatever the theme was when the panel was built).
SetBackgroundColour(dp_panel_bg());
body_panel->SetBackgroundColour(dp_panel_bg());
m_form->SetBackgroundColour(dp_panel_bg());
auto* root = new wxBoxSizer(wxVERTICAL);
@@ -3521,7 +3524,9 @@ DesignPanel::DesignPanel(wxWindow* parent)
build_phase("sidebar and tool cards");
// Right column: a small view toolbar over the live 3D viewport that mirrors
// the CadDocument body.
m_viewport = new DesignCanvas(this);
auto* view_col = new wxPanel(body_panel, wxID_ANY); // the centre pane: sketch banner over the viewport
view_col->SetBackgroundColour(dp_panel_bg());
m_viewport = new DesignCanvas(view_col);
build_phase("3D canvas");
m_viewport->set_on_sketch_commit([this](const SketchProfile& prof, const SketchPlane& plane) {
@@ -4339,7 +4344,7 @@ DesignPanel::DesignPanel(wxWindow* parent)
// The sketch banner sits ABOVE the viewport rather than floating inside it: a child window
// over a wxGLCanvas is a platform argument (it is a native window on GTK and does not
// reliably stack over GL), and the banner's job is to be unmissable, not to be clever.
m_sketch_banner = new wxPanel(this, wxID_ANY);
m_sketch_banner = new wxPanel(view_col, wxID_ANY);
m_sketch_banner->SetBackgroundColour(wxColour(0, 122, 116)); // Orca teal: not a plate colour
m_sketch_banner_txt = new wxStaticText(m_sketch_banner, wxID_ANY, wxString());
m_sketch_banner_txt->SetForegroundColour(*wxWHITE);
@@ -4356,16 +4361,33 @@ DesignPanel::DesignPanel(wxWindow* parent)
// The bottom 3D-navigator orb handles all view orientation, so no separate view buttons.
// Fit view is a double-click on the viewport (the tool intercepts it -> zoom_to_volumes).
vcol->Add(m_viewport, 1, wxEXPAND);
view_col->SetSizer(vcol);
// Onshape layout: top toolbar over [ slim left column | center viewport ].
auto* body = new wxBoxSizer(wxHORIZONTAL);
body->Add(m_form, 0, wxEXPAND);
body->Add(vcol, 1, wxEXPAND);
// Onshape layout: top toolbar over [ slim left column | center viewport ], with the column
// docked like Prepare's sidebar: left by default, movable to the right or floating, resizable
// and collapsible.
m_aui.init(body_panel);
m_aui.AddPane(m_form, AuiMgr::sidebar_pane_info().MinSize(m_form->GetMinSize()));
m_aui.AddPane(view_col, wxAuiPaneInfo().Name("main").CenterPane().PaneBorder(false));
m_default_layout = m_aui.SavePerspective();
load_window_layout();
m_aui.track_docked_size(m_form);
// The collapse button sits on the canvas edge the sidebar is docked on, and is gone while it
// floats. A click arrives inside the canvas's mouse handler, so the relayout waits for it.
m_viewport->set_sidebar_collapse(
[this] {
const wxAuiPaneInfo& sidebar = m_aui.GetPane(m_form);
if (!sidebar.IsOk() || sidebar.IsFloating())
return CollapseSide::None;
return sidebar.dock_direction == wxAUI_DOCK_RIGHT ? CollapseSide::Right : CollapseSide::Left;
},
[this] { CallAfter([this] { collapse_sidebar(!m_sidebar_collapsed); }); });
collapse_sidebar(m_sidebar_collapsed); // the button's tooltip
auto* outer = new wxBoxSizer(wxVERTICAL);
outer->Add(m_toolbar, 0, wxEXPAND);
outer->Add(new wxStaticLine(this, wxID_ANY), 0, wxEXPAND);
outer->Add(body, 1, wxEXPAND);
outer->Add(body_panel, 1, wxEXPAND);
SetSizer(outer);
// The atlas says a verb is wired; the registrations above say what it runs. Nothing checks
@@ -7215,6 +7237,7 @@ void DesignPanel::on_tab_hidden()
{
if (m_viewport)
m_viewport->leave_viewport(); // hand the shared camera back to the editor tabs
update_sidebar_pane();
}
void DesignPanel::on_tab_shown()
@@ -7232,7 +7255,7 @@ void DesignPanel::on_tab_shown()
update_reference_planes(); // entering the Design tab: show the XY/XZ/YZ planes if no object yet
if (show_clock.Time() > 100) // a slow first show is what users report; the usual one is not news
BOOST_LOG_TRIVIAL(info) << "Design tab shown: bed, project recipe and planes in " << show_clock.Time() << " ms";
sync_sidebar_width(); // keep the panel as wide as Prepare's so the canvas edge doesn't jump
update_sidebar_pane();
if (m_viewport) m_viewport->force_repaint(); // the page was just re-shown: paint it for real
}
@@ -7267,6 +7290,7 @@ void DesignPanel::msw_rescale()
void DesignPanel::on_sys_color_changed()
{
m_aui.apply_color_mode();
// Every chrome colour here was set from a DpToken in the theme that was current at the time.
// Move each one, background and text, onto the same token in the new theme; any other colour
// (the teal accents, the status colours) is the same in both and stays.
@@ -7325,19 +7349,83 @@ void DesignPanel::reset_canvas_volumes()
if (m_viewport) m_viewport->reset_canvas_volumes();
}
// Match Prepare's sidebar width instead of hardcoding one. Design used a fixed 264 px against
// Prepare's ~467, so the canvas edge jumped sideways on every tab switch; reading the live width
// also means the two stay aligned if Orca ever changes its sidebar.
void DesignPanel::sync_sidebar_width()
void DesignPanel::shutdown()
{
if (m_form == nullptr) return;
Plater* pl = wxGetApp().plater();
if (pl == nullptr) return;
const int w = pl->sidebar().GetSize().GetWidth();
if (w < 200) return; // sidebar not laid out yet — keep what we have
if (m_form->GetMinSize().GetWidth() == w) return;
m_form->SetMinSize(wxSize(w, -1));
Layout();
wxAuiPaneInfo& sidebar = m_aui.GetPane(m_form);
if (!sidebar.IsOk()) // shut down already, floating: a layout saved now would lack the sidebar
return;
// Saved hidden only when collapsed, whichever tab is shown.
sidebar.Show(!m_sidebar_collapsed);
wxGetApp().app_config->set("design_window_layout", m_aui.SavePerspective().utf8_string());
// A floating frame is a child of the managed panel and dereferences its manager when it is
// deleted, so it must not outlive m_aui, a member. Detaching queues the frame for deletion, which
// runs before the main frame destroys its children (~wxTopLevelWindowBase deletes pending child
// frames).
if (sidebar.IsFloating())
m_aui.DetachPane(m_form);
}
void DesignPanel::reset_window_layout()
{
load_default_layout();
collapse_sidebar(false);
update_sidebar_pane(true);
}
// The sidebar where the user left it, collapsed if it was.
void DesignPanel::load_window_layout()
{
const wxString saved = wxString::FromUTF8(wxGetApp().app_config->get("design_window_layout"));
if (saved.empty() || !m_aui.LoadPerspective(saved, false)) {
if (!saved.empty())
BOOST_LOG_TRIVIAL(warning) << "Design tab: failed to restore the saved window layout";
load_default_layout();
}
wxAuiPaneInfo& sidebar = m_aui.GetPane(m_form);
m_sidebar_collapsed = !sidebar.IsShown();
if ((m_aui.GetFlags() & wxAUI_MGR_ALLOW_FLOATING) == 0) // saved where windows can float
sidebar.Dock().Floatable(false);
update_sidebar_pane(true);
}
// Docked where Prepare's sidebar is, and as wide, so the canvas edge does not move between the tabs.
void DesignPanel::load_default_layout()
{
m_aui.LoadPerspective(m_default_layout, false);
Plater* plater = wxGetApp().plater();
const Sidebar::DockingState prepare = plater != nullptr ? plater->get_sidebar_docking_state() : Sidebar::None;
if (prepare == Sidebar::None)
return;
wxAuiPaneInfo& sidebar = m_aui.GetPane(m_form);
if (prepare == Sidebar::Right)
sidebar.Right();
const int width = plater->sidebar().GetSize().GetWidth();
if (width >= sidebar.min_size.GetWidth()) // Prepare's sidebar has been laid out
sidebar.BestSize(width, sidebar.best_size.GetHeight());
}
// The collapse button on the canvas and Shift+Tab, as in Prepare.
void DesignPanel::collapse_sidebar(bool collapse)
{
m_sidebar_collapsed = collapse;
if (m_viewport)
m_viewport->set_sidebar_collapse_tooltip(wxGetApp().shortcuts().with_key(
(collapse ? _L("Expand sidebar") : _L("Collapse sidebar")).utf8_string(), Shortcut::CollapseSidebar));
update_sidebar_pane();
}
// The sidebar shows unless collapsed; a floating one also only while the tab is shown, since it is
// a top-level window and does not hide with the page.
void DesignPanel::update_sidebar_pane(bool force_update)
{
wxAuiPaneInfo& sidebar = m_aui.GetPane(m_form);
const bool show = !m_sidebar_collapsed && (sidebar.IsDocked() || IsShownOnScreen());
if (sidebar.IsOk() && sidebar.IsShown() != show) {
sidebar.Show(show);
force_update = true;
}
if (force_update)
m_aui.Update();
}
void DesignPanel::load_recipe(const std::string& blob)
+14 -1
View File
@@ -21,6 +21,7 @@
#include "libslic3r/CAD/CadDocument.hpp"
#include "slic3r/GUI/CAD/DesignInteraction.hpp" // CadLevel: what one Esc press means
#include "slic3r/GUI/AuiMgr.hpp"
#include "slic3r/GUI/Lazy.hpp"
class ComboBox; // Orca dropdown (Widgets/ComboBox.hpp) — replaces wxChoice everywhere here
@@ -70,6 +71,8 @@ public:
void on_sys_color_changed();
void unbind_canvas_event_handlers(); // app close / language switch, from the plater's teardown
void reset_canvas_volumes();
void shutdown(); // app close / language switch, from MainFrame: save the window layout
void reset_window_layout(); // View > Reset Window Layout, with Prepare's
void clear_document(); // New Project / Open Project: drop the document with the project
// Rebuild off the UI thread (progress dialog only if it turns out to be slow), so a feature
// op on a heavy imported solid does not freeze the window. Returns m_doc.recompute()'s result.
@@ -497,6 +500,17 @@ private:
wxScrolledWindow* m_form{nullptr};
DesignCanvas* m_viewport{nullptr};
// Below the toolbar, m_form docks beside the viewport column like Prepare's sidebar: it can
// move to the other side, float, be resized and be collapsed, and the layout is kept between
// sessions.
AuiMgr m_aui;
wxString m_default_layout;
bool m_sidebar_collapsed{false};
void load_window_layout();
void load_default_layout();
void collapse_sidebar(bool collapse);
void update_sidebar_pane(bool force_update = false);
// Top contextual toolbar (parented to the panel, above the form/viewport row).
UiMode m_ui_mode{UiMode::Feature};
// Sketch environment banner: a strip across the top of the viewport saying, in words, that
@@ -938,7 +952,6 @@ private:
int tree_selection() const; // selected feature row, or wxNOT_FOUND
int tree_body_selection() const; // selected Parts-list body index, or -1
void refresh_parts(); // rebuild the Bodies list under the feature tree
void sync_sidebar_width(); // keep the panel as wide as Prepare's sidebar
void set_tree_selection(int row);
static int tree_icon_for(CadFeatureType t);
+62 -28
View File
@@ -1440,7 +1440,7 @@ void GLCanvas3D::on_change_color_mode(bool is_dark, bool reinit) {
// set dirty to re-generate icon texture
m_separator_toolbar.set_icon_dirty();
m_main_toolbar.set_icon_dirty();
wxGetApp().plater()->get_collapse_toolbar().set_icon_dirty();
collapse_toolbar().set_icon_dirty();
m_assemble_view_toolbar.set_icon_dirty();
m_gizmos.set_icon_dirty();
}
@@ -1972,6 +1972,12 @@ void GLCanvas3D::enable_collapse_toolbar(bool enable)
m_collapse_toolbar_enabled = enable;
}
void GLCanvas3D::set_collapse_toolbar(GLToolbar* toolbar, std::function<CollapseSide()> side)
{
m_collapse_toolbar = toolbar;
m_collapse_side = std::move(side);
}
void GLCanvas3D::enable_plate_chrome(bool enable)
{
m_plate_chrome_enabled = enable;
@@ -2052,24 +2058,33 @@ void GLCanvas3D::update_volumes_colors_by_extruder()
bool GLCanvas3D::is_collapse_toolbar_on_left() const
{
auto state = wxGetApp().plater()->get_sidebar_docking_state();
return state == Sidebar::Left;
return collapse_side() == CollapseSide::Left;
}
float GLCanvas3D::get_collapse_toolbar_width() const
{
GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
const auto state = wxGetApp().plater()->get_sidebar_docking_state();
return state != Sidebar::None ? collapse_toolbar.get_width() : 0;
return collapse_side() != CollapseSide::None ? collapse_toolbar().get_width() : 0;
}
float GLCanvas3D::get_collapse_toolbar_height() const
{
GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
const auto state = wxGetApp().plater()->get_sidebar_docking_state();
return collapse_side() != CollapseSide::None ? collapse_toolbar().get_height() : 0;
}
return state != Sidebar::None ? collapse_toolbar.get_height() : 0;
GLToolbar& GLCanvas3D::collapse_toolbar() const
{
return m_collapse_toolbar != nullptr ? *m_collapse_toolbar : wxGetApp().plater()->get_collapse_toolbar();
}
CollapseSide GLCanvas3D::collapse_side() const
{
if (m_collapse_side)
return m_collapse_side();
switch (wxGetApp().plater()->get_sidebar_docking_state()) {
case Sidebar::Left: return CollapseSide::Left;
case Sidebar::Right: return CollapseSide::Right;
default: return CollapseSide::None;
}
}
bool GLCanvas3D::make_current_for_postinit() {
@@ -2274,7 +2289,7 @@ void GLCanvas3D::_render_frame(bool scene_dirty, bool only_init)
tooltip = m_assemble_view_toolbar.get_tooltip();
if (tooltip.empty())
tooltip = wxGetApp().plater()->get_collapse_toolbar().get_tooltip();
tooltip = collapse_toolbar().get_tooltip();
// BBS
#if 0
@@ -3475,7 +3490,7 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
m_overlay_dirty |= m_assemble_view_toolbar.update_items_state();
// BBS
//m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
m_overlay_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state();
m_overlay_dirty |= collapse_toolbar().update_items_state();
// apply() DRAINS the 3D-mouse queue, so only the canvas actually on screen may call it: a
// hidden canvas renders nothing, so the motion it swallowed moves the shared camera without
// ever being drawn and the next visible frame jumps several states at once.
@@ -4267,6 +4282,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// (drag/orbit/wheel) so the camera keeps working over the display-only plate.
#ifdef SLIC3R_CAD
if (m_design_sketch_tool != nullptr && m_design_sketch_tool->has_display()) {
// Except over the sidebar collapse button, which is drawn over the sketch.
if (collapse_toolbar().on_mouse(evt, *this)) {
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
mouse_up_cleanup();
m_mouse.set_start_position_3D_as_invalid();
return;
}
if (evt.LeftDown() && m_canvas != nullptr)
m_canvas->SetFocus(); // grab keyboard focus so Delete/keys reach this canvas
if (m_design_sketch_tool->on_mouse(evt, *this)) {
@@ -4315,7 +4337,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
return;
}
if (!mouse_in_layer_editing && wxGetApp().plater()->get_collapse_toolbar().on_mouse(evt, *this)) {
if (!mouse_in_layer_editing && collapse_toolbar().on_mouse(evt, *this)) {
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
mouse_up_cleanup();
m_mouse.set_start_position_3D_as_invalid();
@@ -6892,7 +6914,7 @@ void GLCanvas3D::_switch_toolbars_icon_filename()
m_main_toolbar.init(background_data);
m_assemble_view_toolbar.init(background_data);
m_separator_toolbar.init(background_data);
wxGetApp().plater()->get_collapse_toolbar().init(background_data);
collapse_toolbar().init(background_data);
// main toolbar
{
@@ -7320,7 +7342,17 @@ bool GLCanvas3D::_init_view_toolbar()
bool GLCanvas3D::_init_collapse_toolbar()
{
return wxGetApp().plater()->init_collapse_toolbar();
if (m_collapse_toolbar == nullptr)
return wxGetApp().plater()->init_collapse_toolbar();
// Its owner laid it out; the background needs the GL context.
BackgroundTexture::Metadata background_data;
background_data.filename = m_is_dark ? "toolbar_background_dark.png" : "toolbar_background.png";
background_data.left = 16;
background_data.top = 16;
background_data.right = 16;
background_data.bottom = 16;
return m_collapse_toolbar->init(background_data);
}
bool GLCanvas3D::_set_current()
@@ -9085,11 +9117,12 @@ void GLCanvas3D::_render_sequential_clearance()
void GLCanvas3D::_check_and_update_toolbar_icon_scale()
{
// Update collapse toolbar
GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
collapse_toolbar.set_enabled(wxGetApp().plater()->get_sidebar_docking_state() != Sidebar::None);
GLToolbar& collapse_toolbar = this->collapse_toolbar();
collapse_toolbar.set_enabled(collapse_side() != CollapseSide::None);
// Don't update a toolbar scale, when we are on a Preview
if (wxGetApp().plater()->is_preview_shown()) {
// Don't update a toolbar scale, when we are on a Preview. Asked of this canvas, not of the
// plater: the Design tab's canvas is on screen while the plater's current view may be Preview.
if (m_canvas_type == CanvasPreview) {
IMSlider *m_layers_slider = get_gcode_viewer().get_layers_slider();
IMSlider *m_moves_slider = get_gcode_viewer().get_moves_slider();
float sc = get_scale();
@@ -9161,7 +9194,9 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale()
// set minimum scale as a auto scale for the toolbars
float new_scale = std::min(new_h_scale, new_v_scale);
new_scale /= get_scale();
if (fabs(new_scale - scale) > 0.05) // scale is changed by 5% and more
// Only a canvas with toolbars to fit sets the shared size: a collapse button alone (the Design
// tab's canvas) always fits at the largest.
if (items_cnt > collapse_toolbar.get_visible_items_cnt() && fabs(new_scale - scale) > 0.05) // scale is changed by 5% and more
wxGetApp().set_auto_toolbar_icon_scale(new_scale);
}
@@ -9243,7 +9278,7 @@ size_t GLCanvas3D::_overlay_signature(const ImDrawData* draw_data) const
size_t hash = ImGuiWrapper::draw_data_signature(draw_data);
for (size_t state_hash : { m_main_toolbar.get_state_hash(), m_separator_toolbar.get_state_hash(),
m_assemble_view_toolbar.get_state_hash(),
wxGetApp().plater()->get_collapse_toolbar().get_state_hash(),
collapse_toolbar().get_state_hash(),
m_gizmos.get_overlay_state_hash() })
boost::hash_combine(hash, state_hash);
return hash;
@@ -10298,18 +10333,17 @@ void GLCanvas3D::_render_collapse_toolbar() const
if (!m_collapse_toolbar_enabled)
return;
auto& plater = *wxGetApp().plater();
const auto sidebar_docking_dir = plater.get_sidebar_docking_state();
if (sidebar_docking_dir == Sidebar::None) {
const CollapseSide side = collapse_side();
if (side == CollapseSide::None) {
return;
}
GLToolbar& collapse_toolbar = plater.get_collapse_toolbar();
GLToolbar& collapse_toolbar = this->collapse_toolbar();
const Size cnv_size = get_canvas_size();
const float top = 0.5f * (float)cnv_size.get_height();
const float left = sidebar_docking_dir == Sidebar::Right ? 0.5f * (float) cnv_size.get_width() - (float) collapse_toolbar.get_width() :
-0.5f * (float) cnv_size.get_width();
const float left = side == CollapseSide::Right ? 0.5f * (float) cnv_size.get_width() - (float) collapse_toolbar.get_width() :
-0.5f * (float) cnv_size.get_width();
collapse_toolbar.set_position(top, left);
collapse_toolbar.render(*this);
@@ -11705,7 +11739,7 @@ bool GLCanvas3D::_deactivate_layersediting_menu()
bool GLCanvas3D::_deactivate_collapse_toolbar_items()
{
GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
GLToolbar& collapse_toolbar = this->collapse_toolbar();
if (collapse_toolbar.is_item_pressed("print")) {
collapse_toolbar.force_left_action(collapse_toolbar.get_item_id("print"), *this);
return true;
+10
View File
@@ -20,6 +20,7 @@
#include "libslic3r/Line.hpp"
#include "slic3r/GUI/Gizmos/GLGizmoBase.hpp"
#include <stddef.h>
#include <functional>
#include <memory>
#include <chrono>
#include <cstdint>
@@ -594,6 +595,9 @@ private:
mutable float m_sc{1};
mutable float m_paint_toolbar_width;
bool m_collapse_toolbar_enabled{true};
// The collapse button of a sidebar other than Prepare's, from set_collapse_toolbar().
GLToolbar* m_collapse_toolbar{nullptr};
std::function<CollapseSide()> m_collapse_side;
bool m_plate_chrome_enabled{true};
// Design tab: render the world-axis triad at the bed centre (= modeling origin) instead of
// the bed corner. Default false preserves the main editor's corner triad.
@@ -1008,6 +1012,10 @@ public:
void enable_return_toolbar(bool enable);
void enable_separator_toolbar(bool enable);
void enable_collapse_toolbar(bool enable);
// A canvas beside a sidebar other than Prepare's shows that sidebar's collapse button: `toolbar`,
// set up with setup_collapse_toolbar(), on the edge `side` reports. Call before the canvas is
// initialized, which loads the toolbar's background.
void set_collapse_toolbar(GLToolbar* toolbar, std::function<CollapseSide()> side);
void enable_plate_chrome(bool enable);
void set_axes_at_bed_center(bool b) { m_axes_at_bed_center = b; }
void set_show_bed(bool b) { m_show_bed = b; }
@@ -1374,6 +1382,8 @@ private:
// BBS
//bool _init_view_toolbar();
bool _init_collapse_toolbar();
GLToolbar& collapse_toolbar() const;
CollapseSide collapse_side() const;
bool _set_current();
bool _set_shown_canvas_current();
+22
View File
@@ -1672,5 +1672,27 @@ float GLToolbar::get_scaled_icon_size()
return m_layout.icons_size * m_layout.scale;
}
bool setup_collapse_toolbar(GLToolbar& toolbar, std::function<void()> toggle)
{
toolbar.set_layout_type(GLToolbar::Layout::Vertical);
toolbar.set_horizontal_orientation(GLToolbar::Layout::HO_Right);
toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Top);
toolbar.set_border(4.0f);
toolbar.set_separator_size(4);
toolbar.set_gap_size(2);
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 = std::move(toggle);
return toolbar.add_item(item);
}
} // namespace GUI
} // namespace Slic3r
+8
View File
@@ -457,6 +457,14 @@ private:
bool update_items_enabled_state();
};
// The canvas edge a sidebar collapse button sits on: the side its sidebar is docked on, or none
// while that sidebar floats.
enum class CollapseSide { None, Left, Right };
// Lays `toolbar` out as a sidebar collapse button that runs `toggle`: Prepare's, and those of
// other sidebars (GLCanvas3D::set_collapse_toolbar()).
bool setup_collapse_toolbar(GLToolbar& toolbar, std::function<void()> toggle);
} // namespace GUI
} // namespace Slic3r
+8
View File
@@ -1249,6 +1249,10 @@ void MainFrame::shutdown()
m_plugin_pages.shutdown();
if (m_plater != nullptr)
m_plater->remove_dock_panes();
#ifdef SLIC3R_CAD
if (DesignPanel* design = DesignPanel::if_built())
design->shutdown();
#endif
#ifdef __WXGTK__
// Edge panels are child windows — wxWidgets destroys them automatically.
m_edge_bottom = nullptr;
@@ -3377,6 +3381,10 @@ void MainFrame::init_menubar_as_editor()
viewMenu, wxID_ANY, _L("Reset Window Layout"), _L("Reset to default window layout"),
[this](wxCommandEvent&) { m_plater->reset_window_layout(); }, "", this,
[this]() {
#ifdef SLIC3R_CAD
if (shown_design_panel() != nullptr)
return true;
#endif
return is_prepare_or_preview_tab() && m_plater->is_sidebar_enabled();
},
this);
+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)