src/gui/graphicsview/qgraphicslinearlayout.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*!
       
    43     \class QGraphicsLinearLayout
       
    44     \brief The QGraphicsLinearLayout class provides a horizontal or vertical
       
    45     layout for managing widgets in Graphics View.
       
    46     \since 4.4
       
    47     \ingroup graphicsview-api
       
    48 
       
    49     The default orientation for a linear layout is Qt::Horizontal. You can
       
    50     choose a vertical orientation either by calling setOrientation(), or by
       
    51     passing Qt::Vertical to QGraphicsLinearLayout's constructor.
       
    52 
       
    53     The most common way to use QGraphicsLinearLayout is to construct an object
       
    54     on the heap with no parent, add widgets and layouts by calling addItem(),
       
    55     and finally assign the layout to a widget by calling
       
    56     QGraphicsWidget::setLayout().
       
    57 
       
    58     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicslinearlayout.cpp 0
       
    59 
       
    60     You can add widgets, layouts, stretches (addStretch(), insertStretch() or
       
    61     setStretchFactor()), and spacings (setItemSpacing()) to a linear
       
    62     layout. The layout takes ownership of the items. In some cases when the layout 
       
    63     item also inherits from QGraphicsItem (such as QGraphicsWidget) there will be a
       
    64     ambiguity in ownership because the layout item belongs to two ownership hierarchies.
       
    65 	See the documentation of QGraphicsLayoutItem::setOwnedByLayout() how to handle
       
    66 	this.
       
    67 	You can access each item in the layout by calling count() and itemAt(). Calling
       
    68     removeAt() or removeItem() will remove an item from the layout, without
       
    69     destroying it.
       
    70 
       
    71     \section1 Size Hints and Size Policies in QGraphicsLinearLayout
       
    72 
       
    73     QGraphicsLinearLayout respects each item's size hints and size policies,
       
    74     and when the layout contains more space than the items can fill, each item
       
    75     is arranged according to the layout's alignment for that item. You can set
       
    76     an alignment for each item by calling setAlignment(), and check the
       
    77     alignment for any item by calling alignment(). By default, items are
       
    78     centered both vertically and horizontally.
       
    79 
       
    80     \section1 Spacing within QGraphicsLinearLayout
       
    81 
       
    82     Between the items, the layout distributes some space. The actual amount of
       
    83     space depends on the managed widget's current style, but the common
       
    84     spacing is 4. You can also set your own spacing by calling setSpacing(),
       
    85     and get the current spacing value by calling spacing(). If you want to
       
    86     configure individual spacing for your items, you can call setItemSpacing().
       
    87 
       
    88     \section1 Stretch Factor in QGraphicsLinearLayout
       
    89 
       
    90     You can assign a stretch factor to each item to control how much space it
       
    91     will get compared to the other items. By default, two identical widgets
       
    92     arranged in a linear layout will have the same size, but if the first
       
    93     widget has a stretch factor of 1 and the second widget has a stretch
       
    94     factor of 2, the first widget will get 1/3 of the available space, and the
       
    95     second will get 2/3.
       
    96 
       
    97     QGraphicsLinearLayout calculates the distribution of sizes by adding up
       
    98     the stretch factors of all items, and then dividing the available space
       
    99     accordingly. The default stretch factor is 0 for all items; a factor of 0
       
   100     means the item does not have any defined stretch factor; effectively this
       
   101     is the same as setting the stretch factor to 1. The stretch factor only
       
   102     applies to the available space in the lengthwise direction of the layout
       
   103     (following its orientation). If you want to control both the item's
       
   104     horizontal and vertical stretch, you can use QGraphicsGridLayout instead.
       
   105 
       
   106     \section1 QGraphicsLinearLayout Compared to Other Layouts
       
   107 
       
   108     QGraphicsLinearLayout is very similar to QVBoxLayout and QHBoxLayout, but
       
   109     in contrast to these classes, it is used to manage QGraphicsWidget and
       
   110     QGraphicsLayout instead of QWidget and QLayout.
       
   111 
       
   112     \sa QGraphicsGridLayout, QGraphicsWidget
       
   113 */
       
   114 
       
   115 #include "qapplication.h"
       
   116 
       
   117 #ifndef QT_NO_GRAPHICSVIEW
       
   118 
       
   119 #include "qwidget.h"
       
   120 #include "qgraphicslayout_p.h"
       
   121 #include "qgraphicslayoutitem.h"
       
   122 #include "qgraphicslinearlayout.h"
       
   123 #include "qgraphicswidget.h"
       
   124 #include "qgridlayoutengine_p.h"
       
   125 #ifdef QT_DEBUG
       
   126 #include <QtCore/qdebug.h>
       
   127 #endif
       
   128 
       
   129 QT_BEGIN_NAMESPACE
       
   130 
       
   131 class QGraphicsLinearLayoutPrivate : public QGraphicsLayoutPrivate
       
   132 {
       
   133 public:
       
   134     QGraphicsLinearLayoutPrivate(Qt::Orientation orientation) : orientation(orientation) { }
       
   135 
       
   136     void removeGridItem(QGridLayoutItem *gridItem);
       
   137     QLayoutStyleInfo styleInfo() const;
       
   138     void fixIndex(int *index) const;
       
   139     int gridRow(int index) const;
       
   140     int gridColumn(int index) const;
       
   141 
       
   142     Qt::Orientation orientation;
       
   143     QGridLayoutEngine engine;
       
   144 };
       
   145 
       
   146 void QGraphicsLinearLayoutPrivate::removeGridItem(QGridLayoutItem *gridItem)
       
   147 {
       
   148     int index = gridItem->firstRow(orientation);
       
   149     engine.removeItem(gridItem);
       
   150     engine.removeRow(index, orientation);
       
   151 }
       
   152 
       
   153 void QGraphicsLinearLayoutPrivate::fixIndex(int *index) const
       
   154 {
       
   155     int count = engine.rowCount(orientation);
       
   156     if (uint(*index) > uint(count))
       
   157         *index = count;
       
   158 }
       
   159 
       
   160 int QGraphicsLinearLayoutPrivate::gridRow(int index) const
       
   161 {
       
   162     if (orientation == Qt::Horizontal)
       
   163         return 0;
       
   164     return int(qMin(uint(index), uint(engine.rowCount())));
       
   165 }
       
   166 
       
   167 int QGraphicsLinearLayoutPrivate::gridColumn(int index) const
       
   168 {
       
   169     if (orientation == Qt::Vertical)
       
   170         return 0;
       
   171     return int(qMin(uint(index), uint(engine.columnCount())));
       
   172 }
       
   173 
       
   174 QLayoutStyleInfo QGraphicsLinearLayoutPrivate::styleInfo() const
       
   175 {
       
   176     static QWidget *wid = 0;
       
   177     if (!wid)
       
   178         wid = new QWidget;
       
   179     QGraphicsItem *item = parentItem();
       
   180     QStyle *style = (item && item->isWidget()) ? static_cast<QGraphicsWidget*>(item)->style() : QApplication::style();
       
   181     return QLayoutStyleInfo(style, wid);
       
   182 }
       
   183 
       
   184 /*!
       
   185     Constructs a QGraphicsLinearLayout instance. You can pass the
       
   186     \a orientation for the layout, either horizontal or vertical, and
       
   187     \a parent is passed to QGraphicsLayout's constructor.
       
   188 */
       
   189 QGraphicsLinearLayout::QGraphicsLinearLayout(Qt::Orientation orientation, QGraphicsLayoutItem *parent)
       
   190     : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(orientation), parent)
       
   191 {
       
   192 }
       
   193 
       
   194 /*!
       
   195     Constructs a QGraphicsLinearLayout instance using Qt::Horizontal
       
   196     orientation. \a parent is passed to QGraphicsLayout's constructor.
       
   197 */
       
   198 QGraphicsLinearLayout::QGraphicsLinearLayout(QGraphicsLayoutItem *parent)
       
   199     : QGraphicsLayout(*new QGraphicsLinearLayoutPrivate(Qt::Horizontal), parent)
       
   200 {
       
   201 }
       
   202 
       
   203 /*!
       
   204     Destroys the QGraphicsLinearLayout object.
       
   205 */
       
   206 QGraphicsLinearLayout::~QGraphicsLinearLayout()
       
   207 {
       
   208     for (int i = count() - 1; i >= 0; --i) {
       
   209         QGraphicsLayoutItem *item = itemAt(i);
       
   210         // The following lines can be removed, but this removes the item
       
   211         // from the layout more efficiently than the implementation of 
       
   212         // ~QGraphicsLayoutItem.
       
   213         removeAt(i);
       
   214         if (item) {
       
   215             item->setParentLayoutItem(0);
       
   216             if (item->ownedByLayout())
       
   217                 delete item;
       
   218         }
       
   219     }
       
   220 }
       
   221 
       
   222 /*!
       
   223   Change the layout orientation to \a orientation. Changing the layout
       
   224   orientation will automatically invalidate the layout.
       
   225 
       
   226   \sa orientation()
       
   227 */
       
   228 void QGraphicsLinearLayout::setOrientation(Qt::Orientation orientation)
       
   229 {
       
   230     Q_D(QGraphicsLinearLayout);
       
   231     if (orientation != d->orientation) {
       
   232         d->engine.transpose();
       
   233         d->orientation = orientation;
       
   234         invalidate();
       
   235     }
       
   236 }
       
   237 
       
   238 /*!
       
   239   Returns the layout orientation.
       
   240   \sa setOrientation()
       
   241  */
       
   242 Qt::Orientation QGraphicsLinearLayout::orientation() const
       
   243 {
       
   244     Q_D(const QGraphicsLinearLayout);
       
   245     return d->orientation;
       
   246 }
       
   247 
       
   248 /*!
       
   249     \fn void QGraphicsLinearLayout::addItem(QGraphicsLayoutItem *item)
       
   250 
       
   251     This convenience function is equivalent to calling
       
   252     insertItem(-1, \a item).
       
   253 */
       
   254 
       
   255 /*!
       
   256     \fn void QGraphicsLinearLayout::addStretch(int stretch)
       
   257 
       
   258     This convenience function is equivalent to calling
       
   259     insertStretch(-1, \a stretch).
       
   260 */
       
   261 
       
   262 /*!
       
   263     Inserts \a item into the layout at \a index, or before any item that is
       
   264     currently at \a index.
       
   265 
       
   266     \sa addItem(), itemAt(), insertStretch(), setItemSpacing()
       
   267 */
       
   268 void QGraphicsLinearLayout::insertItem(int index, QGraphicsLayoutItem *item)
       
   269 {
       
   270     Q_D(QGraphicsLinearLayout);
       
   271     if (!item) {
       
   272         qWarning("QGraphicsLinearLayout::insertItem: cannot insert null item");
       
   273         return;
       
   274     }
       
   275     if (item == this) {
       
   276         qWarning("QGraphicsLinearLayout::insertItem: cannot insert itself");
       
   277         return;
       
   278     }
       
   279     d->addChildLayoutItem(item);
       
   280 
       
   281     Q_ASSERT(item);
       
   282     d->fixIndex(&index);
       
   283     d->engine.insertRow(index, d->orientation);
       
   284     new QGridLayoutItem(&d->engine, item, d->gridRow(index), d->gridColumn(index), 1, 1, 0, index);
       
   285     invalidate();
       
   286 }
       
   287 
       
   288 /*!
       
   289     Inserts a stretch of \a stretch at \a index, or before any item that is
       
   290     currently at \a index.
       
   291 
       
   292     \sa addStretch(), setStretchFactor(), setItemSpacing(), insertItem()
       
   293 */
       
   294 void QGraphicsLinearLayout::insertStretch(int index, int stretch)
       
   295 {
       
   296     Q_D(QGraphicsLinearLayout);
       
   297     d->fixIndex(&index);
       
   298     d->engine.insertRow(index, d->orientation);
       
   299     d->engine.setRowStretchFactor(index, stretch, d->orientation);
       
   300     invalidate();
       
   301 }
       
   302 
       
   303 /*!
       
   304     Removes \a item from the layout without destroying it. Ownership of
       
   305     \a item is transferred to the caller.
       
   306 
       
   307     \sa removeAt(), insertItem()
       
   308 */
       
   309 void QGraphicsLinearLayout::removeItem(QGraphicsLayoutItem *item)
       
   310 {
       
   311     Q_D(QGraphicsLinearLayout);
       
   312     if (QGridLayoutItem *gridItem = d->engine.findLayoutItem(item)) {
       
   313         item->setParentLayoutItem(0);
       
   314         d->removeGridItem(gridItem);
       
   315         delete gridItem;
       
   316         invalidate();
       
   317     }
       
   318 }
       
   319 
       
   320 /*!
       
   321     Removes the item at \a index without destroying it. Ownership of the item
       
   322     is transferred to the caller.
       
   323 
       
   324     \sa removeItem(), insertItem()
       
   325 */
       
   326 void QGraphicsLinearLayout::removeAt(int index)
       
   327 {
       
   328     Q_D(QGraphicsLinearLayout);
       
   329     if (index < 0 || index >= d->engine.itemCount()) {
       
   330         qWarning("QGraphicsLinearLayout::removeAt: invalid index %d", index);
       
   331         return;
       
   332     }
       
   333     if (QGridLayoutItem *gridItem = d->engine.itemAt(index)) {
       
   334         if (QGraphicsLayoutItem *layoutItem = gridItem->layoutItem())
       
   335             layoutItem->setParentLayoutItem(0);
       
   336         d->removeGridItem(gridItem);
       
   337         delete gridItem;
       
   338         invalidate();
       
   339     }
       
   340 }
       
   341 
       
   342 /*!
       
   343   Sets the layout's spacing to \a spacing. Spacing refers to the
       
   344   vertical and horizontal distances between items.
       
   345 
       
   346    \sa setItemSpacing(), setStretchFactor(), QGraphicsGridLayout::setSpacing()
       
   347 */
       
   348 void QGraphicsLinearLayout::setSpacing(qreal spacing)
       
   349 {
       
   350     Q_D(QGraphicsLinearLayout);
       
   351     if (spacing < 0) {
       
   352         qWarning("QGraphicsLinearLayout::setSpacing: invalid spacing %g", spacing);
       
   353         return;
       
   354     }
       
   355     d->engine.setSpacing(spacing, Qt::Horizontal | Qt::Vertical);
       
   356     invalidate();
       
   357 }
       
   358 
       
   359 /*!
       
   360   Returns the layout's spacing. Spacing refers to the
       
   361   vertical and horizontal distances between items.
       
   362 
       
   363   \sa setSpacing()
       
   364  */
       
   365 qreal QGraphicsLinearLayout::spacing() const
       
   366 {
       
   367     Q_D(const QGraphicsLinearLayout);
       
   368     return d->engine.spacing(d->styleInfo(), d->orientation);
       
   369 }
       
   370 
       
   371 /*!
       
   372     Sets the spacing after item at \a index to \a spacing.
       
   373 */
       
   374 void QGraphicsLinearLayout::setItemSpacing(int index, qreal spacing)
       
   375 {
       
   376     Q_D(QGraphicsLinearLayout);
       
   377     d->engine.setRowSpacing(index, spacing, d->orientation);
       
   378     invalidate();
       
   379 }
       
   380 /*!
       
   381     Returns the spacing after item at \a index.
       
   382 */
       
   383 qreal QGraphicsLinearLayout::itemSpacing(int index) const
       
   384 {
       
   385     Q_D(const QGraphicsLinearLayout);
       
   386     return d->engine.rowSpacing(index, d->orientation);
       
   387 }
       
   388 
       
   389 /*!
       
   390     Sets the stretch factor for \a item to \a stretch. If an item's stretch
       
   391     factor changes, this function will invalidate the layout.
       
   392 
       
   393     Setting \a stretch to 0 removes the stretch factor from the item, and is
       
   394     effectively equivalent to setting \a stretch to 1.
       
   395 
       
   396     \sa stretchFactor()
       
   397 */
       
   398 void QGraphicsLinearLayout::setStretchFactor(QGraphicsLayoutItem *item, int stretch)
       
   399 {
       
   400     Q_D(QGraphicsLinearLayout);
       
   401     if (!item) {
       
   402         qWarning("QGraphicsLinearLayout::setStretchFactor: cannot assign"
       
   403                  " a stretch factor to a null item");
       
   404         return;
       
   405     }
       
   406     if (stretchFactor(item) == stretch)
       
   407         return;
       
   408     d->engine.setStretchFactor(item, stretch, d->orientation);
       
   409     invalidate();
       
   410 }
       
   411 
       
   412 /*!
       
   413     Returns the stretch factor for \a item. The default stretch factor is 0,
       
   414     meaning that the item has no assigned stretch factor.
       
   415 
       
   416     \sa setStretchFactor()
       
   417 */
       
   418 int QGraphicsLinearLayout::stretchFactor(QGraphicsLayoutItem *item) const
       
   419 {
       
   420     Q_D(const QGraphicsLinearLayout);
       
   421     if (!item) {
       
   422         qWarning("QGraphicsLinearLayout::setStretchFactor: cannot return"
       
   423                  " a stretch factor for a null item");
       
   424         return 0;
       
   425     }
       
   426     return d->engine.stretchFactor(item, d->orientation);
       
   427 }
       
   428 
       
   429 /*!
       
   430     Sets the alignment of \a item to \a alignment. If \a item's alignment
       
   431     changes, the layout is automatically invalidated.
       
   432 
       
   433     \sa alignment(), invalidate()
       
   434 */
       
   435 void QGraphicsLinearLayout::setAlignment(QGraphicsLayoutItem *item, Qt::Alignment alignment)
       
   436 {
       
   437     Q_D(QGraphicsLinearLayout);
       
   438     if (this->alignment(item) == alignment)
       
   439         return;
       
   440     d->engine.setAlignment(item, alignment);
       
   441     invalidate();
       
   442 }
       
   443 
       
   444 /*!
       
   445     Returns the alignment for \a item. The default alignment is
       
   446     Qt::AlignCenter.
       
   447 
       
   448     The alignment decides how the item is positioned within its assigned space
       
   449     in the case where there's more space available in the layout than the
       
   450     widgets can occupy.
       
   451 
       
   452     \sa setAlignment()
       
   453 */
       
   454 Qt::Alignment QGraphicsLinearLayout::alignment(QGraphicsLayoutItem *item) const
       
   455 {
       
   456     Q_D(const QGraphicsLinearLayout);
       
   457     return d->engine.alignment(item);
       
   458 }
       
   459 
       
   460 #if 0 // ###
       
   461 QSizePolicy::ControlTypes QGraphicsLinearLayout::controlTypes(LayoutSide side) const
       
   462 {
       
   463     return d->engine.controlTypes(side);
       
   464 }
       
   465 #endif
       
   466 
       
   467 /*!
       
   468     \reimp
       
   469 */
       
   470 int QGraphicsLinearLayout::count() const
       
   471 {
       
   472     Q_D(const QGraphicsLinearLayout);
       
   473     return d->engine.itemCount();
       
   474 }
       
   475 
       
   476 /*!
       
   477     \reimp
       
   478     When iterating from 0 and up, it will return the items in the visual arranged order.
       
   479 */
       
   480 QGraphicsLayoutItem *QGraphicsLinearLayout::itemAt(int index) const
       
   481 {
       
   482     Q_D(const QGraphicsLinearLayout);
       
   483     if (index < 0 || index >= d->engine.itemCount()) {
       
   484         qWarning("QGraphicsLinearLayout::itemAt: invalid index %d", index);
       
   485         return 0;
       
   486     }
       
   487     QGraphicsLayoutItem *item = 0;
       
   488     if (QGridLayoutItem *gridItem = d->engine.itemAt(index))
       
   489         item = gridItem->layoutItem();
       
   490     return item;
       
   491 }
       
   492 
       
   493 /*!
       
   494     \reimp
       
   495 */
       
   496 void QGraphicsLinearLayout::setGeometry(const QRectF &rect)
       
   497 {
       
   498     Q_D(QGraphicsLinearLayout);
       
   499     QGraphicsLayout::setGeometry(rect);
       
   500     QRectF effectiveRect = geometry();
       
   501     qreal left, top, right, bottom;
       
   502     getContentsMargins(&left, &top, &right, &bottom);
       
   503     Qt::LayoutDirection visualDir = d->visualDirection();
       
   504     d->engine.setVisualDirection(visualDir);
       
   505     if (visualDir == Qt::RightToLeft)
       
   506         qSwap(left, right);
       
   507     effectiveRect.adjust(+left, +top, -right, -bottom);
       
   508 #ifdef QT_DEBUG
       
   509     if (qt_graphicsLayoutDebug()) {
       
   510         static int counter = 0;
       
   511         qDebug() << counter++ << "QGraphicsLinearLayout::setGeometry - " << rect;
       
   512         dump(1);
       
   513     }
       
   514 #endif
       
   515     d->engine.setGeometries(d->styleInfo(), effectiveRect);
       
   516 #ifdef QT_DEBUG
       
   517     if (qt_graphicsLayoutDebug()) {
       
   518         qDebug() << "post dump";
       
   519         dump(1);
       
   520     }
       
   521 #endif
       
   522 }
       
   523 
       
   524 /*!
       
   525     \reimp
       
   526 */
       
   527 QSizeF QGraphicsLinearLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
       
   528 {
       
   529     Q_D(const QGraphicsLinearLayout);
       
   530     qreal left, top, right, bottom;
       
   531     getContentsMargins(&left, &top, &right, &bottom);
       
   532     return d->engine.sizeHint(d->styleInfo(), which , constraint) + QSizeF(left + right, top + bottom);
       
   533 }
       
   534 
       
   535 /*!
       
   536     \reimp
       
   537 */
       
   538 void QGraphicsLinearLayout::invalidate()
       
   539 {
       
   540     Q_D(QGraphicsLinearLayout);
       
   541     d->engine.invalidate();
       
   542     QGraphicsLayout::invalidate();
       
   543 }
       
   544 
       
   545 #ifdef QT_DEBUG
       
   546 void QGraphicsLinearLayout::dump(int indent) const
       
   547 {
       
   548     if (qt_graphicsLayoutDebug()) {
       
   549         Q_D(const QGraphicsLinearLayout);
       
   550         qDebug("%*s%s layout", indent, "",
       
   551                d->orientation == Qt::Horizontal ? "Horizontal" : "Vertical");
       
   552         d->engine.dump(indent + 1);
       
   553     }
       
   554 }
       
   555 #endif
       
   556 
       
   557 QT_END_NAMESPACE
       
   558         
       
   559 #endif //QT_NO_GRAPHICSVIEW