Skip to content

Commit 498adcc

Browse files
committed
top toolbar layout fix
Replaced reactive geometryChange handling (pendingWidth, forced sync resize, deferred QTimer fixup) with one idempotent pass in updatePolish(), extracted it into TopLevelToolBarsLayout.
1 parent dc2e678 commit 498adcc

6 files changed

Lines changed: 339 additions & 287 deletions

File tree

framework/dockwindow_v2/internal/dockbase.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ public slots:
189189
protected:
190190
friend class DockWindow;
191191
friend class DropController;
192+
friend class TopLevelToolBarsLayout;
192193

193194
void componentComplete() override;
194195

framework/dockwindow_v2/qml/Muse/Dock/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ qt_add_qml_module(muse_dockwindow_qml
2424
dockwindow.h
2525
foreign.cpp
2626
foreign.h
27+
topleveltoolbarslayout.cpp
28+
topleveltoolbarslayout.h
2729
QML_FILES
2830
DockFloatingWindow.qml
2931
DockFrame.qml

framework/dockwindow_v2/qml/Muse/Dock/dockwindow.cpp

Lines changed: 12 additions & 273 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@
2222

2323
#include "dockwindow.h"
2424

25-
#include <QTimer>
26-
2725
#include "kddockwidgets/src/LayoutSaver.h"
28-
#include "kddockwidgets/src/Config.h"
2926
#include "kddockwidgets/src/core/DockRegistry.h"
3027
#include "kddockwidgets/src/core/Layout.h"
3128
#include "kddockwidgets/src/core/MainWindow.h"
@@ -44,6 +41,7 @@
4441
#include "docktoolbarview.h"
4542
#include "dockingholderview.h"
4643
#include "dockwindow.h"
44+
#include "topleveltoolbarslayout.h"
4745

4846
#include "muse_framework_config.h"
4947

@@ -53,9 +51,6 @@ using namespace muse::dock;
5351
using namespace muse::async;
5452

5553
namespace muse::dock {
56-
//! NOTE: Toolbar's maximum lenght, see DockToolBar.qml
57-
static constexpr int UNCONSTRAINED_TOOLBAR_WIDTH = 16777215;
58-
5954
static const QList<Location> POSSIBLE_LOCATIONS {
6055
Location::Left,
6156
Location::Right,
@@ -103,22 +98,6 @@ static void clearRegistry(int ctx)
10398
}
10499
}
105100

106-
class DockWindow::UniqueConnectionHolder : public QObject
107-
{
108-
Q_OBJECT
109-
public:
110-
UniqueConnectionHolder(DockPageView* page, DockWindow* parent)
111-
: QObject(parent), m_page(page) {}
112-
113-
void alignTopLevelToolBars()
114-
{
115-
static_cast<DockWindow*>(parent())->alignTopLevelToolBars(m_page);
116-
}
117-
118-
private:
119-
DockPageView* m_page = nullptr;
120-
};
121-
122101
DockWindow::DockWindow(QQuickItem* parent)
123102
: QQuickItem(parent), muse::Contextable(muse::iocCtxForQmlObject(this)),
124103
m_toolBars(this),
@@ -129,12 +108,6 @@ DockWindow::DockWindow(QQuickItem* parent)
129108
DockWindow::~DockWindow()
130109
{
131110
dockWindowProvider()->deinit();
132-
133-
// Without this, the connections would be deleted by the QObject destructor,
134-
// because they are child objects of this. But since they use DockWindow-
135-
// specific code (rather than QObject-specific), we need to delete them
136-
// before the end of the DockWindow destructor.
137-
qDeleteAll(m_pageConnections);
138111
}
139112

140113
void DockWindow::componentComplete()
@@ -149,91 +122,28 @@ void DockWindow::componentComplete()
149122
KDDockWidgets::MainWindowOption_None,
150123
this);
151124

125+
m_topLevelToolBarsLayout = new TopLevelToolBarsLayout(m_mainWindow, this);
126+
152127
connect(qApp, &QCoreApplication::aboutToQuit, this, &DockWindow::onQuit);
153128
connect(this, &QQuickItem::windowChanged, this, &DockWindow::windowPropertyChanged);
154129
}
155130

