summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/dw-grows.doc43
-rw-r--r--dw/Makefile.am7
-rw-r--r--dw/alignedtablecell.cc (renamed from dw/tablecell.cc)23
-rw-r--r--dw/alignedtablecell.hh (renamed from dw/tablecell.hh)14
-rw-r--r--dw/image.cc75
-rw-r--r--dw/layout.cc74
-rw-r--r--dw/layout.hh3
-rw-r--r--dw/outofflowmgr.cc254
-rw-r--r--dw/outofflowmgr.hh11
-rw-r--r--dw/ruler.cc19
-rw-r--r--dw/ruler.hh7
-rw-r--r--dw/simpletablecell.cc46
-rw-r--r--dw/simpletablecell.hh21
-rw-r--r--dw/style.hh16
-rw-r--r--dw/table.cc951
-rw-r--r--dw/table.hh50
-rw-r--r--dw/table_iterator.cc134
-rw-r--r--dw/textblock.cc194
-rw-r--r--dw/textblock.hh21
-rw-r--r--dw/textblock_linebreaking.cc51
-rw-r--r--dw/ui.cc73
-rw-r--r--dw/ui.hh9
-rw-r--r--dw/widget.cc339
-rw-r--r--dw/widget.hh69
-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
28 files changed, 1188 insertions, 1343 deletions
diff --git a/doc/dw-grows.doc b/doc/dw-grows.doc
index 32800c19..7ed938e5 100644
--- a/doc/dw-grows.doc
+++ b/doc/dw-grows.doc
@@ -14,6 +14,45 @@ calculating widget sizes. Goals are:
- *display: inline-block*;
- <button>.
-(...)
+A short sketch:
-*/ \ No newline at end of file
+**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.
+
+**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.
+
+*/
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..1fba7588 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,17 @@ 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::wordWrap(int wordIndex, bool wrapAll)
{
Textblock::Word *word;
const char *p;
@@ -73,7 +78,7 @@ int TableCell::wordWrap(int wordIndex, bool wrapAll)
return ret;
}
-int TableCell::getValue ()
+int AlignedTableCell::getValue ()
{
Textblock::Word *word;
int i, wordIndex;
@@ -104,7 +109,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/tablecell.hh b/dw/alignedtablecell.hh
index 1e13abf9..eafff468 100644
--- a/dw/tablecell.hh
+++ b/dw/alignedtablecell.hh
@@ -1,12 +1,12 @@
-#ifndef __DW_TABLECELL_HH__
-#define __DW_TABLECELL_HH__
+#ifndef __DW_ALIGNEDTABLECELL_HH__
+#define __DW_ALIGNEDTABLECELL_HH__
#include "core.hh"
#include "alignedtextblock.hh"
namespace dw {
-class TableCell: public AlignedTextblock
+class AlignedTableCell: public AlignedTextblock
{
private:
int charWordIndex, charWordPos;
@@ -20,10 +20,12 @@ protected:
public:
static int CLASS_ID;
- TableCell(TableCell *ref, bool limitTextWidth);
- ~TableCell();
+ AlignedTableCell(AlignedTableCell *ref, bool limitTextWidth);
+ ~AlignedTableCell();
+
+ bool isBlockLevel ();
};
} // namespace dw
-#endif // __DW_TABLECELL_HH__
+#endif // __DW_ALIGNEDTABLECELL_HH__
diff --git a/dw/image.cc b/dw/image.cc
index e71c8f2f..9c8e5f00 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->descent = boxRestHeight ();
- requisition->width = altTextWidth;
- requisition->ascent = getStyle()->font->ascent;
- requisition->descent = getStyle()->font->descent;
- } else {
- requisition->width = 0;
- requisition->ascent = 0;
- requisition->descent = 0;
+ 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)
diff --git a/dw/layout.cc b/dw/layout.cc
index 1609dae0..818effd2 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,13 @@ 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");
+ assert (topLevel); // No toplevel widget would have no size.
+ containerSizeChanged (topLevel);
+ }
// Set viewport sizes.
view->setViewportSize (viewportWidth, viewportHeight,
@@ -932,16 +947,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;
@@ -1269,8 +1274,11 @@ void Layout::viewportSizeChanged (View *view, int width, int height)
/* 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,35 @@ 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);
+
+ if (topLevel)
+ containerSizeChanged (topLevel);
+}
+
+bool Layout::widgetAffectedByContainerSizeChange (Widget *widget)
+{
+ return true; // TODO only absolute dimensions? Depending on widget class?
+}
+
+void Layout::containerSizeChanged (Widget *widget)
+{
+ if (widgetAffectedByContainerSizeChange (widget)) {
+ widget->queueResize (0, false);
+
+ // TODO Wrong! Iteration must stop when the *container* (not the
+ // *parent*!) is unaffected. (Does not matter as long as
+ // widgetAffectedByContainerSizeChange() returns always true.)
+
+ Iterator *it =
+ widget->iterator ((Content::Type)
+ (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
+ false);
+ while (it->next ())
+ containerSizeChanged (it->getContent()->widget);
+ it->unref ();
+ }
}
} // namespace core
diff --git a/dw/layout.hh b/dw/layout.hh
index 2120d877..0dc3cfbc 100644
--- a/dw/layout.hh
+++ b/dw/layout.hh
@@ -267,6 +267,9 @@ private:
void enterResizeIdle () { resizeIdleCounter++; }
void leaveResizeIdle () { resizeIdleCounter--; }
+ bool widgetAffectedByContainerSizeChange (Widget *widget);
+ void containerSizeChanged (Widget *widget);
+
public:
Layout (Platform *platform);
~Layout ();
diff --git a/dw/outofflowmgr.cc b/dw/outofflowmgr.cc
index eb5bf3e8..1e80cec3 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
@@ -709,8 +709,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 +1042,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,11 +1067,11 @@ 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;
@@ -1087,11 +1087,11 @@ int OutOfFlowMgr::calcFloatX (Float *vloat, Side side, int gbX, int gbWidth,
case RIGHT:
// In some cases, the actual (allocated) width is too large; we
- // use the "available" width here.
- gbActualWidth = min (gbWidth, gbAvailWidth);
+ // use the line break width here.
+ gbActualWidth = min (gbWidth, gbLineBreakWidth);
DBG_OBJ_MSGF ("resize.oofm", 1,
"right: gbActualWidth = min (%d, %d) = %d",
- gbWidth, gbAvailWidth, gbActualWidth);
+ gbWidth, gbLineBreakWidth, gbActualWidth);
// Similar for right floats, but in this case, floats are
// shifted to the right when they are too big (instead of
@@ -1565,7 +1565,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 +1582,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 +1681,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 +1763,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,7 +1918,7 @@ 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 ();
+ int tbAvWidth = textblock->getLineBreakWidth ();
thisBorder = tba->x + min (tba->width, tbAvWidth) - fla->x;
DBG_OBJ_MSGF ("border", 1,
"not GB: thisBorder = %d + min (%d, %d) - %d "
@@ -2070,120 +2057,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 +2087,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 +2105,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..441c4408 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);
diff --git a/dw/ruler.cc b/dw/ruler.cc
index 2b5288c2..b014654d 100644
--- a/dw/ruler.cc
+++ b/dw/ruler.cc
@@ -29,25 +29,26 @@ 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 ());
+ requisition->width = lout::misc::max (getAvailWidth (),
+ 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 ();
+ correctExtremes (extremes);
+}
+
+bool Ruler::isBlockLevel ()
+{
+ return true;
}
void Ruler::draw (core::View *view, core::Rectangle *area)
diff --git a/dw/ruler.hh b/dw/ruler.hh
index 863792dd..eea1f952 100644
--- a/dw/ruler.hh
+++ b/dw/ruler.hh
@@ -15,17 +15,16 @@ 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 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..3a356cbc
--- /dev/null
+++ b/dw/simpletablecell.cc
@@ -0,0 +1,46 @@
+/*
+ * 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;
+}
+
+} // namespace dw
diff --git a/dw/simpletablecell.hh b/dw/simpletablecell.hh
new file mode 100644
index 00000000..a97464e4
--- /dev/null
+++ b/dw/simpletablecell.hh
@@ -0,0 +1,21 @@
+#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 ();
+
+ bool isBlockLevel ();
+};
+
+} // namespace dw
+
+#endif // __DW_SIMPLETABLECELL_HH__
diff --git a/dw/style.hh b/dw/style.hh
index 2cc258bf..da214ca1 100644
--- a/dw/style.hh
+++ b/dw/style.hh
@@ -564,22 +564,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..f6073b2d 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,11 +41,6 @@ Table::Table(bool limitTextWidth)
rowClosed = false;
- // random values
- availWidth = 100;
- availAscent = 100;
- availDescent = 0;
-
numRows = 0;
numCols = 0;
curRow = -1;
@@ -57,18 +51,13 @@ Table::Table(bool limitTextWidth)
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);
-
redrawX = 0;
redrawY = 0;
}
-
Table::~Table()
{
for (int i = 0; i < children->size (); i++) {
@@ -94,17 +83,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 +109,39 @@ void Table::sizeRequestImpl (core::Requisition *requisition)
+ getStyle()->vBorderSpacing;
requisition->descent = 0;
+ DBG_OBJ_MSG_END ();
}
void Table::getExtremesImpl (core::Extremes *extremes)
{
- if (numCols == 0) {
- extremes->minWidth = extremes->maxWidth = 0;
- return;
- }
-
- forceCalcColumnExtremes ();
+ DBG_OBJ_MSG ("resize", 0, "<b>getExtremesImpl</b>");
+ DBG_OBJ_MSG_START ();
- 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->maxWidth = 0;
+ else {
+ 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;
+ }
+
+ correctExtremes (extremes);
}
- _MSG(" Table::getExtremesImpl, {%d, %d} numCols=%d\n",
- extremes->minWidth, extremes->maxWidth, numCols);
+ 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 +156,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 +180,8 @@ void Table::sizeAllocateImpl (core::Allocation *allocation)
x += colWidths->get (col) + getStyle()->hBorderSpacing;
}
+
+ DBG_OBJ_MSG_END ();
}
void Table::resizeDrawImpl ()
@@ -202,30 +192,63 @@ void Table::resizeDrawImpl ()
redrawY = getHeight ();
}
-void Table::setWidth (int width)
+int Table::getAvailWidthOfChild (Widget *child)
{
- // 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)", child);
+ DBG_OBJ_MSG_START ();
-void Table::setAscent (int ascent)
-{
- if (availAscent != ascent) {
- availAscent = ascent;
- queueResize (0, false);
+ calcCellSizes (false);
+
+ int width;
+
+ if (core::style::isAbsLength (child->getStyle()->width)) {
+ DBG_OBJ_MSG ("resize", 1, "absolute length");
+ width = core::style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth ();
+ } else if (core::style::isPerLength (child->getStyle()->width)) {
+ DBG_OBJ_MSG ("resize", 1, "percentage length");
+ int containerContentWidth = getAvailWidth () - boxDiffWidth ();
+ width = core::style::multiplyWithPerLength (containerContentWidth,
+ child->getStyle()->width)
+ + child->boxDiffWidth ();
+ } else {
+ width = -1;
+ DBG_OBJ_MSG ("resize", 1, "no length specified");
+
+ // "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);
+ }
+ }
+ }
+
+ assert (width != -1);
}
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_MSG_END ();
+ return width;
}
-void Table::setDescent (int descent)
+bool Table::isBlockLevel ()
{
- if (availDescent != descent) {
- availDescent = descent;
- queueResize (0, false);
- }
+ return true;
}
void Table::draw (core::View *view, core::Rectangle *area)
@@ -272,6 +295,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 +400,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 +422,7 @@ void Table::addRow (core::style::Style *style)
rowClosed = false;
}
-TableCell *Table::getCellRef ()
+AlignedTableCell *Table::getCellRef ()
{
core::Widget *child;
@@ -401,8 +430,8 @@ 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;
}
}
@@ -480,103 +509,96 @@ void Table::reallocChildren (int newNumCols, int newNumRows)
// ----------------------------------------------------------------------
-void Table::calcCellSizes ()
+void Table::calcCellSizes (bool calcHeights)
{
- if (needsResize () || resizeQueued ())
- forceCalcCellSizes ();
+ DBG_OBJ_MSG ("resize", 0, "<b>calcCellSizes</b>");
+ DBG_OBJ_MSG_START ();
+
+ if ((calcHeights && (needsResize () || resizeQueued () ||
+ extremesChanged () || extremesQueued ())) ||
+ (extremesChanged () || extremesQueued ()))
+ 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 totalWidth = 0, 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);
+ totalWidth = getAvailWidth ();
if (totalWidth < extremes.minWidth)
totalWidth = extremes.minWidth;
- totalWidth = totalWidth
- - (numCols + 1) * getStyle()->hBorderSpacing
- - getStyle()->boxDiffWidth ();
-
- _MSG(" totalWidth2 = %d curCol=%d\n", totalWidth,curCol);
-
+ totalWidth -= ((numCols + 1) * getStyle()->hBorderSpacing
+ + getStyle()->boxDiffWidth ());
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);
-
-
- apportion_percentages2 (totalWidth, forceTotalWidth);
- if (!hasColPercent)
- apportion2 (totalWidth, forceTotalWidth);
+ apportion2 (totalWidth, getStyle()->width != core::style::LENGTH_AUTO,
+ 0, colExtremes->size() - 1, colWidths, 0, true);
- 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);
+ 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));
+ }
- 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);
+ 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 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 +652,8 @@ void Table::apportionRowSpan ()
setCumHeight (i+1, cumHeight->get(i) + rowHeight[i]);
}
delete[] rowHeight;
+
+ DBG_OBJ_MSG_END ();
}
@@ -640,8 +664,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 +679,170 @@ 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;
+ if (numCols > 0) {
+ lout::misc::SimpleVector<int> colSpanCells (8);
+ colExtremes->setSize (numCols);
- 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);
-
- 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;
- }
-
- _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!)
- */
+ // 1. cells with colspan = 1
+ for (int col = 0; col < numCols; col++) {
+ colExtremes->getRef(col)->minWidth = 0;
+ colExtremes->getRef(col)->maxWidth = 0;
+
+ for (int row = 0; row < numRows; row++) {
+ 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);
+
+ 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.minWidth);
+ } else {
+ colSpanCells.increase ();
+ colSpanCells.setLast (n);
+ }
}
- } else {
- colSpanCells->increase();
- colSpanCells->set(colSpanCells->size()-1, n);
}
}
- }
- /* 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;
- }
+ // 2. cells with colspan > 1
+
+ // TODO: Is this old comment still relevant? "If needed, here we
+ // set proportionally apportioned col maximums."
- _MSG("cs=%d spanWidth=%d,%d sumCols=%d,%d\n",
- cs,cellMinW,cellMaxW,minSumCols,maxSumCols);
+ for (int i = 0; i < colSpanCells.size(); i++) {
+ int n = colSpanCells.get (i);
+ int col = n % numCols;
+ int cs = children->get(n)->cell.colspanEff;
- if (minSumCols >= cellMinW && maxSumCols >= cellMaxW)
- continue;
+ core::Extremes cellExtremes;
+ children->get(n)->cell.widget->getExtremes (&cellExtremes);
- // 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;
+ int minSumCols = 0, maxSumCols = 0;
+ for (int j = 0; j < cs; j++) {
+ minSumCols += colExtremes->getRef(col + j)->minWidth;
+ maxSumCols += colExtremes->getRef(col + j)->maxWidth;
}
- }
-
- // 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;
+ DBG_OBJ_MSGF ("resize", 1, "cs = %d cell: %d / %d, sum: %d / %d\n",
+ cs, cellExtremes.minWidth, cellExtremes.maxWidth,
+ minSumCols, maxSumCols);
+
+ bool changeMin = cellExtremes.minWidth > minSumCols;
+ bool changeMax = cellExtremes.maxWidth > maxSumCols;
+ if (changeMin || changeMax) {
+ // TODO This differs from the documentation? Should work, anyway.
+ misc::SimpleVector<int> newMin, newMax;
+ if (changeMin)
+ apportion2 (cellExtremes.minWidth, true, col, col + cs - 1,
+ &newMin, 0, false);
+ if (changeMax)
+ apportion2 (cellExtremes.maxWidth, true, col, col + cs - 1,
+ &newMax, 0, false);
+
+ for (int j = 0; j < cs; j++) {
+ if (changeMin)
+ colExtremes->getRef(col + j)->minWidth = newMin.get (i);
+ if (changeMax)
+ colExtremes->getRef(col + j)->maxWidth = newMax.get (i);
+ // For cases where min and max are somewhat confused:
+ colExtremes->getRef(col + j)->maxWidth =
+ misc::max (colExtremes->getRef(col + j)->minWidth,
+ colExtremes->getRef(col + j)->maxWidth);
}
}
-
- 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);
-
}
-#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, "maxWidth",
+ colExtremes->get(i).maxWidth);
}
- 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);
-
- 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)
-{
- 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);
-
- 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;
- }
-
- _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;
-
- _MSG("APP_P, col %d minWidth=%d maxWidth=%d\n", col,
- colExtremes->getRef(col)->minWidth,
- colExtremes->getRef(col)->maxWidth);
- }
- 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);
- }
+/**
+ * \brief Actual apportionment function.
+ */
+void Table::apportion2 (int totalWidth, bool forceTotalWidth,
+ int firstCol, int lastCol,
+ misc::SimpleVector<int> *dest, int destOffset,
+ bool setRedrawX)
+{
+ DBG_OBJ_MSGF ("resize", 0, "<b>apportion2</b> (%d, %s, %d, %d, ..., %d, %s)",
+ totalWidth, forceTotalWidth ? "true" : "false", firstCol,
+ lastCol, destOffset, setRedrawX ? "true" : "false");
+ DBG_OBJ_MSG_START ();
+
+ if (lastCol >= firstCol) {
+ int minWidth = 0, maxWidth = 0, availWidth;
+
+ for (int col = firstCol; col <= lastCol; col++) {
+ maxWidth += colExtremes->get(col).maxWidth;
+ minWidth += colExtremes->get(col).minWidth;
}
+
+ dest->setSize (destOffset + lastCol - firstCol + 11, 0);
+
+ if (!forceTotalWidth && maxWidth < totalWidth) {
+ // Enough space for the maximum table, don't widen past max.
+ availWidth = maxWidth;
+ } else
+ availWidth = totalWidth;
- // 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;
- }
+ DBG_OBJ_MSGF ("resize", 1,
+ "maxWidth = %d, minWidth = %d, availWidth = %d",
+ maxWidth, minWidth, availWidth);
- _MSG("APP_P, oldTotalWidth=%d totalWidth=%d"
- " workingWidth=%d extraWidth=%d sumMinNonPer=%d\n",
- oldTotalWidth,totalWidth,workingWidth,extraWidth,sumMinNonPer);
+ // General case.
+ int curTargetWidth = misc::max (availWidth, minWidth);
+ int curExtraWidth = curTargetWidth - minWidth;
+ int curMaxWidth = maxWidth;
+ int curNewWidth = minWidth;
- for (int col = 0; col < numCols; col++) {
+ for (int col = firstCol; col <= lastCol; 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);
- }
- }
+ int colMaxWidth = colExtremes->getRef(col)->maxWidth;
+ int w = (curMaxWidth <= 0) ? 0 :
+ (int)((float)curTargetWidth * colMaxWidth/curMaxWidth);
- 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);
- }
- }
- }
- }
-#ifdef DBG
- MSG("APP_P, result ={ ");
- for (int col = 0; col < numCols; col++)
- MSG("%d ", colWidths->get(col));
- MSG("}\n");
-#endif
- apportion2 (totalWidth, 2);
+ if (w <= colMinWidth)
+ w = colMinWidth;
+ else if (curNewWidth - colMinWidth + w > curTargetWidth)
+ w = colMinWidth + curExtraWidth;
-#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
- }
-}
-
-// ----------------------------------------------------------------------
+ _MSG("w = %d\n", w);
-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;
-}
+ curNewWidth -= colMinWidth;
+ curMaxWidth -= colMaxWidth;
+ curExtraWidth -= (w - colMinWidth);
+ curTargetWidth -= w;
-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();
+ // TODO Adapted from old inline function "setColWidth". But
+ // (i) is this anyway correct (w is not x)? And does the
+ // performance gain actually play a role?
+ if (setRedrawX && w != dest->get (destOffset + col))
+ redrawX = lout::misc::min (redrawX, w);
- 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;
+ dest->set (destOffset + col, w);
}
- } 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..caa66efe 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,20 +388,10 @@ 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;
-
inline bool childDefined(int n)
{
return n < children->size() && children->get(n) != NULL &&
@@ -405,15 +400,17 @@ 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 apportion2 (int totalWidth, int forceTotalWidth);
- void apportion_percentages2 (int totalWidth, int forceTotalWidth);
+ void apportion2 (int totalWidth, bool forceTotalWidth,
+ int firstCol, int lastCol,
+ lout::misc::SimpleVector<int> *dest, int destOffset,
+ bool setRedrawX);
void setCumHeight (int row, int value)
{
@@ -423,23 +420,16 @@ 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 isBlockLevel ();
+
void draw (core::View *view, core::Rectangle *area);
//bool buttonPressImpl (core::EventButton *event);
@@ -458,7 +448,7 @@ public:
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/textblock.cc b/dw/textblock.cc
index beb3f3f8..b822ffb4 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -225,7 +225,6 @@ Textblock::Textblock (bool limitTextWidth)
{
DBG_OBJ_CREATE ("dw::Textblock");
registerName ("dw::Textblock", &CLASS_ID);
- setFlags (BLOCK_LEVEL);
setFlags (USES_HINTS);
setButtonSensitive(true);
@@ -265,14 +264,10 @@ Textblock::Textblock (bool limitTextWidth)
hoverLink = -1;
- // random values
- availWidth = 100;
- availAscent = 100;
- availDescent = 0;
+ // random value
+ lineBreakWidth = 100;
- DBG_OBJ_SET_NUM ("availWidth", availWidth);
- DBG_OBJ_SET_NUM ("availAscent", availAscent);
- DBG_OBJ_SET_NUM ("availDescent", availDescent);
+ DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
verticalOffset = 0;
DBG_OBJ_SET_NUM ("verticalOffset", verticalOffset);
@@ -338,6 +333,8 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
DBG_OBJ_MSG ("resize", 0, "<b>sizeRequestImpl</b> ()");
DBG_OBJ_MSG_START ();
+ lineBreakWidth = getAvailWidth ();
+
rewrap ();
showMissingLines ();
@@ -393,19 +390,21 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
}
DBG_OBJ_MSGF ("resize", 1,
- "before considering availWidth (= %d): %d * (%d + %d)",
- availWidth, requisition->width, requisition->ascent,
+ "before considering lineBreakWidth (= %d): %d * (%d + %d)",
+ lineBreakWidth, requisition->width, requisition->ascent,
requisition->descent);
- if (requisition->width < availWidth) {
- requisition->width = availWidth;
- DBG_OBJ_MSGF ("resize", 1, "adjusting to availWidth => %d",
+ // TODO The following will not be necessary anymore:
+ if (requisition->width < lineBreakWidth) {
+ requisition->width = lineBreakWidth;
+ DBG_OBJ_MSGF ("resize", 1, "adjusting to lineBreakWidth => %d",
requisition->width);
}
+ correctRequisition (requisition, core::splitHeightPreserveAscent);
+
DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
requisition->width, requisition->ascent, requisition->descent);
-
DBG_OBJ_MSG_END ();
}
@@ -414,44 +413,10 @@ 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->maxWidth = word->size.width;
}
void Textblock::getExtremesImpl (core::Extremes *extremes)
@@ -492,6 +457,8 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
extremes->maxWidth = misc::max (extremes->maxWidth, oofMaxWidth);
}
+ correctExtremes (extremes);
+
DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
extremes->minWidth, extremes->maxWidth);
@@ -773,53 +740,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)
@@ -1061,78 +984,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();
-
- /* 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);
- }
+ widget->sizeRequest (size);
- 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;
diff --git a/dw/textblock.hh b/dw/textblock.hh
index 3254b843..44fa8a57 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.
*
@@ -489,7 +489,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 +516,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;
@@ -737,7 +737,7 @@ 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);
@@ -748,11 +748,12 @@ protected:
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 +815,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_linebreaking.cc b/dw/textblock_linebreaking.cc
index a773f24c..c7c30aee 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 {
@@ -637,7 +637,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.)
@@ -1474,7 +1474,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 +1526,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 +1583,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 +1596,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 - innerPadding;
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 +1623,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, innerPadding, leftBorder, rightBorder,
+ lineBreakWidth);
DBG_OBJ_MSG_END ();
- return availWidth;
+ return lineBreakWidth;
}
void Textblock::initLine1Offset (int wordIndex)
@@ -1639,18 +1640,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,7 +1672,7 @@ void Textblock::alignLine (int lineIndex)
DBG_OBJ_MSG_START ();
Line *line = lines->getRef (lineIndex);
- int availWidth = calcAvailWidth (lineIndex);
+ int lineBreakWidth = calcLineBreakWidth (lineIndex);
if (line->firstWord <= line->lastWord) {
Word *firstWord = words->getRef (line->firstWord);
Word *lastWord = words->getRef (line->lastWord);
@@ -1704,18 +1705,18 @@ 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->leftOffset = lineBreakWidth - lastWord->totalWidth;
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->leftOffset = (lineBreakWidth - lastWord->totalWidth) / 2;
break;
default:
/* compiler happiness */
diff --git a/dw/ui.cc b/dw/ui.cc
index 8fb34c96..7b394cc5 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)
@@ -88,36 +89,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 +194,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 +327,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..6fc3d28a 100644
--- a/dw/ui.hh
+++ b/dw/ui.hh
@@ -241,9 +241,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 +334,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 +401,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..d3c13d4f 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();
}
@@ -323,6 +341,152 @@ void Widget::sizeRequest (Requisition *requisition)
}
/**
+ * Return available width including margin/border/padding
+ * (extraSpace?), not only the content width.
+ */
+int Widget::getAvailWidth ()
+{
+ // TODO Correct by extremes?
+
+ DBG_OBJ_MSG ("resize", 0, "<b>getAvailWidth</b> ()");
+ DBG_OBJ_MSG_START ();
+
+ int width;
+
+ if (container == NULL) {
+ // TODO Consider nested layouts (e. g. <button>).
+ if (style::isAbsLength (getStyle()->width))
+ width = style::absLengthVal (getStyle()->width) + boxDiffWidth ();
+ else {
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ if (style::isPerLength (getStyle()->width)) {
+ width = style::multiplyWithPerLength (viewportWidth,
+ getStyle()->width)
+ + boxDiffWidth ();
+ } else
+ width = viewportWidth;
+ }
+ } else
+ width = container->getAvailWidthOfChild (this);
+
+ 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 ()
+{
+ // TODO Correct by ... not extremes, but ...? (Height extremes?)
+
+ DBG_OBJ_MSG ("resize", 0, "<b>getAvailHeight</b> ()");
+ DBG_OBJ_MSG_START ();
+
+ int height;
+
+ if (container == NULL) {
+ // TODO Consider nested layouts (e. g. <button>).
+ if (style::isAbsLength (getStyle()->height))
+ height = style::absLengthVal (getStyle()->height) + boxDiffHeight ();
+ else if (style::isPerLength (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 = style::multiplyWithPerLength (layout->viewportHeight,
+ getStyle()->height)
+ + boxDiffHeight ();
+ else
+ height = layout->viewportHeight;
+ } else
+ height = container->getAvailHeightOfChild (this);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_MSG_END ();
+
+ return height;
+}
+
+void Widget::correctRequisition (Requisition *requisition,
+ void (*splitHeightFun)(int height, int *ascent,
+ int *descent))
+{
+ // 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))
+ requisition->width =
+ style::absLengthVal (getStyle()->width) + boxDiffWidth ();
+ else if (style::isPerLength (getStyle()->width)) {
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ requisition->width =
+ style::multiplyWithPerLength (viewportWidth, getStyle()->width)
+ + boxDiffWidth ();
+ }
+
+ // TODO Perhaps split first, then add box ascent and descent.
+ if (style::isAbsLength (getStyle()->height))
+ splitHeightFun (style::absLengthVal (getStyle()->height)
+ + boxDiffHeight (),
+ &requisition->ascent, &requisition->descent);
+ else if (style::isPerLength (getStyle()->height)) {
+ // For layout->viewportHeight, see comment in getAvailHeight().
+ splitHeightFun (style::multiplyWithPerLength (layout->viewportHeight,
+ getStyle()->height)
+ + boxDiffHeight (),
+ &requisition->ascent, &requisition->descent);
+ }
+ } 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)",
+ extremes->minWidth, extremes->maxWidth);
+ 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 =
+ style::multiplyWithPerLength (viewportWidth, getStyle()->width)
+ + boxDiffWidth ();
+ }
+ } 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)
@@ -787,6 +951,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 +966,144 @@ void Widget::markExtremesChange (int ref)
{
}
+int Widget::getAvailWidthOfChild (Widget *child)
+{
+ // 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)", child);
+ DBG_OBJ_MSG_START ();
+
+ int width;
+
+ if (style::isAbsLength (child->getStyle()->width))
+ width = style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth ();
+ else {
+ int containerContentWidth = getAvailWidth () - boxDiffWidth ();
+ if (style::isPerLength (child->getStyle()->width))
+ width = style::multiplyWithPerLength (containerContentWidth,
+ child->getStyle()->width)
+ + child->boxDiffWidth ();
+ else
+ // Some widgets will use the whole width, so this is a
+ // meaningful value.
+ width = containerContentWidth;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_MSG_END ();
+
+ return width;
+}
+
+int Widget::getAvailHeightOfChild (Widget *child)
+{
+ // Again, a suitable implementation for all widgets (perhaps).
+
+ // TODO Correct by extremes? (Height extemes?)
+
+ DBG_OBJ_MSGF ("resize", 0, "<b>getAvailHeightOfChild</b> (%p)", child);
+ DBG_OBJ_MSG_START ();
+
+ int height;
+
+ if (style::isAbsLength (child->getStyle()->height))
+ height = style::absLengthVal (child->getStyle()->height)
+ + child->boxDiffHeight ();
+ else {
+ int containerContentHeight = getAvailHeight () - boxDiffHeight ();
+ if (style::isPerLength (child->getStyle()->height))
+ height = style::multiplyWithPerLength (containerContentHeight,
+ child->getStyle()->height)
+ + child->boxDiffHeight ();
+ else
+ // Although no widget will probably use the whole height, we
+ // have to return some value here.
+ height = containerContentHeight;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_MSG_END ();
+
+ return height;
+}
+
+void Widget::correctRequisitionOfChild (Widget *child, Requisition *requisition,
+ void (*splitHeightFun)(int height,
+ int *ascent,
+ int *descent))
+{
+ // 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 containerWidth = getAvailWidth () - boxDiffWidth ();
+ requisition->width =
+ style::multiplyWithPerLength (containerWidth,
+ child->getStyle()->width)
+ + child->boxDiffWidth ();
+ }
+
+ // 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 containerHeight = getAvailHeight () - boxDiffHeight ();
+ splitHeightFun (style::multiplyWithPerLength (containerHeight,
+ child->getStyle()->height)
+ + child->boxDiffHeight (),
+ &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))
+ extremes->minWidth =extremes->maxWidth =
+ style::absLengthVal (child->getStyle()->width)
+ + child->boxDiffWidth ();
+ else if (style::isPerLength (child->getStyle()->width)) {
+ int containerWidth = getAvailWidth () - boxDiffWidth ();
+ extremes->minWidth =extremes->maxWidth =
+ style::multiplyWithPerLength (containerWidth, child->getStyle()->width)
+ + child->boxDiffWidth ();
+ }
+
+ 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 +1123,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 +1152,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 +1160,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 +1172,23 @@ 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..326d00ec 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;
@@ -191,6 +193,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 +263,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;
}
}
}
@@ -309,6 +312,17 @@ protected:
*/
virtual void markExtremesChange (int ref);
+ virtual int getAvailWidthOfChild (Widget *child);
+ virtual int getAvailHeightOfChild (Widget *child);
+ virtual void correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun)(int height,
+ int *ascent,
+ int
+ *descent));
+ virtual void correctExtremesOfChild (Widget *child, Extremes *extremes);
+
+
virtual void notifySetAsTopLevel();
virtual void notifySetParent();
@@ -396,7 +410,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 +419,30 @@ 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 ();
+ int getAvailHeight ();
+ void correctRequisition (Requisition *requisition,
+ void (*splitHeightFun)(int height, int *ascent,
+ int *descent));
+ void correctExtremes (Extremes *extremes);
+
+ virtual bool isBlockLevel ();
+ virtual bool isPossibleContainer ();
bool intersects (Rectangle *area, Rectangle *intersection);
@@ -470,6 +501,10 @@ 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/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);