/** \page dw-grows GROWS - Grand Redesign Of Widget Sizes
The complex "widget
sizes" is currently divided into three documents: \ref
dw-widget-sizes, **Grand Redesign Of Widget Sizes** (this document),
and \ref dw-size-request-pos. Furthermore, there are some notes in
\ref dw-miscellaneous.
This paper describes (will describe) some design changes to
calculating widget sizes. Goals are:
- Simplification of widget size calculation by the parent widget;
dw::Textblock::calcWidgetSize, dw::OutOfFlowMgr::ensureFloatSize
etc. should become simpler or perhaps even obsolete.
- Making the implementation of some features possible:
- *max-width*, *max-height*, *min-width*, *min-height*;
- correct aspect ratio for images with only one percentage size defined;
- *display: inline-block*;
- <button>.
A short sketch
==============
**dw::core::Widget::sizeRequest and dw::core::Widget::getExtremes will
return final results.** The caller does not have to correct the size,
e. g. when percentages are defined. As an example,
dw::Textblock::calcWidgetSize has already become much simpler.
**A new hierarchy, *container*:** Aside from dw::core::Widget::parent
and dw::core::Widget::generator, there is a third hierarchy
dw::core::Widget::container, which is (unlike *generator*) always a
direct ancestor, and represents what in CSS is called *containing
block*. Containers are important to define the "context size", which
is (not solely) used for percentage sizes.
(There is another "containing block", dw::Textblock::containingBlock;
these may be consolidated some day.)
**The process of size calculation is split between the widget itself
and its container:**
- The container provides some abstract methods:
dw::core::Widget::getAvailWidthOfChild,
dw::core::Widget::getAvailHeightOfChild,
dw::core::Widget::correctRequisitionOfChild, and
dw::core::Widget::correctExtremesOfChild, which can be used in the
actual implementation of dw::core::Widget::sizeRequestImpl;
different containers with different ways how to arrange their
children will implement these methods in a different way. (Simple
example: the *available width* for children within a textblock is
the *available width* for the textblock itself, minus
margin/border/padding; on the other hand, it is completely different
for children of tables, for which a complex column width calculation
is used.)
- The actual size calculation is, however, controlled by the widget
itself, which only *uses* these methods above.
Update: This is not fully correct; the parents are also involved
for calculating available widths and heights, at least when CSS 'width'
and 'height' are not set.
**Size hints are removed.** Instead, the container methods in the
previous paragraph are used. Changes of container sizes (especially
viewport the size) are handled in a different way.
**Extremes are extended by intrinsic values.** In some cases (see
dw::Table::forceCalcCellSizes, case *minWidth* > *totalWidth*, for an
example) it is useful to know about minimal and maximal width of a
widget independent of CSS attributes. For this, dw::core::Extremes is
extended by:
- dw::core::Extremes::minWidthIntrinsic and
- dw::core::Extremes::maxWidthIntrinsic.
The rules for the calculation:
1. If a widget has no children, it calculates *minWidthIntrinsic* and
*maxWidthIntrinsic* as those values not affected by CSS hints.
(dw::core::Widget::correctExtremes will not change these values.)
2. A widget must calculate *minWidthIntrinsic* and *maxWidthIntrinsic*
from *minWidthIntrinsic* and *maxWidthIntrinsic* of its children,
and *minWidth* and *maxWidth* from *minWidth* and *maxWidth* of its
children.
3. At the end, *minWidth* and *maxWidth* of a widget are corrected by
CSS attributes. (dw::core::Widget::correctExtremes will do this.)
Notice: Currently, dw::core::Widget::getExtremesImpl must
set all four members in dw::core::Extremes; this may change.
Another **extension of extremes: *adjustmentWidth*.** This is used as
minimum for the width, when "adjust_min_width" (or,
"adjust_table_min_width", respectively) is set.
The rules for the calculation:
1. If a widget has no children, it can choose a suitable value,
typically based on dw::core::Extremes::minWidth and
dw::core::Extremes::minWidthIntrinsic.
2. A widget must calculate *adjustmentWidth* from *adjustmentWidth* of
its children.
*Note:* An implementation of dw::core::Widget::getExtremesImpl may set
this value *after* calling dw::core::Widget::correctExtremesOfChild,
so that it cannot be used for the correction of extremes. In this case
*useAdjustmentWidth = false* should be passed to
dw::core::Widget::correctExtremesOfChild. On the other hand, if known
before, *useAdjustmentWidth* should be set to *true*.
Rules for *new* methods related to resizing
===========================================
- Of course, *sizeRequestImpl* may (should) call *correctRequisition*,
and *getExtremesImpl* may (should) call *correctExtremes*.
- *sizeRequestImpl* (and *correctRequisition*) is allowed to call
*getAvailWidth* and *getAvailHeight* with *forceValue* set, but
*getExtremesImpl* (and *correctExtremes*) is allowed to call these
only with *forceValue* unset.
- For this reason, *sizeRequestImpl* is indeed allowed to call
*getExtremes* (dw::Table does so), but the opposite
(*getExtremesImpl* calling *sizeRequest*) is not allowed
anymore. (Before GROWS, the standard implementation
dw::core::Widget::getExtremesImpl did so.)
- Finally, *getAvailWidth* and *getAvailHeight* may call
*getExtremes*, if and only if *forceValue* is set.
Here is a diagram showing all permitted dependencies:
\dot
digraph G {
node [shape=record, fontname=Helvetica, fontsize=10, color="#c0c0c0"];
edge [arrowhead="open", arrowtail="none", color="#404040"];
"sizeRequest[Impl]" -> "getExtremes[Impl]";
"sizeRequest[Impl]" -> correctRequisition;
"getExtremes[Impl]" -> correctExtremes;
"sizeRequest[Impl]" -> "getAvail[Width|Height] (true)";
"getExtremes[Impl]" -> "getAvail[Width|Height] (false)";
correctRequisition -> "getAvail[Width|Height] (true)";
correctExtremes -> "getAvail[Width|Height] (false)";
"getAvail[Width|Height] (true)" -> "getExtremes[Impl]";
}
\enddot
Open issues
===========
**Do CSS size dimensions override intrinsic sizes in all cases?** If a
textblock needs at least, say, 100 pixels width so that the text can
be read, but has a specification "width: 50px", should half of the
text be invisible? Or should the width be corrected again to 100
pixels?
Currently, in the CSS size specification is honoured in all cases,
with one exception: see dw::Textblock::sizeRequestImpl and see
dw::Textblock::getExtremesImpl (the time when
dw::core::Widget::correctRequisition and
dw::core::Widget::correctExtremes, respectively, is called).
*Not* honouring the CSS size specification in all cases could improve
readability in some cases, so this could depend on a user preference.
**Update:** There is now a dillorc option adjust_min_width,
which is implemented for widths, but not heights (since it is based on
width extremes, but there are currently no height extremes).
Another problem is that in most cases, there is no clippping, so that
contents may exceed the allocation of the widget, but redrawing is not
necessarily triggered.
**Percentage values for margins and paddings, as well as negative
margins** are interesting applications, but have not been considered
yet. For negative margins, a new attribute
dw::core::Widget::extraSpace could solve the problem of widgets
sticking out of the allocation of parent.
**Clarify percentage heights.** Search in widget.cc, and compare
section 10.5 ('height') of the CSS 2.1 specification to section 10.2
('width').
**Fast queue resize does not work fully.** Example: run
*test/dw-simple-container-test* (dw_simple_container_test.cc), resize
(best maximize) the window and follow (e. g. by using RTFL) what
happens in consequence of dw::core::Layout::viewportSizeChanged. The
dw::SimpleContainer in the middle is not affected, so only the two
dw::Textblock's (at the top and at the bottom) call queueResize with
*fast = true*, and so get *NEEDS_RESIZE* set; but since it is not set
for the dw::SimpleContainer, *sizeRequest* is never called for the
bottom dw::Textblock.
There does not seem to be a real case for this problem in dillo, since
all widgets which may contain other widgets (except
dw::SimpleContainer, which is not used outside tests) use the
available width and height (dw::core::Widget::usesAvailWidth and
dw::core::Widget::usesAvailHeight), and so are always affected by
viewport size changes.
*/