156131
void DockWindow::geometryChange(const QRectF& newGeometry, const QRectF& oldGeometry)
157132
{
158-
const bool widthChanged = m_currentPage && !qFuzzyCompare(newGeometry.width(), oldGeometry.width());
159-
const bool shrinking = widthChanged && newGeometry.width() < oldGeometry.width();
160-
161-
if (widthChanged) {
162-
m_pendingWidth = int(newGeometry.width());
163-
164-
if (shrinking) {
165-
//! NOTE: Unpin the paddings first so compact mode can actually shrink the toolbars' content
166-
for (DockToolBarView* toolBar : topLevelToolBars(m_currentPage)) {
167-
toolBar->setMinimumWidth(toolBar->contentWidth());
168-
}
169-
}
170-
171-
adjustContentForAvailableSpace(m_currentPage);
172-
alignTopLevelToolBars(m_currentPage);
173-
174-
//! NOTE: Apply the new size to the layout synchronously
175-
applyLayoutSizeToFitWindow();
176-
177-
m_pendingWidth = -1;
178-
179-
//! NOTE: The synchronous resize above can be partial when KDDockWidgets' async item-size sync
180-
//! hasn't settled yet. So let's shedule another layout
181-
scheduleDeferredLayoutFix();
182-
}
183-
184133
QQuickItem::geometryChange(newGeometry, oldGeometry);
185-
}
186-
187-
void DockWindow::applyLayoutSizeToFitWindow()
188-
{
189-
KDDockWidgets::Core::MainWindow* mw = m_mainWindow ? m_mainWindow->mainWindow() : nullptr;
190-
KDDockWidgets::Core::Layout* layout = mw ? mw->layout() : nullptr;
191-
if (!layout) {
192-
return;
193-
}
194-
195-
const int targetWidth = m_pendingWidth >= 0 ? m_pendingWidth : int(width());
196-
const int layoutMin = layout->layoutMinimumSize().width();
197-
198-
const int applyWidth = std::max(targetWidth, layoutMin);
199134

200-
if (applyWidth != layout->layoutSize().width()) {
201-
layout->setLayoutSize(QSize(applyWidth, layout->layoutSize().height()));
135+
if (m_currentPage && !qFuzzyCompare(newGeometry.width(), oldGeometry.width())) {
136+
polish();
202137
}
203138
}
204139

205-
void DockWindow::scheduleDeferredLayoutFix()
140+
void DockWindow::updatePolish()
206141
{
207-
if (m_layoutFixScheduled) {
208-
return;
209-
}
142+
QQuickItem::updatePolish();
210143

211-
m_layoutFixScheduled = true;
212-
213-
QTimer::singleShot(0, this, [this]() {
214-
runDeferredLayoutFix();
215-
});
216-
}
217-
218-
void DockWindow::runDeferredLayoutFix()
219-
{
220-
m_layoutFixScheduled = false;
221-
222-
if (!m_currentPage) {
223-
return;
224-
}
225-
226-
adjustContentForAvailableSpace(m_currentPage);
227-
alignTopLevelToolBars(m_currentPage);
228-
229-
//! NOTE: Force the layouting items to pick up the current dock minimums
230-
for (DockBase* dock : m_currentPage->allDocks()) {
231-
if (dock) {
232-
dock->syncLayoutItemMinSize();
233-
}
144+
if (m_topLevelToolBarsLayout) {
145+
m_topLevelToolBarsLayout->relayout();
234146
}
235-
236-
applyLayoutSizeToFitWindow();
237147
}
238148

239149
void DockWindow::onQuit()
@@ -492,95 +402,6 @@ void DockWindow::loadPanels(const DockPageView* page)
492402
}
493403
}
494404

