/*************************************************************************** * Copyright (C) 2008 by Volker Lanz * * * * 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 2 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***************************************************************************/ #include "gui/partwidgetbase.h" #include "gui/partwidget.h" #include "core/partition.h" #include #include const qint32 PartWidgetBase::m_Spacing = 3; const qint32 PartWidgetBase::m_BorderWidth = 5; const qint32 PartWidgetBase::m_BorderHeight = 5; const qint32 PartWidgetBase::m_MinWidth = 20; template T sum(const QList& list) { T rval = 0; foreach(const T& val, list) rval += val; return rval; } bool distributeLostPixels(QList& 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& childrenWidth, 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 minWidth() 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] < PartWidgetBase::minWidth()) { adjust += PartWidgetBase::minWidth() - childrenWidth[i]; childrenWidth[i] = PartWidgetBase::minWidth(); } // 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; foreach(int w, childrenWidth) if (w > PartWidgetBase::minWidth()) 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] > PartWidgetBase::minWidth()) 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& widgets) { if (partitions.size() == 0) return; QList childrenWidth; 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); // now go level the widths as long as required while (levelChildrenWidths(childrenWidth, destWidgetWidth)) ; // move the children to their positions and resize them for (int i = 0, x = borderWidth(); i < widgets.size(); i++) { widgets[i]->setMinimumWidth(minWidth()); widgets[i]->move(x, borderHeight()); widgets[i]->resize(childrenWidth[i], destWidget->height() - 2 * borderHeight()); x += childrenWidth[i] + spacing(); } }