/****************************************************************************
**
** Explanation of the layout subsystem.
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the Qt GUI Toolkit.
** EDITIONS: FREE, PROFESSIONAL, ENTERPRISE
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

/*!
    \page layout.html

    \title Layout Classes
    \ingroup architecture
    \ingroup classlists
    \brief A tour of the standard layout managers and an introduction
    to custom layouts.

    The Qt layout system provides a simple and powerful way of
    specifying the layout of child widgets.

    By specifying the logical layout once, you get the following
    benefits:

    \list
    \o Positioning of child widgets.
    \o Sensible default sizes for windows.
    \o Sensible minimum sizes for windows.
    \o Resize handling.
    \o Automatic update when contents change:
        \list
        \o Font size, text or other contents of child widgets.
        \o Hiding or showing a child widget.
        \o Removal of child widgets.
        \endlist
    \endlist

    The disadvantage of hand-written layout code is that it isn't
    very convenient when you're experimenting with the design of a
    form and you have to go through the compile, link and run cycle
    for each change. Our solution is \l{Qt Designer}, a GUI visual
    design tool which makes it fast and easy to experiment with
    layouts and which generates the C++ layout code for you.

    Qt's layout classes were designed for hand-written C++ code, so
    they're easy to understand and use. The code generated for forms
    created using \l{Qt Designer} also uses the layout classes.

    Topics:

    \tableofcontents

    \section1 Horizontal, Vertical, and Grid Layouts

    The easiest way to give you widgets a good layout is to use the
    built-in layout managers: QHBoxLayout, QVBoxLayout, and
    QGridLayout. These classes inherit from QLayout, which in turn
    derives from QObject (not QWidget). They take care of geometry
    management for a set of widgets. To create more complex layouts,
    you can nest layout managers inside each other.

    \list
    \o A QHBoxLayout lays out widgets in a horizontal row,
       from left to right (or right to left for right-to-left
       languages).

       \image qhboxlayout-with-5-children.png A QHBoxLayout with five child widgets

    \o A QVBoxLayout lays out widgets in a vertical column, from top
       to bottom.

       \image qvboxlayout-with-5-children.png A QVBoxLayout with five child widgets

    \o A QGridLayout lays out widgets in a two-dimensional grid.
       Widgets can occupy multiple cells.

       \image qgridlayout-with-5-children.png A QGridLayout with five child widgets
    \endlist

    The following code creates a QHBoxLayout that manages the
    geometry of five \l{QPushButton}s, as shown on the first
    screenshot above:

    \quotefromfile snippets/layouts/layouts.cpp
    \skipto window = new QWidget
    \printline window
    \printline button1
    \printuntil button5
    \printline layout = new QHBoxLayout
    \printuntil setLayout(layout)
    \printline show

    The code for QVBoxLayout is identical, except the line where the
    layout is created. The code for QGridLayout is a bit different,
    because we need to specify the row and column position of the
    child widget:

    \skipto layout = new QVBoxLayout
    \skipto window = new QWidget
    \printline window
    \printline button1
    \printuntil button5
    \printline layout = new QGridLayout
    \printuntil setLayout(layout)
    \printline show

    The third QPushButton spans 2 columns. This is possible by
    specifying 2 as the fourth argument to QGridLayout::addWidget().

    When you use a layout, you don't need to pass a parent when
    constructing the child widgets. The layout will automatically
    reparent the widgets (using QWidget::setParent()) so that they
    are children of the widget on which the layout is installed.

    \bold{Important:} Widgets in a layout are children of the widget
    on which the layout is installed, \e not of the layout itself.
    Widgets can only have other widgets as parent, not layouts.

    You can nest layouts using \c addLayout() on a layout; the inner
    layout then becomes a child of the layout it is inserted into.
    The \l{layouts/basiclayouts}{Basic Layouts} example uses this
    feature to create a complex dialog.

    \section1 Adding Widgets to a Layout

    When you add widgets to a layout, the layout process works as
    follows:

    \list 1
    \o All the widgets will initially be allocated an amount of space in
       accordance with their QWidget::sizePolicy(). 

    \o If any of the widgets have stretch factors set, with a value
       greater than zero, then they are allocated space in proportion
       to their stretch factor (explained below).

    \o If any of the widgets have stretch factors set to zero they
       will only get more space if no other widgets want the space.
       Of these, space is allocated to widgets with an
       \l{QSizePolicy::Expanding}{Expanding} size policy first.

    \o Any widgets that are allocated less space than their minimum size
       (or minimum size hint if no minimum size is specified) are allocated
       this minimum size they require. (Widgets don't have to have a minimum
       size or minimum size hint in which case the strech factor is their
       determining factor.)

    \o Any widgets that are allocated more space than their maximum size
       are allocated the maximum size space they require. (Widgets don't have
       to have a maximum size in which case the strech factor is their
       determining factor.)
    \endlist

    \section2 Stretch Factors
    \keyword stretch factor

    Widgets are normally created without any stretch factor set. When
    they are laid out in a layout the widgets are given a share of
    space in accordance with their QWidget::sizePolicy() or their
    minimum size hint whichever is the greater. Stretch factors are
    used to change how much space widgets are given in proportion to
    one another.

    If we have three widgets laid out using a QHBoxLayout with no
    stretch factors set we will get a layout like this:

    \img layout1.png Three widgets in a row

    If we apply stretch factors to each widget, they will be laid out in
    proportion (but never less than their minimum size hint), e.g.

    \img layout2.png Three widgets with different stretch factors in a row

    \section1 Custom Widgets in Layouts

    When you make your own widget class, you should also communicate its
    layout properties. If the widget has a QLayout, this is already taken
    care of. If the widget does not have any child widgets, or uses manual
    layout, you can change the behavior of the widget using any or all of
    the following mechanisms:

    \list
    \o Reimplement QWidget::sizeHint() to return the preferred size of the
       widget.
    \o Reimplement QWidget::minimumSizeHint() to return the smallest size the
       widget can have.
    \o Call QWidget::setSizePolicy() to specify the space requirements of the
       widget.
    \endlist

    Call QWidget::updateGeometry() whenever the size hint, minimum
    size hint or size policy changes. This will cause a layout
    recalculation. Multiple consecutive calls to
    QWidget::updateGeometry() will only cause one recalculation.

    If the preferred height of your widget depends on its actual
    width (e.g., a label with automatic word-breaking), set the
    \l{QSizePolicy::hasHeightForWidth()}{height-for-width} flag in
    the widget's \l{QWidget::sizePolicy}{size policy} and reimplement
    QWidget::heightForWidth().

    Even if you implement QWidget::heightForWidth(), it is still a
    good idea to provide a reasonable sizeHint().

    For further guidance when implementing these functions, see the
    \l{http://doc.trolltech.com/qq/qq04-height-for-width.html}{Trading
    Height for Width} article in \e{Qt Quarterly}.

    \section1 Layout Issues

    The use of rich text in a label widget can introduce some
    problems to the layout of its parent widget. Problems occur due
    to the way rich text is handled by Qt's layout managers when the
    label is word wrapped.

    In certain cases the parent layout is put into
    QLayout::FreeResize mode, meaning that it will not adapt the
    layout of its contents to fit inside small sized windows, or even
    prevent the user from making the window too small to be usable.
    This can be overcome by subclassing the problematic widgets, and
    implementing suitable sizeHint() and minimumSizeHint() functions.

    \section1 Manual Layout

    If you are making a one-of-a-kind special layout, you can also
    make a custom widget as described above. Reimplement
    QWidget::resizeEvent() to calculate the required distribution of
    sizes and call \l{QWidget::setGeometry()}{setGeometry()} on each
    child.

    The widget will get an event of type QEvent::LayoutRequest when
    the layout needs to be recalculated. Reimplement QWidget::event()
    to handle QEvent::LayoutRequest events.

    \section1 Writing Custom Layout Managers

    An alternative to manual layout is to write your own layout
    manager by subclassing QLayout. The
    \l{layouts/borderlayout}{Border Layout} and
    \l{layouts/flowlayout}{Flow Layout} examples show how to do this.

    Here we present an example in detail. The class CardLayout is
    inspired by the Java layout manager of the same name. It lays out
    the items (widgets or nested layouts) on top of each other, each
    item offset by QLayout::spacing().

    To write your own layout class, you must define the following:
    \list
    \o A data structure to store the items handled by the layout. Each
    item is a \link QLayoutItem QLayoutItem\endlink. We will use a
    QList in this example.
    \o \link QLayout::addItem() addItem() \endlink, how to add items to
    the layout.
    \o \link QLayout::setGeometry() setGeometry() \endlink, how to perform
    the layout.
    \o \link QLayout::sizeHint() sizeHint() \endlink, the preferred size
    of the layout.
    \o \link QLayout::itemAt() itemAt() \endlink, how to iterate over
    the layout.
    \o \link QLayout::takeAt() takeAt() \endlink, how to remove items
     from the layout.
    \endlist

    In most cases, you will also implement \link QLayout::minimumSize()
    minimumSize\endlink().

    \section2 The Header File (\c card.h)

    \code
        #ifndef CARD_H
        #define CARD_H

        #include <QLayout>
        #include <QList>

        class CardLayout : public QLayout
        {
        public:
            CardLayout(QWidget *parent, int dist)
                : QLayout(parent, 0, dist) {}
            CardLayout(QLayout *parent, int dist)
                : QLayout(parent, dist) {}
            CardLayout(int dist)
                : QLayout(dist) {}
            ~CardLayout();

            void addItem(QLayoutItem *item);
            QSize sizeHint() const;
            QSize minimumSize() const;
            QLayoutItem *itemAt(int) const;
            QLayoutItem *takeAt(int);
            void setGeometry(const QRect &rect);

        private:
            QList<QLayoutItem*> list;
        };
        #endif
    \endcode

    \section2 The Implementation File (\c card.cpp)

    \code
        #include "card.h"
    \endcode

    First we define two functions that iterate over the layout: 
    itemAt() and takeAt(). These functions are used internally by the
    layout system to handle deletion of widgets. They are also available
    for application programmers. 

    ItemAt() returns the item at the given index. takeAt() removes the
    item at the given index, and returns it. In this case we use the list
    index as the layout index. In other cases where we have a more complex
    data structure, we may have to spend more effort defining a linear
    order for the items.

    \code
        QLayoutItem *CardLayout::itemAt(int idx) const
        {
            // QList::value() performs index checking, and returns 0 if we are
            // outside the valid range
            return list.value(idx);
        }

        QLayoutItem *CardLayout::takeAt(int idx)
        {
            // QList::take does not do index checking
            return idx >= 0 && idx < list.size() ? list.takeAt(idx) : 0;
        }
    \endcode

    addItem() implements the default placement strategy for layout items.
    It must be implemented. It is used by QLayout::add(), by the QLayout
    constructor that takes a layout as parent. If your layout
    has advanced placement options that require parameters, you must
    provide extra access functions such as the row and column spanning
    overloads of \l QGridLayout::addItem(), addWidget(), and addLayout().

    \code
        void CardLayout::addItem(QLayoutItem *item)
        {
            list.append(item);
        }
    \endcode

    The layout takes over responsibility of the items added. Since
    QLayoutItem does not inherit QObject, we must delete the items
    manually. The function QLayout::deleteAllItems() uses takeAt()
    defined above to delete all the items in the layout.

    \code
        CardLayout::~CardLayout()
        {
            deleteAllItems();
        }
    \endcode

    The setGeometry() function actually performs the layout. The rectangle
    supplied as an argument does not include margin(). If relevant, use
    spacing() as the distance between items.

    \code
        void CardLayout::setGeometry(const QRect &r)
        {
            QLayout::setGeometry(r);

            if (list.size() == 0)
                return;

            int w = r.width() - (list.count() - 1) * spacing();
            int h = r.height() - (list.count() - 1) * spacing();
            int i = 0;
            while (i < list.size()) {
                QLayoutItem *o = list.at(i);
                QRect geom(r.x() + i * spacing(), r.y() + i * spacing(), w, h);
                o->setGeometry(geom);
                ++i;
            }
        }
    \endcode

    sizeHint() and minimumSize() are normally very similar in
    implementation. The sizes returned by both functions should include
    spacing(), but not margin().

    \code
        QSize CardLayout::sizeHint() const
        {
            QSize s(0,0);
            int n = list.count();
            if (n > 0)
                s = QSize(100,70); //start with a nice default size
            int i = 0;
            while (i < n) {
                QLayoutItem *o = list.at(i);
                s = s.expandedTo(o->sizeHint());
                ++i;
            }
            return s + n*QSize(spacing(), spacing());
        }

        QSize CardLayout::minimumSize() const
        {
            QSize s(0,0);
            int n = list.count();
            int i = 0;
            while (i < n) {
                QLayoutItem *o = list.at(i);
                s = s.expandedTo(o->minimumSize());
                ++i;
            }
            return s + n*QSize(spacing(), spacing());
        }
    \endcode

    \section2 Further Notes

    This layout does not handle height for width.

    We ignore QLayoutItem::isEmpty(), this means that the layout will
    treat hidden widgets as visible.

    For complex layouts, speed can be greatly increased by caching
    calculated values. In that case, implement QLayoutItem::invalidate()
    to mark the cached data as dirty.

    Calling QLayoutItem::sizeHint(), etc. may be expensive, so you should
    store the value in a local variable if you need it again later in the
    same function.

    You should not call QLayoutItem::setGeometry() twice on the same item
    in the same function. That can be very expensive if the item has
    several child widgets, because it must do a complete layout
    every time. Instead, calculate the geometry and then set it. (This
    doesn't only apply to layouts, you should do the same if you implement
    your own resizeEvent().)
*/
