From 754c3cb7c63e42eb224e39e589889808df14869d Mon Sep 17 00:00:00 2001 From: David Capello Date: Wed, 7 May 2025 22:55:59 -0300 Subject: [PATCH] Fix several layout saving/loading issues * Better support to load legacy timeline information: we have to estimate workspace bounds) * Auto-save layouts after resizing a splitter/dock * Fix resetting expansive widgets inside docks after switching tabs * Load mirrored layout correctly if it was the last selected layout --- src/app/ui/dock.cpp | 12 ++++---- src/app/ui/main_window.cpp | 59 +++++++++++++++++++++++++++----------- src/app/ui/main_window.h | 1 + 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/app/ui/dock.cpp b/src/app/ui/dock.cpp index 543ec2668..335672c8b 100644 --- a/src/app/ui/dock.cpp +++ b/src/app/ui/dock.cpp @@ -314,14 +314,11 @@ void Dock::onSizeHint(ui::SizeHintEvent& ev) for (int i = 0; i < kSides; ++i) { auto* widget = m_sides[i]; - if (!widget || !widget->isVisible() || widget->isDecorative()) { - m_sizes[i] = gfx::Size(0, 0); + if (!widget || !widget->isVisible() || widget->isDecorative()) continue; - } const int spacing = (m_aligns[i] & EXPANSIVE ? childSpacing() : 0); - const auto hint = m_sides[i]->sizeHint(fitIn); - m_sizes[i] = hint; + const auto hint = (m_aligns[i] & EXPANSIVE ? m_sizes[i] : widget->sizeHint(fitIn)); switch (i) { case kTopIndex: @@ -633,6 +630,11 @@ bool Dock::onProcessMessage(ui::Message* msg) m_dropzonePlaceholder = nullptr; m_dragging = false; + + // Call UserResizedDock signal after resizing a Dock splitter + if (m_hit.sideIndex >= 0) + onUserResizedDock(); + m_hit = Hit(); } break; diff --git a/src/app/ui/main_window.cpp b/src/app/ui/main_window.cpp index 0390ce22d..12449595f 100644 --- a/src/app/ui/main_window.cpp +++ b/src/app/ui/main_window.cpp @@ -183,10 +183,6 @@ void MainWindow::initialize() m_saveDockLayoutConn = m_customizableDock->UserResizedDock.connect(&MainWindow::saveActiveLayout, this); - setDefaultLayout(); - if (LayoutPtr layout = m_layoutSelector->activeLayout()) - loadUserLayout(layout.get()); - // Reconfigure workspace when the timeline position is changed. auto& pref = Preferences::instance(); pref.general.timelinePosition.AfterChange.connect([this] { configureWorkspaceLayout(); }); @@ -412,22 +408,32 @@ void MainWindow::setDefaultLayout() const auto timelineSplitterPos = get_config_double(kLegacyLayoutMainWindowSection, kLegacyLayoutTimelineSplitter, 75.0) / 100.0; const auto timelinePos = Preferences::instance().general.timelinePosition(); - const auto workspaceBounds = m_workspace->bounds(); + + // We calculate a estimate of the workspace bounds (as we don't yet + // know its size, because we're just constructing the dock where the + // workspace will be inside). + const int kLegacySplitterSeparation = 3 * ui::guiscale(); + auto workspaceBounds = bounds(); + workspaceBounds.w -= colorBarWidth + m_toolBar->sizeHint().w + 2 * kLegacySplitterSeparation; + workspaceBounds.h -= m_menuBar->sizeHint().h + m_tabsBar->sizeHint().h + + m_contextBar->sizeHint().h + m_statusBar->sizeHint().h; int timelineSide; - switch (timelinePos) { - case gen::TimelinePosition::LEFT: timelineSide = ui::LEFT; break; - case gen::TimelinePosition::RIGHT: timelineSide = ui::LEFT; break; - default: - case gen::TimelinePosition::BOTTOM: timelineSide = ui::BOTTOM; break; - } - gfx::Size timelineSize(75, 75); - if ((timelineSide & RIGHT) || (timelineSide & LEFT)) { - timelineSize.w = (workspaceBounds.w * (1.0 - timelineSplitterPos)) / guiscale(); - } - if ((timelineSide & BOTTOM) || (timelineSide & TOP)) { - timelineSize.h = (workspaceBounds.h * (1.0 - timelineSplitterPos)) / guiscale(); + switch (timelinePos) { + case gen::TimelinePosition::LEFT: + timelineSide = ui::LEFT; + timelineSize.w = (workspaceBounds.w * (1.0 - timelineSplitterPos)); + break; + case gen::TimelinePosition::RIGHT: + timelineSide = ui::RIGHT; + timelineSize.w = (workspaceBounds.w * (1.0 - timelineSplitterPos)); + break; + default: + case gen::TimelinePosition::BOTTOM: + timelineSide = ui::BOTTOM; + timelineSize.h = (workspaceBounds.h * (1.0 - timelineSplitterPos)); + break; } // Timeline config @@ -509,6 +515,25 @@ void MainWindow::onResize(ui::ResizeEvent& ev) { ui::Window::onResize(ev); + // Load default or user-selected layout after the first resize event + // is received. + if (m_firstResize) { + m_firstResize = false; + setDefaultLayout(); + + const std::string layoutId = m_layoutSelector->activeLayoutId(); + if (layoutId != Layout::kDefault) { + // Load the mirror layout + if (layoutId == Layout::kMirroredDefault) { + setMirroredDefaultLayout(); + } + // Or load an user defined layout + else if (LayoutPtr layout = m_layoutSelector->activeLayout()) { + loadUserLayout(layout.get()); + } + } + } + os::Window* nativeWindow = (display() ? display()->nativeWindow() : nullptr); if (nativeWindow && nativeWindow->screen()) { const int scale = nativeWindow->scale() * ui::guiscale(); diff --git a/src/app/ui/main_window.h b/src/app/ui/main_window.h index e7229ddfb..b109e3ebb 100644 --- a/src/app/ui/main_window.h +++ b/src/app/ui/main_window.h @@ -164,6 +164,7 @@ private: obs::scoped_connection m_timelineResizeConn; obs::scoped_connection m_colorBarResizeConn; obs::scoped_connection m_saveDockLayoutConn; + bool m_firstResize = true; }; } // namespace app