00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "compactlayout.h"
00023
00024 #include <QtCore/QHash>
00025
00026 #include <QtGui/QGraphicsWidget>
00027 #include <kdebug.h>
00028
00029 namespace SystemTray
00030 {
00031
00032
00033 class CompactLayout::Private
00034 {
00035 public:
00036 Private(CompactLayout *q)
00037 : q(q),
00038 spacing(4.0)
00039 {
00040 }
00041
00042 QHash<QGraphicsLayoutItem*, QRectF> calculateGeometries(const QRectF &rect,
00043 Qt::SizeHint which,
00044 const QSizeF &constraint) const;
00045 void addPadding(QHash<QGraphicsLayoutItem*, QRectF> &geometries,
00046 const QSizeF &constraint);
00047 QSizeF hackedConstraint(const QSizeF &constraint) const;
00048 void updateParentWidget(QGraphicsWidget *item);
00049 QRectF boundingRect(const QList<QRectF> &rects) const;
00050
00051 CompactLayout *q;
00052 qreal spacing;
00053 QList<QGraphicsLayoutItem*> items;
00054 };
00055
00056
00057 CompactLayout::CompactLayout(QGraphicsLayoutItem *parent)
00058 : QGraphicsLayout(parent),
00059 d(new Private(this))
00060 {
00061 }
00062
00063
00064 CompactLayout::~CompactLayout()
00065 {
00066 foreach (QGraphicsLayoutItem* item, d->items) {
00067 removeItem(item);
00068 }
00069 delete d;
00070 }
00071
00072
00073 qreal CompactLayout::spacing() const
00074 {
00075 return d->spacing;
00076 }
00077
00078
00079 void CompactLayout::setSpacing(qreal spacing)
00080 {
00081 d->spacing = spacing;
00082 }
00083
00084
00085 void CompactLayout::insertItem(int index, QGraphicsLayoutItem *item)
00086 {
00087 index = qBound(0, index, d->items.count());
00088
00089 item->setParentLayoutItem(this);
00090
00091 QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget *>(item);
00092 if (widget) {
00093 d->updateParentWidget(widget);
00094 }
00095
00096 if (index == d->items.count()) {
00097 d->items.append(item);
00098 } else {
00099 d->items.insert(index, item);
00100 }
00101
00102 updateGeometry();
00103 activate();
00104 }
00105
00106 void CompactLayout::addItem(QGraphicsLayoutItem *item)
00107 {
00108 insertItem(d->items.count(), item);
00109 }
00110
00111 void CompactLayout::Private::updateParentWidget(QGraphicsWidget *item)
00112 {
00113 QGraphicsLayoutItem *parentItem = q->parentLayoutItem();
00114 while (parentItem && parentItem->isLayout()) {
00115 parentItem = parentItem->parentLayoutItem();
00116 }
00117
00118 if (parentItem) {
00119 item->setParentItem(static_cast<QGraphicsWidget*>(parentItem));
00120 }
00121 }
00122
00123
00124 void CompactLayout::removeItem(QGraphicsLayoutItem *item)
00125 {
00126 d->items.removeAll(item);
00127 item->setParentLayoutItem(0);
00128 updateGeometry();
00129 activate();
00130 }
00131
00132
00133 bool CompactLayout::containsItem(QGraphicsLayoutItem *item) const
00134 {
00135 return d->items.contains(item);
00136 }
00137
00138
00139 int CompactLayout::count() const
00140 {
00141 return d->items.count();
00142 }
00143
00144
00145 void CompactLayout::setGeometry(const QRectF &rect)
00146 {
00147
00148 QHash<QGraphicsLayoutItem*, QRectF> geometries;
00149 geometries = d->calculateGeometries(rect, Qt::PreferredSize, rect.size());
00150 d->addPadding(geometries, rect.size());
00151
00152 QHashIterator<QGraphicsLayoutItem*, QRectF> i(geometries);
00153 while (i.hasNext()) {
00154 i.next();
00155 QGraphicsLayoutItem *item = i.key();
00156 item->setGeometry(i.value());
00157 }
00158 }
00159
00160
00161 void CompactLayout::Private::addPadding(QHash<QGraphicsLayoutItem*, QRectF> &geometries, const QSizeF &constraint)
00162 {
00163 QSizeF size = boundingRect(geometries.values()).size();
00164
00165 qreal xAdjustment = (constraint.width() - size.width()) / 2.0;
00166 qreal yAdjustment = (constraint.height() - size.height()) / 2.0;
00167
00168 if (xAdjustment || yAdjustment) {
00169 foreach (QGraphicsLayoutItem *item, items) {
00170 QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget *>(item);
00171 if (widget && !widget->isVisible()) {
00172 continue;
00173 }
00174
00175 geometries[item].moveLeft(geometries[item].left() + xAdjustment);
00176 geometries[item].moveTop(geometries[item].top() + yAdjustment);
00177 }
00178 }
00179 }
00180
00181
00182 QGraphicsLayoutItem* CompactLayout::itemAt(int index) const
00183 {
00184 return d->items.at(index);
00185 }
00186
00187
00188 void CompactLayout::removeAt(int index)
00189 {
00190 QGraphicsLayoutItem* item = itemAt(index);
00191 if (item) {
00192 item->setParentLayoutItem(0);
00193 d->items.removeAt(index);
00194 }
00195 }
00196
00197
00198 QSizeF CompactLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
00199 {
00200 if (which != Qt::PreferredSize) {
00201 return QSizeF();
00202 }
00203
00204 QHash<QGraphicsLayoutItem*, QRectF> geometries =
00205 d->calculateGeometries(geometry(), which, d->hackedConstraint(constraint));
00206
00207 return d->boundingRect(geometries.values()).size();
00208 }
00209
00210
00211 QRectF CompactLayout::Private::boundingRect(const QList<QRectF> &rects) const
00212 {
00213 QRectF boundingRect;
00214
00215 foreach (const QRectF &rect, rects) {
00216 if (boundingRect.isNull()) {
00217 boundingRect = rect;
00218 } else {
00219 boundingRect = boundingRect.united(rect);
00220 }
00221 }
00222
00223 return boundingRect;
00224 }
00225
00226
00227 QHash<QGraphicsLayoutItem*, QRectF> CompactLayout::Private::calculateGeometries(const QRectF &geom, Qt::SizeHint which, const QSizeF &constraint) const
00228 {
00229 QSizePolicy sizePolicy;
00230
00231 if (q->parentLayoutItem()->parentLayoutItem()) {
00232 sizePolicy = q->parentLayoutItem()->parentLayoutItem()->sizePolicy();
00233 } else if (q->parentLayoutItem()) {
00234 sizePolicy = q->parentLayoutItem()->sizePolicy();
00235 } else {
00236 sizePolicy = q->sizePolicy();
00237 }
00238
00239 QHash<QGraphicsLayoutItem*, QRectF> geometries;
00240 QList<qreal> xPositions;
00241 QList<qreal> yPositions;
00242
00243 xPositions << geom.left();
00244 yPositions << geom.top();
00245
00246 foreach (QGraphicsLayoutItem *item, items) {
00247 QGraphicsWidget *widget = dynamic_cast<QGraphicsWidget *>(item);
00248 if (widget && !widget->isVisible()) {
00249 continue;
00250 }
00251
00252 QRectF rect;
00253 rect.setSize(item->effectiveSizeHint(which));
00254
00255 rect.setWidth(qBound(item->minimumWidth(), rect.width(), constraint.width()));
00256 rect.setHeight(qBound(item->minimumHeight(), rect.height(), constraint.height()));
00257
00258
00259
00260 foreach (qreal x, xPositions) {
00261 rect.moveLeft(x);
00262 if (rect.right() >= xPositions.last()) {
00263 continue;
00264 }
00265
00266 foreach (qreal y, yPositions) {
00267 rect.moveTop(y);
00268 if (rect.bottom() >= yPositions.last()) {
00269 continue;
00270 }
00271
00272 bool overlapping = false;
00273 foreach (const QRectF &existingRect, geometries) {
00274 if (existingRect.intersects(rect)) {
00275 overlapping = true;
00276 }
00277 }
00278
00279 if (!overlapping) {
00280 goto positioning_done;
00281 }
00282 }
00283 }
00284
00285
00286
00287 Qt::Orientation direction;
00288
00289 {
00290 const int yDelta = yPositions.last() + rect.height() - constraint.height();
00291 const int xDelta = xPositions.last() + rect.width() - constraint.width();
00292
00293 if (int(constraint.height()) == 0 && constraint.width() > 0) {
00294 direction = Qt::Vertical;
00295 } else if (int(constraint.width()) == 0 && constraint.height() > 0) {
00296 direction = Qt::Horizontal;
00297
00298 } else if ((sizePolicy.verticalPolicy() != QSizePolicy::Expanding) && xDelta < 0) {
00299 direction = Qt::Horizontal;
00300 } else if ((sizePolicy.horizontalPolicy() != QSizePolicy::Expanding) && yDelta < 0) {
00301 direction = Qt::Vertical;
00302
00303 } else if (sizePolicy.horizontalPolicy() != QSizePolicy::Expanding) {
00304 direction = Qt::Horizontal;
00305 } else if (sizePolicy.verticalPolicy() != QSizePolicy::Expanding) {
00306 direction = Qt::Vertical;
00307
00308 } else if (yPositions.last() >= xPositions.last()) {
00309 direction = Qt::Horizontal;
00310 } else {
00311 direction = Qt::Vertical;
00312 }
00313 }
00314
00315 if (direction == Qt::Horizontal) {
00316 rect.moveTop(yPositions.first());
00317 rect.moveLeft(xPositions.last());
00318 } else {
00319 rect.moveLeft(xPositions.first());
00320 rect.moveTop(yPositions.last());
00321 }
00322
00323 positioning_done:
00324 if (!xPositions.contains(rect.right() + spacing)) {
00325 xPositions.append(rect.right() + spacing);
00326 qSort(xPositions);
00327 }
00328
00329 if (!yPositions.contains(rect.bottom() + spacing)) {
00330 yPositions.append(rect.bottom() + spacing);
00331 qSort(yPositions);
00332 }
00333
00334 geometries[item] = rect;
00335 }
00336
00337 return geometries;
00338 }
00339
00340
00341 QSizeF CompactLayout::Private::hackedConstraint(const QSizeF &constraint) const
00342 {
00343
00344
00345
00346
00347
00348 if (constraint.width() != -1 || constraint.height() != -1) {
00349 return constraint;
00350 }
00351
00352 const QGraphicsWidget *widget = 0;
00353 const QGraphicsLayoutItem *item = q;
00354
00355 while (item && !widget) {
00356 item = item->parentLayoutItem();
00357 if (!item->isLayout()) {
00358 widget = static_cast<const QGraphicsWidget*>(item);
00359 }
00360 }
00361
00362 if (!widget) {
00363 return constraint;
00364 }
00365
00366 QSizeF parentSize;
00367 qreal xMargins = 0.0, yMargins = 0.0;
00368
00369 while (widget->parentWidget()) {
00370 widget = widget->parentWidget();
00371 parentSize = widget->size();
00372
00373 qreal left, top, right, bottom;
00374
00375 if (widget->layout()) {
00376 widget->layout()->getContentsMargins(&left, &top, &right, &bottom);
00377 } else {
00378 widget->getContentsMargins(&left, &top, &right, &bottom);
00379 }
00380
00381 xMargins += left + right;
00382 yMargins += top + bottom;
00383 }
00384
00385 return parentSize - QSizeF(xMargins, yMargins);
00386 }
00387
00388
00389 }