495-
void DockWindow::alignTopLevelToolBars(const DockPageView* page)
496-
{
497-
const QList<DockToolBarView*> topToolBars = topLevelToolBars(page);
498-
499-
//! NOTE: Reset paddings/pins first, so that widths from a previous
500-
//! configuration do not accumulate
501-
for (DockToolBarView* toolBar : topToolBars) {
502-
toolBar->setMaximumWidth(UNCONSTRAINED_TOOLBAR_WIDTH);
503-
toolBar->setMinimumWidth(toolBar->contentWidth());
504-
}
505-
506-
DockToolBarView* lastLeftToolBar = nullptr;
507-
DockToolBarView* lastCentralToolBar = nullptr;
508-
509-
int leftBlockWidth = 0;
510-
int centralBlockWidth = 0;
511-
int rightBlockWidth = 0;
512-
513-
int leftCount = 0;
514-
int centralCount = 0;
515-
int rightCount = 0;
516-
517-
const int separator = KDDockWidgets::Config::self(iocContext()->id).separatorThickness();
518-
519-
for (DockToolBarView* toolBar : topToolBars) {
520-
if (toolBar->floating() || !toolBar->isVisible()) {
521-
continue;
522-
}
523-
524-
switch (static_cast<DockToolBarAlignment::Type>(toolBar->alignment())) {
525-
case DockToolBarAlignment::Left:
526-
lastLeftToolBar = toolBar;
527-
leftBlockWidth += toolBar->contentWidth();
528-
++leftCount;
529-
break;
530-
case DockToolBarAlignment::Center:
531-
lastCentralToolBar = toolBar;
532-
centralBlockWidth += toolBar->contentWidth();
533-
++centralCount;
534-
break;
535-
case DockToolBarAlignment::Right:
536-
rightBlockWidth += toolBar->contentWidth();
537-
++rightCount;
538-
break;
539-
}
540-
}
541-
542-
leftBlockWidth += separator * std::max(0, leftCount - 1);
543-
centralBlockWidth += separator * std::max(0, centralCount - 1);
544-
rightBlockWidth += separator * std::max(0, rightCount - 1);
545-
546-
const int separatorLeftCentral = (leftCount > 0 && centralCount > 0) ? separator : 0;
547-
const int separatorCentralRight = (centralCount > 0 && rightCount > 0) ? separator : 0;
548-
const int separatorLeftRight = (leftCount > 0 && centralCount == 0 && rightCount > 0) ? separator : 0;
549-
550-
const int occupied = leftBlockWidth + centralBlockWidth + rightBlockWidth
551-
+ separatorLeftCentral + separatorCentralRight + separatorLeftRight;
552-
553-
//! NOTE: During a resize the new width isn't propagated to width yet
554-
const int availableWidth = m_pendingWidth >= 0 ? m_pendingWidth : int(width());
555-
556-
const int freeSpace = availableWidth - occupied;
557-
if (freeSpace <= 0) {
558-
return;
559-
}
560-
561-
DockToolBarView* grower = lastLeftToolBar ? lastLeftToolBar : lastCentralToolBar;
562-
563-
int paddingForLastCentral = 0;
564-
if (lastCentralToolBar && lastCentralToolBar != grower) {
565-
paddingForLastCentral = (availableWidth - centralBlockWidth) / 2 - rightBlockWidth - separatorCentralRight;
566-
paddingForLastCentral = std::min(std::max(paddingForLastCentral, 0), freeSpace);
567-
}
568-
569-
for (DockToolBarView* toolBar : topToolBars) {
570-
if (toolBar->floating() || !toolBar->isVisible() || toolBar == grower) {
571-
continue;
572-
}
573-
574-
const int pinnedWidth = (toolBar == lastCentralToolBar)
575-
? toolBar->contentWidth() + paddingForLastCentral
576-
: toolBar->contentWidth();
577-
578-
//! NOTE: max before min
579-
toolBar->setMaximumWidth(pinnedWidth);
580-
toolBar->setMinimumWidth(pinnedWidth);
581-
}
582-
}
583-
584405
void DockWindow::addDock(DockBase* dock, Location location, const DockBase* relativeTo)
585406
{
586407
TRACEFUNC;
@@ -850,7 +671,7 @@ void DockWindow::initDocks(DockPageView* page)
850671
TRACEFUNC;
851672

852673
//! before init we should correct toolbars sizes
853-
adjustContentForAvailableSpace(page);
674+
m_topLevelToolBarsLayout->adjustContentForAvailableSpace(page);
854675

855676
for (DockToolBarView* toolbar : m_toolBars.list()) {
856677
toolbar->setParentItem(this);
@@ -862,88 +683,8 @@ void DockWindow::initDocks(DockPageView* page)
862683
page->init();
863684
}
864685

865-
alignTopLevelToolBars(page);
866-
867-
if (!m_pageConnections.contains(page)) {
868-
m_pageConnections[page] = new UniqueConnectionHolder(page, this);
869-
}
870-
871-
UniqueConnectionHolder* holder = m_pageConnections[page];
872-
873-
for (DockToolBarView* toolbar : topLevelToolBars(page)) {
874-
connect(toolbar, &DockToolBarView::floatingChanged,
875-
this, &DockWindow::scheduleDeferredLayoutFix, Qt::UniqueConnection);
876-
877-
connect(toolbar, &DockToolBarView::contentSizeChanged,
878-
holder, &UniqueConnectionHolder::alignTopLevelToolBars, Qt::UniqueConnection);
879-
880-
connect(toolbar, &DockToolBarView::visibleChanged,
881-
holder, &UniqueConnectionHolder::alignTopLevelToolBars, Qt::UniqueConnection);
882-
}
883-
}
884-
885-
void DockWindow::adjustContentForAvailableSpace(DockPageView* page)
886-
{
887-
if (!page) {
888-
return;
889-
}
890-
891-
int spaceWidth = m_pendingWidth >= 0 ? m_pendingWidth : int(width());
892-
893-
auto adjustDocks = [&spaceWidth](QList<DockBase*> docks) {
894-
int width = 0;
895-
for (DockBase* dock : docks) {
896-
width += dock->contentWidth();
897-
}
898-
899-
docks.erase(std::remove_if(docks.begin(), docks.end(), [](const DockBase* dock){
900-
return dock->compactPriorityOrder() == -1;
901-
}), docks.end());
902-
903-
if (docks.empty()) {
904-
return;
905-
}
906-
907-
std::sort(docks.begin(), docks.end(), [](const DockBase* dock1, DockBase* dock2) {
908-
return dock1->compactPriorityOrder() < dock2->compactPriorityOrder();
909-
});
910-
911-
if (width >= spaceWidth) {
912-
for (DockBase* dock : docks) {
913-
if (!dock->isCompact()) {
914-
dock->setIsCompact(true);
915-
916-
width -= dock->nonCompactWidth();
917-
width += dock->width();
918-
}
919-
}
920-
} else {
921-
for (int i = docks.size() - 1; i >= 0; i--) {
922-
DockBase* dock = docks.at(i);
923-
if (!dock->isCompact()) {
924-
continue;
925-
}
926-
927-
int actualWidth = dock->contentWidth();
928-
int nonCompactWidth = dock->nonCompactWidth();
929-
if (width - actualWidth + nonCompactWidth < spaceWidth) {
930-
dock->setIsCompact(false);
931-
}
932-
933-
break;
934-
}
935-
}
936-
};
937-
938-
QList<DockBase*> topLevelToolBarsDocks;
939-
940-
for (DockToolBarView* toolBar : topLevelToolBars(page)) {
941-
if (!toolBar->dockWidget()->isFloating() && toolBar->isVisible()) {
942-
topLevelToolBarsDocks << toolBar;
943-
}
944-
}
945-
946-
adjustDocks(topLevelToolBarsDocks);
686+
m_topLevelToolBarsLayout->setUpPageConnections(page);
687+
m_topLevelToolBarsLayout->scheduleRelayout();
947688
}
948689

949690
void DockWindow::notifyAboutDocksOpenStatus()
@@ -985,5 +726,3 @@ QList<DockToolBarView*> DockWindow::topLevelToolBars(const DockPageView* page) c
985726

986727
return toolBars;
987728
}
988-
989-
#include "dockwindow.moc"

0 commit comments

Comments
 (0)