LCOV - code coverage report
Current view: top level - muse/framework/dockwindow_v2/qml/Muse/Dock - topleveltoolbarslayout.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 97.9 % 146 143
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "topleveltoolbarslayout.h"
      24              : 
      25              : #include "kddockwidgets/src/Config.h"
      26              : #include "kddockwidgets/src/core/DockWidget.h"
      27              : #include "kddockwidgets/src/core/Layout.h"
      28              : #include "kddockwidgets/src/core/MainWindow.h"
      29              : #include "kddockwidgets/src/qtquick/views/MainWindow.h"
      30              : 
      31              : #include "dockpageview.h"
      32              : #include "docktoolbarview.h"
      33              : #include "dockwindow.h"
      34              : 
      35              : using namespace muse::dock;
      36              : 
      37              : namespace muse::dock {
      38              : //! NOTE: Toolbar's maximum lenght, see DockToolBar.qml
      39              : static constexpr int UNCONSTRAINED_TOOLBAR_WIDTH = 16777215;
      40              : }
      41              : 
      42           24 : TopLevelToolBarsLayout::TopLevelToolBarsLayout(KDDockWidgets::QtQuick::MainWindow* mainWindow, DockWindow* window)
      43           24 :     : QObject(window), m_mainWindow(mainWindow), m_window(window)
      44              : {
      45           24 : }
      46              : 
      47            6 : void TopLevelToolBarsLayout::setUpPageConnections(const DockPageView* page)
      48              : {
      49           15 :     for (DockToolBarView* toolBar : topLevelToolBars(page)) {
      50            9 :         connect(toolBar, &DockToolBarView::floatingChanged,
      51            9 :                 this, &TopLevelToolBarsLayout::scheduleRelayout, Qt::UniqueConnection);
      52              : 
      53            9 :         connect(toolBar, &DockToolBarView::contentSizeChanged,
      54            9 :                 this, &TopLevelToolBarsLayout::scheduleRelayout, Qt::UniqueConnection);
      55              : 
      56            9 :         connect(toolBar, &DockToolBarView::visibleChanged,
      57           18 :                 this, &TopLevelToolBarsLayout::scheduleRelayout, Qt::UniqueConnection);
      58            6 :     }
      59            6 : }
      60              : 
      61            9 : void TopLevelToolBarsLayout::scheduleRelayout()
      62              : {
      63            9 :     m_window->polish();
      64            9 : }
      65              : 
      66           14 : void TopLevelToolBarsLayout::relayout()
      67              : {
      68           14 :     DockPageView* page = currentPage();
      69           14 :     if (!page) {
      70            1 :         return;
      71              :     }
      72              : 
      73           13 :     const int width = availableWidth();
      74              : 
      75           13 :     adjustContentForAvailableSpace(page);
      76           13 :     alignToolBars(page, width);
      77              : 
      78              :     //! NOTE: Force the layouting items to pick up the current dock minimums
      79           32 :     for (DockBase* dock : page->allDocks()) {
      80           19 :         if (dock) {
      81            9 :             dock->syncLayoutItemMinSize();
      82              :         }
      83           13 :     }
      84              : 
      85           13 :     if (!applyLayoutSizeToFitWindow(width)) {
      86            1 :         scheduleRelayout();
      87              :     }
      88              : }
      89              : 
      90           25 : void TopLevelToolBarsLayout::adjustContentForAvailableSpace(const DockPageView* page)
      91              : {
      92           25 :     if (!page) {
      93            0 :         return;
      94              :     }
      95              : 
      96           25 :     const int spaceWidth = availableWidth();
      97           25 :     const int separator = separatorThickness();
      98              : 
      99           25 :     auto adjustDocks = [spaceWidth, separator](QList<DockBase*> docks) {
     100           25 :         int width = separator * std::max(0, int(docks.size()) - 1);
     101           74 :         for (DockBase* dock : docks) {
     102           49 :             width += dock->contentWidth();
     103              :         }
     104              : 
     105           25 :         docks.erase(std::remove_if(docks.begin(), docks.end(), [](const DockBase* dock){
     106           49 :             return dock->compactPriorityOrder() == -1;
     107              :         }), docks.end());
     108              : 
     109           25 :         if (docks.empty()) {
     110           16 :             return;
     111              :         }
     112              : 
     113            9 :         std::sort(docks.begin(), docks.end(), [](const DockBase* dock1, DockBase* dock2) {
     114           10 :             return dock1->compactPriorityOrder() < dock2->compactPriorityOrder();
     115              :         });
     116              : 
     117            9 :         if (width > spaceWidth) {
     118            5 :             for (DockBase* dock : docks) {
     119            4 :                 if (width <= spaceWidth) {
     120            1 :                     break;
     121              :                 }
     122              : 
     123            3 :                 if (!dock->isCompact()) {
     124            3 :                     dock->setIsCompact(true);
     125              : 
     126            3 :                     width -= dock->nonCompactWidth();
     127            3 :                     width += dock->width();
     128              :                 }
     129              :             }
     130              :         } else {
     131           12 :             for (int i = docks.size() - 1; i >= 0; i--) {
     132            9 :                 DockBase* dock = docks.at(i);
     133            9 :                 if (!dock->isCompact()) {
     134            5 :                     continue;
     135              :                 }
     136              : 
     137            4 :                 int actualWidth = dock->contentWidth();
     138            4 :                 int nonCompactWidth = dock->nonCompactWidth();
     139            4 :                 if (width - actualWidth + nonCompactWidth <= spaceWidth) {
     140            3 :                     dock->setIsCompact(false);
     141              :                 }
     142              : 
     143            4 :                 break;
     144              :             }
     145              :         }
     146           25 :     };
     147              : 
     148           25 :     QList<DockBase*> topLevelToolBarsDocks;
     149              : 
     150           78 :     for (DockToolBarView* toolBar : topLevelToolBars(page)) {
     151           53 :         if (!isToolBarFloating(toolBar) && toolBar->isVisible()) {
     152           49 :             topLevelToolBarsDocks << toolBar;
     153              :         }
     154           25 :     }
     155              : 
     156           25 :     adjustDocks(topLevelToolBarsDocks);
     157           25 : }
     158              : 
     159           13 : void TopLevelToolBarsLayout::alignToolBars(const DockPageView* page, int availableWidth)
     160              : {
     161           13 :     const QList<DockToolBarView*> topToolBars = topLevelToolBars(page);
     162              : 
     163              :     //! NOTE: Reset paddings/pins first, so that widths from a previous
     164              :     //! configuration do not accumulate
     165           42 :     for (DockToolBarView* toolBar : topToolBars) {
     166           29 :         toolBar->setMaximumWidth(UNCONSTRAINED_TOOLBAR_WIDTH);
     167           29 :         toolBar->setMinimumWidth(toolBar->contentWidth());
     168              :     }
     169              : 
     170           13 :     DockToolBarView* lastLeftToolBar = nullptr;
     171           13 :     DockToolBarView* lastCentralToolBar = nullptr;
     172              : 
     173           13 :     int leftBlockWidth = 0;
     174           13 :     int centralBlockWidth = 0;
     175           13 :     int rightBlockWidth = 0;
     176              : 
     177           13 :     int leftCount = 0;
     178           13 :     int centralCount = 0;
     179           13 :     int rightCount = 0;
     180              : 
     181           13 :     const int separator = separatorThickness();
     182              : 
     183           42 :     for (DockToolBarView* toolBar : topToolBars) {
     184           29 :         if (toolBar->floating() || !toolBar->isVisible()) {
     185            2 :             continue;
     186              :         }
     187              : 
     188           27 :         switch (static_cast<DockToolBarAlignment::Type>(toolBar->alignment())) {
     189           10 :         case DockToolBarAlignment::Left:
     190           10 :             lastLeftToolBar = toolBar;
     191           10 :             leftBlockWidth += toolBar->contentWidth();
     192           10 :             ++leftCount;
     193           10 :             break;
     194            5 :         case DockToolBarAlignment::Center:
     195            5 :             lastCentralToolBar = toolBar;
     196            5 :             centralBlockWidth += toolBar->contentWidth();
     197            5 :             ++centralCount;
     198            5 :             break;
     199           12 :         case DockToolBarAlignment::Right:
     200           12 :             rightBlockWidth += toolBar->contentWidth();
     201           12 :             ++rightCount;
     202           12 :             break;
     203              :         }
     204              :     }
     205              : 
     206           13 :     leftBlockWidth += separator * std::max(0, leftCount - 1);
     207           13 :     centralBlockWidth += separator * std::max(0, centralCount - 1);
     208           13 :     rightBlockWidth += separator * std::max(0, rightCount - 1);
     209              : 
     210           13 :     const int separatorLeftCentral = (leftCount > 0 && centralCount > 0) ? separator : 0;
     211           13 :     const int separatorCentralRight = (centralCount > 0 && rightCount > 0) ? separator : 0;
     212           13 :     const int separatorLeftRight = (leftCount > 0 && centralCount == 0 && rightCount > 0) ? separator : 0;
     213              : 
     214           13 :     const int occupied = leftBlockWidth + centralBlockWidth + rightBlockWidth
     215           13 :                          + separatorLeftCentral + separatorCentralRight + separatorLeftRight;
     216              : 
     217           13 :     const int freeSpace = availableWidth - occupied;
     218           13 :     if (freeSpace <= 0) {
     219            1 :         return;
     220              :     }
     221              : 
     222           12 :     DockToolBarView* grower = lastLeftToolBar ? lastLeftToolBar : lastCentralToolBar;
     223           12 :     if (!grower) {
     224              :         //! NOTE: No toolbar to absorb the free space; leave all the toolbars
     225              :         //! unpinned so the layout can distribute it
     226            3 :         return;
     227              :     }
     228              : 
     229            9 :     int paddingForLastCentral = 0;
     230            9 :     if (lastCentralToolBar && lastCentralToolBar != grower) {
     231            3 :         paddingForLastCentral = (availableWidth - centralBlockWidth) / 2 - rightBlockWidth - separatorCentralRight;
     232            3 :         paddingForLastCentral = std::min(std::max(paddingForLastCentral, 0), freeSpace);
     233              :     }
     234              : 
     235           34 :     for (DockToolBarView* toolBar : topToolBars) {
     236           25 :         if (toolBar->floating() || !toolBar->isVisible() || toolBar == grower) {
     237           11 :             continue;
     238              :         }
     239              : 
     240              :         const int pinnedWidth = (toolBar == lastCentralToolBar)
     241           14 :                                 ? toolBar->contentWidth() + paddingForLastCentral
     242           11 :                                 : toolBar->contentWidth();
     243              : 
     244              :         //! NOTE: max before min
     245           14 :         toolBar->setMaximumWidth(pinnedWidth);
     246           14 :         toolBar->setMinimumWidth(pinnedWidth);
     247              :     }
     248           13 : }
     249              : 
     250            3 : bool TopLevelToolBarsLayout::applyLayoutSizeToFitWindow(int targetWidth)
     251              : {
     252            3 :     KDDockWidgets::Core::MainWindow* mw = m_mainWindow ? m_mainWindow->mainWindow() : nullptr;
     253            3 :     KDDockWidgets::Core::Layout* layout = mw ? mw->layout() : nullptr;
     254            3 :     if (!layout) {
     255            0 :         return true;
     256              :     }
     257              : 
     258            3 :     const int applyWidth = std::max(targetWidth, layout->layoutMinimumSize().width());
     259              : 
     260            3 :     if (applyWidth != layout->layoutSize().width()) {
     261            0 :         layout->setLayoutSize(QSize(applyWidth, layout->layoutSize().height()));
     262              :     }
     263              : 
     264            3 :     return layout->layoutSize().width() == applyWidth;
     265              : }
     266              : 
     267            3 : DockPageView* TopLevelToolBarsLayout::currentPage() const
     268              : {
     269            3 :     return m_window->currentPage();
     270              : }
     271              : 
     272           12 : QList<DockToolBarView*> TopLevelToolBarsLayout::topLevelToolBars(const DockPageView* page) const
     273              : {
     274           12 :     return m_window->topLevelToolBars(page);
     275              : }
     276              : 
     277            9 : int TopLevelToolBarsLayout::availableWidth() const
     278              : {
     279            9 :     return int(m_window->width());
     280              : }
     281              : 
     282            9 : int TopLevelToolBarsLayout::separatorThickness() const
     283              : {
     284            9 :     return KDDockWidgets::Config::self(m_window->iocContext()->id).separatorThickness();
     285              : }
     286              : 
     287           12 : bool TopLevelToolBarsLayout::isToolBarFloating(const DockToolBarView* toolBar) const
     288              : {
     289           12 :     return toolBar->dockWidget()->isFloating();
     290              : }
        

Generated by: LCOV version 2.0-1