mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-05 14:51:06 +00:00
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:
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user