File indexing completed on 2024-04-28 05:45:53
0001 /* 0002 SPDX-FileCopyrightText: 2008-2010 Volker Lanz <vl@fidra.de> 0003 SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org> 0004 SPDX-FileCopyrightText: 2014-2017 Andrius Štikonas <andrius@stikonas.eu 0005 SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org> 0006 0007 SPDX-License-Identifier: GPL-3.0-or-later 0008 */ 0009 0010 #include "gui/partwidgetbase.h" 0011 #include "gui/partwidget.h" 0012 0013 #include "core/partition.h" 0014 0015 #include <cmath> 0016 0017 const qint32 PartWidgetBase::m_Spacing = 2; 0018 const qint32 PartWidgetBase::m_BorderWidth = 3; 0019 const qint32 PartWidgetBase::m_BorderHeight = 3; 0020 const qint32 PartWidgetBase::m_MinWidth = 30; 0021 0022 template<typename T> 0023 T sum(const QList<T>& list) 0024 { 0025 T rval = 0; 0026 for (const T & val : list) 0027 rval += val; 0028 return rval; 0029 } 0030 0031 bool distributeLostPixels(QList<qint32>& childrenWidth, qint32 lostPixels) 0032 { 0033 if (lostPixels == 0 || childrenWidth.size() == 0) 0034 return false; 0035 0036 while (lostPixels > 0) 0037 for (qint32 i = 0; i < childrenWidth.size() && lostPixels > 0; i++) { 0038 childrenWidth[i]++; 0039 lostPixels--; 0040 } 0041 0042 return true; 0043 } 0044 0045 bool levelChildrenWidths(QList<qint32>& childrenWidth, const QList<qint32>& minChildrenWidth, const qint32 destWidgetWidth) 0046 { 0047 if (childrenWidth.size() == 0) 0048 return false; 0049 0050 distributeLostPixels(childrenWidth, destWidgetWidth - sum(childrenWidth)); 0051 0052 // if we find out a partition is too narrow, adjust its screen 0053 // width to its minimum width and increase adjust by how much we had to increase the 0054 // screen width. thus, in the end, we have the number of pixels we need 0055 // to find somewhere else in adjust. 0056 qint32 adjust = 0; 0057 for (qint32 i = 0; i < childrenWidth.size(); i++) 0058 if (childrenWidth[i] < minChildrenWidth[i]) { 0059 adjust += minChildrenWidth[i] - childrenWidth[i]; 0060 childrenWidth[i] = minChildrenWidth[i]; 0061 } 0062 0063 // find out how many partitions are wide enough to have their width reduced; we'd love to 0064 // check for w > minWidth - (pixels_to_reduce_by), but that last value _depends_ on the 0065 // number we're trying to find here... 0066 qint32 numReducable = 0; 0067 for (qint32 i = 0; i < childrenWidth.size(); i++) 0068 if (childrenWidth[i] > minChildrenWidth[i]) 0069 numReducable++; 0070 0071 // no need to do anything... or nothing can be done because all are too narrow 0072 if (adjust == 0 || numReducable == 0) 0073 return false; 0074 0075 // if we have adjusted one or more partitions (and not ALL of them, because in that 0076 // case, nothing will help us), go through the partitions again and reduce the 0077 // on screen widths of those big enough anyway 0078 const qint32 reduce = static_cast<qint32>(std::ceil(1.0 * adjust / numReducable)); 0079 for (qint32 i = 0; i < childrenWidth.size(); i++) 0080 if (childrenWidth[i] > minChildrenWidth[i]) 0081 childrenWidth[i] -= reduce; 0082 0083 // distribute pixels lost due to rounding errors 0084 distributeLostPixels(childrenWidth, destWidgetWidth - sum(childrenWidth)); 0085 0086 return true; 0087 } 0088 0089 void PartWidgetBase::positionChildren(const QWidget* destWidget, const PartitionNode::Partitions& partitions, QList<PartWidget*> widgets) const 0090 { 0091 if (partitions.size() == 0) 0092 return; 0093 0094 QList<qint32> childrenWidth; 0095 QList<qint32> minChildrenWidth; 0096 const qint32 destWidgetWidth = destWidget->width() - 2 * borderWidth() - (partitions.size() - 1) * spacing(); 0097 0098 if (destWidgetWidth < 0) 0099 return; 0100 0101 qint64 totalLength = 0; 0102 for (const auto &p : partitions) 0103 totalLength += p->length(); 0104 0105 if (totalLength < 1) 0106 return; 0107 0108 // calculate unleveled width for each child and store it 0109 for (const auto &p : partitions) { 0110 childrenWidth.append(static_cast<qint32>(p->length() * destWidgetWidth / totalLength)); 0111 0112 // Calculate the minimum width for the widget. This is easy for primary and logical partitions: they 0113 // just have a fixed min width (configured in m_MinWidth). But for extended partitions things 0114 // are not quite as simple. We need to calc the sum of the min widths for each child, taking 0115 // spacing and borders into account, and add our own min width. 0116 qint32 min = (minWidth() + 2 * borderWidth() + spacing()) * p->children().size() - spacing() + 2 * borderWidth(); 0117 0118 // if it's too small, this partition is a primary or logical so just use the configured value 0119 if (min < minWidth()) 0120 min = minWidth(); 0121 minChildrenWidth.append(min); 0122 } 0123 0124 // now go level the widths as long as required 0125 while (levelChildrenWidths(childrenWidth, minChildrenWidth, destWidgetWidth)) 0126 ; 0127 0128 // move the children to their positions and resize them 0129 for (int i = 0, x = borderWidth(); i < widgets.size(); i++) { 0130 widgets[i]->setMinimumWidth(minChildrenWidth[i]); 0131 widgets[i]->move(x, borderHeight()); 0132 widgets[i]->resize(childrenWidth[i], destWidget->height() - 2 * borderHeight()); 0133 x += childrenWidth[i] + spacing(); 0134 } 0135 } 0136 0137 const QList<PartWidget*> PartWidgetBase::childWidgets() const 0138 { 0139 QList<PartWidget*> rval; 0140 0141 for (auto &o : children()) 0142 if (PartWidget* w = qobject_cast<PartWidget*>(o)) 0143 rval.append(w); 0144 0145 return rval; 0146 }