kpmcore/src/gui/partwidgetbase.cpp

156 lines
5.6 KiB
C++

/*************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 3 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>.*
*************************************************************************/
#include "gui/partwidgetbase.h"
#include "gui/partwidget.h"
#include "core/partition.h"
#include <cmath>
const qint32 PartWidgetBase::m_Spacing = 2;
const qint32 PartWidgetBase::m_BorderWidth = 3;
const qint32 PartWidgetBase::m_BorderHeight = 3;
const qint32 PartWidgetBase::m_MinWidth = 30;
template<typename T>
T sum(const QList<T>& list)
{
T rval = 0;
foreach(const T& val, list)
rval += val;
return rval;
}
bool distributeLostPixels(QList<qint32>& childrenWidth, qint32 lostPixels)
{
if (lostPixels == 0 || childrenWidth.size() == 0)
return false;
while (lostPixels > 0)
for (qint32 i = 0; i < childrenWidth.size() && lostPixels > 0; i++)
{
childrenWidth[i]++;
lostPixels--;
}
return true;
}
bool levelChildrenWidths(QList<qint32>& childrenWidth, const QList<qint32>& minChildrenWidth, const qint32 destWidgetWidth)
{
if (childrenWidth.size() == 0)
return false;
distributeLostPixels(childrenWidth, destWidgetWidth - sum(childrenWidth));
// if we find out a partition is too narrow, adjust its screen
// width to its minimum width and increase adjust by how much we had to increase the
// screen width. thus, in the end, we have the number of pixels we need
// to find somewhere else in adjust.
qint32 adjust = 0;
for (qint32 i = 0; i < childrenWidth.size(); i++)
if (childrenWidth[i] < minChildrenWidth[i])
{
adjust += minChildrenWidth[i] - childrenWidth[i];
childrenWidth[i] = minChildrenWidth[i];
}
// find out how many partitions are wide enough to have their width reduced; we'd love to
// check for w > minWidth - (pixels_to_reduce_by), but that last value _depends_ on the
// number we're trying to find here...
qint32 numReducable = 0;
for (qint32 i = 0; i < childrenWidth.size(); i++)
if (childrenWidth[i] > minChildrenWidth[i])
numReducable++;
// no need to do anything... or nothing can be done because all are too narrow
if (adjust == 0 || numReducable == 0)
return false;
// if we have adjusted one or more partitions (and not ALL of them, because in that
// case, nothing will help us), go through the partitions again and reduce the
// on screen widths of those big enough anyway
const qint32 reduce = ceil(1.0 * adjust / numReducable);
for (qint32 i = 0; i < childrenWidth.size(); i++)
if (childrenWidth[i] > minChildrenWidth[i])
childrenWidth[i] -= reduce;
// distribute pixels lost due to rounding errors
distributeLostPixels(childrenWidth, destWidgetWidth - sum(childrenWidth));
return true;
}
void PartWidgetBase::positionChildren(const QWidget* destWidget, const PartitionNode::Partitions& partitions, QList<PartWidget*> widgets) const
{
if (partitions.size() == 0)
return;
QList<qint32> childrenWidth;
QList<qint32> minChildrenWidth;
const qint32 destWidgetWidth = destWidget->width() - 2 * borderWidth() - (partitions.size() - 1) * spacing();
if (destWidgetWidth < 0)
return;
qint64 totalLength = 0;
foreach (const Partition* p, partitions)
totalLength += p->length();
// calculate unleveled width for each child and store it
for (int i = 0; i < partitions.size(); i++)
{
childrenWidth.append(partitions[i]->length() * destWidgetWidth / totalLength);
// Calculate the minimum width for the widget. This is easy for primary and logical partitions: they
// just have a fixed min width (configured in m_MinWidth). But for extended partitions things
// are not quite as simple. We need to calc the sum of the min widths for each child, taking
// spacing and borders into account, and add our own min width.
qint32 min = (minWidth() + 2 * borderWidth() + spacing()) * partitions[i]->children().size() - spacing() + 2 * borderWidth();
// if it's too small, this partition is a primary or logical so just use the configured value
if (min < minWidth())
min = minWidth();
minChildrenWidth.append(min);
}
// now go level the widths as long as required
while (levelChildrenWidths(childrenWidth, minChildrenWidth, destWidgetWidth))
;
// move the children to their positions and resize them
for (int i = 0, x = borderWidth(); i < widgets.size(); i++)
{
widgets[i]->setMinimumWidth(minChildrenWidth[i]);
widgets[i]->move(x, borderHeight());
widgets[i]->resize(childrenWidth[i], destWidget->height() - 2 * borderHeight());
x += childrenWidth[i] + spacing();
}
}
QList<PartWidget*> PartWidgetBase::childWidgets()
{
QList<PartWidget*> rval;
foreach(QObject* o, children())
if (PartWidget* w = qobject_cast<PartWidget*>(o))
rval.append(w);
return rval;
}