diff options
-rw-r--r-- | doc/dw-grows.doc | 43 | ||||
-rw-r--r-- | dw/Makefile.am | 7 | ||||
-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.cc | 75 | ||||
-rw-r--r-- | dw/layout.cc | 74 | ||||
-rw-r--r-- | dw/layout.hh | 3 | ||||
-rw-r--r-- | dw/outofflowmgr.cc | 254 | ||||
-rw-r--r-- | dw/outofflowmgr.hh | 11 | ||||
-rw-r--r-- | dw/ruler.cc | 19 | ||||
-rw-r--r-- | dw/ruler.hh | 7 | ||||
-rw-r--r-- | dw/simpletablecell.cc | 46 | ||||
-rw-r--r-- | dw/simpletablecell.hh | 21 | ||||
-rw-r--r-- | dw/style.hh | 16 | ||||
-rw-r--r-- | dw/table.cc | 951 | ||||
-rw-r--r-- | dw/table.hh | 50 | ||||
-rw-r--r-- | dw/table_iterator.cc | 134 | ||||
-rw-r--r-- | dw/textblock.cc | 194 | ||||
-rw-r--r-- | dw/textblock.hh | 21 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 51 | ||||
-rw-r--r-- | dw/ui.cc | 73 | ||||
-rw-r--r-- | dw/ui.hh | 9 | ||||
-rw-r--r-- | dw/widget.cc | 339 | ||||
-rw-r--r-- | dw/widget.hh | 69 | ||||
-rw-r--r-- | lout/misc.hh | 15 | ||||
-rw-r--r-- | src/table.cc | 5 | ||||
-rw-r--r-- | test/dw_table.cc | 1 | ||||
-rw-r--r-- | test/dw_table_aligned.cc | 6 |
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. 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 */ @@ -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) { /** @@ -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); |