Codebase list dillo / upstream/3_hg20110824 doc / dw-widget-sizes.doc
upstream/3_hg20110824

Tree @upstream/3_hg20110824 (Download .tar.gz)

dw-widget-sizes.doc @upstream/3_hg20110824raw · history · blame

/** \page dw-widget-sizes Sizes of Dillo Widgets

<h2>Allocation</h2>

Each widget has an \em allocation at a given time, this includes

<ul>
<li> the position (\em x, \em y) relative to the upper left corner of the
     canvas, and
<li> the size (\em width, \em ascent, \em descent).
</ul>

The \em canvas is the whole area available for the widgets, in most
cases, only a part is seen in a viewport. The allocation of the toplevel widget is exactly the allocation of the canvas, i.e.

<ul>
<li> the position of the toplevel widget is always (0, 0), and
<li> the canvas size is defined by the size of the toplevel widget.
</ul>

The size of a widget is not simply defined by the width and the
height, instead, widgets may have a base line, and so are vertically
divided into an ascender (which height is called \em ascent), and a
descender (which height is called \em descent). The total height is so
the sum of \em ascent and \em descent.

Sizes of zero are allowed. The upper limit for the size of a widget is
defined by the limits of the C++ type \em int.

\image html dw-size-of-widget.png Allocation of a Widget

In the example in the image, the widget has the following allocation:

<ul>
<li>\em x = 50
<li>\em y = 50
<li>\em width = 150
<li>\em ascent = 150
<li>\em descent = 100
</ul>

The current allocation of a widget is hold in
dw::core::Widget::allocation. It can be set from outside by
calling dw::core::Widget::sizeAllocate. This is a concrete method,
which will call dw::core::Widget::sizeAllocateImpl (see code of
dw::core::Widget::sizeAllocate for details).

For trivial widgets (like dw::Bullet),
dw::core::Widget::sizeAllocateImpl does not need to be
implemented. For more complex widgets, the implementation should call
dw::core::Widget::sizeAllocate (not
dw::core::Widget::sizeAllocateImpl) on all child widgets, with
appropriate child allocations. dw::core::Widget::allocation should not
be changed here, this is already done in
dw::core::Widget::sizeAllocate.

<h2>Requisitions</h2>

A widget may prefer a given size for the allocation. This size, the
\em requisition, should be returned by the method
dw::core::Widget::sizeRequestImpl. In the simplest case, this is
independent of the context, e.g. for an
image. dw::Image::sizeRequestImpl returns the following size:

<ul>
<li> If no buffer has yet been assigned (see dw::Image for more details),
     the size necessary for the alternative text is returned. If no
     alternative text has been set, zero is returned.

<li> If a buffer has been assigned (by dw::Image::setBuffer), the root
     size is returned (i.e. the original size of the image to display).
</ul>

This is a bit simplified, dw::Image::sizeRequestImpl should also deal
with margins, borders and paddings, see dw::core::style.

From the outside, dw::Image::sizeRequest should be called, which does
a bit of optimization. Notice that in dw::Image::sizeRequestImpl, no
optimization like lazy evaluation is necessary, this is already done
in dw::Image::sizeRequest.

A widget, which has children, will likely call dw::Image::sizeRequest
on its children, to calculate the total requisition.

The caller (this is either the dw::core::Layout, or the parent
widget), may, but also may not consider the requisition. Instead, a
widget must deal with any allocation. (For example, dw::Image scales
the image buffer when allocated at another size.)

<h2>Size Hints</h2>

Some widgets do not have an inherent size, but depend on the context,
e.g. the viewport size. These widgets should adhere to <i>size hints</i>,
i.e. implement the methods dw::core::Widget::setWidth,
dw::core::Widget::setAscent and dw::core::Widget::setDescent. The values
passed to the callees are

<ul>
<li> the viewport size (ascent is the heigt here, while descent is 0) for
     the toplevel widget, and
<li> determined by the parent for its child widgets.
</ul>

Generally, the values should define the available space for the
widget.

A widget, which depends on size hints, should call
dw::core::Widget::queueResize, when apropriate.

\todo There should be a definition of "available space".

<h2>Width Extremes</h2>

dw::Table uses width extremes for fast calculation of column
widths. The structure dw::core::Extremes represents the minimal and
maximal width of a widget, as defined by:

<ul>
<li> the minimal width is the smallest width, at which a widget can still
     display contents, and
<li> the maximal width is the largest width, above which increasing the width
     does not make any sense.
</ul>

Especially the latter is vaguely defined, here are some examples:

<ul>
<li> For those widgets, which do not depend on size hints, the minimal and
     the maximal width is the inherent width (the one returned by
     dw::core::Widget::sizeRequest).

<li> For a textblock, the minimal width is the width of the widest
     (unbreakable) word, the maximal width is the width of the total
     paragraph (stretching a paragraph further would only waste space).
     Actually, the implementation of dw::Textblock::getExtremesImpl is
     a bit more complex.

<li> dw::Table is an example, where the width extremes are calculated
     from the width extremes of the children.
</ul>

Handling width extremes is similar to handling requisitions, a widget
must implement dw::core::Widget::getExtremesImpl, but a caller will
use dw::core::Widget::getExtremes.


<h2>Resizing</h2>

When the widget changes its size (requisition), it should call
dw::core::Widget::queueResize. The next call of
dw::core::Widget::sizeRequestImpl should then return the new
size. See dw::Image::setBuffer as an example.

Interna are described in the code of dw::core::Widget::queueResize.

<h3>Incremental Resizing</h3>

A widget may calculate its size based on size calculations already
done before. In this case, a widget must exactly know the reasons, why
a call of dw::core::Widget::sizeRequestImpl is necessary. To make use
of this, a widget must implement the following:

<ol>
<li> There is a member dw::core::Widget::parentRef, which is
     totally under control of the parent widget (and so sometimes not
     used at all). It is necessary to define how parentRef is used
     by a specific parent widget, and it has to be set to the correct
     value whenever necessary.

<li> The widget must implement dw::core::Widget::markSizeChange and
     dw::core::Widget::markExtremesChange, these methods are called in
     two cases:

     <ol>
     <li> directly after dw::core::Widget::queueResize, with the argument
          ref was passed to dw::core::Widget::queueResize, and
     <li> if a child widget has called dw::core::Widget::queueResize,
          with the value of the parent_ref member of this child.
     </ol>
</ol>

This way, a widget can exactly keep track on size changes, and so
implement resizing in a faster way. A good example on how to use this
is dw::Textblock.

*/