aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/dw-grows.doc101
-rw-r--r--doc/dw-widget-sizes.doc24
-rw-r--r--dw/Makefile.am7
-rw-r--r--dw/alignedtablecell.cc (renamed from dw/tablecell.cc)35
-rw-r--r--dw/alignedtablecell.hh34
-rw-r--r--dw/bullet.cc11
-rw-r--r--dw/bullet.hh2
-rw-r--r--dw/image.cc80
-rw-r--r--dw/image.hh1
-rw-r--r--dw/layout.cc68
-rw-r--r--dw/layout.hh8
-rw-r--r--dw/listitem.cc2
-rw-r--r--dw/outofflowmgr.cc288
-rw-r--r--dw/outofflowmgr.hh12
-rw-r--r--dw/ruler.cc29
-rw-r--r--dw/ruler.hh9
-rw-r--r--dw/simpletablecell.cc58
-rw-r--r--dw/simpletablecell.hh24
-rw-r--r--dw/style.hh25
-rw-r--r--dw/table.cc1243
-rw-r--r--dw/table.hh69
-rw-r--r--dw/table_iterator.cc134
-rw-r--r--dw/tablecell.hh29
-rw-r--r--dw/textblock.cc321
-rw-r--r--dw/textblock.hh38
-rw-r--r--dw/textblock_iterator.cc2
-rw-r--r--dw/textblock_linebreaking.cc208
-rw-r--r--dw/types.hh2
-rw-r--r--dw/ui.cc78
-rw-r--r--dw/ui.hh10
-rw-r--r--dw/widget.cc698
-rw-r--r--dw/widget.hh88
-rw-r--r--lout/debug.hh8
-rw-r--r--lout/misc.hh15
-rw-r--r--src/table.cc5
-rw-r--r--test/dw_table.cc1
-rw-r--r--test/dw_table_aligned.cc6
37 files changed, 2233 insertions, 1540 deletions
diff --git a/doc/dw-grows.doc b/doc/dw-grows.doc
index 32800c19..8c2941dd 100644
--- a/doc/dw-grows.doc
+++ b/doc/dw-grows.doc
@@ -14,6 +14,103 @@ calculating widget sizes. Goals are:
- *display: inline-block*;
- <button>.
-(...)
-*/ \ No newline at end of file
+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.&nbsp;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.
+
+<div style="border: 2px solid #ffff00; margin-top: 0.5em;
+ margin-bottom: 0.5em; padding: 0.5em 1em; background-color: #ffffe0">
+ <b>Update:</b> 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.</div>
+
+**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.)
+
+<div style="border: 2px solid #ffff00; margin-top: 0.5em;
+ margin-bottom: 0.5em; padding: 0.5em 1em; background-color: #ffffe0">
+ <b>Notice:</b> Currently, dw::core::Widget::getExtremesImpl must
+ set all four members in dw::core::Extremes; this may change.</div>
+
+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.
+
+**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.
+
+*/
diff --git a/doc/dw-widget-sizes.doc b/doc/dw-widget-sizes.doc
index a9b6b00c..a82d3b99 100644
--- a/doc/dw-widget-sizes.doc
+++ b/doc/dw-widget-sizes.doc
@@ -1,5 +1,9 @@
/** \page dw-widget-sizes Sizes of Dillo Widgets
+<div style="border: 2px solid #ff4040; margin-bottom: 0.5em;
+padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b>
+Not up to date, see \ref dw-grows.</div>
+
Allocation
==========
@@ -87,23 +91,9 @@ the image buffer when allocated at another size.)
Size Hints
==========
-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
-
-- the viewport size (ascent is the heigt here, while descent is 0) for
- the toplevel widget, and
-- determined by the parent for its child widgets.
-
-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".
+<div style="border: 2px solid #ff4040; margin-bottom: 0.5em;
+padding: 0.5em 1em; background-color: #fff0f0"><b>Info:</b>
+Size hints have been removed, see \ref dw-grows.</div>
Width Extremes
diff --git a/dw/Makefile.am b/dw/Makefile.am
index 5306c5a5..25d8bbce 100644
--- a/dw/Makefile.am
+++ b/dw/Makefile.am
@@ -57,6 +57,8 @@ libDw_fltk_a_SOURCES = \
libDw_fltk_a_CXXFLAGS = @LIBFLTK_CXXFLAGS@
libDw_widgets_a_SOURCES = \
+ alignedtablecell.cc \
+ alignedtablecell.hh \
alignedtextblock.cc \
alignedtextblock.hh \
bullet.cc \
@@ -71,10 +73,11 @@ libDw_widgets_a_SOURCES = \
outofflowmgr.hh \
ruler.cc \
ruler.hh \
+ simpletablecell.cc \
+ simpletablecell.hh \
table.cc \
+ table_iterator.cc \
table.hh \
- tablecell.cc \
- tablecell.hh \
textblock.cc \
textblock_iterator.cc \
textblock_linebreaking.cc \
diff --git a/dw/tablecell.cc b/dw/alignedtablecell.cc
index cbd5e0bf..a9f091f3 100644
--- a/dw/tablecell.cc
+++ b/dw/alignedtablecell.cc
@@ -19,19 +19,19 @@
-#include "tablecell.hh"
+#include "alignedtablecell.hh"
#include "../lout/debug.hh"
#include <stdio.h>
namespace dw {
-int TableCell::CLASS_ID = -1;
+int AlignedTableCell::CLASS_ID = -1;
-TableCell::TableCell (TableCell *ref, bool limitTextWidth):
+AlignedTableCell::AlignedTableCell (AlignedTableCell *ref, bool limitTextWidth):
AlignedTextblock (limitTextWidth)
{
- DBG_OBJ_CREATE ("dw::TableCell");
- registerName ("dw::TableCell", &CLASS_ID);
+ DBG_OBJ_CREATE ("dw::AlignedTableCell");
+ registerName ("dw::AlignedTableCell", &CLASS_ID);
/** \bug ignoreLine1OffsetSometimes does not work? */
//ignoreLine1OffsetSometimes = true;
@@ -40,12 +40,29 @@ TableCell::TableCell (TableCell *ref, bool limitTextWidth):
setButtonSensitive(true);
}
-TableCell::~TableCell()
+AlignedTableCell::~AlignedTableCell()
{
DBG_OBJ_DELETE ();
}
-int TableCell::wordWrap(int wordIndex, bool wrapAll)
+bool AlignedTableCell::isBlockLevel ()
+{
+ return false;
+}
+
+int AlignedTableCell::applyPerWidth (int containerWidth,
+ core::style::Length perWidth)
+{
+ return core::style::multiplyWithPerLength (containerWidth, perWidth);
+}
+
+int AlignedTableCell::applyPerHeight (int containerHeight,
+ core::style::Length perHeight)
+{
+ return core::style::multiplyWithPerLength (containerHeight, perHeight);
+}
+
+int AlignedTableCell::wordWrap(int wordIndex, bool wrapAll)
{
Textblock::Word *word;
const char *p;
@@ -73,7 +90,7 @@ int TableCell::wordWrap(int wordIndex, bool wrapAll)
return ret;
}
-int TableCell::getValue ()
+int AlignedTableCell::getValue ()
{
Textblock::Word *word;
int i, wordIndex;
@@ -104,7 +121,7 @@ int TableCell::getValue ()
return w;
}
-void TableCell::setMaxValue (int maxValue, int value)
+void AlignedTableCell::setMaxValue (int maxValue, int value)
{
line1Offset = maxValue - value;
queueResize (OutOfFlowMgr::createRefNormalFlow (0), true);
diff --git a/dw/alignedtablecell.hh b/dw/alignedtablecell.hh
new file mode 100644
index 00000000..caf59307
--- /dev/null
+++ b/dw/alignedtablecell.hh
@@ -0,0 +1,34 @@
+#ifndef __DW_ALIGNEDTABLECELL_HH__
+#define __DW_ALIGNEDTABLECELL_HH__
+
+#include "core.hh"
+#include "alignedtextblock.hh"
+
+namespace dw {
+
+class AlignedTableCell: public AlignedTextblock
+{
+private:
+ int charWordIndex, charWordPos;
+
+protected:
+ int wordWrap (int wordIndex, bool wrapAll);
+
+ int getValue ();
+ void setMaxValue (int maxValue, int value);
+
+public:
+ static int CLASS_ID;
+
+ AlignedTableCell(AlignedTableCell *ref, bool limitTextWidth);
+ ~AlignedTableCell();
+
+ int applyPerWidth (int containerWidth, core::style::Length perWidth);
+ int applyPerHeight (int containerHeight, core::style::Length perHeight);
+
+ bool isBlockLevel ();
+};
+
+} // namespace dw
+
+#endif // __DW_ALIGNEDTABLECELL_HH__
diff --git a/dw/bullet.cc b/dw/bullet.cc
index af7f5451..b74f836c 100644
--- a/dw/bullet.cc
+++ b/dw/bullet.cc
@@ -27,6 +27,12 @@ namespace dw {
Bullet::Bullet ()
{
+ DBG_OBJ_CREATE ("dw::Bullet");
+}
+
+Bullet::~Bullet ()
+{
+ DBG_OBJ_DELETE ();
}
void Bullet::sizeRequestImpl (core::Requisition *requisition)
@@ -36,6 +42,11 @@ void Bullet::sizeRequestImpl (core::Requisition *requisition)
requisition->descent = 0;
}
+void Bullet::containerSizeChangedForChildren ()
+{
+ // Nothing to do.
+}
+
void Bullet::draw (core::View *view, core::Rectangle *area)
{
int x, y, l;
diff --git a/dw/bullet.hh b/dw/bullet.hh
index 98854abb..97a4909d 100644
--- a/dw/bullet.hh
+++ b/dw/bullet.hh
@@ -15,11 +15,13 @@ class Bullet: public core::Widget
{
protected:
void sizeRequestImpl (core::Requisition *requisition);
+ void containerSizeChangedForChildren ();
void draw (core::View *view, core::Rectangle *area);
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
public:
Bullet ();
+ ~Bullet ();
};
} // namespace dw
diff --git a/dw/image.cc b/dw/image.cc
index e71c8f2f..ae48961f 100644
--- a/dw/image.cc
+++ b/dw/image.cc
@@ -170,45 +170,50 @@ Image::~Image()
void Image::sizeRequestImpl (core::Requisition *requisition)
{
+ DBG_OBJ_MSG ("resize", 0, "<b>sizeRequestImpl</b> ()");
+ DBG_OBJ_MSG_START ();
+
if (buffer) {
- if (getStyle ()->height == core::style::LENGTH_AUTO &&
- core::style::isAbsLength (getStyle ()->width) &&
- buffer->getRootWidth () > 0) {
- // preserve aspect ratio when only width is given
- requisition->width = core::style::absLengthVal (getStyle ()->width);
- requisition->ascent = buffer->getRootHeight () *
- requisition->width / buffer->getRootWidth ();
- } else if (getStyle ()->width == core::style::LENGTH_AUTO &&
- core::style::isAbsLength (getStyle ()->height) &&
- buffer->getRootHeight () > 0) {
- // preserve aspect ratio when only height is given
- requisition->ascent = core::style::absLengthVal (getStyle ()->height);
- requisition->width = buffer->getRootWidth () *
- requisition->ascent / buffer->getRootHeight ();
- } else {
- requisition->width = buffer->getRootWidth ();
- requisition->ascent = buffer->getRootHeight ();
- }
- requisition->descent = 0;
- } else {
- if (altText && altText[0]) {
- if (altTextWidth == -1)
- altTextWidth =
- layout->textWidth (getStyle()->font, altText, strlen (altText));
+ requisition->width = buffer->getRootWidth ();
+ requisition->ascent = buffer->getRootHeight ();
+ } else
+ requisition->width = requisition->ascent = 0;
+
+ requisition->width += boxDiffWidth ();
+ requisition->ascent += boxOffsetY ();
- requisition->width = altTextWidth;
- requisition->ascent = getStyle()->font->ascent;
- requisition->descent = getStyle()->font->descent;
- } else {
- requisition->width = 0;
- requisition->ascent = 0;
- requisition->descent = 0;
+ requisition->descent = boxRestHeight ();
+
+ correctRequisition (requisition, core::splitHeightPreserveDescent);
+
+ if (buffer) {
+ // If one dimension is set, preserve the aspect ratio (without
+ // extraSpace/margin/border/padding). Notice that
+ // requisition->descent could have been changed in
+ // core::splitHeightPreserveDescent, so we do not make any
+ // assumtions here about it (and requisition->ascent).
+
+ // TODO Check again possible overflows. (Aren't buffer
+ // dimensions limited to 2^15?)
+
+ if (getStyle()->width == core::style::LENGTH_AUTO &&
+ getStyle()->height != core::style::LENGTH_AUTO) {
+ requisition->width =
+ (requisition->ascent + requisition->descent - boxDiffHeight ())
+ * buffer->getRootWidth () / buffer->getRootHeight ()
+ + boxDiffWidth ();
+ } else if (getStyle()->width != core::style::LENGTH_AUTO &&
+ getStyle()->height == core::style::LENGTH_AUTO) {
+ requisition->ascent = (requisition->width + boxDiffWidth ())
+ * buffer->getRootHeight () / buffer->getRootWidth ()
+ + boxOffsetY ();
+ requisition->descent = boxRestHeight ();
}
- }
+ }
- requisition->width += getStyle()->boxDiffWidth ();
- requisition->ascent += getStyle()->boxOffsetY ();
- requisition->descent += getStyle()->boxRestHeight ();
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_MSG_END ();
}
void Image::sizeAllocateImpl (core::Allocation *allocation)
@@ -247,6 +252,11 @@ void Image::sizeAllocateImpl (core::Allocation *allocation)
}
}
+void Image::containerSizeChangedForChildren ()
+{
+ // Nothing to do.
+}
+
void Image::enterNotifyImpl (core::EventCrossing *event)
{
// BUG: this is wrong for image maps, but the cursor position is unknown.
diff --git a/dw/image.hh b/dw/image.hh
index a712936e..2d3cafd6 100644
--- a/dw/image.hh
+++ b/dw/image.hh
@@ -131,6 +131,7 @@ private:
protected:
void sizeRequestImpl (core::Requisition *requisition);
void sizeAllocateImpl (core::Allocation *allocation);
+ void containerSizeChangedForChildren ();
void draw (core::View *view, core::Rectangle *area);
diff --git a/dw/layout.cc b/dw/layout.cc
index 1609dae0..3cc13980 100644
--- a/dw/layout.cc
+++ b/dw/layout.cc
@@ -277,6 +277,11 @@ Layout::Layout (Platform *platform)
viewportWidth = viewportHeight = 0;
hScrollbarThickness = vScrollbarThickness = 0;
+ DBG_OBJ_SET_NUM ("viewportWidth", viewportWidth);
+ DBG_OBJ_SET_NUM ("viewportHeight", viewportHeight);
+ DBG_OBJ_SET_NUM ("hScrollbarThickness", hScrollbarThickness);
+ DBG_OBJ_SET_NUM ("vScrollbarThickness", vScrollbarThickness);
+
requestedAnchor = NULL;
scrollIdleId = -1;
scrollIdleNotInterrupted = false;
@@ -371,13 +376,17 @@ void Layout::addWidget (Widget *widget)
topLevel = widget;
widget->layout = this;
+ widget->container = NULL;
+ DBG_OBJ_SET_PTR_O (widget, "container", widget->container);
+
queueResizeList->clear ();
- widget->notifySetAsTopLevel();
+ widget->notifySetAsTopLevel ();
findtextState.setWidget (widget);
canvasHeightGreater = false;
- setSizeHints ();
+ DBG_OBJ_SET_SYM ("canvasHeightGreater",
+ canvasHeightGreater ? "true" : "false");
// Do not directly call Layout::queueResize(), but
// Widget::queueResize(), so that all flags are set properly,
@@ -471,6 +480,11 @@ void Layout::attachView (View *view)
hScrollbarThickness = view->getHScrollbarThickness ();
vScrollbarThickness = view->getVScrollbarThickness ();
}
+
+ DBG_OBJ_SET_NUM ("viewportWidth", viewportWidth);
+ DBG_OBJ_SET_NUM ("viewportHeight", viewportHeight);
+ DBG_OBJ_SET_NUM ("hScrollbarThickness", hScrollbarThickness);
+ DBG_OBJ_SET_NUM ("vScrollbarThickness", vScrollbarThickness);
}
/*
@@ -908,12 +922,12 @@ void Layout::resizeIdle ()
int currVThickness = currVScrollbarThickness();
if (!canvasHeightGreater &&
- canvasAscent + canvasDescent
- > viewportHeight - currHThickness) {
+ canvasAscent + canvasDescent > viewportHeight - currHThickness) {
canvasHeightGreater = true;
- setSizeHints ();
- /* May queue a new resize. */
- }
+ DBG_OBJ_SET_SYM ("canvasHeightGreater",
+ canvasHeightGreater ? "true" : "false");
+ containerSizeChanged ();
+ }
// Set viewport sizes.
view->setViewportSize (viewportWidth, viewportHeight,
@@ -932,16 +946,6 @@ void Layout::resizeIdle ()
leaveResizeIdle ();
}
-void Layout::setSizeHints ()
-{
- if (topLevel) {
- topLevel->setWidth (viewportWidth
- - (canvasHeightGreater ? vScrollbarThickness : 0));
- topLevel->setAscent (viewportHeight - hScrollbarThickness);
- topLevel->setDescent (0);
- }
-}
-
void Layout::queueDraw (int x, int y, int width, int height)
{
Rectangle area;
@@ -1264,13 +1268,17 @@ void Layout::scrollPosChanged (View *view, int x, int y)
*/
void Layout::viewportSizeChanged (View *view, int width, int height)
{
- _MSG("Layout::viewportSizeChanged w=%d h=%d new_w=%d new_h=%d\n",
- viewportWidth, viewportHeight, width, height);
+ DBG_OBJ_MSGF ("resize", 0, "<b>viewportSizeChanged</b> (%p, %d, %d)",
+ view, width, height);
+ DBG_OBJ_MSG_START ();
/* If the width has become higher, we test again, whether the vertical
* scrollbar (so to speak) can be hidden again. */
- if (usesViewport && width > viewportWidth)
+ if (usesViewport && width > viewportWidth) {
canvasHeightGreater = false;
+ DBG_OBJ_SET_SYM ("canvasHeightGreater",
+ canvasHeightGreater ? "true" : "false");
+ }
/* if size changes, redraw this view.
* TODO: this is a resize call (redraw/resize code needs a review). */
@@ -1285,7 +1293,25 @@ void Layout::viewportSizeChanged (View *view, int width, int height)
viewportWidth = width;
viewportHeight = height;
- setSizeHints ();
+ DBG_OBJ_SET_NUM ("viewportWidth", viewportWidth);
+ DBG_OBJ_SET_NUM ("viewportHeight", viewportHeight);
+
+ containerSizeChanged ();
+
+ DBG_OBJ_MSG_END ();
+}
+
+void Layout::containerSizeChanged ()
+{
+ DBG_OBJ_MSG ("resize", 0, "<b>containerSizeChanged</b> ()");
+ DBG_OBJ_MSG_START ();
+
+ if (topLevel) {
+ topLevel->containerSizeChanged ();
+ queueResize (true);
+ }
+
+ DBG_OBJ_MSG_END ();
}
} // namespace core
diff --git a/dw/layout.hh b/dw/layout.hh
index 2120d877..d83aeedb 100644
--- a/dw/layout.hh
+++ b/dw/layout.hh
@@ -157,13 +157,15 @@ private:
public:
Widget *widget;
int ref;
- bool extremesChanged;
+ bool extremesChanged, fast;
- inline QueueResizeItem (Widget *widget, int ref, bool extremesChanged)
+ inline QueueResizeItem (Widget *widget, int ref, bool extremesChanged,
+ bool fast)
{
this->widget = widget;
this->ref = ref;
this->extremesChanged = extremesChanged;
+ this->fast = fast;
}
};
@@ -267,6 +269,8 @@ private:
void enterResizeIdle () { resizeIdleCounter++; }
void leaveResizeIdle () { resizeIdleCounter--; }
+ void containerSizeChanged ();
+
public:
Layout (Platform *platform);
~Layout ();
diff --git a/dw/listitem.cc b/dw/listitem.cc
index 05344d79..65293d8d 100644
--- a/dw/listitem.cc
+++ b/dw/listitem.cc
@@ -69,7 +69,7 @@ int ListItem::getValue ()
void ListItem::setMaxValue (int maxValue, int value)
{
- innerPadding = maxValue;
+ leftInnerPadding = maxValue;
line1Offset = - value;
redrawY = 0;
queueResize (0, true);
diff --git a/dw/outofflowmgr.cc b/dw/outofflowmgr.cc
index eb5bf3e8..c774d0d9 100644
--- a/dw/outofflowmgr.cc
+++ b/dw/outofflowmgr.cc
@@ -616,7 +616,7 @@ void OutOfFlowMgr::sizeAllocateEnd (Textblock *caller)
Textblock *tb = key->getTypedValue();
tbInfo->updateAllocation ();
- tbInfo->availWidth = tb->getAvailWidth ();
+ tbInfo->lineBreakWidth = tb->getLineBreakWidth ();
}
// There are cases where some allocated floats (TODO: later also
@@ -641,6 +641,16 @@ void OutOfFlowMgr::sizeAllocateEnd (Textblock *caller)
DBG_OBJ_MSG_END ();
}
+void OutOfFlowMgr::containerSizeChangedForChildren ()
+{
+ for (int i = 0; i < leftFloatsCB->size (); i++)
+ leftFloatsCB->get(i)->getWidget()->containerSizeChanged ();
+ for (int i = 0; i < rightFloatsCB->size (); i++)
+ rightFloatsCB->get(i)->getWidget()->containerSizeChanged ();
+ for (int i = 0; i < absolutelyPositioned->size(); i++)
+ absolutelyPositioned->get(i)->widget->containerSizeChanged ();
+}
+
bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, int *minFloatPos,
Widget **minFloat)
{
@@ -709,8 +719,8 @@ bool OutOfFlowMgr::hasRelationChanged (TBInfo *tbInfo, Side side,
int newFlx =
calcFloatX (vloat, side,
- gba->x - containingBlockAllocation.x,
- gba->width, vloat->generatingBlock->getAvailWidth ());
+ gba->x - containingBlockAllocation.x, gba->width,
+ vloat->generatingBlock->getLineBreakWidth ());
int newFly = vloat->generatingBlock->getAllocation()->y
- containingBlockAllocation.y + vloat->yReal;
@@ -1042,11 +1052,11 @@ void OutOfFlowMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat)
ensureFloatSize (vloat);
Allocation *gba = getAllocation (vloat->generatingBlock);
- int availWidth = vloat->generatingBlock->getAvailWidth();
+ int lineBreakWidth = vloat->generatingBlock->getLineBreakWidth();
Allocation childAllocation;
childAllocation.x = cba->x +
- calcFloatX (vloat, side, gba->x - cba->x, gba->width, availWidth);
+ calcFloatX (vloat, side, gba->x - cba->x, gba->width, lineBreakWidth);
childAllocation.y = gba->y + vloat->yReal;
childAllocation.width = vloat->size.width;
childAllocation.ascent = vloat->size.ascent;
@@ -1067,14 +1077,14 @@ void OutOfFlowMgr::sizeAllocateFloats (Side side, int newLastAllocatedFloat)
* gbX is given relative to the CB, as is the return value.
*/
int OutOfFlowMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
- int gbAvailWidth)
+ int gbLineBreakWidth)
{
DBG_OBJ_MSGF ("resize.oofm", 0, "<b>calcFloatX</b> (%p, %s, %d, %d, %d)",
vloat->getWidget (), side == LEFT ? "LEFT" : "RIGHT", gbX,
- gbWidth, gbAvailWidth);
+ gbWidth, gbLineBreakWidth);
DBG_OBJ_MSG_START ();
- int gbActualWidth, x;
+ int x;
switch (side) {
case LEFT:
@@ -1086,22 +1096,20 @@ int OutOfFlowMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
break;
case RIGHT:
- // In some cases, the actual (allocated) width is too large; we
- // use the "available" width here.
- gbActualWidth = min (gbWidth, gbAvailWidth);
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "right: gbActualWidth = min (%d, %d) = %d",
- gbWidth, gbAvailWidth, gbActualWidth);
-
// Similar for right floats, but in this case, floats are
// shifted to the right when they are too big (instead of
// shifting the generator to the right).
- x = max (gbX + gbActualWidth - vloat->size.width
+
+ // Notice that not the actual width, but the line break width is
+ // used. (This changed for GROWS, where the width of a textblock
+ // is often smaller that the line break.)
+
+ x = max (gbX + gbLineBreakWidth - vloat->size.width
- vloat->generatingBlock->getStyle()->boxRestWidth(),
// Do not exceed CB allocation:
0);
DBG_OBJ_MSGF ("resize.oofm", 1, "x = max (%d + %d - %d - %d, 0) = %d",
- gbX, gbActualWidth, vloat->size.width,
+ gbX, gbLineBreakWidth, vloat->size.width,
vloat->generatingBlock->getStyle()->boxRestWidth(), x);
break;
@@ -1206,6 +1214,9 @@ void OutOfFlowMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock,
case FLOAT_LEFT:
leftFloatsAll->put (vloat);
DBG_OBJ_SET_NUM ("leftFloatsAll.size", leftFloatsAll->size());
+ DBG_OBJ_ARRATTRSET_PTR ("leftFloatsAll", leftFloatsAll->size() - 1,
+ "widget", vloat->getWidget ());
+
widget->parentRef = createRefLeftFloat (leftFloatsAll->size() - 1);
tbInfo->leftFloatsGB->put (vloat);
@@ -1230,6 +1241,9 @@ void OutOfFlowMgr::addWidgetOOF (Widget *widget, Textblock *generatingBlock,
case FLOAT_RIGHT:
rightFloatsAll->put (vloat);
DBG_OBJ_SET_NUM ("rightFloatsAll.size", rightFloatsAll->size());
+ DBG_OBJ_ARRATTRSET_PTR ("rightFloatsAll", rightFloatsAll->size() - 1,
+ "widget", vloat->getWidget ());
+
widget->parentRef = createRefRightFloat (rightFloatsAll->size() - 1);
tbInfo->rightFloatsGB->put (vloat);
@@ -1565,7 +1579,7 @@ bool OutOfFlowMgr::collidesH (Float *vloat, Float *other, SFVType type)
if (vloat->generatingBlock == other->generatingBlock)
collidesH = vloat->size.width + other->size.width
+ vloat->generatingBlock->getStyle()->boxDiffWidth()
- > vloat->generatingBlock->getAvailWidth();
+ > vloat->generatingBlock->getLineBreakWidth();
else {
assert (wasAllocated (vloat->generatingBlock));
assert (wasAllocated (other->generatingBlock));
@@ -1582,7 +1596,7 @@ bool OutOfFlowMgr::collidesH (Float *vloat, Float *other, SFVType type)
vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
LEFT : RIGHT,
gba->x, gba->width,
- vloat->generatingBlock->getAvailWidth ());
+ vloat->generatingBlock->getLineBreakWidth ());
// Generally: right border of the left float > left border of
// the right float (all in canvas coordinates).
@@ -1681,13 +1695,13 @@ void OutOfFlowMgr::getFloatsSize (Requisition *cbReq, Side side, int *width,
if (vloat->generatingBlock == containingBlock) {
x = calcFloatX (vloat, side, 0, cbReq->width,
- vloat->generatingBlock->getAvailWidth ());
+ vloat->generatingBlock->getLineBreakWidth ());
y = vloat->yReal;
} else {
Allocation *gba = getAllocation(vloat->generatingBlock);
x = calcFloatX (vloat, side,
gba->x - containingBlockAllocation.x, gba->width,
- vloat->generatingBlock->getAvailWidth ());
+ vloat->generatingBlock->getLineBreakWidth ());
y = gba->y - containingBlockAllocation.y + vloat->yReal;
}
@@ -1763,19 +1777,6 @@ void OutOfFlowMgr::getFloatsExtremes (Extremes *cbExtr, Side side,
vloat->getWidget (), vloat->generatingBlock,
extr.minWidth, extr.maxWidth);
- if (isAbsLength (vloat->getWidget()->getStyle()->width)) {
- int width = absLengthVal (vloat->getWidget()->getStyle()->width);
- if (extr.minWidth < width)
- extr.minWidth = width;
- if (extr.maxWidth > width)
- // maxWidth not smaller than minWidth
- extr.maxWidth = max (width, extr.minWidth);
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "corrected by absolute width %d: %d / %d",
- width, extr.minWidth, extr.maxWidth);
- }
-
// TODO: Or zero (instead of rightDiff) for right floats?
*minWidth =
max (*minWidth,
@@ -1931,12 +1932,12 @@ int OutOfFlowMgr::getBorder (Textblock *textblock, Side side, int y, int h,
fla->x, fla->width, tba->x, thisBorder);
} else {
// See also calcFloatX.
- int tbAvWidth = textblock->getAvailWidth ();
- thisBorder = tba->x + min (tba->width, tbAvWidth) - fla->x;
+ thisBorder =
+ tba->x + textblock->getLineBreakWidth () - fla->x;
DBG_OBJ_MSGF ("border", 1,
- "not GB: thisBorder = %d + min (%d, %d) - %d "
+ "not GB: thisBorder = %d + %d - %d "
"= %d",
- tba->x, tba->width, tbAvWidth, fla->x,
+ tba->x, textblock->getLineBreakWidth (), fla->x,
thisBorder);
}
}
@@ -2070,120 +2071,21 @@ int OutOfFlowMgr::getClearPosition (Textblock *tb, Side side)
void OutOfFlowMgr::ensureFloatSize (Float *vloat)
{
- if (vloat->dirty ||
- (vloat->cbAvailWidth != containingBlock->getAvailWidth () &&
- (// If the size of the containing block has changed (represented
- // currently by the available width), a recalculation of a relative
- // float width may also be necessary.
- isPerLength (vloat->getWidget()->getStyle()->width) ||
- // Similar for "auto" widths of textblocks etc.
- (vloat->getWidget()->usesHints () &&
- vloat->getWidget()->getStyle()->width == LENGTH_AUTO)))) {
+ // Historical note: relative sizes (e. g. percentages) are already
+ // handled by (at this time) Layout::containerSizeChanged, so
+ // Float::dirty will be set.
+
+ if (vloat->dirty) {
DBG_OBJ_MSGF ("resize.oofm", 0,
"<b>ensureFloatSize</b> (%p): recalculation",
vloat->getWidget ());
DBG_OBJ_MSG_START ();
- Extremes extremes;
- vloat->getWidget()->getExtremes (&extremes);
- DBG_OBJ_MSGF ("resize.oofm", 1, "getExtremes => %d / %d",
- extremes.minWidth, extremes.maxWidth);
-
- // TODO Ugly. Soon to be replaced by cleaner code? See also
- // comment in Textblock::calcWidgetSize.
-
- if (vloat->getWidget()->usesHints ()) {
- // For widths defined by CSS, similar adjustments (extremes
- // etc.) like below are necessary, to prevent CPU hogging.
-
- Length cssWidth = vloat->getWidget()->getStyle()->width;
- if (isAbsLength (cssWidth)) {
- int width = absLengthVal (cssWidth);
- DBG_OBJ_MSGF ("resize.oofm", 1, "about to set absolute width: %d",
- width);
- width = adjustFloatWidth (width, &extremes);
- vloat->getWidget()->setWidth (width);
- } else if (cssWidth == LENGTH_AUTO || isPerLength (cssWidth)) {
- // It is important that the width of the *CB* is not
- // larger than its minimal width, when the latter is set
- // as size hint; otherwise we have an endless queueResize
- // cycle (resulting in CPU hogging) when the CB is part of
- // a narrow table column. To prevent this, the width of
- // the *float* has to be limited (cf. also getExtremes).
-
- int availWidth, leftDiff, rightDiff;
- if (getFloatDiffToCB (vloat, &leftDiff, &rightDiff))
- availWidth = containingBlock->getAvailWidth()
- - (vloat->getWidget()->getStyle()->vloat == FLOAT_LEFT ?
- leftDiff : rightDiff);
- else
- // Not allocated: next allocation will take care.
- availWidth = containingBlock->getAvailWidth();
-
- int width;
-
- if (cssWidth == LENGTH_AUTO) {
- width = availWidth;
- DBG_OBJ_MSGF ("resize.oofm", 1, "setting width 'auto': %d",
- width);
- } else {
- width = multiplyWithPerLength (availWidth, cssWidth);
-
- // Some more corrections (nonsense percentage values):
- if (width < 1)
- width = 1;
- if (width > availWidth)
- width = availWidth;
-
- DBG_OBJ_MSGF ("resize.oofm", 1,
- "about to set percentage width: %d * %g -> %d",
- availWidth, perLengthVal (cssWidth), width);
- width = adjustFloatWidth (width, &extremes);
- }
-
- vloat->getWidget()->setWidth (width);
- } else
- DBG_OBJ_MSG ("resize.oofm", 1,
- "setting width: <b>relative length? may be a bug</b>");
- } else
- DBG_OBJ_MSG ("resize.oofm", 1, "setting no width: uses no hints");
-
- // This is a bit hackish: We first request the size, then set
- // the available width (also considering the one of the
- // containing block, and the extremes of the float), then
- // request the size again, which may of course have a different
- // result. This is a fix for the bug:
- //
- // Text in floats, which are wider because of an image, are
- // broken at a too narrow width. Reproduce:
- // test/floats2.html. After the image has been loaded, the
- // text "Some text in a float." should not be broken
- // anymore.
- //
- // If the call of setWidth not is neccessary, the second call
- // will read the size from the cache, so no redundant
- // calculation is necessary.
- //
- // Furthermore, extremes are considered; especially, floats are too
- // wide, sometimes.
-
- vloat->getWidget()->sizeRequest (&vloat->size);
- DBG_OBJ_MSGF ("resize.oofm", 1, "sizeRequest (1) => %d * (%d + %d)",
- vloat->size.width, vloat->size.ascent, vloat->size.descent);
-
- // Set width ...
- int width = vloat->size.width;
- DBG_OBJ_MSGF ("resize.oofm", 1, "new width: %d", width);
- width = adjustFloatWidth (width, &extremes);
- vloat->getWidget()->setWidth (width);
vloat->getWidget()->sizeRequest (&vloat->size);
- DBG_OBJ_MSGF ("resize.oofm", 1, "sizeRequest (2) => %d * (%d + %d)",
- vloat->size.width, vloat->size.ascent, vloat->size.descent);
-
- vloat->cbAvailWidth = containingBlock->getAvailWidth ();
+ vloat->cbLineBreakWidth = containingBlock->getLineBreakWidth ();
vloat->dirty = false;
- DBG_OBJ_MSGF ("resize.oofm", 1, "final size: %d * (%d + %d)",
+ DBG_OBJ_MSGF ("resize.oofm", 1, "size: %d * (%d + %d)",
vloat->size.width, vloat->size.ascent, vloat->size.descent);
DBG_OBJ_SET_NUM_O (vloat->getWidget(), "<Float>.size.width",
@@ -2199,39 +2101,6 @@ void OutOfFlowMgr::ensureFloatSize (Float *vloat)
}
}
-int OutOfFlowMgr::adjustFloatWidth (int width, Extremes *extremes)
-{
- DBG_OBJ_MSGF ("resize.oofm", 0,
- "<b>adjustFloatWidth</b> (%d, (%d, %d)) [CB->availWidth = %d]",
- width, extremes->minWidth, extremes->maxWidth,
- containingBlock->getAvailWidth());
- DBG_OBJ_MSG_START ();
-
- // Consider extremes (as described above).
- if (width < extremes->minWidth) {
- width = extremes->minWidth;
- DBG_OBJ_MSGF ("resize.oofm", 1, "adjusted to minWidth: %d", width);
- }
- if (width > extremes->maxWidth) {
- width = extremes->maxWidth;
- DBG_OBJ_MSGF ("resize.oofm", 1, "adjusted to maxWidth: %d", width);
- }
- // Finally, consider the available width of the containing
- // block. Order is important: to prevent problems, the available
- // width of the float must never be larger than the one of the
- // containing block. (Somewhat hackish, will be solved cleaner with
- // GROWS.)
- if (width > containingBlock->getAvailWidth()) {
- width = containingBlock->getAvailWidth();
- DBG_OBJ_MSGF ("resize.oofm", 1, "adjusted to CB::availWidth: %d", width);
- }
-
- DBG_OBJ_MSGF ("resize.oofm", 1, "=> %d", width);
- DBG_OBJ_MSG_END ();
-
- return width;
-}
-
void OutOfFlowMgr::getAbsolutelyPositionedSize (Requisition *cbReq, int *width,
int *height)
{
@@ -2250,69 +2119,8 @@ void OutOfFlowMgr::getAbsolutelyPositionedExtremes (Extremes *cbExtr,
void OutOfFlowMgr::ensureAbsolutelyPositionedSizeAndPosition
(AbsolutelyPositioned *abspos)
{
- // No work is done anymore on this, since widget sizes will be
- // redesigned before absolute positions are finished.
-
- if (abspos->dirty) {
- Style *style = abspos->widget->getStyle();
- int availWidth = containingBlock->getAvailWidth();
- int availHeight =
- containingBlock->getAvailAscent() + containingBlock->getAvailDescent();
-
- if (style->left == LENGTH_AUTO)
- abspos->xCB = 0;
- else
- abspos->xCB =
- calcValueForAbsolutelyPositioned (abspos, style->left, availWidth);
-
- if (style->top == LENGTH_AUTO)
- abspos->yCB = 0;
- else
- abspos->yCB =
- calcValueForAbsolutelyPositioned (abspos, style->top, availHeight);
-
- abspos->width = -1; // undefined
- if (style->width != LENGTH_AUTO)
- abspos->width = calcValueForAbsolutelyPositioned (abspos, style->width,
- availWidth);
- else if (style->right != LENGTH_AUTO) {
- int right = calcValueForAbsolutelyPositioned (abspos, style->right,
- availWidth);
- abspos->width = max (0, availWidth - (abspos->xCB + right));
- }
-
- abspos->height = -1; // undefined
- if (style->height != LENGTH_AUTO)
- abspos->height = calcValueForAbsolutelyPositioned (abspos,
- style->height,
- availHeight);
- else if (style->bottom != LENGTH_AUTO) {
- int bottom = calcValueForAbsolutelyPositioned (abspos, style->bottom,
- availHeight);
- abspos->height = max (0, availHeight - (abspos->yCB + bottom));
- }
-
- if (abspos->width != -1)
- abspos->widget->setWidth (abspos->width);
-
- if (abspos->height != -1) {
- abspos->widget->setAscent (abspos->height);
- abspos->widget->setDescent (0); // TODO
- }
-
- if (abspos->width == -1 || abspos->height == -1) {
- Requisition req;
- abspos->widget->sizeRequest (&req);
-
- if (abspos->width == -1)
- abspos->width = req.width;
-
- if (abspos->height == -1)
- abspos->height = req.ascent + req.descent;
- }
-
- abspos->dirty = false;
- }
+ // TODO
+ assertNotReached ();
}
int OutOfFlowMgr::calcValueForAbsolutelyPositioned
diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh
index 429482fd..19205717 100644
--- a/dw/outofflowmgr.hh
+++ b/dw/outofflowmgr.hh
@@ -97,9 +97,9 @@ private:
respectively. -1 initially. */
int sideSpanningIndex, mark;
core::Requisition size;
- int cbAvailWidth; /* On which the calculation of relative sizes
- is based. Height not yet used, and probably
- not added before size redesign. */
+ int cbLineBreakWidth; /* On which the calculation of relative sizes
+ is based. Height not yet used, and probably
+ not added before size redesign. */
bool dirty, sizeChangedSinceLastAllocation;
Float (OutOfFlowMgr *oofm, core::Widget *widget,
@@ -172,7 +172,7 @@ private:
class TBInfo: public WidgetInfo
{
public:
- int availWidth;
+ int lineBreakWidth;
int index; // position within "tbInfos"
TBInfo *parent;
@@ -272,7 +272,7 @@ private:
void moveFromGBToCB (Side side);
void sizeAllocateFloats (Side side, int newLastAllocatedFloat);
int calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
- int gbAvailWidth);
+ int gbLineBreakWidth);
bool hasRelationChanged (TBInfo *tbInfo,int *minFloatPos,
core::Widget **minFloat);
@@ -319,7 +319,6 @@ private:
int getClearPosition (Textblock *tb, Side side);
void ensureFloatSize (Float *vloat);
- int adjustFloatWidth (int width, core::Extremes *extremes);
void tellFloatPosition (core::Widget *widget, int yReq);
@@ -395,6 +394,7 @@ public:
void sizeAllocateStart (Textblock *caller, core::Allocation *allocation);
void sizeAllocateEnd (Textblock *caller);
+ void containerSizeChangedForChildren ();
void draw (core::View *view, core::Rectangle *area);
void markSizeChange (int ref);
diff --git a/dw/ruler.cc b/dw/ruler.cc
index 2b5288c2..b624718d 100644
--- a/dw/ruler.cc
+++ b/dw/ruler.cc
@@ -29,25 +29,38 @@ namespace dw {
Ruler::Ruler ()
{
setFlags (USES_HINTS);
- setFlags (BLOCK_LEVEL);
unsetFlags (HAS_CONTENTS);
- availWidth = 0;
}
void Ruler::sizeRequestImpl (core::Requisition *requisition)
{
requisition->width =
- lout::misc::max (availWidth, getStyle()->boxDiffWidth ());
+ lout::misc::max (getAvailWidth (true), getStyle()->boxDiffWidth ());
requisition->ascent = getStyle()->boxOffsetY ();
requisition->descent = getStyle()->boxRestHeight ();
}
-void Ruler::setWidth (int width)
+void Ruler::getExtremesImpl (core::Extremes *extremes)
{
- if (availWidth != width) {
- availWidth = width;
- queueResize (0, false);
- }
+ extremes->minWidth = extremes->maxWidth = getStyle()->boxDiffWidth ();
+ extremes->minWidthIntrinsic = extremes->minWidth;
+ extremes->maxWidthIntrinsic = extremes->maxWidth;
+ correctExtremes (extremes);
+}
+
+bool Ruler::isBlockLevel ()
+{
+ return true;
+}
+
+void Ruler::containerSizeChangedForChildren ()
+{
+ // Nothing to do.
+}
+
+bool Ruler::usesAvailWidth ()
+{
+ return true;
}
void Ruler::draw (core::View *view, core::Rectangle *area)
diff --git a/dw/ruler.hh b/dw/ruler.hh
index 863792dd..1f3491bc 100644
--- a/dw/ruler.hh
+++ b/dw/ruler.hh
@@ -15,17 +15,18 @@ namespace dw {
*/
class Ruler: public core::Widget
{
-private:
- int availWidth;
-
protected:
void sizeRequestImpl (core::Requisition *requisition);
- void setWidth (int width);
+ void getExtremesImpl (core::Extremes *extremes);
+ void containerSizeChangedForChildren ();
+ bool usesAvailWidth ();
void draw (core::View *view, core::Rectangle *area);
public:
Ruler ();
+ bool isBlockLevel ();
+
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
};
diff --git a/dw/simpletablecell.cc b/dw/simpletablecell.cc
new file mode 100644
index 00000000..083deaed
--- /dev/null
+++ b/dw/simpletablecell.cc
@@ -0,0 +1,58 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+
+#include "simpletablecell.hh"
+#include "../lout/debug.hh"
+
+namespace dw {
+
+int SimpleTableCell::CLASS_ID = -1;
+
+SimpleTableCell::SimpleTableCell (bool limitTextWidth):
+ Textblock (limitTextWidth)
+{
+ DBG_OBJ_CREATE ("dw::SimpleTableCell");
+ registerName ("dw::SimpleTableCell", &CLASS_ID);
+}
+
+SimpleTableCell::~SimpleTableCell()
+{
+ DBG_OBJ_DELETE ();
+}
+
+bool SimpleTableCell::isBlockLevel ()
+{
+ return false;
+}
+
+int SimpleTableCell::applyPerWidth (int containerWidth,
+ core::style::Length perWidth)
+{
+ return core::style::multiplyWithPerLength (containerWidth, perWidth);
+}
+
+int SimpleTableCell::applyPerHeight (int containerHeight,
+ core::style::Length perHeight)
+{
+ return core::style::multiplyWithPerLength (containerHeight, perHeight);
+}
+
+} // namespace dw
diff --git a/dw/simpletablecell.hh b/dw/simpletablecell.hh
new file mode 100644
index 00000000..a452add9
--- /dev/null
+++ b/dw/simpletablecell.hh
@@ -0,0 +1,24 @@
+#ifndef __DW_SIMPLETABLECELL_HH__
+#define __DW_SIMPLETABLECELL_HH__
+
+#include "textblock.hh"
+
+namespace dw {
+
+class SimpleTableCell: public Textblock
+{
+public:
+ static int CLASS_ID;
+
+ SimpleTableCell (bool limitTextWidth);
+ ~SimpleTableCell ();
+
+ int applyPerWidth (int containerWidth, core::style::Length perWidth);
+ int applyPerHeight (int containerHeight, core::style::Length perHeight);
+
+ bool isBlockLevel ();
+};
+
+} // namespace dw
+
+#endif // __DW_SIMPLETABLECELL_HH__
diff --git a/dw/style.hh b/dw/style.hh
index 2cc258bf..578e65c0 100644
--- a/dw/style.hh
+++ b/dw/style.hh
@@ -435,7 +435,8 @@ inline int absLengthVal(Length l) { return l >> 2; }
* When possible, do not use this function directly; it may be removed
* soon. Instead, use multiplyWithPerLength or multiplyWithPerLengthRounded.
*/
-inline double perLengthVal(Length l) { return (double)(l & ~3) / (1 << 18); }
+inline double perLengthVal_useThisOnlyForDebugging(Length l)
+{ return (double)(l & ~3) / (1 << 18); }
/** \brief Returns the value of a relative length, as a float.
*
@@ -450,7 +451,7 @@ inline double relLengthVal(Length l) { return (double)(l & ~3) / (1 << 18); }
* Use this instead of perLengthVal, when possible.
*/
inline int multiplyWithPerLength(int x, Length l) {
- return x * perLengthVal(l);
+ return x * perLengthVal_useThisOnlyForDebugging (l);
}
/**
@@ -459,8 +460,8 @@ inline int multiplyWithPerLength(int x, Length l) {
*
* (This function exists for backward compatibility.)
*/
-inline int multiplyWithPerLengthRounded (int x, Length l) {
- return lout::misc::roundInt (x * perLengthVal(l));
+inline int multiplyWithPerLengthRounded(int x, Length l) {
+ return lout::misc::roundInt (x * perLengthVal_useThisOnlyForDebugging (l));
}
inline int multiplyWithRelLength(int x, Length l) {
@@ -564,22 +565,14 @@ public:
= borderStyle.left = val; }
inline int boxOffsetX ()
- {
- return margin.left + borderWidth.left + padding.left;
- }
+ { return margin.left + borderWidth.left + padding.left; }
inline int boxRestWidth ()
- {
- return margin.right + borderWidth.right + padding.right;
- }
+ { return margin.right + borderWidth.right + padding.right; }
inline int boxDiffWidth () { return boxOffsetX () + boxRestWidth (); }
inline int boxOffsetY ()
- {
- return margin.top + borderWidth.top + padding.top;
- }
+ { return margin.top + borderWidth.top + padding.top; }
inline int boxRestHeight ()
- {
- return margin.bottom + borderWidth.bottom + padding.bottom;
- }
+ { return margin.bottom + borderWidth.bottom + padding.bottom; }
inline int boxDiffHeight () { return boxOffsetY () + boxRestHeight (); }
inline bool hasBackground ()
diff --git a/dw/table.cc b/dw/table.cc
index 565dfc9e..18597099 100644
--- a/dw/table.cc
+++ b/dw/table.cc
@@ -1,7 +1,7 @@
/*
* Dillo Widget
*
- * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ * Copyright 2005-2007, 2014 Sebastian Geerken <sgeerken@dillo.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,7 +34,6 @@ Table::Table(bool limitTextWidth)
{
DBG_OBJ_CREATE ("dw::Table");
registerName ("dw::Table", &CLASS_ID);
- setFlags (BLOCK_LEVEL);
setFlags (USES_HINTS);
setButtonSensitive(false);
@@ -42,33 +41,30 @@ Table::Table(bool limitTextWidth)
rowClosed = false;
- // random values
- availWidth = 100;
- availAscent = 100;
- availDescent = 0;
-
numRows = 0;
numCols = 0;
curRow = -1;
curCol = 0;
+ DBG_OBJ_SET_NUM ("numCols", numCols);
+ DBG_OBJ_SET_NUM ("numRows", numCols);
+
children = new misc::SimpleVector <Child*> (16);
colExtremes = new misc::SimpleVector<core::Extremes> (8);
colWidths = new misc::SimpleVector <int> (8);
cumHeight = new misc::SimpleVector <int> (8);
rowSpanCells = new misc::SimpleVector <int> (8);
- colSpanCells = new misc::SimpleVector <int> (8);
baseline = new misc::SimpleVector <int> (8);
rowStyle = new misc::SimpleVector <core::style::Style*> (8);
- hasColPercent = 0;
- colPercents = new misc::SimpleVector <core::style::Length> (8);
+ colWidthsUpToDateWidthColExtremes = true;
+ DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes",
+ colWidthsUpToDateWidthColExtremes);
redrawX = 0;
redrawY = 0;
}
-
Table::~Table()
{
for (int i = 0; i < children->size (); i++) {
@@ -94,17 +90,18 @@ Table::~Table()
delete colWidths;
delete cumHeight;
delete rowSpanCells;
- delete colSpanCells;
delete baseline;
delete rowStyle;
- delete colPercents;
DBG_OBJ_DELETE ();
}
void Table::sizeRequestImpl (core::Requisition *requisition)
{
- forceCalcCellSizes ();
+ DBG_OBJ_MSG ("resize", 0, "<b>sizeRequestImpl</b>");
+ DBG_OBJ_MSG_START ();
+
+ forceCalcCellSizes (true);
/**
* \bug Baselines are not regarded here.
@@ -119,40 +116,46 @@ void Table::sizeRequestImpl (core::Requisition *requisition)
+ getStyle()->vBorderSpacing;
requisition->descent = 0;
+ correctRequisition (requisition, core::splitHeightPreserveDescent);
+
+ DBG_OBJ_MSG_END ();
}
void Table::getExtremesImpl (core::Extremes *extremes)
{
- if (numCols == 0) {
- extremes->minWidth = extremes->maxWidth = 0;
- return;
- }
+ DBG_OBJ_MSG ("resize", 0, "<b>getExtremesImpl</b>");
+ DBG_OBJ_MSG_START ();
- forceCalcColumnExtremes ();
-
- extremes->minWidth = extremes->maxWidth =
- (numCols + 1) * getStyle()->hBorderSpacing
- + getStyle()->boxDiffWidth ();
- for (int col = 0; col < numCols; col++) {
- extremes->minWidth += colExtremes->getRef(col)->minWidth;
- extremes->maxWidth += colExtremes->getRef(col)->maxWidth;
- }
- if (core::style::isAbsLength (getStyle()->width)) {
- extremes->minWidth =
- misc::max (extremes->minWidth,
- core::style::absLengthVal(getStyle()->width));
- extremes->maxWidth =
- misc::max (extremes->maxWidth,
- core::style::absLengthVal(getStyle()->width));
+ if (numCols == 0)
+ extremes->minWidth = extremes->minWidthIntrinsic = extremes->maxWidth =
+ extremes->maxWidthIntrinsic = boxDiffWidth ();
+ else {
+ forceCalcColumnExtremes ();
+
+ extremes->minWidth = extremes->minWidthIntrinsic = extremes->maxWidth =
+ extremes->maxWidthIntrinsic =
+ (numCols + 1) * getStyle()->hBorderSpacing + boxDiffWidth ();
+ for (int col = 0; col < numCols; col++) {
+ extremes->minWidth += colExtremes->getRef(col)->minWidth;
+ extremes->minWidthIntrinsic +=
+ colExtremes->getRef(col)->minWidthIntrinsic;
+ extremes->maxWidth += colExtremes->getRef(col)->maxWidth;
+ extremes->maxWidthIntrinsic +=
+ colExtremes->getRef(col)->maxWidthIntrinsic;
+ }
}
- _MSG(" Table::getExtremesImpl, {%d, %d} numCols=%d\n",
- extremes->minWidth, extremes->maxWidth, numCols);
+ correctExtremes (extremes);
+
+ DBG_OBJ_MSG_END ();
}
void Table::sizeAllocateImpl (core::Allocation *allocation)
{
- calcCellSizes ();
+ DBG_OBJ_MSG ("resize", 0, "<b>sizeAllocateImpl</b>");
+ DBG_OBJ_MSG_START ();
+
+ calcCellSizes (true);
/**
* \bug Baselines are not regarded here.
@@ -167,8 +170,7 @@ void Table::sizeAllocateImpl (core::Allocation *allocation)
for (int row = 0; row < numRows; row++) {
int n = row * numCols + col;
if (childDefined (n)) {
- int width =
- (children->get(n)->cell.colspanEff - 1)
+ int width = (children->get(n)->cell.colspanEff - 1)
* getStyle()->hBorderSpacing;
for (int i = 0; i < children->get(n)->cell.colspanEff; i++)
width += colWidths->get (col + i);
@@ -192,6 +194,8 @@ void Table::sizeAllocateImpl (core::Allocation *allocation)
x += colWidths->get (col) + getStyle()->hBorderSpacing;
}
+
+ DBG_OBJ_MSG_END ();
}
void Table::resizeDrawImpl ()
@@ -202,32 +206,84 @@ void Table::resizeDrawImpl ()
redrawY = getHeight ();
}
-void Table::setWidth (int width)
+int Table::getAvailWidthOfChild (Widget *child, bool forceValue)
{
- // If limitTextWidth is set, a queueResize may also be necessary.
- if (availWidth != width || limitTextWidth) {
- _MSG(" Table::setWidth %d\n", width);
- availWidth = width;
- queueResize (0, false);
+ DBG_OBJ_MSGF ("resize", 0, "<b>getAvailWidthOfChild</b> (%p, %s)",
+ child, forceValue ? "true" : "false");
+ DBG_OBJ_MSG_START ();
+
+ int width = -1;
+
+ // Unlike other containers, the table widget sometimes narrows
+ // columns to a width less than specified by CSS (see
+ // forceCalcCellSizes). For this reason, the column widths have to
+ // be calculated in all cases.
+ if (forceValue) {
+ calcCellSizes (false);
+
+ // "child" is not a direct child, but a direct descendant.
+ // Search for the actual childs.
+ Widget *actualChild = child;
+ while (actualChild != NULL && actualChild->getParent () != this)
+ actualChild = actualChild->getParent ();
+
+ assert (actualChild != NULL);
+
+ // TODO This is inefficient. (Use parentRef?)
+ for (int row = numRows - 1; width == -1 && row >= 0; row--) {
+ for (int col = 0; width == -1 && col < numCols; col++) {
+ int n = row * numCols + col;
+ if (childDefined (n) &&
+ children->get(n)->cell.widget == actualChild) {
+ DBG_OBJ_MSGF ("resize", 1, "calculated from column %d", col);
+ width = (children->get(n)->cell.colspanEff - 1)
+ * getStyle()->hBorderSpacing;
+ for (int i = 0; i < children->get(n)->cell.colspanEff; i++)
+ width += colWidths->get (col + i);
+ width = misc::max (width, 0);
+ }
+ }
+ }
+
+ assert (width != -1);
}
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_MSG_END ();
+ return width;
}
-void Table::setAscent (int ascent)
+int Table::applyPerWidth (int containerWidth, core::style::Length perWidth)
{
- if (availAscent != ascent) {
- availAscent = ascent;
- queueResize (0, false);
- }
+ return core::style::multiplyWithPerLength (containerWidth, perWidth);
}
-void Table::setDescent (int descent)
+int Table::applyPerHeight (int containerHeight, core::style::Length perHeight)
{
- if (availDescent != descent) {
- availDescent = descent;
- queueResize (0, false);
+ return core::style::multiplyWithPerLength (containerHeight, perHeight);
+}
+
+void Table::containerSizeChangedForChildren ()
+{
+ for (int col = 0; col < numCols; col++) {
+ for (int row = 0; row < numRows; row++) {
+ int n = row * numCols + col;
+ if (childDefined (n))
+ children->get(n)->cell.widget->containerSizeChanged ();
+ }
}
}
+bool Table::usesAvailWidth ()
+{
+ return true;
+}
+
+bool Table::isBlockLevel ()
+{
+ return true;
+}
+
void Table::draw (core::View *view, core::Rectangle *area)
{
// Can be optimized, by iterating on the lines in area.
@@ -272,6 +328,10 @@ core::Iterator *Table::iterator (core::Content::Type mask, bool atEnd)
void Table::addCell (Widget *widget, int colspan, int rowspan)
{
+ DBG_OBJ_MSGF ("resize", 0, "<b>addCell</b> (%p, %d, %d)",
+ widget, colspan, rowspan);
+ DBG_OBJ_MSG_START ();
+
const int maxspan = 100;
Child *child;
int colspanEff;
@@ -373,6 +433,8 @@ void Table::addCell (Widget *widget, int colspan, int rowspan)
}
MSG("\n");
#endif
+
+ DBG_OBJ_MSG_END ();
}
void Table::addRow (core::style::Style *style)
@@ -393,7 +455,7 @@ void Table::addRow (core::style::Style *style)
rowClosed = false;
}
-TableCell *Table::getCellRef ()
+AlignedTableCell *Table::getCellRef ()
{
core::Widget *child;
@@ -401,14 +463,93 @@ TableCell *Table::getCellRef ()
int n = curCol + row * numCols;
if (childDefined (n)) {
child = children->get(n)->cell.widget;
- if (child->instanceOf (TableCell::CLASS_ID))
- return (TableCell*)child;
+ if (child->instanceOf (AlignedTableCell::CLASS_ID))
+ return (AlignedTableCell*)child;
}
}
return NULL;
}
+const char *Table::getExtrModName (ExtrMod mod)
+{
+ switch (mod) {
+ case MIN:
+ return "MIN";
+
+ case MIN_INTR:
+ return "MIN_INTR";
+
+ case MIN_MIN:
+ return "MIN_MIN";
+
+ case MAX_MIN:
+ return "MAX_MIN";
+
+ case MAX:
+ return "MAX";
+
+ case MAX_INTR:
+ return "MAX_INTR";
+
+ default:
+ misc::assertNotReached ();
+ return NULL;
+ }
+}
+
+int Table::getExtreme (core::Extremes *extremes, ExtrMod mod)
+{
+ switch (mod) {
+ case MIN:
+ return extremes->minWidth;
+
+ case MIN_INTR:
+ return extremes->minWidthIntrinsic;
+
+ case MIN_MIN:
+ return misc::min (extremes->minWidth, extremes->minWidthIntrinsic);
+
+ case MAX_MIN:
+ return misc::max (extremes->minWidth, extremes->minWidthIntrinsic);
+
+ case MAX:
+ return extremes->maxWidth;
+
+ case MAX_INTR:
+ return extremes->maxWidthIntrinsic;
+
+ default:
+ misc::assertNotReached (); return 0;
+ }
+}
+
+void Table::setExtreme (core::Extremes *extremes, ExtrMod mod, int value)
+{
+ switch (mod) {
+ case MIN:
+ extremes->minWidth = value;
+ break;
+
+ case MIN_INTR:
+ extremes->minWidthIntrinsic = value;
+ break;
+
+ // MIN_MIN and MAX_MIN not supported here.
+
+ case MAX:
+ extremes->maxWidth = value;
+ break;
+
+ case MAX_INTR:
+ extremes->maxWidthIntrinsic = value;
+ break;
+
+ default:
+ misc::assertNotReached ();
+ }
+}
+
void Table::reallocChildren (int newNumCols, int newNumRows)
{
assert (newNumCols >= numCols);
@@ -476,107 +617,174 @@ void Table::reallocChildren (int newNumCols, int newNumRows)
numCols = newNumCols;
numRows = newNumRows;
+
+ DBG_OBJ_SET_NUM ("numCols", numCols);
+ DBG_OBJ_SET_NUM ("numRows", numCols);
}
// ----------------------------------------------------------------------
-void Table::calcCellSizes ()
+void Table::calcCellSizes (bool calcHeights)
{
- if (needsResize () || resizeQueued ())
- forceCalcCellSizes ();
+ DBG_OBJ_MSGF ("resize", 0, "<b>calcCellSizes</b> (%s)",
+ calcHeights ? "true" : "false");
+ DBG_OBJ_MSG_START ();
+
+ bool sizeChanged = needsResize () || resizeQueued ();
+ bool extremesChanges = extremesChanged () || extremesQueued ();
+
+ if (calcHeights ? (extremesChanges || sizeChanged) :
+ (extremesChanges || !colWidthsUpToDateWidthColExtremes))
+ forceCalcCellSizes (calcHeights);
+
+ DBG_OBJ_MSG_END ();
}
-void Table::forceCalcCellSizes ()
+void Table::forceCalcCellSizes (bool calcHeights)
{
- int totalWidth = 0, childHeight, forceTotalWidth = 1;
+ DBG_OBJ_MSG ("resize", 0, "<b>forceCalcCellSizes</b>");
+ DBG_OBJ_MSG_START ();
+
+ int childHeight;
core::Extremes extremes;
// Will also call calcColumnExtremes(), when needed.
getExtremes (&extremes);
- if (core::style::isAbsLength (getStyle()->width)) {
- totalWidth = core::style::absLengthVal (getStyle()->width);
- } else if (core::style::isPerLength (getStyle()->width)) {
- /*
- * If the width is > 100%, we use 100%, this prevents ugly
- * results. (May be changed in future, when a more powerful
- * rendering is implemented, to handle fixed positions etc.,
- * as defined by CSS2.)
- */
- totalWidth =
- misc::min (core::style::multiplyWithPerLength (availWidth,
- getStyle()->width),
- availWidth);
- } else if (getStyle()->width == core::style::LENGTH_AUTO) {
- totalWidth = availWidth;
- forceTotalWidth = 0;
- }
-
- _MSG(" availWidth = %d\n", availWidth);
- _MSG(" totalWidth1 = %d\n", totalWidth);
-
- if (totalWidth < extremes.minWidth)
- totalWidth = extremes.minWidth;
- totalWidth = totalWidth
- - (numCols + 1) * getStyle()->hBorderSpacing
- - getStyle()->boxDiffWidth ();
-
- _MSG(" totalWidth2 = %d curCol=%d\n", totalWidth,curCol);
+ int availWidth = getAvailWidth (true);
+ int totalWidth = availWidth -
+ ((numCols + 1) * getStyle()->hBorderSpacing + boxDiffWidth ());
+ DBG_OBJ_MSGF ("resize", 1,
+ "totalWidth = %d - ((%d - 1) * %d + %d) = <b>%d</b>",
+ availWidth, numCols, getStyle()->hBorderSpacing,
+ boxDiffWidth (), totalWidth);
colWidths->setSize (numCols, 0);
cumHeight->setSize (numRows + 1, 0);
rowSpanCells->setSize (0);
baseline->setSize (numRows);
- _MSG(" extremes = %d,%d\n", extremes.minWidth, extremes.maxWidth);
- _MSG(" getStyle()->boxDiffWidth() = %d\n", getStyle()->boxDiffWidth());
- _MSG(" getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
+ misc::SimpleVector<int> *oldColWidths = colWidths;
+ colWidths = new misc::SimpleVector <int> (8);
+ int minWidth = 0;
+ for (int col = 0; col < colExtremes->size(); col++)
+ minWidth += getColExtreme (col, MIN);
+
+ DBG_OBJ_MSGF ("resize", 1, "minWidth (= %d) > totalWidth (= %d)?",
+ minWidth, totalWidth);
+
+ if (minWidth > totalWidth)
+ // The sum of all column minima is larger than the available
+ // width, so we narrow the columns (see also CSS2 spec,
+ // section 17.5, #6). We use a similar apportioning, but not
+ // bases on minimal and maximal widths, but on intrinsic minimal
+ // widths and corrected minimal widths. This way, intrinsic
+ // extremes are preferred (so avoiding columns too narrow for
+ // the actual contents), at the expenses of corrected ones
+ // (which means that sometimes CSS values are handled
+ // incorrectly).
+
+ apportion2 (totalWidth, 0, colExtremes->size() - 1, MIN_MIN, MAX_MIN,
+ colWidths, 0);
+ else {
+ // Normal apportioning.
+ int width;
+ if (getStyle()->width == core::style::LENGTH_AUTO) {
+ // Do not force width, when maximal width is smaller.
+ int maxWidth = 0;
+ for (int col = 0; col < colExtremes->size(); col++)
+ maxWidth += getColExtreme (col, MAX);
+ width = misc::min (totalWidth, maxWidth);
+ DBG_OBJ_MSGF ("resize", 1, "width = min (%d, %d) = %d",
+ totalWidth, maxWidth, width);
+ } else
+ // CSS 'width' defined: force this width.
+ width = totalWidth;
- apportion_percentages2 (totalWidth, forceTotalWidth);
- if (!hasColPercent)
- apportion2 (totalWidth, forceTotalWidth);
+ apportion2 (width, 0, colExtremes->size() - 1, MIN, MAX, colWidths, 0);
+ }
- setCumHeight (0, 0);
- for (int row = 0; row < numRows; row++) {
- /**
- * \bug dw::Table::baseline is not filled.
- */
- int rowHeight = 0;
+ // TODO: Adapted from old inline function "setColWidth". But (i) is
+ // this anyway correct (col width is is not x)? And does the
+ // performance gain actually play a role?
+ for (int col = 0; col < colExtremes->size(); col++) {
+ if (colWidths->get (col) != oldColWidths->get (col))
+ redrawX = lout::misc::min (redrawX, colWidths->get (col));
+ }
+
+ DBG_IF_RTFL {
+ DBG_OBJ_SET_NUM ("colWidths.size", colWidths->size ());
+ for (int i = 0; i < colWidths->size (); i++)
+ DBG_OBJ_ARRSET_NUM ("colWidths", i, colWidths->get (i));
+ }
- for (int col = 0; col < numCols; col++) {
- int n = row * numCols + col;
- if (childDefined (n)) {
- int width = (children->get(n)->cell.colspanEff - 1)
- * getStyle()->hBorderSpacing;
- for (int i = 0; i < children->get(n)->cell.colspanEff; i++)
- width += colWidths->get (col + i);
+ colWidthsUpToDateWidthColExtremes = true;
+ DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes",
+ colWidthsUpToDateWidthColExtremes);
- core::Requisition childRequisition;
- children->get(n)->cell.widget->setWidth (width);
- children->get(n)->cell.widget->sizeRequest (&childRequisition);
- childHeight = childRequisition.ascent + childRequisition.descent;
- if (children->get(n)->cell.rowspan == 1) {
- rowHeight = misc::max (rowHeight, childHeight);
- } else {
- rowSpanCells->increase();
- rowSpanCells->set(rowSpanCells->size()-1, n);
- }
+ for (int col = 0; col < numCols; col++) {
+ if (col >= oldColWidths->size () || col >= colWidths->size () ||
+ oldColWidths->get (col) != colWidths->get (col)) {
+ // Column width has changed, tell children about this.
+ for (int row = 0; row < numRows; row++) {
+ int n = row * numCols + col;
+ // TODO: Columns spanning several rows are only regarded
+ // when the first column is affected.
+ if (childDefined (n))
+ children->get(n)->cell.widget->containerSizeChanged ();
}
- }/*for col*/
+ }
+ }
+
+ delete oldColWidths;
- setCumHeight (row + 1,
- cumHeight->get (row) + rowHeight + getStyle()->vBorderSpacing);
+ if (calcHeights) {
+ setCumHeight (0, 0);
+ for (int row = 0; row < numRows; row++) {
+ /**
+ * \bug dw::Table::baseline is not filled.
+ */
+ int rowHeight = 0;
+
+ for (int col = 0; col < numCols; col++) {
+ int n = row * numCols + col;
+ if (childDefined (n)) {
+ int width = (children->get(n)->cell.colspanEff - 1)
+ * getStyle()->hBorderSpacing;
+ for (int i = 0; i < children->get(n)->cell.colspanEff; i++)
+ width += colWidths->get (col + i);
+
+ core::Requisition childRequisition;
+ //children->get(n)->cell.widget->setWidth (width);
+ children->get(n)->cell.widget->sizeRequest (&childRequisition);
+ childHeight = childRequisition.ascent + childRequisition.descent;
+ if (children->get(n)->cell.rowspan == 1) {
+ rowHeight = misc::max (rowHeight, childHeight);
+ } else {
+ rowSpanCells->increase();
+ rowSpanCells->set(rowSpanCells->size()-1, n);
+ }
+ }
+ } // for col
+
+ setCumHeight (row + 1,
+ cumHeight->get (row) + rowHeight + getStyle()->vBorderSpacing);
+ } // for row
- }/*for row*/
+ apportionRowSpan ();
+ }
- apportionRowSpan ();
+ DBG_OBJ_MSG_END ();
}
void Table::apportionRowSpan ()
{
+ DBG_OBJ_MSG ("resize", 0, "<b>apportionRowSpan</b>");
+ DBG_OBJ_MSG_START ();
+
int *rowHeight = NULL;
for (int c = 0; c < rowSpanCells->size(); ++c) {
@@ -630,6 +838,8 @@ void Table::apportionRowSpan ()
setCumHeight (i+1, cumHeight->get(i) + rowHeight[i]);
}
delete[] rowHeight;
+
+ DBG_OBJ_MSG_END ();
}
@@ -640,8 +850,13 @@ void Table::apportionRowSpan ()
*/
void Table::calcColumnExtremes ()
{
+ DBG_OBJ_MSG ("resize", 0, "<b>calcColumnExtremes</b>");
+ DBG_OBJ_MSG_START ();
+
if (extremesChanged () || extremesQueued ())
forceCalcColumnExtremes ();
+
+ DBG_OBJ_MSG_END ();
}
@@ -650,570 +865,286 @@ void Table::calcColumnExtremes ()
*/
void Table::forceCalcColumnExtremes ()
{
- _MSG(" Table::forceCalcColumnExtremes numCols=%d\n", numCols);
+ DBG_OBJ_MSG ("resize", 0, "<b>forceCalcColumnExtremes</b>");
+ DBG_OBJ_MSG_START ();
- if (numCols == 0)
- return;
-
- colExtremes->setSize (numCols);
- colPercents->setSize (numCols);
- colSpanCells->setSize (0);
- /* 1. cells with colspan = 1 */
- for (int col = 0; col < numCols; col++) {
- colExtremes->getRef(col)->minWidth = 0;
- colExtremes->getRef(col)->maxWidth = 0;
- colPercents->set(col, core::style::LENGTH_AUTO);
+ if (numCols > 0) {
+ lout::misc::SimpleVector<int> colSpanCells (8);
+ colExtremes->setSize (numCols);
- for (int row = 0; row < numRows; row++) {
- int n = row * numCols + col;
- if (!childDefined (n))
- continue;
- if (children->get(n)->cell.colspanEff == 1) {
- core::Extremes cellExtremes;
- int cellMinW, cellMaxW, pbm;
- core::style::Length width =
- children->get(n)->cell.widget->getStyle()->width;
- pbm = (numCols + 1) * getStyle()->hBorderSpacing
- + children->get(n)->cell.widget->getStyle()->boxDiffWidth ();
- children->get(n)->cell.widget->getExtremes (&cellExtremes);
- if (core::style::isAbsLength (width)) {
- // Fixed lengths include table padding, border and margin.
- cellMinW = cellExtremes.minWidth;
- cellMaxW = misc::max (cellMinW,
- core::style::absLengthVal(width) - pbm);
- } else {
- cellMinW = cellExtremes.minWidth;
- cellMaxW = cellExtremes.maxWidth;
+ // 1. cells with colspan = 1
+ for (int col = 0; col < numCols; col++) {
+ DBG_OBJ_MSGF ("resize", 1, "column %d", col);
+ DBG_OBJ_MSG_START ();
+
+ colExtremes->getRef(col)->minWidth = 0;
+ colExtremes->getRef(col)->minWidthIntrinsic = 0;
+ colExtremes->getRef(col)->maxWidth = 0;
+ colExtremes->getRef(col)->maxWidthIntrinsic = 0;
+
+ for (int row = 0; row < numRows; row++) {
+ DBG_OBJ_MSGF ("resize", 1, "row %d", row);
+ DBG_OBJ_MSG_START ();
+
+ int n = row * numCols + col;
+
+ if (childDefined (n)) {
+ if (children->get(n)->cell.colspanEff == 1) {
+ core::Extremes cellExtremes;
+ children->get(n)->cell.widget->getExtremes (&cellExtremes);
+
+ DBG_OBJ_MSGF ("resize", 1, "child: %d / %d",
+ cellExtremes.minWidth, cellExtremes.maxWidth);
+
+ colExtremes->getRef(col)->minWidthIntrinsic =
+ misc::max (colExtremes->getRef(col)->minWidthIntrinsic,
+ cellExtremes.minWidthIntrinsic);
+ colExtremes->getRef(col)->maxWidthIntrinsic =
+ misc::max (colExtremes->getRef(col)->minWidthIntrinsic,
+ colExtremes->getRef(col)->maxWidthIntrinsic,
+ cellExtremes.maxWidthIntrinsic);
+
+ colExtremes->getRef(col)->minWidth =
+ misc::max (colExtremes->getRef(col)->minWidth,
+ cellExtremes.minWidth);
+ colExtremes->getRef(col)->maxWidth =
+ misc::max (colExtremes->getRef(col)->minWidth,
+ colExtremes->getRef(col)->maxWidth,
+ cellExtremes.maxWidth);
+
+ DBG_OBJ_MSGF ("resize", 1, "column: %d / %d (%d / %d)",
+ colExtremes->getRef(col)->minWidth,
+ colExtremes->getRef(col)->maxWidth,
+ colExtremes->getRef(col)->minWidthIntrinsic,
+ colExtremes->getRef(col)->maxWidthIntrinsic);
+ } else {
+ colSpanCells.increase ();
+ colSpanCells.setLast (n);
+ }
}
- _MSG("FCCE, col%d colMin,colMax,cellMin,cellMax = %d,%d,%d,%d\n",
- col,
- colExtremes->getRef(col)->minWidth,
- colExtremes->getRef(col)->maxWidth,
- cellMinW, cellMaxW);
-
- colExtremes->getRef(col)->minWidth =
- misc::max (colExtremes->getRef(col)->minWidth, cellMinW);
- colExtremes->getRef(col)->maxWidth =
- misc::max (colExtremes->getRef(col)->minWidth, misc::max (
- colExtremes->getRef(col)->maxWidth,
- cellMaxW));
-
- // Also fill the colPercents array in this pass
- if (core::style::isPerLength (width)) {
- hasColPercent = 1;
- if (colPercents->get(col) == core::style::LENGTH_AUTO)
- colPercents->set(col, width);
- } else if (core::style::isAbsLength (width)) {
- // We treat LEN_ABS as a special case of LEN_AUTO.
- /*
- * if (colPercents->get(col) == LEN_AUTO)
- * colPercents->set(col, LEN_ABS);
- *
- * (Hint: that's old code!)
- */
- }
- } else {
- colSpanCells->increase();
- colSpanCells->set(colSpanCells->size()-1, n);
+ DBG_OBJ_MSG_END ();
}
- }
- }
- /* 2. cells with colspan > 1 */
- /* If needed, here we set proportionally apportioned col maximums */
- for (int c = 0; c < colSpanCells->size(); ++c) {
- core::Extremes cellExtremes;
- int cellMinW, cellMaxW, pbm;
- int n = colSpanCells->get(c);
- int col = n % numCols;
- int cs = children->get(n)->cell.colspanEff;
- core::style::Length width =
- children->get(n)->cell.widget->getStyle()->width;
- pbm = (numCols + 1) * getStyle()->hBorderSpacing
- + children->get(n)->cell.widget->getStyle()->boxDiffWidth ();
- children->get(n)->cell.widget->getExtremes (&cellExtremes);
- if (core::style::isAbsLength (width)) {
- // Fixed lengths include table padding, border and margin.
- cellMinW = cellExtremes.minWidth;
- cellMaxW =
- misc::max (cellMinW, core::style::absLengthVal(width) - pbm);
- } else {
- cellMinW = cellExtremes.minWidth;
- cellMaxW = cellExtremes.maxWidth;
- }
- int minSumCols = 0, maxSumCols = 0;
- for (int i = 0; i < cs; ++i) {
- minSumCols += colExtremes->getRef(col+i)->minWidth;
- maxSumCols += colExtremes->getRef(col+i)->maxWidth;
+ DBG_OBJ_MSG_END ();
}
- _MSG("cs=%d spanWidth=%d,%d sumCols=%d,%d\n",
- cs,cellMinW,cellMaxW,minSumCols,maxSumCols);
+ // 2. cells with colspan > 1
- if (minSumCols >= cellMinW && maxSumCols >= cellMaxW)
- continue;
+ // TODO: Is this old comment still relevant? "If needed, here we
+ // set proportionally apportioned col maximums."
- // Cell size is too small; apportion {min,max} for this colspan.
- int spanMinW = misc::max (misc::max (cs, minSumCols),
- cellMinW - (cs-1) * getStyle()->hBorderSpacing),
- spanMaxW = misc::max (misc::max (cs, maxSumCols),
- cellMaxW - (cs-1) * getStyle()->hBorderSpacing);
-
- if (minSumCols == 0) {
- // No single cells defined for this span => pre-apportion equally
- minSumCols = spanMinW; maxSumCols = spanMaxW;
- int minW = spanMinW, maxW = spanMaxW;
- for (int i = 0; i < cs; ++i) {
- colExtremes->getRef(col+i)->minWidth = minW / (cs - i);
- colExtremes->getRef(col+i)->maxWidth = maxW / (cs - i);
- minW -= colExtremes->getRef(col+i)->minWidth;
- maxW -= colExtremes->getRef(col+i)->maxWidth;
- }
- }
+ for (int i = 0; i < colSpanCells.size(); i++) {
+ int n = colSpanCells.get (i);
+ int col = n % numCols;
+ int cs = children->get(n)->cell.colspanEff;
- // These values will help if the span has percents.
- int spanHasColPercent = 0;
- int availSpanMinW = spanMinW;
- float cumSpanPercent = 0.0f;
- for (int i = col; i < col + cs; ++i) {
- if (core::style::isPerLength (colPercents->get(i))) {
- cumSpanPercent += core::style::perLengthVal (colPercents->get(i));
- ++spanHasColPercent;
- } else
- availSpanMinW -= colExtremes->getRef(i)->minWidth;
- }
-
- // Calculate weighted-apportion columns for this span.
- int wMin = 0, wMax;
- int cumMaxWnew = 0, cumMaxWold = 0, goalMaxW = spanMaxW;
- int curAppW = maxSumCols;
- int curExtraW = spanMinW - minSumCols;
- for (int i = col; i < col + cs; ++i) {
-
- if (!spanHasColPercent) {
- int d_a = colExtremes->getRef(i)->maxWidth;
- int d_w = curAppW > 0 ? (int)((float)curExtraW * d_a/curAppW) : 0;
- if (d_a < 0||d_w < 0) {
- MSG("d_a=%d d_w=%d\n",d_a,d_w);
- exit(1);
- }
- wMin = colExtremes->getRef(i)->minWidth + d_w;
- colExtremes->getRef(i)->minWidth = wMin;
- curExtraW -= d_w;
- curAppW -= d_a;
- } else {
- if (core::style::isPerLength (colPercents->get(i))) {
- // multiplyWithPerLength would cause rounding errors,
- // therefore the deprecated way, using perLengthVal:
- wMin = misc::max (colExtremes->getRef(i)->minWidth,
- (int)(availSpanMinW *
- core::style::perLengthVal
- (colPercents->get (i))
- / cumSpanPercent));
- colExtremes->getRef(i)->minWidth = wMin;
- }
- }
-
- wMax = (goalMaxW-cumMaxWnew <= 0) ? 0 :
- (int)((float)(goalMaxW-cumMaxWnew)
- * colExtremes->getRef(i)->maxWidth
- / (maxSumCols-cumMaxWold));
- wMax = misc::max (wMin, wMax);
- cumMaxWnew += wMax;
- cumMaxWold += colExtremes->getRef(i)->maxWidth;
- colExtremes->getRef(i)->maxWidth = wMax;
-
- _MSG("i=%d, wMin=%d wMax=%d cumMaxWold=%d\n",
- i,wMin,wMax,cumMaxWold);
+ core::Extremes cellExtremes;
+ children->get(n)->cell.widget->getExtremes (&cellExtremes);
+ calcExtremesSpanMulteCols (col, cs, &cellExtremes, MIN, MAX);
+ calcExtremesSpanMulteCols (col, cs, &cellExtremes, MIN_INTR, MAX_INTR);
}
-#ifdef DBG
- MSG("col min,max: [");
- for (int i = 0; i < numCols; i++)
- MSG("%d,%d ",
- colExtremes->getRef(i)->minWidth,
- colExtremes->getRef(i)->maxWidth);
- MSG("]\n");
- MSG("getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
-#endif
}
-}
-/**
- * \brief Apportionment function for AUTO-length columns.
- * 'extremes' comes filled, 'result' comes defined for percentage columns.
- */
-void Table::apportion2 (int totalWidth, int forceTotalWidth)
-{
- if (colExtremes->size() == 0)
- return;
-#ifdef DBG
- MSG("app2, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
- availWidth, totalWidth, forceTotalWidth);
- MSG("app2, extremes: ( ");
- for (int i = 0; i < colExtremes->size (); i++)
- MSG("%d,%d ",
- colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
- MSG(")\n");
-#endif
- int minAutoWidth = 0, maxAutoWidth = 0, availAutoWidth = totalWidth;
- for (int col = 0; col < numCols; col++) {
- if (core::style::isAbsLength (colPercents->get(col))) {
- // set absolute lengths
- setColWidth (col, colExtremes->get(col).minWidth);
+ DBG_IF_RTFL {
+ DBG_OBJ_SET_NUM ("colExtremes.size", colExtremes->size ());
+ for (int i = 0; i < colExtremes->size (); i++) {
+ DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "minWidth",
+ colExtremes->get(i).minWidth);
+ DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "minWidthIntrinsic",
+ colExtremes->get(i).minWidthIntrinsic);
+ DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "maxWidth",
+ colExtremes->get(i).maxWidth);
+ DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "maxWidthIntrinsic",
+ colExtremes->get(i).maxWidthIntrinsic);
}
- if (colPercents->get(col) == core::style::LENGTH_AUTO) {
- maxAutoWidth += colExtremes->get(col).maxWidth;
- minAutoWidth += colExtremes->get(col).minWidth;
- } else
- availAutoWidth -= colWidths->get(col);
}
- if (!maxAutoWidth) // no core::style::LENGTH_AUTO cols!
- return;
-
- colWidths->setSize (colExtremes->size (), 0);
+ colWidthsUpToDateWidthColExtremes = false;
+ DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes",
+ colWidthsUpToDateWidthColExtremes);
- if (!forceTotalWidth && maxAutoWidth < availAutoWidth) {
- // Enough space for the maximum table, don't widen past max.
- availAutoWidth = maxAutoWidth;
- }
-
- // General case.
- int curTargetWidth = misc::max (availAutoWidth, minAutoWidth);
- int curExtraWidth = curTargetWidth - minAutoWidth;
- int curMaxWidth = maxAutoWidth;
- int curNewWidth = minAutoWidth;
- for (int col = 0; col < numCols; col++) {
- _MSG("app2, col %d, minWidth=%d maxWidth=%d\n",
- col, colExtremes->getRef(col)->minWidth,
- colExtremes->get(col).maxWidth);
-
- if (colPercents->get(col) != core::style::LENGTH_AUTO)
- continue;
-
- int colMinWidth = colExtremes->getRef(col)->minWidth;
- int colMaxWidth = colExtremes->getRef(col)->maxWidth;
- int w = (curMaxWidth <= 0) ? 0 :
- (int)((float)curTargetWidth * colMaxWidth/curMaxWidth);
-
- _MSG("app2, curTargetWidth=%d colMaxWidth=%d curMaxWidth=%d "
- "curNewWidth=%d ",
- curTargetWidth, colMaxWidth,curMaxWidth,curNewWidth);
- _MSG("w = %d, ", w);
-
- if (w <= colMinWidth)
- w = colMinWidth;
- else if (curNewWidth - colMinWidth + w > curTargetWidth)
- w = colMinWidth + curExtraWidth;
-
- _MSG("w = %d\n", w);
-
- curNewWidth -= colMinWidth;
- curMaxWidth -= colMaxWidth;
- curExtraWidth -= (w - colMinWidth);
- curTargetWidth -= w;
- setColWidth (col, w);
- }
-#ifdef DBG
- MSG("app2, result: ( ");
- for (int i = 0; i < colWidths->size (); i++)
- MSG("%d ", colWidths->get (i));
- MSG(")\n");
-#endif
+ DBG_OBJ_MSG_END ();
}
-void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
+void Table::calcExtremesSpanMulteCols (int col, int cs,
+ core::Extremes *cellExtremes,
+ ExtrMod minExtrMod, ExtrMod maxExtrMod)
{
- int hasTablePercent = core::style::isPerLength (getStyle()->width) ? 1 : 0;
-
- if (colExtremes->size() == 0 || (!hasTablePercent && !hasColPercent))
- return;
-
- // If there's a table-wide percentage, totalWidth comes already scaled.
- _MSG("APP_P, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
- availWidth, totalWidth, forceTotalWidth);
+ DBG_OBJ_MSGF ("resize", 0,
+ "<b>calcExtremesSpanMulteCols (%d, %d, ..., %s, %s)",
+ col, cs, getExtrModName (minExtrMod),
+ getExtrModName (minExtrMod));
+ DBG_OBJ_MSG_START ();
+
+ int cellMin = getExtreme (cellExtremes, minExtrMod);
+ int cellMax = getExtreme (cellExtremes, maxExtrMod);
+
+ int minSumCols = 0, maxSumCols = 0;
+
+ for (int j = 0; j < cs; j++) {
+ minSumCols += getColExtreme (col + j, minExtrMod);
+ maxSumCols += getColExtreme (col + j, maxExtrMod);
+ }
- if (!hasColPercent) {
-#ifdef DBG
- MSG("APP_P, only a table-wide percentage\n");
- MSG("APP_P, extremes = { ");
- for (int col = 0; col < numCols; col++)
- MSG("%d,%d ", colExtremes->getRef(col)->minWidth,
- colExtremes->getRef(col)->maxWidth);
- MSG("}\n");
-#endif
- // It has only a table-wide percentage. Apportion non-absolute widths.
- int sumMaxWidth = 0, perAvailWidth = totalWidth;
- for (int col = 0; col < numCols; col++) {
- if (core::style::isAbsLength (colPercents->get(col)))
- perAvailWidth -= colExtremes->getRef(col)->maxWidth;
- else
- sumMaxWidth += colExtremes->getRef(col)->maxWidth;
+ DBG_OBJ_MSGF ("resize", 1, "cs = %d, cell: %d / %d, sum: %d / %d\n",
+ cs, cellMin, cellMax, minSumCols, maxSumCols);
+
+ bool changeMin = cellMin > minSumCols;
+ bool changeMax = cellMax > maxSumCols;
+ if (changeMin || changeMax) {
+ // TODO This differs from the documentation? Should work, anyway.
+ misc::SimpleVector<int> newMin, newMax;
+ if (changeMin)
+ apportion2 (cellMin, col, col + cs - 1, MIN, MAX, &newMin, 0);
+ if (changeMax)
+ apportion2 (cellMax, col, col + cs - 1, MIN, MAX, &newMax, 0);
+
+ for (int j = 0; j < cs; j++) {
+ if (changeMin)
+ setColExtreme (col + j, minExtrMod, newMin.get (j));
+ if (changeMax)
+ setColExtreme (col + j, maxExtrMod, newMax.get (j));
+
+ // For cases where min and max are somewhat confused:
+ setColExtreme (col + j, maxExtrMod,
+ misc::max (getColExtreme (col + j, minExtrMod),
+ getColExtreme (col + j, maxExtrMod)));
}
+ }
- _MSG("APP_P, perAvailWidth=%d, sumMaxWidth=%d\n",
- perAvailWidth, sumMaxWidth);
-
- for (int col = 0; col < numCols; col++) {
- int max_wi = colExtremes->getRef(col)->maxWidth, new_wi;
- if (!core::style::isAbsLength (colPercents->get(col))) {
- new_wi =
- misc::max (colExtremes->getRef(col)->minWidth,
- (int)((float)max_wi * perAvailWidth/sumMaxWidth));
- setColWidth (col, new_wi);
- perAvailWidth -= new_wi;
- sumMaxWidth -= max_wi;
- }
- }
-#ifdef DBG
- MSG("APP_P, result = { ");
- for (int col = 0; col < numCols; col++)
- MSG("%d ", colWidths->get(col));
- MSG("}\n");
-#endif
-
- } else {
- // we'll have to apportion...
- _MSG("APP_P, we'll have to apportion...\n");
-
- // Calculate cumPercent and available space
- float cumPercent = 0.0f;
- int hasAutoCol = 0;
- int sumMinWidth = 0, sumMaxWidth = 0, sumMinNonPer = 0, sumMaxNonPer = 0;
- for (int col = 0; col < numCols; col++) {
- if (core::style::isPerLength (colPercents->get(col))) {
- cumPercent += core::style::perLengthVal (colPercents->get(col));
- } else {
- sumMinNonPer += colExtremes->getRef(col)->minWidth;
- sumMaxNonPer += colExtremes->getRef(col)->maxWidth;
- if (colPercents->get(col) == core::style::LENGTH_AUTO)
- hasAutoCol++;
- }
- sumMinWidth += colExtremes->getRef(col)->minWidth;
- sumMaxWidth += colExtremes->getRef(col)->maxWidth;
+ DBG_OBJ_MSG_END ();
+}
- _MSG("APP_P, col %d minWidth=%d maxWidth=%d\n", col,
- colExtremes->getRef(col)->minWidth,
- colExtremes->getRef(col)->maxWidth);
+/**
+ * \brief Actual apportionment function.
+ */
+void Table::apportion2 (int totalWidth, int firstCol, int lastCol,
+ ExtrMod minExtrMod, ExtrMod maxExtrMod,
+ misc::SimpleVector<int> *dest, int destOffset)
+{
+ DBG_OBJ_MSGF ("resize", 0,
+ "<b>apportion2</b> (%d, %d, %d, %s, %s, ..., %d)",
+ totalWidth, firstCol, lastCol, getExtrModName (minExtrMod),
+ getExtrModName (maxExtrMod), destOffset);
+ DBG_OBJ_MSG_START ();
+
+ if (lastCol >= firstCol) {
+ dest->setSize (destOffset + lastCol - firstCol + 1, 0);
+
+ int totalMin = 0, totalMax = 0;
+ for (int col = firstCol; col <= lastCol; col++) {
+ totalMin += getColExtreme (col, minExtrMod);
+ totalMax += getColExtreme (col, maxExtrMod);
}
- int oldTotalWidth = totalWidth;
- if (!forceTotalWidth) {
- if (sumMaxNonPer == 0 || cumPercent < 0.99f) {
- // only percentage columns, or cumPercent < 100% => restrict width
- int totW = (int)(sumMaxNonPer / (1.0f - cumPercent));
- for (int col = 0; col < numCols; col++) {
- totW = misc::max
- (totW,
- (int)(colExtremes->getRef(col)->maxWidth
- / core::style::perLengthVal (colPercents->get(col))));
- }
- totalWidth = misc::min (totW, totalWidth);
+
+ DBG_OBJ_MSGF ("resize", 1,
+ "totalWidth = %d, totalMin = %d, totalMax = %d",
+ totalWidth, totalMin, totalMax);
+
+ // The actual calculation is rather simple, the ith value is:
+ //
+ //
+ // (max[i] - min[i]) * (totalMax - totalMin)
+ // width[i] = totalMin + -----------------------------------------
+ // (totalWidth - totalMin)
+ //
+ // (Regard "total" as "sum".) With the following general
+ // definitions (for both the list and sums):
+ //
+ // diffExtr = max - min
+ // diffWidth = width - min
+ //
+ // it is simplified to:
+ //
+ // diffExtr[i] * totalDiffWidth
+ // diffWidth[i] = ----------------------------
+ // totalDiffExtr
+ //
+ // Of course, if totalDiffExtr is 0, this is not defined;
+ // instead, we apportion according to the minima:
+ //
+ // min[i] * totalWidth
+ // width[i] = -------------------
+ // totalMin
+ //
+ // Since min[i] <= max[i] for all i, totalMin == totalMax
+ // implies that min[i] == max[i] for all i.
+ //
+ // Third, it totalMin == 0 (which also implies min[i] = max[i] = 0),
+ // the result is
+ //
+ // width[i] = totalWidth / n
+
+ int totalDiffExtr = totalMax - totalMin;
+ if (totalDiffExtr != 0) {
+ // Normal case. The algorithm described in
+ // "rounding-errors.doc" is used, with:
+ //
+ // x[i] = diffExtr[i]
+ // y[i] = diffWidth[i]
+ // a = totalDiffWidth
+ // b = totalDiffExtr
+
+ DBG_OBJ_MSG ("resize", 1, "normal case");
+
+ int totalDiffWidth = totalWidth - totalMin;
+ int cumDiffExtr = 0, cumDiffWidth = 0;
+
+ for (int col = firstCol; col <= lastCol; col++) {
+ int min = getColExtreme (col, minExtrMod);
+ int max = getColExtreme (col, maxExtrMod);
+ int diffExtr = max - min;
+
+ cumDiffExtr += diffExtr;
+ int diffWidth =
+ (cumDiffExtr * totalDiffWidth) / totalDiffExtr - cumDiffWidth;
+ cumDiffWidth += diffWidth;
+
+ dest->set (destOffset - firstCol + col, diffWidth + min);
}
- }
-
- // make sure there's enough space
- totalWidth = misc::max (totalWidth, sumMinWidth);
- // extraWidth is always >= 0
- int extraWidth = totalWidth - sumMinWidth;
- int sumMinWidthPer = sumMinWidth - sumMinNonPer;
- int curPerWidth = sumMinWidthPer;
- // percentages refer to workingWidth
- int workingWidth = totalWidth - sumMinNonPer;
- if (cumPercent < 0.99f) {
- // In this case, use the whole table width
- workingWidth = totalWidth;
- curPerWidth = sumMinWidth;
- }
-
- _MSG("APP_P, oldTotalWidth=%d totalWidth=%d"
- " workingWidth=%d extraWidth=%d sumMinNonPer=%d\n",
- oldTotalWidth,totalWidth,workingWidth,extraWidth,sumMinNonPer);
-
- for (int col = 0; col < numCols; col++) {
- int colMinWidth = colExtremes->getRef(col)->minWidth;
- if (core::style::isPerLength (colPercents->get(col))) {
- int w = core::style::multiplyWithPerLength (workingWidth,
- colPercents->get(col));
- if (w < colMinWidth)
- w = colMinWidth;
- else if (curPerWidth - colMinWidth + w > workingWidth)
- w = colMinWidth + extraWidth;
- extraWidth -= (w - colMinWidth);
- curPerWidth += (w - colMinWidth);
- setColWidth (col, w);
- } else {
- setColWidth (col, colMinWidth);
+ } else if (totalMin != 0) {
+ // Special case. Again, same algorithm, with
+ //
+ // x[i] = min[i]
+ // y[i] = width[i]
+ // a = totalWidth
+ // b = totalMin
+
+ DBG_OBJ_MSG ("resize", 1, "special case 1");
+
+ int cumMin = 0, cumWidth = 0;
+ for (int col = firstCol; col <= lastCol; col++) {
+ int min = getColExtreme (col, minExtrMod);
+ cumMin += min;
+ int width = (cumMin * totalWidth) / totalMin - cumWidth;
+ cumWidth += width;
+
+ dest->set (destOffset - firstCol + col, width);
}
- }
-
- if (cumPercent < 0.99f) {
- // Will have to apportion the other columns
-#ifdef DBG
- MSG("APP_P, extremes: ( ");
- for (int i = 0; i < colExtremes->size (); i++)
- MSG("%d,%d ",
- colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
- MSG(")\n");
-#endif
- curPerWidth -= sumMinNonPer;
- int perWidth = (int)(curPerWidth/cumPercent);
- totalWidth = misc::max (totalWidth, perWidth);
- totalWidth = misc::min (totalWidth, oldTotalWidth);
-
- _MSG("APP_P, curPerWidth=%d perWidth=%d, totalWidth=%d\n",
- curPerWidth, perWidth, totalWidth);
-
- if (hasAutoCol == 0) {
- // Special case, cumPercent < 100% and no other columns to expand.
- // We'll honor totalWidth by expanding the percentage cols.
- int extraWidth = totalWidth - curPerWidth - sumMinNonPer;
- for (int col = 0; col < numCols; col++) {
- if (core::style::isPerLength (colPercents->get(col))) {
- // This could cause rounding errors:
- //
- // int d =
- // core::dw::multiplyWithPerLength (extraWidth,
- // colPercents->get(col))
- // / cumPercent;
- //
- // Thus the "old" way:
- int d =
- (int)(extraWidth *
- core::style::perLengthVal (colPercents->get(col))
- / cumPercent);
- setColWidth (col, colWidths->get(col) + d);
- }
- }
+ } else if (totalMin != 0) {
+ // Last special case. Ssame algorithm, with
+ //
+ // x[i] = 1 (so cumX = i = col - firstCol + 1)
+ // y[i] = width[i]
+ // a = totalWidth
+ // b = n = lastCol - firstCol + 1
+
+ DBG_OBJ_MSG ("resize", 1, "special case 2");
+
+ int cumWidth = 0, n = (lastCol - firstCol + 1);
+ for (int col = firstCol; col <= lastCol; col++) {
+ int i = (col - firstCol + 1);
+ int width = (i * totalWidth) / n - cumWidth;
+ cumWidth += width;
+
+ dest->set (destOffset - firstCol + col, width);
}
}
-#ifdef DBG
- MSG("APP_P, result ={ ");
- for (int col = 0; col < numCols; col++)
- MSG("%d ", colWidths->get(col));
- MSG("}\n");
-#endif
- apportion2 (totalWidth, 2);
-
-#ifdef DBG
- MSG("APP_P, percent={");
- for (int col = 0; col < numCols; col++)
- MSG("%f ", core::dw::perLengthVal (colPercents->get(col)));
- MSG("}\n");
- MSG("APP_P, result ={ ");
- for (int col = 0; col < numCols; col++)
- MSG("%d ", colWidths->get(col));
- MSG("}\n");
-#endif
}
-}
-
-// ----------------------------------------------------------------------
-
-Table::TableIterator::TableIterator (Table *table,
- core::Content::Type mask, bool atEnd):
- core::Iterator (table, mask, atEnd)
-{
- index = atEnd ? table->children->size () : -1;
- content.type = atEnd ? core::Content::END : core::Content::START;
-}
-
-Table::TableIterator::TableIterator (Table *table,
- core::Content::Type mask, int index):
- core::Iterator (table, mask, false)
-{
- this->index = index;
-
- if (index < 0)
- content.type = core::Content::START;
- else if (index >= table->children->size ())
- content.type = core::Content::END;
- else {
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- }
-}
-
-object::Object *Table::TableIterator::clone()
-{
- return new TableIterator ((Table*)getWidget(), getMask(), index);
-}
-
-int Table::TableIterator::compareTo(object::Comparable *other)
-{
- return index - ((TableIterator*)other)->index;
-}
-
-bool Table::TableIterator::next ()
-{
- Table *table = (Table*)getWidget();
-
- if (content.type == core::Content::END)
- return false;
-
- // tables only contain widgets (in flow):
- if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) {
- content.type = core::Content::END;
- return false;
- }
-
- do {
- index++;
- if (index >= table->children->size ()) {
- content.type = core::Content::END;
- return false;
- }
- } while (table->children->get(index) == NULL ||
- table->children->get(index)->type != Child::CELL);
-
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- return true;
-}
-
-bool Table::TableIterator::prev ()
-{
- Table *table = (Table*)getWidget();
-
- if (content.type == core::Content::START)
- return false;
-
- // tables only contain widgets (in flow):
- if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) {
- content.type = core::Content::START;
- return false;
- }
-
- do {
- index--;
- if (index < 0) {
- content.type = core::Content::START;
- return false;
- }
- } while (table->children->get(index) == NULL ||
- table->children->get(index)->type != Child::CELL);
-
- content.type = core::Content::WIDGET_IN_FLOW;
- content.widget = table->children->get(index)->cell.widget;
- return true;
-}
-
-void Table::TableIterator::highlight (int start, int end,
- core::HighlightLayer layer)
-{
- /** todo Needs this an implementation? */
-}
-
-void Table::TableIterator::unhighlight (int direction,
- core::HighlightLayer layer)
-{
-}
-
-void Table::TableIterator::getAllocation (int start, int end,
- core::Allocation *allocation)
-{
- /** \bug Not implemented. */
+
+ DBG_OBJ_MSG_END ();
}
} // namespace dw
diff --git a/dw/table.hh b/dw/table.hh
index 6966a163..186f1f50 100644
--- a/dw/table.hh
+++ b/dw/table.hh
@@ -2,7 +2,7 @@
#define __DW_TABLE_HH__
#include "core.hh"
-#include "tablecell.hh"
+#include "alignedtablecell.hh"
#include "../lout/misc.hh"
namespace dw {
@@ -10,6 +10,11 @@ namespace dw {
/**
* \brief A Widget for rendering tables.
*
+ * <div style="border: 2px solid #ff0000; margin-top: 0.5em;
+ * margin-bottom: 0.5em; padding: 0.5em 1em;
+ * background-color: #ffefe0"><b>Warning:</b> Some parts of this
+ * description are outdated since \ref dw-grows.</div>
+ *
* <h3>Introduction</h3>
*
* The dw::Table widget is used to render HTML tables.
@@ -191,8 +196,9 @@ namespace dw {
*
* <ul>
* <li> the specified absolute width of the table, when given, or
- * <li> the available width (set by dw::Table::setWidth) times the specified
- * percentage width of t(at max 100%), if the latter is given, or
+ * <li> the available width (set by dw::Table::setWidth [TODO outdated]) times
+ * the specified percentage width of t(at max 100%), if the latter is
+ * given, or
* <li> otherwise the available width.
* </ul>
*
@@ -356,7 +362,6 @@ private:
friend class TableIterator;
bool limitTextWidth, rowClosed;
- int availWidth, availAscent, availDescent; // set by set...
int numRows, numCols, curRow, curCol;
lout::misc::SimpleVector<Child*> *children;
@@ -383,19 +388,22 @@ private:
* If a Cell has rowspan > 1, it goes into this array
*/
lout::misc::SimpleVector<int> *rowSpanCells;
- /**
- * If a Cell has colspan > 1, it goes into this array
- */
- lout::misc::SimpleVector<int> *colSpanCells;
lout::misc::SimpleVector<int> *baseline;
lout::misc::SimpleVector<core::style::Style*> *rowStyle;
- /**
- * hasColPercent becomes true when any cell specifies a percentage width.
- */
- int hasColPercent;
- lout::misc::SimpleVector<core::style::Length> *colPercents;
+ bool colWidthsUpToDateWidthColExtremes;
+
+ enum ExtrMod { MIN, MIN_INTR, MIN_MIN, MAX_MIN, MAX, MAX_INTR };
+
+ const char *getExtrModName (ExtrMod mod);
+ int getExtreme (core::Extremes *extremes, ExtrMod mod);
+ void setExtreme (core::Extremes *extremes, ExtrMod mod, int value);
+
+ inline int getColExtreme (int col, ExtrMod mod) {
+ return getExtreme (colExtremes->getRef(col), mod); }
+ inline void setColExtreme (int col, ExtrMod mod, int value) {
+ setExtreme (colExtremes->getRef(col), mod, value); }
inline bool childDefined(int n)
{
@@ -405,15 +413,19 @@ private:
void reallocChildren (int newNumCols, int newNumRows);
- void calcCellSizes ();
- void forceCalcCellSizes ();
+ void calcCellSizes (bool calcHeights);
+ void forceCalcCellSizes (bool calcHeights);
void apportionRowSpan ();
void calcColumnExtremes ();
void forceCalcColumnExtremes ();
+ void calcExtremesSpanMulteCols (int col, int cs,
+ core::Extremes *cellExtremes,
+ ExtrMod minExtrMod, ExtrMod maxExtrMod);
- void apportion2 (int totalWidth, int forceTotalWidth);
- void apportion_percentages2 (int totalWidth, int forceTotalWidth);
+ void apportion2 (int totalWidth, int firstCol, int lastCol,
+ ExtrMod minExtrMod, ExtrMod maxExtrMod,
+ lout::misc::SimpleVector<int> *dest, int destOffset);
void setCumHeight (int row, int value)
{
@@ -423,23 +435,19 @@ private:
}
}
- inline void setColWidth (int col, int value)
- {
- if (value != colWidths->get (col)) {
- redrawX = lout::misc::min (redrawX, value);
- colWidths->set (col, value);
- }
- }
-
protected:
void sizeRequestImpl (core::Requisition *requisition);
void getExtremesImpl (core::Extremes *extremes);
void sizeAllocateImpl (core::Allocation *allocation);
void resizeDrawImpl ();
- void setWidth (int width);
- void setAscent (int ascent);
- void setDescent (int descent);
+ int getAvailWidthOfChild (Widget *child, bool forceValue);
+
+ void containerSizeChangedForChildren ();
+ bool usesAvailWidth ();
+
+ bool isBlockLevel ();
+
void draw (core::View *view, core::Rectangle *area);
//bool buttonPressImpl (core::EventButton *event);
@@ -454,11 +462,14 @@ public:
Table(bool limitTextWidth);
~Table();
+ int applyPerWidth (int containerWidth, core::style::Length perWidth);
+ int applyPerHeight (int containerHeight, core::style::Length perHeight);
+
core::Iterator *iterator (core::Content::Type mask, bool atEnd);
void addCell (Widget *widget, int colspan, int rowspan);
void addRow (core::style::Style *style);
- TableCell *getCellRef ();
+ AlignedTableCell *getCellRef ();
};
} // namespace dw
diff --git a/dw/table_iterator.cc b/dw/table_iterator.cc
new file mode 100644
index 00000000..4da0ef4f
--- /dev/null
+++ b/dw/table_iterator.cc
@@ -0,0 +1,134 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2005-2007, 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * (This file was originally part of textblock.cc.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "table.hh"
+
+using namespace lout;
+
+namespace dw {
+
+Table::TableIterator::TableIterator (Table *table,
+ core::Content::Type mask, bool atEnd):
+ core::Iterator (table, mask, atEnd)
+{
+ index = atEnd ? table->children->size () : -1;
+ content.type = atEnd ? core::Content::END : core::Content::START;
+}
+
+Table::TableIterator::TableIterator (Table *table,
+ core::Content::Type mask, int index):
+ core::Iterator (table, mask, false)
+{
+ this->index = index;
+
+ if (index < 0)
+ content.type = core::Content::START;
+ else if (index >= table->children->size ())
+ content.type = core::Content::END;
+ else {
+ content.type = core::Content::WIDGET_IN_FLOW;
+ content.widget = table->children->get(index)->cell.widget;
+ }
+}
+
+object::Object *Table::TableIterator::clone()
+{
+ return new TableIterator ((Table*)getWidget(), getMask(), index);
+}
+
+int Table::TableIterator::compareTo(object::Comparable *other)
+{
+ return index - ((TableIterator*)other)->index;
+}
+
+bool Table::TableIterator::next ()
+{
+ Table *table = (Table*)getWidget();
+
+ if (content.type == core::Content::END)
+ return false;
+
+ // tables only contain widgets (in flow):
+ if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) {
+ content.type = core::Content::END;
+ return false;
+ }
+
+ do {
+ index++;
+ if (index >= table->children->size ()) {
+ content.type = core::Content::END;
+ return false;
+ }
+ } while (table->children->get(index) == NULL ||
+ table->children->get(index)->type != Child::CELL);
+
+ content.type = core::Content::WIDGET_IN_FLOW;
+ content.widget = table->children->get(index)->cell.widget;
+ return true;
+}
+
+bool Table::TableIterator::prev ()
+{
+ Table *table = (Table*)getWidget();
+
+ if (content.type == core::Content::START)
+ return false;
+
+ // tables only contain widgets (in flow):
+ if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) {
+ content.type = core::Content::START;
+ return false;
+ }
+
+ do {
+ index--;
+ if (index < 0) {
+ content.type = core::Content::START;
+ return false;
+ }
+ } while (table->children->get(index) == NULL ||
+ table->children->get(index)->type != Child::CELL);
+
+ content.type = core::Content::WIDGET_IN_FLOW;
+ content.widget = table->children->get(index)->cell.widget;
+ return true;
+}
+
+void Table::TableIterator::highlight (int start, int end,
+ core::HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Table::TableIterator::unhighlight (int direction,
+ core::HighlightLayer layer)
+{
+}
+
+void Table::TableIterator::getAllocation (int start, int end,
+ core::Allocation *allocation)
+{
+ /** \bug Not implemented. */
+}
+
+} // namespace dw
diff --git a/dw/tablecell.hh b/dw/tablecell.hh
deleted file mode 100644
index 1e13abf9..00000000
--- a/dw/tablecell.hh
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __DW_TABLECELL_HH__
-#define __DW_TABLECELL_HH__
-
-#include "core.hh"
-#include "alignedtextblock.hh"
-
-namespace dw {
-
-class TableCell: public AlignedTextblock
-{
-private:
- int charWordIndex, charWordPos;
-
-protected:
- int wordWrap (int wordIndex, bool wrapAll);
-
- int getValue ();
- void setMaxValue (int maxValue, int value);
-
-public:
- static int CLASS_ID;
-
- TableCell(TableCell *ref, bool limitTextWidth);
- ~TableCell();
-};
-
-} // namespace dw
-
-#endif // __DW_TABLECELL_HH__
diff --git a/dw/textblock.cc b/dw/textblock.cc
index beb3f3f8..8cb42999 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -225,13 +225,12 @@ Textblock::Textblock (bool limitTextWidth)
{
DBG_OBJ_CREATE ("dw::Textblock");
registerName ("dw::Textblock", &CLASS_ID);
- setFlags (BLOCK_LEVEL);
setFlags (USES_HINTS);
setButtonSensitive(true);
containingBlock = NULL;
hasListitemValue = false;
- innerPadding = 0;
+ leftInnerPadding = 0;
line1Offset = 0;
ignoreLine1OffsetSometimes = false;
mustQueueResize = false;
@@ -265,14 +264,9 @@ Textblock::Textblock (bool limitTextWidth)
hoverLink = -1;
- // random values
- availWidth = 100;
- availAscent = 100;
- availDescent = 0;
-
- DBG_OBJ_SET_NUM ("availWidth", availWidth);
- DBG_OBJ_SET_NUM ("availAscent", availAscent);
- DBG_OBJ_SET_NUM ("availDescent", availDescent);
+ // -1 means undefined.
+ lineBreakWidth = -1;
+ DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
verticalOffset = 0;
DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset);
@@ -338,6 +332,14 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
DBG_OBJ_MSG ("resize", 0, "<b>sizeRequestImpl</b> ()");
DBG_OBJ_MSG_START ();
+ int newLineBreakWidth = getAvailWidth (true);
+ if (newLineBreakWidth != lineBreakWidth) {
+ lineBreakWidth = newLineBreakWidth;
+ wrapRefLines = 0;
+ DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
+ DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
+ }
+
rewrap ();
showMissingLines ();
@@ -369,18 +371,33 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
requisition->descent = 0;
}
- DBG_OBJ_MSGF ("resize", 1, "inner padding = %d, boxDiffWidth = %d",
- innerPadding, getStyle()->boxDiffWidth ());
+ DBG_OBJ_MSGF ("resize", 1, "left inner padding = %d, boxDiffWidth = %d",
+ leftInnerPadding, getStyle()->boxDiffWidth ());
- requisition->width += innerPadding + getStyle()->boxDiffWidth ();
+ requisition->width += leftInnerPadding + getStyle()->boxDiffWidth ();
requisition->ascent += verticalOffset + getStyle()->boxOffsetY ();
requisition->descent += getStyle()->boxRestHeight ();
+ DBG_OBJ_MSGF ("resize", 1, "before correction: %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+
+ correctRequisition (requisition, core::splitHeightPreserveAscent);
+
// Dealing with parts out of flow, which may overlap the borders of
// the text block. Base lines are ignored here: they do not play a
// role (currently) and caring about them (for the future) would
// cause too much problems.
+ // Notice that the order is not typical: correctRequisition should
+ // be the last call. However, calling correctRequisition after
+ // outOfFlowMgr->getSize may result again in a size which is too
+ // small for floats, so triggering again (and again) the resize
+ // idle function resulting in CPU hogging. See also
+ // getExtremesImpl.
+ //
+ // Is this really what we want? An alternative could be that
+ // OutOfFlowMgr::getSize honours CSS attributes an corrected sizes.
+
DBG_OBJ_MSGF ("resize", 1, "before considering OOF widgets: %d * (%d + %d)",
requisition->width, requisition->ascent, requisition->descent);
@@ -392,20 +409,8 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
requisition->descent = oofHeight - requisition->ascent;
}
- DBG_OBJ_MSGF ("resize", 1,
- "before considering availWidth (= %d): %d * (%d + %d)",
- availWidth, requisition->width, requisition->ascent,
- requisition->descent);
-
- if (requisition->width < availWidth) {
- requisition->width = availWidth;
- DBG_OBJ_MSGF ("resize", 1, "adjusting to availWidth => %d",
- requisition->width);
- }
-
- DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ DBG_OBJ_MSGF ("resize", 1, "final: %d * (%d + %d)",
requisition->width, requisition->ascent, requisition->descent);
-
DBG_OBJ_MSG_END ();
}
@@ -414,44 +419,11 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
*/
void Textblock::getWordExtremes (Word *word, core::Extremes *extremes)
{
- if (word->content.type == core::Content::WIDGET_IN_FLOW) {
- if (word->content.widget->usesHints ()) {
- word->content.widget->getExtremes (extremes);
-
- if (core::style::isAbsLength (word->content.widget
- ->getStyle()->width)) {
- int width =
- core::style::absLengthVal (word->content.widget
- ->getStyle()->width);
- if (extremes->minWidth < width)
- extremes->minWidth = width;
- if (extremes->maxWidth > width)
- // maxWidth not smaller than minWidth
- extremes->maxWidth = misc::max (width, extremes->minWidth);
- }
- } else {
- if (core::style::isPerLength
- (word->content.widget->getStyle()->width)) {
- extremes->minWidth = 0;
- if (word->content.widget->hasContents ())
- extremes->maxWidth = 1000000;
- else
- extremes->maxWidth = 0;
- } else if (core::style::isAbsLength
- (word->content.widget->getStyle()->width)) {
- /* Fixed lengths are only applied to the content, so we have to
- * add padding, border and margin. */
- extremes->minWidth = extremes->maxWidth =
- core::style::absLengthVal (word->content.widget->getStyle()
- ->width)
- + word->style->boxDiffWidth ();
- } else
- word->content.widget->getExtremes (extremes);
- }
- } else {
- extremes->minWidth = word->size.width;
- extremes->maxWidth = word->size.width;
- }
+ if (word->content.type == core::Content::WIDGET_IN_FLOW)
+ word->content.widget->getExtremes (extremes);
+ else
+ extremes->minWidth = extremes->minWidthIntrinsic = extremes->maxWidth =
+ extremes->maxWidthIntrinsic = word->size.width;
}
void Textblock::getExtremesImpl (core::Extremes *extremes)
@@ -459,41 +431,83 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
DBG_OBJ_MSG ("resize", 0, "<b>getExtremesImpl</b>");
DBG_OBJ_MSG_START ();
+ // TODO Can extremes depend on the available width? Should not; if
+ // they do, the following code must be reactivated, but it causes
+ // an endless recursion.
+#if 0
+ int newLineBreakWidth = getAvailWidth (true);
+ if (newLineBreakWidth != lineBreakWidth) {
+ lineBreakWidth = newLineBreakWidth;
+ wrapRefParagraphs = 0;
+ DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
+ DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefLines);
+ }
+#endif
+
fillParagraphs ();
if (paragraphs->size () == 0) {
/* empty page */
extremes->minWidth = 0;
+ extremes->minWidthIntrinsic = 0;
extremes->maxWidth = 0;
+ extremes->maxWidthIntrinsic = 0;
} else {
Paragraph *lastPar = paragraphs->getLastRef ();
extremes->minWidth = lastPar->maxParMin;
+ extremes->minWidthIntrinsic = lastPar->maxParMinIntrinsic;
extremes->maxWidth = lastPar->maxParMax;
+ extremes->maxWidthIntrinsic = lastPar->maxParMaxIntrinsic;
- DBG_OBJ_MSGF ("resize", 1, "paragraphs[%d]->maxParMin = %d",
- paragraphs->size () - 1, lastPar->maxParMin);
- DBG_OBJ_MSGF ("resize", 1, "paragraphs[%d]->maxParMax = %d",
- paragraphs->size () - 1, lastPar->maxParMax);
+ DBG_OBJ_MSGF ("resize", 1, "paragraphs[%d]->maxParMin = %d (%d)",
+ paragraphs->size () - 1, lastPar->maxParMin,
+ lastPar->maxParMinIntrinsic);
+ DBG_OBJ_MSGF ("resize", 1, "paragraphs[%d]->maxParMax = %d (%d)",
+ paragraphs->size () - 1, lastPar->maxParMax,
+ lastPar->maxParMaxIntrinsic);
}
- int diff = innerPadding + getStyle()->boxDiffWidth ();
+ DBG_OBJ_MSGF ("resize", 0, "after considering paragraphs: %d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ int diff = leftInnerPadding + getStyle()->boxDiffWidth ();
extremes->minWidth += diff;
+ extremes->minWidthIntrinsic += diff;
extremes->maxWidth += diff;
+ extremes->maxWidthIntrinsic += diff;
+
+ DBG_OBJ_MSGF ("resize", 0, "after adding diff: %d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ // For the order, see similar reasoning in sizeRequestImpl.
+
+ correctExtremes (extremes);
+
+ DBG_OBJ_MSGF ("resize", 0, "after correction: %d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
if (outOfFlowMgr) {
int oofMinWidth, oofMaxWidth;
outOfFlowMgr->getExtremes (extremes, &oofMinWidth, &oofMaxWidth);
- DBG_OBJ_MSGF ("resize", 1, "extremes: %d / %d, corrected: %d / %d",
- extremes->minWidth, extremes->maxWidth,
+ DBG_OBJ_MSGF ("resize", 1, "OOFM correction: %d / %d",
oofMinWidth, oofMaxWidth);
extremes->minWidth = misc::max (extremes->minWidth, oofMinWidth);
+ extremes->minWidthIntrinsic =
+ misc::max (extremes->minWidthIntrinsic, oofMinWidth);
extremes->maxWidth = misc::max (extremes->maxWidth, oofMaxWidth);
+ extremes->maxWidthIntrinsic =
+ misc::max (extremes->maxWidthIntrinsic, oofMinWidth);
}
- DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
- extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_MSGF ("resize", 0,
+ "finally, after considering OOFM: %d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
DBG_OBJ_MSG_END ();
}
@@ -523,8 +537,13 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
}
for (lineIndex = 0; lineIndex < lines->size (); lineIndex++) {
+ // Especially for floats, allocation->width may be different
+ // from the line break width, so that for centered and right
+ // text, the offsets have to be recalculated again.
+ calcTextOffset (lineIndex, allocation->width);
+
line = lines->getRef (lineIndex);
- xCursor = line->offsetCompleteWidget;
+ xCursor = line->textOffset;
for (wordIndex = line->firstWord; wordIndex <= line->lastWord;
wordIndex++) {
@@ -632,6 +651,23 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
}
}
+void Textblock::containerSizeChangedForChildren ()
+{
+ for (int i = 0; i < words->size (); i++) {
+ Word *word = words->getRef (i);
+ if (word->content.type == core::Content::WIDGET_IN_FLOW)
+ word->content.widget->containerSizeChanged ();
+ }
+
+ if (outOfFlowMgr)
+ outOfFlowMgr->containerSizeChangedForChildren ();
+}
+
+bool Textblock::usesAvailWidth ()
+{
+ return true;
+}
+
void Textblock::resizeDrawImpl ()
{
DBG_OBJ_MSG ("draw", 0, "<b>resizeDrawImpl</b> ()");
@@ -773,53 +809,9 @@ void Textblock::notifySetParent ()
assert (containingBlock != NULL);
}
-void Textblock::setWidth (int width)
+bool Textblock::isBlockLevel ()
{
- /* If limitTextWidth is set to YES, a queueResize() may also be
- * necessary. */
- if (availWidth != width || limitTextWidth) {
- DBG_OBJ_MSGF ("resize", 0, "<b>setWidth</b> (%d)", width);
- DBG_OBJ_MSG_START ();
-
- availWidth = width;
- DBG_OBJ_SET_NUM ("availWidth", availWidth);
- queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
- mustQueueResize = false;
- redrawY = 0;
- DBG_OBJ_SET_NUM ("redrawY", redrawY);
-
- DBG_OBJ_MSG_END ();
- }
-}
-
-void Textblock::setAscent (int ascent)
-{
- if (availAscent != ascent) {
- DBG_OBJ_MSGF ("resize", 0, "<b>setAscent</b> (%d)", ascent);
- DBG_OBJ_MSG_START ();
-
- availAscent = ascent;
- DBG_OBJ_SET_NUM ("availAscent", availAscent);
- queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
- mustQueueResize = false;
-
- DBG_OBJ_MSG_END ();
- }
-}
-
-void Textblock::setDescent (int descent)
-{
- if (availDescent != descent) {
- DBG_OBJ_MSGF ("resize", 0, "<b>setDescent</b> (%d)", descent);
- DBG_OBJ_MSG_START ();
-
- availDescent = descent;
- DBG_OBJ_SET_NUM ("availDescent", availDescent);
- queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
- mustQueueResize = false;
-
- DBG_OBJ_MSG_END ();
- }
+ return true;
}
bool Textblock::buttonPressImpl (core::EventButton *event)
@@ -935,11 +927,11 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType,
// Choose this break.
wordIndex = line->lastWord;
charPos = core::SelectionState::END_OF_WORD;
- } else if (event->xWidget < line->offsetCompleteWidget) {
+ } else if (event->xWidget < line->textOffset) {
// Left of the first word in the line.
wordIndex = line->firstWord;
} else {
- int nextWordStartX = line->offsetCompleteWidget;
+ int nextWordStartX = line->textOffset;
for (wordIndex = line->firstWord;
wordIndex <= line->lastWord;
@@ -1052,7 +1044,6 @@ core::Iterator *Textblock::iterator (core::Content::Type mask, bool atEnd)
return new TextblockIterator (this, mask, atEnd);
}
-
/**
* Calculate the size of a widget within the page.
* (Subject of change in the near future!)
@@ -1061,78 +1052,11 @@ void Textblock::calcWidgetSize (core::Widget *widget, core::Requisition *size)
{
DBG_OBJ_MSGF ("resize", 0, "<b>calcWidgetSize</b> (%p, ...)", widget);
- core::Requisition requisition;
- int availWidth, availAscent, availDescent;
- core::style::Style *wstyle = widget->getStyle();
+ widget->sizeRequest (size);
- /* We ignore line1_offset[_eff]. */
- availWidth = this->availWidth - getStyle()->boxDiffWidth () - innerPadding;
- availAscent = this->availAscent - getStyle()->boxDiffHeight ();
- availDescent = this->availDescent;
-
- if (widget->usesHints ()) {
- // This is a simplified version of calcAvailWidth (see there for
- // more details). Until recently, the *attribute* availWidth was
- // used, widthout any corrections. To limit the damage, only
- // includde left and right border (by floats), until the Great
- // Redesign Of Widget Sizes (GROWS).
- int corrAvailWidth;
- // Textblocks keep track of borders themselves, so they get the
- // total available width. (Should once replaced by something
- // like OOFAware.)
- if (widget->instanceOf (Textblock::CLASS_ID))
- corrAvailWidth = availWidth;
- else
- corrAvailWidth =
- misc::max (availWidth - (newLineLeftBorder + newLineRightBorder),
- 0);
-
- DBG_OBJ_MSGF ("resize", 1, "setting hints: %d, %d, %d",
- corrAvailWidth, availAscent, availDescent);
- widget->setWidth (corrAvailWidth);
- widget->setAscent (availAscent);
- widget->setDescent (availDescent);
- widget->sizeRequest (size);
- DBG_OBJ_MSGF ("resize", 1, "sizeRequest => %d * (%d + %d)",
- size->width, size->ascent, size->descent);
- } else {
- if (wstyle->width == core::style::LENGTH_AUTO ||
- wstyle->height == core::style::LENGTH_AUTO) {
- widget->sizeRequest (&requisition);
- DBG_OBJ_MSGF ("resize", 1, "AUTO; sizeRequest => %d * (%d + %d)",
- requisition.width, requisition.ascent,
- requisition.descent);
- }
-
- if (wstyle->width == core::style::LENGTH_AUTO)
- size->width = requisition.width;
- else if (core::style::isAbsLength (wstyle->width))
- /* Fixed lengths are only applied to the content, so we have to
- * add padding, border and margin. */
- size->width = core::style::absLengthVal (wstyle->width)
- + wstyle->boxDiffWidth ();
- else
- size->width =
- core::style::multiplyWithPerLength (availWidth, wstyle->width);
-
- if (wstyle->height == core::style::LENGTH_AUTO) {
- size->ascent = requisition.ascent;
- size->descent = requisition.descent;
- } else if (core::style::isAbsLength (wstyle->height)) {
- /* Fixed lengths are only applied to the content, so we have to
- * add padding, border and margin. */
- size->ascent = core::style::absLengthVal (wstyle->height)
- + wstyle->boxDiffHeight ();
- size->descent = 0;
- } else {
- size->ascent =
- core::style::multiplyWithPerLength (wstyle->height, availAscent);
- size->descent =
- core::style::multiplyWithPerLength (wstyle->height, availDescent);
- }
- }
-
- /* ascent and descent in words do not contain margins. */
+ // Ascent and descent in words do not contain margins.
+ // TODO: Re-evaluate (GROWS)!
+ core::style::Style *wstyle = widget->getStyle();
size->ascent -= wstyle->margin.top;
size->descent -= wstyle->margin.bottom;
@@ -1454,7 +1378,7 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
area->x, area->y, area->width, area->height);
DBG_OBJ_MSG_START ();
- int xWidget = line->offsetCompleteWidget;
+ int xWidget = line->textOffset;
int yWidgetBase = lineYOffsetWidget (line) + line->boxAscent;
DBG_OBJ_MSGF ("draw", 1, "line from %d to %d (%d words), at (%d, %d)",
@@ -1647,7 +1571,7 @@ Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace)
if (yWidgetBase + line->boxDescent <= y)
return NULL;
- xCursor = line->offsetCompleteWidget;
+ xCursor = line->textOffset;
for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
word = words->getRef (wordIndex);
lastXCursor = xCursor;
@@ -1720,6 +1644,11 @@ Textblock::Word *Textblock::addWord (int width, int ascent, int descent,
width, ascent, descent, flags, style);
DBG_OBJ_MSG_START ();
+ if (lineBreakWidth == -1) {
+ lineBreakWidth = getAvailWidth (true);
+ DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
+ }
+
words->increase ();
DBG_OBJ_SET_NUM ("words.size", words->size ());
int wordNo = words->size () - 1;
diff --git a/dw/textblock.hh b/dw/textblock.hh
index 3254b843..b112ba29 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -130,7 +130,7 @@ namespace dw {
* widget:
*
* <ul>
- * <li> The available size of the widget has changed, e.g., because the
+ * <li> The line break size of the widget has changed, e.g., because the
* user has changed the size of the browser window. In this case,
* it is necessary to rewrap all the lines.
*
@@ -306,14 +306,18 @@ protected:
int parMin; /* The sum of all word minima (plus spaces,
hyphen width etc.) since the last possible
break within this paragraph. */
+ int parMinIntrinsic;
int parMax; /* The sum of all word maxima in this
paragraph (plus spaces, hyphen width
etc.). */
+ int parMaxIntrinsic;
int maxParMin; /* Maximum of all paragraph minima (value of
"parMin"), including this paragraph. */
+ int maxParMinIntrinsic;
int maxParMax; /* Maximum of all paragraph maxima (value of
"parMax""), including this paragraph. */
+ int maxParMaxIntrinsic;
};
struct Line
@@ -334,8 +338,7 @@ protected:
int contentAscent; /* ??? */
int contentDescent; /* ??? */
int breakSpace; /* Space between this line and the next one. */
- int leftOffset; /* ??? */
- int offsetCompleteWidget; /* ??? */
+ int textOffset; /* ??? */
/* This is similar to descent, but includes the bottom margins of the
* widgets within this line. */
@@ -361,6 +364,9 @@ protected:
* even a following line, when positioned before (this is the
* reason this attribute exists); see \ref dw-out-of-flow. */
int lastOofRefPositionedBeforeThisLine;
+
+ int leftOffset, rightOffset;
+ enum { LEFT, RIGHT, CENTER } alignment;
};
struct Word
@@ -472,7 +478,7 @@ protected:
/* These fields provide some ad-hoc-functionality, used by sub-classes. */
bool hasListitemValue; /* If true, the first word of the page is treated
specially (search in source). */
- int innerPadding; /* This is an additional padding on the left side
+ int leftInnerPadding; /* This is an additional padding on the left side
(used by ListItem). */
int line1Offset; /* This is an additional offset of the first line.
May be negative (shift to left) or positive
@@ -489,7 +495,7 @@ protected:
* (which is used by DwTable!), and
* (ii) line1_offset is ignored (line1_offset_eff is set to 0),
* when line1_offset plus the width of the first word is
- * greater than the the available witdh.
+ * greater than the the line break witdh.
*
* \todo Eliminate all these ad-hoc features by a new, simpler and
* more elegant design. ;-)
@@ -516,8 +522,8 @@ protected:
int redrawY;
int lastWordDrawn;
- /* These values are set by set_... */
- int availWidth, availAscent, availDescent;
+ /* This value is (currently) set by setAscent(). */
+ int lineBreakWidth;
// Additional vertical offset, used for the "clear" attribute.
int verticalOffset;
@@ -702,8 +708,6 @@ protected:
bool sendSelectionEvent (core::SelectionState::EventType eventType,
core::MousePositionEvent *event);
- void accumulateWordExtremes (int firstWord, int lastWord,
- int *maxOfMinWidth, int *sumOfMaxWidth);
void processWord (int wordIndex);
virtual int wordWrap (int wordIndex, bool wrapAll);
int wrapWordInFlow (int wordIndex, bool wrapAll);
@@ -737,22 +741,26 @@ protected:
void moveWordIndices (int wordIndex, int num, int *addIndex1 = NULL);
void accumulateWordForLine (int lineIndex, int wordIndex);
void accumulateWordData (int wordIndex);
- int calcAvailWidth (int lineIndex);
+ int calcLineBreakWidth (int lineIndex);
void initLine1Offset (int wordIndex);
void alignLine (int lineIndex);
+ void calcTextOffset (int lineIndex, int totalWidth);
void sizeRequestImpl (core::Requisition *requisition);
void getExtremesImpl (core::Extremes *extremes);
void sizeAllocateImpl (core::Allocation *allocation);
+ void containerSizeChangedForChildren ();
+ bool usesAvailWidth ();
void resizeDrawImpl ();
void markSizeChange (int ref);
void markExtremesChange (int ref);
+
void notifySetAsTopLevel();
void notifySetParent();
- void setWidth (int width);
- void setAscent (int ascent);
- void setDescent (int descent);
+
+ bool isBlockLevel ();
+
void draw (core::View *view, core::Rectangle *area);
bool buttonPressImpl (core::EventButton *event);
@@ -814,9 +822,7 @@ public:
queueResize (-1, extremesChanged);
DBG_OBJ_MSG_END ();
}
- inline int getAvailWidth () { return availWidth; }
- inline int getAvailAscent () { return availAscent; }
- inline int getAvailDescent () { return availDescent; }
+ inline int getLineBreakWidth () { return lineBreakWidth; }
};
#define DBG_SET_WORD_PENALTY(n, i, is) \
diff --git a/dw/textblock_iterator.cc b/dw/textblock_iterator.cc
index c26b7f6e..56ad6e15 100644
--- a/dw/textblock_iterator.cc
+++ b/dw/textblock_iterator.cc
@@ -289,7 +289,7 @@ void Textblock::TextblockIterator::getAllocation (int start, int end,
Word *word = textblock->words->getRef (index);
allocation->x =
- textblock->allocation.x + line->offsetCompleteWidget;
+ textblock->allocation.x + line->textOffset;
for (int i = line->firstWord; i < index; i++) {
Word *w = textblock->words->getRef(i);
diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc
index a773f24c..7787ce63 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -92,7 +92,7 @@ void Textblock::BadnessAndPenalty::calcBadness (int totalWidth, int idealWidth,
badness = ratio * ratio * ratio;
}
}
- } else { // if (totalWidth > availWidth)
+ } else { // if (totalWidth > idealWidth)
if (totalShrinkability == 0)
badnessState = TOO_TIGHT;
else {
@@ -378,10 +378,6 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
lineWidth);
}
- int maxOfMinWidth, sumOfMaxWidth;
- accumulateWordExtremes (firstWord, lastWord, &maxOfMinWidth,
- &sumOfMaxWidth);
-
lines->increase ();
DBG_OBJ_SET_NUM ("lines.size", lines->size ());
@@ -403,10 +399,17 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
line->boxDescent = line->contentDescent = 0;
line->marginDescent = 0;
line->breakSpace = 0;
- line->leftOffset = 0;
line->finished = false;
+
+ bool regardBorder = mustBorderBeRegarded (line);
+ line->leftOffset = misc::max (regardBorder ? newLineLeftBorder : 0,
+ boxOffsetX () + leftInnerPadding
+ + (lineIndex == 0 ? line1OffsetEff : 0));
+ line->rightOffset = misc::max (regardBorder ? newLineRightBorder : 0,
+ boxRestWidth ());
alignLine (lineIndex);
+ calcTextOffset (lineIndex, lineBreakWidth);
for (int i = line->firstWord; i < line->lastWord; i++) {
Word *word = words->getRef (i);
@@ -438,14 +441,6 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
// the height should be positive.
line->boxAscent = misc::max (line->boxAscent, 1);
- // Calculate offsetCompleteWidget, which includes also floats.
- int leftBorder = mustBorderBeRegarded (line) ? newLineLeftBorder : 0;
- line->offsetCompleteWidget =
- misc::max (leftBorder,
- getStyle()->boxOffsetX() + innerPadding
- + (lineIndex == 0 ? line1OffsetEff : 0))
- + line->leftOffset;
-
DBG_OBJ_MSGF ("construct.line", 1, "top = %d\n", line->top);
DBG_OBJ_MSGF ("construct.line", 1, "boxAscent = %d\n", line->boxAscent);
DBG_OBJ_MSGF ("construct.line", 1, "boxDescent = %d\n", line->boxDescent);
@@ -455,8 +450,7 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
line->contentDescent);
DBG_OBJ_MSGF ("construct.line", 1, "maxLineWidth = %d (lineWidth = %d)\n",
line->maxLineWidth, lineWidth);
- DBG_OBJ_MSGF ("construct.line", 1, "offsetCompleteWidget = %d\n",
- line->offsetCompleteWidget);
+ DBG_OBJ_MSGF ("construct.line", 1, "textOffset = %d\n", line->textOffset);
mustQueueResize = true;
@@ -467,7 +461,7 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
//words->getRef(line->lastWord)->badnessAndPenalty.print ();
//printf ("\n");
- int xWidget = line->offsetCompleteWidget;
+ int xWidget = line->textOffset;
for (int i = firstWord; i <= lastWord; i++) {
Word *word = words->getRef (i);
if (word->wordImgRenderer)
@@ -489,44 +483,6 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
return line;
}
-void Textblock::accumulateWordExtremes (int firstWord, int lastWord,
- int *maxOfMinWidth, int *sumOfMaxWidth)
-{
- int parMin = 0;
- *maxOfMinWidth = *sumOfMaxWidth = 0;
-
- for (int i = firstWord; i <= lastWord; i++) {
- Word *word = words->getRef (i);
- bool atLastWord = i == lastWord;
-
- core::Extremes extremes;
- getWordExtremes (word, &extremes);
-
- // Minimum: between two *possible* breaks (or at the end).
- // TODO This is redundant to getExtremesImpl().
- // TODO: Again, index 1 is used for lineCanBeBroken(). See getExtremes().
- if (word->badnessAndPenalty.lineCanBeBroken (1) || atLastWord) {
- parMin += extremes.minWidth + word->hyphenWidth;
- *maxOfMinWidth = misc::max (*maxOfMinWidth, parMin);
- parMin = 0;
- } else
- // Shrinkability could be considered, but really does not play a
- // role.
- parMin += extremes.minWidth + word->origSpace;
-
- //printf ("[%p] after word: ", this);
- //printWord (word);
- //printf ("\n");
-
- //printf ("[%p] (%d / %d) => parMin = %d, maxOfMinWidth = %d\n",
- // this, extremes.minWidth, extremes.maxWidth, parMin,
- // *maxOfMinWidth);
-
- *sumOfMaxWidth += (extremes.maxWidth + word->origSpace);
- // Notice that the last space is added. See also: Line::parMax.
- }
-}
-
void Textblock::processWord (int wordIndex)
{
DBG_OBJ_MSGF ("construct.all", 0, "<b>processWord</b> (%d)", wordIndex);
@@ -637,7 +593,7 @@ int Textblock::wrapWordInFlow (int wordIndex, bool wrapAll)
// be left empty.
// (In other cases, lines are never left empty, even if this means
- // that the contents is wider than the available witdh. Leaving
+ // that the contents is wider than the line break width. Leaving
// lines empty does not make sense without floats, since there will
// be no possibility with more space anymore.)
@@ -1209,12 +1165,15 @@ void Textblock::handleWordExtremes (int wordIndex)
core::Extremes wordExtremes;
getWordExtremes (word, &wordExtremes);
- DBG_OBJ_MSGF ("construct.paragraph", 1, "extremes: %d / %d",
- wordExtremes.minWidth, wordExtremes.maxWidth);
+ DBG_OBJ_MSGF ("construct.paragraph", 1, "extremes: %d (%d) / %d (%d",
+ wordExtremes.minWidth, wordExtremes.minWidthIntrinsic,
+ wordExtremes.maxWidth, wordExtremes.maxWidthIntrinsic);
if (wordIndex == 0) {
wordExtremes.minWidth += line1OffsetEff;
+ wordExtremes.minWidthIntrinsic += line1OffsetEff;
wordExtremes.maxWidth += line1OffsetEff;
+ wordExtremes.maxWidthIntrinsic += line1OffsetEff;
}
if (paragraphs->size() == 0 ||
@@ -1227,13 +1186,17 @@ void Textblock::handleWordExtremes (int wordIndex)
Paragraph *par = paragraphs->getLastRef();
par->firstWord = par->lastWord = wordIndex;
- par->parMin = par->parMax = 0;
+ par->parMin = par->parMinIntrinsic = par->parMax = par->parMaxIntrinsic
+ = 0;
if (prevPar) {
par->maxParMin = prevPar->maxParMin;
+ par->maxParMinIntrinsic = prevPar->maxParMinIntrinsic;
par->maxParMax = prevPar->maxParMax;
+ par->maxParMaxIntrinsic = prevPar->maxParMaxIntrinsic;
} else
- par->maxParMin = par->maxParMax = 0;
+ par->maxParMin = par->maxParMinIntrinsic = par->maxParMax =
+ par->maxParMaxIntrinsic = 0;
DBG_OBJ_MSGF ("construct.paragraph", 1, "new par: %d",
paragraphs->size() - 1);
@@ -1261,22 +1224,41 @@ void Textblock::handleWordExtremes (int wordIndex)
lastPar->firstWord, lastPar->lastWord, corrDiffMin,
corrDiffMax);
+ DBG_OBJ_MSGF ("construct.paragraph", 1,
+ "before: parMin = %d (%d) (max = %d (%d)), "
+ "parMax = %d (%d) (max = %d (%d))",
+ lastPar->parMin, lastPar->parMinIntrinsic,
+ lastPar->maxParMin, lastPar->maxParMinIntrinsic,
+ lastPar->parMax, lastPar->parMaxIntrinsic,
+ lastPar->maxParMax, lastPar->maxParMaxIntrinsic);
+
// Minimum: between two *possible* breaks.
// Shrinkability could be considered, but really does not play a role.
lastPar->parMin += wordExtremes.minWidth + word->hyphenWidth + corrDiffMin;
+ lastPar->parMinIntrinsic +=
+ wordExtremes.minWidthIntrinsic + word->hyphenWidth + corrDiffMin;
lastPar->maxParMin = misc::max (lastPar->maxParMin, lastPar->parMin);
+ lastPar->maxParMinIntrinsic =
+ misc::max (lastPar->maxParMinIntrinsic, lastPar->parMinIntrinsic);
if (word->badnessAndPenalty.lineCanBeBroken (1) &&
(word->flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) == 0)
- lastPar->parMin = 0;
+ lastPar->parMin = lastPar->parMinIntrinsic = 0;
// Maximum: between two *necessary* breaks.
lastPar->parMax += wordExtremes.maxWidth + word->hyphenWidth + corrDiffMax;
+ lastPar->parMaxIntrinsic +=
+ wordExtremes.maxWidthIntrinsic + word->hyphenWidth + corrDiffMax;
lastPar->maxParMax = misc::max (lastPar->maxParMax, lastPar->parMax);
+ lastPar->maxParMaxIntrinsic =
+ misc::max (lastPar->maxParMaxIntrinsic, lastPar->parMaxIntrinsic);
DBG_OBJ_MSGF ("construct.paragraph", 1,
- "=> parMin = %d (max = %d), parMax = %d (max = %d)",
- lastPar->parMin, lastPar->maxParMin, lastPar->parMax,
- lastPar->maxParMax);
+ "after: parMin = %d (%d) (max = %d (%d)), "
+ "parMax = %d (%d) (max = %d (%d))",
+ lastPar->parMin, lastPar->parMinIntrinsic,
+ lastPar->maxParMin, lastPar->maxParMinIntrinsic,
+ lastPar->parMax, lastPar->parMaxIntrinsic,
+ lastPar->maxParMax, lastPar->maxParMaxIntrinsic);
lastPar->lastWord = wordIndex;
DBG_OBJ_MSG_END ();
@@ -1474,7 +1456,7 @@ void Textblock::accumulateWordForLine (int lineIndex, int wordIndex)
word->content.widget->getStyle()->margin.bottom);
if (lines->size () == 1 &&
- word->content.widget->blockLevel () &&
+ word->content.widget->isBlockLevel () &&
getStyle ()->borderWidth.top == 0 &&
getStyle ()->padding.top == 0) {
// collapse top margins of parent element and its first child
@@ -1526,12 +1508,13 @@ void Textblock::accumulateWordData (int wordIndex)
Word *word = words->getRef (wordIndex);
DBG_OBJ_MSGF ("construct.word.accum", 2, "lineIndex = %d", lineIndex);
- int availWidth = calcAvailWidth (lineIndex);
+ int lineBreakWidth = calcLineBreakWidth (lineIndex);
DBG_OBJ_MSGF ("construct.word.accum", 2,
- "(%s existing line %d starts with word %d; availWidth = %d)",
+ "(%s existing line %d starts with word %d; "
+ "lineBreakWidth = %d)",
lineIndex < lines->size () ? "already" : "not yet",
- lineIndex, firstWordOfLine, availWidth);
+ lineIndex, firstWordOfLine, lineBreakWidth);
if (wordIndex == firstWordOfLine) {
// first word of the (not neccessarily yet existing) line
@@ -1582,7 +1565,7 @@ void Textblock::accumulateWordData (int wordIndex)
"totalShrinkability = %d + ... = %d",
word->totalSpaceShrinkability, totalShrinkability);
- word->badnessAndPenalty.calcBadness (word->totalWidth, availWidth,
+ word->badnessAndPenalty.calcBadness (word->totalWidth, lineBreakWidth,
totalStretchability,
totalShrinkability);
@@ -1595,22 +1578,22 @@ void Textblock::accumulateWordData (int wordIndex)
DBG_OBJ_MSG_END ();
}
-int Textblock::calcAvailWidth (int lineIndex)
+int Textblock::calcLineBreakWidth (int lineIndex)
{
DBG_OBJ_MSGF ("construct.word.width", 1,
- "<b>calcAvailWidth</b> (%d <i>of %d</i>)",
+ "<b>calcLineBreakWidth</b> (%d <i>of %d</i>)",
lineIndex, lines->size());
DBG_OBJ_MSG_START ();
- int availWidth = this->availWidth - innerPadding;
+ int lineBreakWidth = this->lineBreakWidth - leftInnerPadding;
if (limitTextWidth &&
layout->getUsesViewport () &&
// margin/border/padding will be subtracted later, via OOFM.
- availWidth - getStyle()->boxDiffWidth()
+ lineBreakWidth - getStyle()->boxDiffWidth()
> layout->getWidthViewport () - 10)
- availWidth = layout->getWidthViewport () - 10;
+ lineBreakWidth = layout->getWidthViewport () - 10;
if (lineIndex == 0)
- availWidth -= line1OffsetEff;
+ lineBreakWidth -= line1OffsetEff;
int leftBorder, rightBorder;
if (mustBorderBeRegarded (lineIndex)) {
@@ -1622,14 +1605,14 @@ int Textblock::calcAvailWidth (int lineIndex)
leftBorder = misc::max (leftBorder, getStyle()->boxOffsetX());
rightBorder = misc::max (rightBorder, getStyle()->boxRestWidth());
- availWidth -= (leftBorder + rightBorder);
+ lineBreakWidth -= (leftBorder + rightBorder);
DBG_OBJ_MSGF ("construct.word.width", 2, "=> %d - %d - (%d + %d) = %d\n",
- this->availWidth, innerPadding, leftBorder, rightBorder,
- availWidth);
+ this->lineBreakWidth, leftInnerPadding, leftBorder,
+ rightBorder, lineBreakWidth);
DBG_OBJ_MSG_END ();
- return availWidth;
+ return lineBreakWidth;
}
void Textblock::initLine1Offset (int wordIndex)
@@ -1639,18 +1622,18 @@ void Textblock::initLine1Offset (int wordIndex)
/* Test whether line1Offset can be used. */
if (wordIndex == 0) {
if (ignoreLine1OffsetSometimes &&
- line1Offset + word->size.width > availWidth) {
+ line1Offset + word->size.width > lineBreakWidth) {
line1OffsetEff = 0;
} else {
int indent = 0;
if (word->content.type == core::Content::WIDGET_IN_FLOW &&
- word->content.widget->blockLevel() == true) {
+ word->content.widget->isBlockLevel()) {
/* don't use text-indent when nesting blocks */
} else {
if (core::style::isPerLength(getStyle()->textIndent)) {
indent = core::style::multiplyWithPerLengthRounded
- (this->availWidth, getStyle()->textIndent);
+ (lineBreakWidth, getStyle()->textIndent);
} else {
indent = core::style::absLengthVal (getStyle()->textIndent);
}
@@ -1671,10 +1654,12 @@ void Textblock::alignLine (int lineIndex)
DBG_OBJ_MSG_START ();
Line *line = lines->getRef (lineIndex);
- int availWidth = calcAvailWidth (lineIndex);
+
if (line->firstWord <= line->lastWord) {
Word *firstWord = words->getRef (line->firstWord);
Word *lastWord = words->getRef (line->lastWord);
+ int lineBreakWidth =
+ this->lineBreakWidth - (line->leftOffset + line->rightOffset);
for (int i = line->firstWord; i < line->lastWord; i++)
words->getRef(i)->origSpace = words->getRef(i)->effSpace;
@@ -1684,18 +1669,18 @@ void Textblock::alignLine (int lineIndex)
case core::style::TEXT_ALIGN_LEFT:
DBG_OBJ_MSG ("construct.line", 1,
"first word has 'text-align: left'");
- line->leftOffset = 0;
+ line->alignment = Line::LEFT;
break;
case core::style::TEXT_ALIGN_STRING: /* handled elsewhere (in the
* future)? */
DBG_OBJ_MSG ("construct.line", 1,
"first word has 'text-align: string'");
- line->leftOffset = 0;
+ line->alignment = Line::LEFT;
break;
case core::style::TEXT_ALIGN_JUSTIFY: /* see some lines above */
- line->leftOffset = 0;
DBG_OBJ_MSG ("construct.line", 1,
"first word has 'text-align: justify'");
+ line->alignment = Line::LEFT;
// Do not justify the last line of a paragraph (which ends on a
// BREAK or with the last word of the page).
if(!(lastWord->content.type == core::Content::BREAK ||
@@ -1704,35 +1689,64 @@ void Textblock::alignLine (int lineIndex)
// when the line would be shrunken otherwise. (This solution is
// far from perfect, but a better solution would make changes in
// the line breaking algorithm necessary.)
- availWidth < lastWord->totalWidth)
- justifyLine (line, availWidth - lastWord->totalWidth);
+ lineBreakWidth < lastWord->totalWidth)
+ justifyLine (line, lineBreakWidth - lastWord->totalWidth);
break;
case core::style::TEXT_ALIGN_RIGHT:
DBG_OBJ_MSG ("construct.line", 1,
"first word has 'text-align: right'");
- line->leftOffset = availWidth - lastWord->totalWidth;
+ line->alignment = Line::RIGHT;
break;
case core::style::TEXT_ALIGN_CENTER:
DBG_OBJ_MSG ("construct.line", 1,
"first word has 'text-align: center'");
- line->leftOffset = (availWidth - lastWord->totalWidth) / 2;
+ line->alignment = Line::CENTER;
break;
default:
- /* compiler happiness */
- line->leftOffset = 0;
+ // compiler happiness
+ line->alignment = Line::LEFT;
}
- /* For large lines (images etc), which do not fit into the viewport: */
- if (line->leftOffset < 0)
- line->leftOffset = 0;
- }
+ } else
+ // empty line (only line break);
+ line->alignment = Line::LEFT;
} else
// empty line
- line->leftOffset = 0;
+ line->alignment = Line::LEFT;
DBG_OBJ_MSG_END ();
}
+void Textblock::calcTextOffset (int lineIndex, int totalWidth)
+{
+ Line *line = lines->getRef (lineIndex);
+ int lineWidth = line->firstWord <= line->lastWord ?
+ words->getRef(line->lastWord)->totalWidth : 0;
+
+ switch (line->alignment) {
+ case Line::LEFT:
+ line->textOffset = line->leftOffset;
+ break;
+
+ case Line::RIGHT:
+ line->textOffset = totalWidth - line->rightOffset - lineWidth;
+ break;
+
+ case Line::CENTER:
+ line->textOffset =
+ (line->leftOffset + totalWidth - line->rightOffset - lineWidth) / 2;
+ break;
+
+ default:
+ misc::assertNotReached ();
+ break;
+ }
+
+ // For large lines (images etc), which do not fit into the viewport:
+ if (line->textOffset < line->leftOffset)
+ line->textOffset = line->leftOffset;
+}
+
/**
* Rewrap the page from the line from which this is necessary.
* There are basically two times we'll want to do this:
diff --git a/dw/types.hh b/dw/types.hh
index e910d296..36d6caa1 100644
--- a/dw/types.hh
+++ b/dw/types.hh
@@ -180,6 +180,8 @@ struct Extremes
{
int minWidth;
int maxWidth;
+ int minWidthIntrinsic;
+ int maxWidthIntrinsic;
};
struct Content
diff --git a/dw/ui.cc b/dw/ui.cc
index 8fb34c96..9f5bb280 100644
--- a/dw/ui.cc
+++ b/dw/ui.cc
@@ -56,6 +56,7 @@ void Embed::sizeRequestImpl (Requisition *requisition)
void Embed::getExtremesImpl (Extremes *extremes)
{
resource->getExtremes (extremes);
+ correctExtremes (extremes);
}
void Embed::sizeAllocateImpl (Allocation *allocation)
@@ -63,6 +64,11 @@ void Embed::sizeAllocateImpl (Allocation *allocation)
resource->sizeAllocate (allocation);
}
+void Embed::containerSizeChangedForChildren ()
+{
+ // Nothing to do (as long as all resources return empty iterators).
+}
+
void Embed::enterNotifyImpl (core::EventCrossing *event)
{
resource->emitEnter();
@@ -88,36 +94,6 @@ bool Embed::buttonPressImpl (core::EventButton *event)
return handled;
}
-void Embed::setWidth (int width)
-{
- DBG_OBJ_MSGF ("resize", 0, "<b>setWidth</b> (%d)", width);
- DBG_OBJ_MSG_START ();
-
- resource->setWidth (width);
-
- DBG_OBJ_MSG_END ();
-}
-
-void Embed::setAscent (int ascent)
-{
- DBG_OBJ_MSGF ("resize", 0, "<b>setAscent</b> (%d)", ascent);
- DBG_OBJ_MSG_START ();
-
- resource->setAscent (ascent);
-
- DBG_OBJ_MSG_END ();
-}
-
-void Embed::setDescent (int descent)
-{
- DBG_OBJ_MSGF ("resize", 0, "<b>setDescent</b> (%d)", descent);
- DBG_OBJ_MSG_START ();
-
- resource->setDescent (descent);
-
- DBG_OBJ_MSG_END ();
-}
-
void Embed::setDisplayed (bool displayed)
{
resource->setDisplayed (displayed);
@@ -223,18 +199,6 @@ void Resource::sizeAllocate (Allocation *allocation)
{
}
-void Resource::setWidth (int width)
-{
-}
-
-void Resource::setAscent (int ascent)
-{
-}
-
-void Resource::setDescent (int descent)
-{
-}
-
void Resource::setDisplayed (bool displayed)
{
}
@@ -368,36 +332,6 @@ void ComplexButtonResource::sizeAllocate (Allocation *allocation)
{
}
-void ComplexButtonResource::setWidth (int width)
-{
- DBG_OBJ_MSGF ("resize", 0, "<b>setWidth</b> (%d)", width);
- DBG_OBJ_MSG_START ();
-
- childWidget->setWidth (width - 2 * reliefXThickness ());
-
- DBG_OBJ_MSG_END ();
-}
-
-void ComplexButtonResource::setAscent (int ascent)
-{
- DBG_OBJ_MSGF ("resize", 0, "<b>setAscent</b> (%d)", ascent);
- DBG_OBJ_MSG_START ();
-
- childWidget->setAscent (ascent - reliefYThickness ());
-
- DBG_OBJ_MSG_END ();
-}
-
-void ComplexButtonResource::setDescent (int descent)
-{
- DBG_OBJ_MSGF ("resize", 0, "<b>setDescent</b> (%d)", descent);
- DBG_OBJ_MSG_START ();
-
- childWidget->setDescent (descent - reliefYThickness ());
-
- DBG_OBJ_MSG_END ();
-}
-
Iterator *ComplexButtonResource::iterator (Content::Type mask, bool atEnd)
{
/**
diff --git a/dw/ui.hh b/dw/ui.hh
index cab67e17..14ca0bf4 100644
--- a/dw/ui.hh
+++ b/dw/ui.hh
@@ -231,6 +231,7 @@ protected:
void sizeRequestImpl (Requisition *requisition);
void getExtremesImpl (Extremes *extremes);
void sizeAllocateImpl (Allocation *allocation);
+ void containerSizeChangedForChildren ();
void enterNotifyImpl (core::EventCrossing *event);
void leaveNotifyImpl (core::EventCrossing *event);
bool buttonPressImpl (core::EventButton *event);
@@ -241,9 +242,6 @@ public:
Embed(Resource *resource);
~Embed();
- void setWidth (int width);
- void setAscent (int ascent);
- void setDescent (int descent);
void setDisplayed (bool displayed);
void setEnabled (bool enabled);
void draw (View *view, Rectangle *area);
@@ -337,9 +335,6 @@ public:
virtual void sizeRequest (Requisition *requisition) = 0;
virtual void getExtremes (Extremes *extremes);
virtual void sizeAllocate (Allocation *allocation);
- virtual void setWidth (int width);
- virtual void setAscent (int ascent);
- virtual void setDescent (int descent);
virtual void setDisplayed (bool displayed);
virtual void draw (View *view, Rectangle *area);
virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
@@ -407,9 +402,6 @@ public:
void sizeRequest (Requisition *requisition);
void getExtremes (Extremes *extremes);
void sizeAllocate (Allocation *allocation);
- void setWidth (int width);
- void setAscent (int ascent);
- void setDescent (int descent);
Iterator *iterator (Content::Type mask, bool atEnd);
int getClickX () {return click_x;};
int getClickY () {return click_y;};
diff --git a/dw/widget.cc b/dw/widget.cc
index a3d85d0a..2271ee1e 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -70,7 +70,9 @@ Widget::Widget ()
registerName ("dw::core::Widget", &CLASS_ID);
flags = (Flags)(NEEDS_RESIZE | EXTREMES_CHANGED | HAS_CONTENTS);
- parent = generator = NULL;
+ parent = generator = container = NULL;
+ DBG_OBJ_SET_PTR ("container", container);
+
layout = NULL;
allocation.x = -1;
@@ -79,6 +81,8 @@ Widget::Widget ()
allocation.ascent = 1;
allocation.descent = 0;
+ extraSpace.top = extraSpace.right = extraSpace.bottom = extraSpace.left = 0;
+
style = NULL;
bgColor = NULL;
buttonSensitive = true;
@@ -153,6 +157,20 @@ void Widget::setParent (Widget *parent)
//printf ("The %s %p becomes a child of the %s %p\n",
// getClassName(), this, parent->getClassName(), parent);
+ // Determine the container. Currently rather simple; will become
+ // more complicated when absolute and fixed positions are
+ // supported.
+ container = NULL;
+ for (Widget *widget = getParent (); widget != NULL && container == NULL;
+ widget = widget->getParent())
+ if (widget->isPossibleContainer ())
+ container = widget;
+ // If there is no possible container widget, there is
+ // (surprisingly!) also no container (i. e. the viewport is
+ // used). Does not occur in dillo, where the toplevel widget is a
+ // Textblock.
+ DBG_OBJ_SET_PTR ("container", container);
+
notifySetParent();
}
@@ -176,11 +194,16 @@ void Widget::queueDrawArea (int x, int y, int width, int height)
/**
* \brief This method should be called, when a widget changes its size.
+ *
+ * A "fast" queueResize will ignore the anchestors, and furthermore
+ * not trigger the idle function. Used only within
+ * viewportSizeChanged, and not available outside Layout and Widget.
*/
-void Widget::queueResize (int ref, bool extremesChanged)
+void Widget::queueResize (int ref, bool extremesChanged, bool fast)
{
- DBG_OBJ_MSGF ("resize", 0, "<b>queueResize</b> (%d, %s)",
- ref, extremesChanged ? "true" : "false");
+ DBG_OBJ_MSGF ("resize", 0, "<b>queueResize</b> (%d, %s, %s)",
+ ref, extremesChanged ? "true" : "false",
+ fast ? "true" : "false");
DBG_OBJ_MSG_START ();
// queueResize() can be called recursively; calls are queued, so
@@ -189,15 +212,16 @@ void Widget::queueResize (int ref, bool extremesChanged)
if (queueResizeEntered ()) {
DBG_OBJ_MSG ("resize", 1, "put into queue");
layout->queueQueueResizeList->put (new Layout::QueueResizeItem
- (this, ref, extremesChanged));
+ (this, ref, extremesChanged, fast));
} else {
- actualQueueResize (ref, extremesChanged);
+ actualQueueResize (ref, extremesChanged, fast);
while (layout != NULL && layout->queueQueueResizeList->size () > 0) {
Layout::QueueResizeItem *item = layout->queueQueueResizeList->get (0);
DBG_OBJ_MSGF ("resize", 1, "taken out of queue queue (size = %d)",
layout->queueQueueResizeList->size ());
- item->widget->actualQueueResize (item->ref, item->extremesChanged);
+ item->widget->actualQueueResize (item->ref, item->extremesChanged,
+ item->fast);
layout->queueQueueResizeList->remove (0); // hopefully not too large
}
}
@@ -205,22 +229,19 @@ void Widget::queueResize (int ref, bool extremesChanged)
DBG_OBJ_MSG_END ();
}
-void Widget::actualQueueResize (int ref, bool extremesChanged)
+void Widget::actualQueueResize (int ref, bool extremesChanged, bool fast)
{
assert (!queueResizeEntered ());
- DBG_OBJ_MSGF ("resize", 0, "<b>actualQueueResize</b> (%d, %s)",
- ref, extremesChanged ? "true" : "false");
+ DBG_OBJ_MSGF ("resize", 0, "<b>actualQueueResize</b> (%d, %s, %s)",
+ ref, extremesChanged ? "true" : "false",
+ fast ? "true" : "false");
DBG_OBJ_MSG_START ();
enterQueueResize ();
Widget *widget2, *child;
- //printf("The %stop-level %s %p with parentRef = %d has changed its size. "
- // "Layout = %p.\n",
- // parent ? "non-" : "", getClassName(), this, parentRef, layout);
-
Flags resizeFlag, extremesFlag;
if (layout) {
@@ -243,36 +264,160 @@ void Widget::actualQueueResize (int ref, bool extremesChanged)
setFlags (extremesFlag);
markExtremesChange (ref);
}
-
- for (widget2 = parent, child = this; widget2;
- child = widget2, widget2 = widget2->parent) {
- //printf (" Setting %s and ALLOCATE_QUEUED for the "
- // "%stop-level %s %p with parentRef = %d\n",
- // resizeFlag == RESIZE_QUEUED ? "RESIZE_QUEUED" : "NEEDS_RESIZE",
- // widget2->parent ? "non-" : "", widget2->getClassName(), widget2,
- // widget2->parentRef);
-
- if (layout && !widget2->resizeQueued ())
- layout->queueResizeList->put (widget2);
-
- widget2->setFlags (resizeFlag);
- widget2->markSizeChange (child->parentRef);
- widget2->setFlags (ALLOCATE_QUEUED);
-
- if (extremesChanged) {
- widget2->setFlags (extremesFlag);
- widget2->markExtremesChange (child->parentRef);
+
+ if (!fast) {
+ for (widget2 = parent, child = this; widget2;
+ child = widget2, widget2 = widget2->parent) {
+ if (layout && !widget2->resizeQueued ())
+ layout->queueResizeList->put (widget2);
+
+ widget2->setFlags (resizeFlag);
+ widget2->markSizeChange (child->parentRef);
+ widget2->setFlags (ALLOCATE_QUEUED);
+
+ if (extremesChanged) {
+ widget2->setFlags (extremesFlag);
+ widget2->markExtremesChange (child->parentRef);
+ }
}
- }
- if (layout)
- layout->queueResize (extremesChanged);
+ if (layout)
+ layout->queueResize (extremesChanged);
+ }
leaveQueueResize ();
DBG_OBJ_MSG_END ();
}
+void Widget::containerSizeChanged ()
+{
+ DBG_OBJ_MSG ("resize", 0, "<b>containerSizeChanged</b> ()");
+ DBG_OBJ_MSG_START ();
+
+ // If there is a container widget (not the viewport), which has not
+ // changed its size (which can be determined by the respective
+ // flags: this method is called recursively), this widget will
+ // neither change its size. Also, the recursive iteration can be
+ // stopped, since the children of this widget will
+ if (container == NULL ||
+ container->needsResize () || container->resizeQueued () ||
+ container->extremesChanged () || container->extremesQueued ()) {
+ // Viewport (container == NULL) or container widget has changed
+ // its size.
+ if (affectedByContainerSizeChange ())
+ queueResizeFast (0, true);
+
+ // Even if *this* widget is not affected, children may be, so
+ // iterate over children.
+ containerSizeChangedForChildren ();
+ }
+
+ DBG_OBJ_MSG_END ();
+}
+
+bool Widget::affectedByContainerSizeChange ()
+{
+ DBG_OBJ_MSG ("resize", 0, "<b>affectedByContainerSizeChange</b> ()");
+ DBG_OBJ_MSG_START ();
+
+ bool ret;
+
+ // This standard implementation is suitable for all widgets which
+ // call correctRequisition() and correctExtremes(), even in the way
+ // how Textblock and Image do (see comments there). Has to be kept
+ // in sync.
+
+ if (container == NULL) {
+ if (style::isAbsLength (getStyle()->width) &&
+ style::isAbsLength (getStyle()->height))
+ // Both absolute, i. e. fixed: no dependency.
+ ret = false;
+ else if (style::isPerLength (getStyle()->width) ||
+ style::isPerLength (getStyle()->height)) {
+ // Any percentage: certainly dependenant.
+ ret = true;
+ } else
+ // One or both is "auto": depends ...
+ ret =
+ (getStyle()->width == style::LENGTH_AUTO ?
+ usesAvailWidth () : false) ||
+ (getStyle()->height == style::LENGTH_AUTO ?
+ usesAvailHeight () : false);
+ } else
+ ret = this->affectsSizeChangeContainerChild (this);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %s", ret ? "true" : "false");
+ DBG_OBJ_MSG_END ();
+ return ret;
+}
+
+bool Widget::affectsSizeChangeContainerChild (Widget *child)
+{
+ DBG_OBJ_MSGF ("resize", 0, "<b>affectsSizeChangeContainerChild</b> (%p)",
+ child);
+ DBG_OBJ_MSG_START ();
+
+ bool ret;
+
+ // From the point of view of the container. This standard
+ // implementation should be suitable for most (if not all)
+ // containers.
+
+ if (style::isAbsLength (child->getStyle()->width) &&
+ style::isAbsLength (child->getStyle()->height))
+ // Both absolute, i. e. fixed: no dependency.
+ ret = false;
+ else if (style::isPerLength (child->getStyle()->width) ||
+ style::isPerLength (child->getStyle()->height)) {
+ // Any percentage: certainly dependenant.
+ ret = true;
+ } else
+ // One or both is "auto": depends ...
+ ret =
+ (child->getStyle()->width == style::LENGTH_AUTO ?
+ child->usesAvailWidth () : false) ||
+ (child->getStyle()->height == style::LENGTH_AUTO ?
+ child->usesAvailHeight () : false);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %s", ret ? "true" : "false");
+ DBG_OBJ_MSG_END ();
+ return ret;
+}
+
+void Widget::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_MSG ("resize", 0, "<b>containerSizeChangedForChildren</b> ()");
+ DBG_OBJ_MSG_START ();
+
+ // Working, but inefficient standard implementation.
+ Iterator *it = iterator ((Content::Type)(Content::WIDGET_IN_FLOW |
+ Content::WIDGET_OOF_CONT),
+ false);
+ while (it->next ())
+ it->getContent()->widget->containerSizeChanged ();
+ it->unref ();
+
+ DBG_OBJ_MSG_END ();
+}
+
+/**
+ * \brief Must be implemengted by a method returning true, when
+ * getAvailWidth() is called.
+ */
+bool Widget::usesAvailWidth ()
+{
+ return false;
+}
+
+/**
+ * \brief Must be implemengted by a method returning true, when
+ * getAvailHeight() is called.
+ */
+bool Widget::usesAvailHeight ()
+{
+ return false;
+}
/**
* \brief This method is a wrapper for Widget::sizeRequestImpl(); it calls
@@ -323,6 +468,193 @@ void Widget::sizeRequest (Requisition *requisition)
}
/**
+ * Return available width including margin/border/padding
+ * (extraSpace?), not only the content width.
+ */
+int Widget::getAvailWidth (bool forceValue)
+{
+ // TODO Correct by extremes?
+
+ DBG_OBJ_MSGF ("resize", 0, "<b>getAvailWidth</b> (%s)",
+ forceValue ? "true" : "false");
+ DBG_OBJ_MSG_START ();
+
+ int width;
+
+ if (parent == NULL) {
+ DBG_OBJ_MSG ("resize", 1, "no parent, regarding viewport");
+ DBG_OBJ_MSG_START ();
+
+ // TODO Consider nested layouts (e. g. <button>).
+ if (style::isAbsLength (getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (getStyle()->width));
+ width = style::absLengthVal (getStyle()->width) + boxDiffWidth ();
+ } else {
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ if (style::isPerLength (getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->width));
+ width = applyPerWidth (viewportWidth, getStyle()->width);
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ width = viewportWidth;
+ }
+
+ }
+ DBG_OBJ_MSG_END ();
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to parent");
+ DBG_OBJ_MSG_START ();
+ width = parent->getAvailWidthOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_MSG_END ();
+
+ return width;
+}
+
+/**
+ * Return available height including margin/border/padding
+ * (extraSpace?), not only the content height.
+ */
+int Widget::getAvailHeight (bool forceValue)
+{
+ // TODO Correct by ... not extremes, but ...? (Height extremes?)
+
+ DBG_OBJ_MSGF ("resize", 0, "<b>getAvailHeight</b> (%s)",
+ forceValue ? "true" : "false");
+ DBG_OBJ_MSG_START ();
+
+ int height;
+
+ if (parent == NULL) {
+ DBG_OBJ_MSG ("resize", 1, "no parent, regarding viewport");
+ DBG_OBJ_MSG_START ();
+
+ // TODO Consider nested layouts (e. g. <button>).
+ if (style::isAbsLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (getStyle()->height));
+ height = style::absLengthVal (getStyle()->height) + boxDiffHeight ();
+ } else if (style::isPerLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->height));
+ // Notice that here -- unlike getAvailWidth() --
+ // layout->hScrollbarThickness is not considered here;
+ // something like canvasWidthGreater (analogue to
+ // canvasHeightGreater) would be complicated and lead to
+ // possibly contradictory self-references.
+ height = applyPerHeight (layout->viewportHeight, getStyle()->height);
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ height = layout->viewportHeight;
+ }
+
+ DBG_OBJ_MSG_END ();
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to parent");
+ DBG_OBJ_MSG_START ();
+ height = container->getAvailHeightOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_MSG_END ();
+
+ return height;
+}
+
+void Widget::correctRequisition (Requisition *requisition,
+ void (*splitHeightFun) (int, int *, int *))
+{
+ // TODO Correct by extremes?
+
+ DBG_OBJ_MSGF ("resize", 0, "<b>correctRequisition</b> (%d * (%d + %d), ...)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_MSG_START ();
+
+ if (container == NULL) {
+ if (style::isAbsLength (getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (getStyle()->width));
+ requisition->width =
+ style::absLengthVal (getStyle()->width) + boxDiffWidth ();
+ } else if (style::isPerLength (getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->width));
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ requisition->width = applyPerWidth (viewportWidth, getStyle()->width);
+ }
+
+ // TODO Perhaps split first, then add box ascent and descent.
+ if (style::isAbsLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (getStyle()->height));
+ splitHeightFun (style::absLengthVal (getStyle()->height)
+ + boxDiffHeight (),
+ &requisition->ascent, &requisition->descent);
+ } else if (style::isPerLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->height));
+#if 0
+ // TODO Percentage heights are somewhat more complicated. Has
+ // to be clarified.
+
+ // For layout->viewportHeight, see comment in getAvailHeight().
+ splitHeightFun (applyPerHeight (layout->viewportHeight,
+ getStyle()->height),
+ &requisition->ascent, &requisition->descent);
+#endif
+ }
+ } else
+ container->correctRequisitionOfChild (this, requisition, splitHeightFun);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_MSG_END ();
+}
+
+void Widget::correctExtremes (Extremes *extremes)
+{
+ // TODO Extremes only corrected?
+
+ DBG_OBJ_MSGF ("resize", 0, "<b>correctExtremes</b> (%d (%d) / %d (%d))",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+ DBG_OBJ_MSG_START ();
+
+ if (container == NULL) {
+ if (style::isAbsLength (getStyle()->width))
+ extremes->minWidth = extremes->maxWidth =
+ style::absLengthVal (getStyle()->width) + boxDiffWidth ();
+ else if (style::isPerLength (getStyle()->width)) {
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ extremes->minWidth = extremes->maxWidth =
+ applyPerWidth (viewportWidth, getStyle()->width);
+ }
+ } else
+ container->correctExtremesOfChild (this, extremes);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_MSG_END ();
+}
+
+/**
* \brief Wrapper for Widget::getExtremesImpl().
*/
void Widget::getExtremes (Extremes *extremes)
@@ -344,12 +676,26 @@ void Widget::getExtremes (Extremes *extremes)
}
if (extremesChanged ()) {
+ // For backward compatibility (part 1/2):
+ extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1;
+
getExtremesImpl (extremes);
+
+ // For backward compatibility (part 2/2):
+ if (extremes->minWidthIntrinsic == -1)
+ extremes->minWidthIntrinsic = extremes->minWidth;
+ if (extremes->maxWidthIntrinsic == -1)
+ extremes->maxWidthIntrinsic = extremes->maxWidth;
+
this->extremes = *extremes;
unsetFlags (EXTREMES_CHANGED);
DBG_OBJ_SET_NUM ("extremes.minWidth", extremes->minWidth);
+ DBG_OBJ_SET_NUM ("extremes.minWidthIntrinsic",
+ extremes->minWidthIntrinsic);
DBG_OBJ_SET_NUM ("extremes.maxWidth", extremes->maxWidth);
+ DBG_OBJ_SET_NUM ("extremes.maxWidthIntrinsic",
+ extremes->maxWidthIntrinsic);
} else
*extremes = this->extremes;
@@ -507,6 +853,28 @@ void Widget::setStyle (style::Style *style)
queueResize (0, true);
else
queueDraw ();
+
+ // These should better be attributed to the style itself, and a
+ // script processing RTFL messages could transfer it to something
+ // equivalent:
+
+ DBG_OBJ_SET_NUM ("style.margin.top", style->margin.top);
+ DBG_OBJ_SET_NUM ("style.margin.bottom", style->margin.bottom);
+ DBG_OBJ_SET_NUM ("style.margin.left", style->margin.left);
+ DBG_OBJ_SET_NUM ("style.margin.right", style->margin.right);
+
+ DBG_OBJ_SET_NUM ("style.border-width.top", style->borderWidth.top);
+ DBG_OBJ_SET_NUM ("style.border-width.bottom", style->borderWidth.bottom);
+ DBG_OBJ_SET_NUM ("style.border-width.left", style->borderWidth.left);
+ DBG_OBJ_SET_NUM ("style.border-width.right", style->borderWidth.right);
+
+ DBG_OBJ_SET_NUM ("style.padding.top", style->padding.top);
+ DBG_OBJ_SET_NUM ("style.padding.bottom", style->padding.bottom);
+ DBG_OBJ_SET_NUM ("style.padding.left", style->padding.left);
+ DBG_OBJ_SET_NUM ("style.padding.right", style->padding.right);
+
+ DBG_OBJ_SET_NUM ("style.border-spacing (h)", style->hBorderSpacing);
+ DBG_OBJ_SET_NUM ("style.border-spacing (v)", style->vBorderSpacing);
}
/**
@@ -787,6 +1155,7 @@ void Widget::getExtremesImpl (Extremes *extremes)
Requisition requisition;
sizeRequest (&requisition);
extremes->minWidth = extremes->maxWidth = requisition.width;
+ correctExtremes (extremes);
}
void Widget::sizeAllocateImpl (Allocation *allocation)
@@ -801,6 +1170,227 @@ void Widget::markExtremesChange (int ref)
{
}
+int Widget::applyPerWidth (int containerWidth, style::Length perWidth)
+{
+ return style::multiplyWithPerLength (containerWidth, perWidth)
+ + boxDiffWidth ();
+}
+
+int Widget::applyPerHeight (int containerHeight, style::Length perHeight)
+{
+ return style::multiplyWithPerLength (containerHeight, perHeight)
+ + boxDiffHeight ();
+}
+
+int Widget::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ // This is a halfway suitable implementation for all
+ // containers. For simplification, this will be used during the
+ // development; then, a differentiation could be possible.
+
+ // TODO Correct by extremes?
+
+ DBG_OBJ_MSGF ("resize", 0, "<b>getAvailWidthOfChild</b> (%p, %s)",
+ child, forceValue ? "true" : "false");
+ DBG_OBJ_MSG_START ();
+
+ int width;
+
+ if (child->getStyle()->width == style::LENGTH_AUTO) {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ int availWidth = getAvailWidth (forceValue);
+ if (availWidth == -1)
+ width = -1;
+ else
+ width = misc::max (availWidth - boxDiffWidth (), 0);
+ } else {
+ // In most cases, the toplevel widget should be a container, so
+ // the container is non-NULL when the parent is non-NULL. Just
+ // in case ...:
+ Widget *effContainer =
+ child->container ? child->container : child->parent;
+
+ if (effContainer == this) {
+ if (style::isAbsLength (child->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (child->getStyle()->width));
+ width = misc::max (style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth (), 0);
+ } else {
+ assert (style::isPerLength (child->getStyle()->width));
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->getStyle()->width));
+
+ int availWidth = getAvailWidth (forceValue);
+ if (availWidth == -1)
+ width = -1;
+ else
+ width =
+ misc::max (child->applyPerWidth (availWidth - boxDiffWidth (),
+ child->getStyle()->width),
+ 0);
+ }
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to (effective) container");
+ DBG_OBJ_MSG_START ();
+ width = effContainer->getAvailWidthOfChild (child, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_MSG_END ();
+
+ return width;
+}
+
+int Widget::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ // Again, a suitable implementation for all widgets (perhaps).
+
+ // TODO Correct by extremes? (Height extemes?)
+
+ DBG_OBJ_MSGF ("resize", 0, "<b>getAvailHeightOfChild</b> (%p, %s)",
+ child, forceValue ? "true" : "false");
+ DBG_OBJ_MSG_START ();
+
+ int height;
+
+ if (child->getStyle()->height == style::LENGTH_AUTO) {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ int availHeight = getAvailHeight (forceValue);
+ if (availHeight == -1)
+ height = -1;
+ else
+ height = misc::max (availHeight - boxDiffHeight (), 0);
+ } else {
+ // In most cases, the toplevel widget should be a container, so
+ // the container is non-NULL when the parent is non-NULL. Just
+ // in case ...:
+ Widget *effContainer =
+ child->container ? child->container : child->parent;
+
+ if (effContainer == this) {
+ if (style::isAbsLength (child->getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (child->getStyle()->height));
+ height = misc::max (style::absLengthVal (child->getStyle()->height)
+ + child->boxDiffHeight (), 0);
+ } else {
+ assert (style::isPerLength (child->getStyle()->height));
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->getStyle()->height));
+
+ int availHeight = getAvailHeight (forceValue);
+ if (availHeight == -1)
+ height = -1;
+ else
+ height =
+ misc::max (child->applyPerHeight (availHeight -
+ boxDiffHeight (),
+ child->getStyle()->height),
+ 0);
+ }
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to (effective) container");
+ DBG_OBJ_MSG_START ();
+ height = effContainer->getAvailHeightOfChild (child, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_MSG_END ();
+
+ return height;
+}
+
+void Widget::correctRequisitionOfChild (Widget *child, Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*))
+{
+ // Again, a suitable implementation for all widgets (perhaps).
+
+ // TODO Correct by extremes?
+
+ DBG_OBJ_MSGF ("resize", 0,
+ "<b>correctRequisitionOfChild</b> (%p, %d * (%d + %d), ...)",
+ child, requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_MSG_START ();
+
+ if (style::isAbsLength (child->getStyle()->width))
+ requisition->width = style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth ();
+ else if (style::isPerLength (child->getStyle()->width)) {
+ int availWidth = getAvailWidth (false);
+ if (availWidth != -1) {
+ int containerWidth = availWidth - boxDiffWidth ();
+ requisition->width = child->applyPerWidth (containerWidth,
+ child->getStyle()->width);
+ }
+ }
+
+ // TODO Perhaps split first, then add box ascent and descent.
+ if (style::isAbsLength (child->getStyle()->height))
+ splitHeightFun (style::absLengthVal (child->getStyle()->height)
+ + child->boxDiffHeight (),
+ &requisition->ascent, &requisition->descent);
+ else if (style::isPerLength (child->getStyle()->height)) {
+ int availHeight = getAvailHeight (false);
+ if (availHeight != -1) {
+ int containerHeight = availHeight - boxDiffHeight ();
+ splitHeightFun (child->applyPerHeight (containerHeight,
+ child->getStyle()->height),
+ &requisition->ascent, &requisition->descent);
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_MSG_END ();
+}
+
+void Widget::correctExtremesOfChild (Widget *child, Extremes *extremes)
+{
+ // See comment in correctRequisitionOfChild.
+
+ // TODO Extremes only corrected?
+
+ DBG_OBJ_MSGF ("resize", 0,
+ "<b>correctExtremedOfChild</b> (%p, %d / %d)",
+ child, extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_MSG_START ();
+
+ if (style::isAbsLength (child->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (child->getStyle()->width));
+ extremes->minWidth = extremes->maxWidth =
+ style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth ();
+ } else if (style::isPerLength (child->getStyle()->width)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->getStyle()->width));
+ int availWidth = getAvailWidth (false);
+ if (availWidth != -1) {
+ int containerWidth = availWidth - boxDiffWidth ();
+ DBG_OBJ_MSGF ("resize", 1, "containerWidth = %d - %d = %d",
+ availWidth, boxDiffWidth (), containerWidth);
+ extremes->minWidth = extremes->maxWidth =
+ child->applyPerWidth (containerWidth, child->getStyle()->width);
+ }
+ } else
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_MSG_END ();
+}
+
/**
* \brief This method is called after a widget has been set as the top of a
* widget tree.
@@ -820,16 +1410,16 @@ void Widget::notifySetParent()
{
}
-void Widget::setWidth (int width)
-{
-}
-
-void Widget::setAscent (int ascent)
+bool Widget::isBlockLevel ()
{
+ // Most widgets are not block-level.
+ return false;
}
-void Widget::setDescent (int descent)
+bool Widget::isPossibleContainer ()
{
+ // In most (all?) cases identical to:
+ return isBlockLevel ();
}
bool Widget::buttonPressImpl (EventButton *event)
@@ -849,7 +1439,7 @@ bool Widget::motionNotifyImpl (EventMotion *event)
void Widget::enterNotifyImpl (EventCrossing *)
{
- core::style::Tooltip *tooltip = getStyle()->x_tooltip;
+ style::Tooltip *tooltip = getStyle()->x_tooltip;
if (tooltip)
tooltip->onEnter();
@@ -857,7 +1447,7 @@ void Widget::enterNotifyImpl (EventCrossing *)
void Widget::leaveNotifyImpl (EventCrossing *)
{
- core::style::Tooltip *tooltip = getStyle()->x_tooltip;
+ style::Tooltip *tooltip = getStyle()->x_tooltip;
if (tooltip)
tooltip->onLeave();
@@ -869,5 +1459,25 @@ void Widget::removeChild (Widget *child)
misc::assertNotReached ();
}
+// ----------------------------------------------------------------------
+
+void splitHeightPreserveAscent (int height, int *ascent, int *descent)
+{
+ *descent = height - *ascent;
+ if (*descent < 0) {
+ *descent = 0;
+ *ascent = height;
+ }
+}
+
+void splitHeightPreserveDescent (int height, int *ascent, int *descent)
+{
+ *ascent = height - *descent;
+ if (*ascent < 0) {
+ *ascent = 0;
+ *descent = height;
+ }
+}
+
} // namespace core
} // namespace dw
diff --git a/dw/widget.hh b/dw/widget.hh
index e3d9cbe1..00fc2aa5 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -90,11 +90,6 @@ protected:
* The dw::Image widget uses this flag, see dw::Image::setBuffer.
*/
WAS_ALLOCATED = 1 << 8,
-
- /**
- * \brief Set for block-level widgets (as opposed to inline widgets)
- */
- BLOCK_LEVEL = 1 << 9,
};
/**
@@ -127,11 +122,18 @@ private:
/**
* \brief The generating widget, NULL for top-level widgets, or if
- * not set; in the latter case, the effective generator (see
- * getGenerator) is the parent.
+ * not set; in the latter case, the effective generator (see
+ * getGenerator) is the parent.
*/
Widget *generator;
+ /**
+ * \brief The containing widget, equivalent to the "containing
+ * block" defined by CSS. May be NULL, in this case the viewport
+ * is used.
+ */
+ Widget *container;
+
style::Style *style;
Flags flags;
@@ -164,7 +166,10 @@ private:
*/
bool buttonSensitiveSet;
- void actualQueueResize (int ref, bool extremesChanged);
+ void queueResize (int ref, bool extremesChanged, bool fast);
+ inline void queueResizeFast (int ref, bool extremesChanged)
+ { queueResize (ref, extremesChanged, true); }
+ void actualQueueResize (int ref, bool extremesChanged, bool fast);
public:
/**
@@ -191,6 +196,12 @@ protected:
Layout *layout;
+ /**
+ * \brief Space around the margin box. Allocation is extraSpace +
+ * margin + border + padding + contents;
+ */
+ style::Box extraSpace;
+
/*inline void printFlags () {
DBG_IF_RTFL {
char buf[10 * 3 - 1 + 1];
@@ -255,12 +266,7 @@ protected:
case WAS_ALLOCATED:
DBG_OBJ_SET_SYM ("flags.WAS_ALLOCATED",
(flags & WAS_ALLOCATED) ? "true" : "false");
- break;
-
- case BLOCK_LEVEL:
- DBG_OBJ_SET_SYM ("flags.BLOCK_LEVEL",
- (flags & BLOCK_LEVEL) ? "true" : "false");
- break;
+ break;
}
}
}
@@ -272,11 +278,10 @@ protected:
inline void queueDraw ()
- {
- queueDrawArea (0, 0, allocation.width, getHeight());
- }
+ { queueDrawArea (0, 0, allocation.width, getHeight()); }
void queueDrawArea (int x, int y, int width, int height);
- void queueResize (int ref, bool extremesChanged);
+ inline void queueResize (int ref, bool extremesChanged)
+ { queueResize (ref, extremesChanged, false); }
/**
* \brief See \ref dw-widget-sizes.
@@ -309,6 +314,21 @@ protected:
*/
virtual void markExtremesChange (int ref);
+ virtual int getAvailWidthOfChild (Widget *child, bool forceValue);
+ virtual int getAvailHeightOfChild (Widget *child, bool forceValue);
+ virtual void correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*));
+ virtual void correctExtremesOfChild (Widget *child, Extremes *extremes);
+
+ virtual void containerSizeChangedForChildren ();
+
+ virtual bool affectedByContainerSizeChange ();
+ virtual bool affectsSizeChangeContainerChild (Widget *child);
+ virtual bool usesAvailWidth ();
+ virtual bool usesAvailHeight ();
+
virtual void notifySetAsTopLevel();
virtual void notifySetParent();
@@ -396,7 +416,6 @@ public:
inline bool wasAllocated () { return flags & WAS_ALLOCATED; }
inline bool usesHints () { return flags & USES_HINTS; }
inline bool hasContents () { return flags & HAS_CONTENTS; }
- inline bool blockLevel () { return flags & BLOCK_LEVEL; }
void setParent (Widget *parent);
@@ -406,12 +425,34 @@ public:
/** \todo I do not like this. */
inline Allocation *getAllocation () { return &allocation; }
+ inline int boxOffsetX ()
+ { return extraSpace.left + getStyle()->boxOffsetX (); }
+ inline int boxRestWidth ()
+ { return extraSpace.right + getStyle()->boxRestWidth (); }
+ inline int boxDiffWidth () { return boxOffsetX () + boxRestWidth (); }
+ inline int boxOffsetY ()
+ { return extraSpace.top + getStyle()->boxOffsetY (); }
+ inline int boxRestHeight ()
+ { return extraSpace.bottom + getStyle()->boxRestHeight (); }
+ inline int boxDiffHeight () { return boxOffsetY () + boxRestHeight (); }
+
void sizeRequest (Requisition *requisition);
void getExtremes (Extremes *extremes);
void sizeAllocate (Allocation *allocation);
- virtual void setWidth (int width);
- virtual void setAscent (int ascent);
- virtual void setDescent (int descent);
+
+ int getAvailWidth (bool forceValue);
+ int getAvailHeight (bool forceValue);
+ void correctRequisition (Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*));
+ void correctExtremes (Extremes *extremes);
+
+ virtual int applyPerWidth (int containerWidth, style::Length perWidth);
+ virtual int applyPerHeight (int containerHeight, style::Length perHeight);
+
+ virtual bool isBlockLevel ();
+ virtual bool isPossibleContainer ();
+
+ void containerSizeChanged ();
bool intersects (Rectangle *area, Rectangle *intersection);
@@ -470,6 +511,9 @@ public:
virtual void removeChild (Widget *child);
};
+void splitHeightPreserveAscent (int height, int *ascent, int *descent);
+void splitHeightPreserveDescent (int height, int *ascent, int *descent);
+
} // namespace core
} // namespace dw
diff --git a/lout/debug.hh b/lout/debug.hh
index b823f171..034cefcf 100644
--- a/lout/debug.hh
+++ b/lout/debug.hh
@@ -189,6 +189,13 @@
fflush (stdout); \
} D_STMT_END
+#define DBG_OBJ_SET_BOOL(var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
+ RTFL_PREFIX_ARGS, this, var, val ? "true" : "false"); \
+ fflush (stdout); \
+ } D_STMT_END
+
#define DBG_OBJ_SET_PTR_O(obj, var, val) \
D_STMT_START { \
printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \
@@ -282,6 +289,7 @@
#define DBG_OBJ_SET_SYM(var, val) D_STMT_NOP
#define DBG_OBJ_SET_STR(var, val) D_STMT_NOP
#define DBG_OBJ_SET_PTR(var, val) D_STMT_NOP
+#define DBG_OBJ_SET_BOOL(var, val) D_STMT_NOP
#define DBG_OBJ_SET_PTR_O(obj, var, val) D_STMT_NOP
#define DBG_OBJ_ARRSET_NUM(var, ind, val) D_STMT_NOP
#define DBG_OBJ_ARRSET_SYM(var, ind, val) D_STMT_NOP
diff --git a/lout/misc.hh b/lout/misc.hh
index 3082f33c..4c20208a 100644
--- a/lout/misc.hh
+++ b/lout/misc.hh
@@ -223,6 +223,14 @@ public:
assert (i >= 0 && this->num - i > 0);
this->array[i] = t;
}
+
+ /**
+ * \brief Store an object at the end of the vector.
+ */
+ inline void setLast (T t) {
+ assert (this->num > 0);
+ this->array[this->num - 1] = t;
+ }
};
/**
@@ -488,6 +496,13 @@ public:
inline void set (int i, T t) {
*(this->getRef(i)) = t;
}
+
+ /**
+ * \brief Store an object at the end of the vector.
+ */
+ inline void setLast (T t) {
+ *(this->getLastRef()) = t;
+ }
};
/**
diff --git a/src/table.cc b/src/table.cc
index a3002ebf..29b5fbc9 100644
--- a/src/table.cc
+++ b/src/table.cc
@@ -15,6 +15,7 @@
#include "dw/style.hh"
#include "dw/textblock.hh"
#include "dw/table.hh"
+#include "dw/simpletablecell.hh"
#include "prefs.h"
#include "msg.h"
@@ -445,11 +446,11 @@ static void Html_tag_content_table_cell(DilloHtml *html,
rowspan = MAX(1, strtol (attrbuf, NULL, 10));
if (html->style ()->textAlign
== TEXT_ALIGN_STRING)
- col_tb = new dw::TableCell (
+ col_tb = new AlignedTableCell (
((dw::Table*)S_TOP(html)->table)->getCellRef (),
prefs.limit_text_width);
else
- col_tb = new Textblock (prefs.limit_text_width);
+ col_tb = new SimpleTableCell (prefs.limit_text_width);
if (html->style()->borderCollapse == BORDER_MODEL_COLLAPSE){
Html_set_collapsing_border_model(html, col_tb);
diff --git a/test/dw_table.cc b/test/dw_table.cc
index 5416d05b..9bec1a09 100644
--- a/test/dw_table.cc
+++ b/test/dw_table.cc
@@ -26,7 +26,6 @@
#include "../dw/fltkcore.hh"
#include "../dw/fltkviewport.hh"
#include "../dw/table.hh"
-#include "../dw/tablecell.hh"
using namespace dw;
using namespace dw::core;
diff --git a/test/dw_table_aligned.cc b/test/dw_table_aligned.cc
index 96cb0602..bef3d521 100644
--- a/test/dw_table_aligned.cc
+++ b/test/dw_table_aligned.cc
@@ -26,7 +26,7 @@
#include "../dw/fltkcore.hh"
#include "../dw/fltkviewport.hh"
#include "../dw/table.hh"
-#include "../dw/tablecell.hh"
+#include "../dw/alignedtablecell.hh"
using namespace dw;
using namespace dw::core;
@@ -87,10 +87,10 @@ int main(int argc, char **argv)
Style *wordStyle = Style::create (&styleAttrs);
- TableCell *ref = NULL;
+ AlignedTableCell *ref = NULL;
for(int i = 0; i < 10; i++) {
//for(int i = 0; i < 1; i++) {
- TableCell *cell = new TableCell (ref, false);
+ AlignedTableCell *cell = new AlignedTableCell (ref, false);
cell->setStyle (cellStyle);
ref = cell;
table->addRow (wordStyle);