diff options
Diffstat (limited to 'dw/table.cc')
-rw-r--r-- | dw/table.cc | 1291 |
1 files changed, 637 insertions, 654 deletions
diff --git a/dw/table.cc b/dw/table.cc index 565dfc9e..edd83f88 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,41 +34,36 @@ Table::Table(bool limitTextWidth) { DBG_OBJ_CREATE ("dw::Table"); registerName ("dw::Table", &CLASS_ID); - setFlags (BLOCK_LEVEL); - setFlags (USES_HINTS); setButtonSensitive(false); this->limitTextWidth = limitTextWidth; rowClosed = false; - // random values - availWidth = 100; - availAscent = 100; - availDescent = 0; - numRows = 0; numCols = 0; curRow = -1; curCol = 0; + DBG_OBJ_SET_NUM ("numCols", numCols); + DBG_OBJ_SET_NUM ("numRows", numCols); + children = new misc::SimpleVector <Child*> (16); colExtremes = new misc::SimpleVector<core::Extremes> (8); colWidths = new misc::SimpleVector <int> (8); cumHeight = new misc::SimpleVector <int> (8); rowSpanCells = new misc::SimpleVector <int> (8); - colSpanCells = new misc::SimpleVector <int> (8); baseline = new misc::SimpleVector <int> (8); rowStyle = new misc::SimpleVector <core::style::Style*> (8); - hasColPercent = 0; - colPercents = new misc::SimpleVector <core::style::Length> (8); + colWidthsUpToDateWidthColExtremes = true; + DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes", + colWidthsUpToDateWidthColExtremes); redrawX = 0; redrawY = 0; } - Table::~Table() { for (int i = 0; i < children->size (); i++) { @@ -94,17 +89,17 @@ 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_ENTER0 ("resize", 0, "sizeRequestImpl"); + + forceCalcCellSizes (true); /** * \bug Baselines are not regarded here. @@ -119,40 +114,44 @@ void Table::sizeRequestImpl (core::Requisition *requisition) + getStyle()->vBorderSpacing; requisition->descent = 0; + correctRequisition (requisition, core::splitHeightPreserveDescent); + + DBG_OBJ_LEAVE (); } void Table::getExtremesImpl (core::Extremes *extremes) { - if (numCols == 0) { - extremes->minWidth = extremes->maxWidth = 0; - return; - } - - forceCalcColumnExtremes (); + DBG_OBJ_ENTER0 ("resize", 0, "getExtremesImpl"); - extremes->minWidth = extremes->maxWidth = - (numCols + 1) * getStyle()->hBorderSpacing - + getStyle()->boxDiffWidth (); - for (int col = 0; col < numCols; col++) { - extremes->minWidth += colExtremes->getRef(col)->minWidth; - extremes->maxWidth += colExtremes->getRef(col)->maxWidth; - } - if (core::style::isAbsLength (getStyle()->width)) { - extremes->minWidth = - misc::max (extremes->minWidth, - core::style::absLengthVal(getStyle()->width)); - extremes->maxWidth = - misc::max (extremes->maxWidth, - core::style::absLengthVal(getStyle()->width)); + if (numCols == 0) + extremes->minWidth = extremes->minWidthIntrinsic = extremes->maxWidth = + extremes->maxWidthIntrinsic = boxDiffWidth (); + else { + forceCalcColumnExtremes (); + + extremes->minWidth = extremes->minWidthIntrinsic = extremes->maxWidth = + extremes->maxWidthIntrinsic = + (numCols + 1) * getStyle()->hBorderSpacing + boxDiffWidth (); + for (int col = 0; col < numCols; col++) { + extremes->minWidth += colExtremes->getRef(col)->minWidth; + extremes->minWidthIntrinsic += + colExtremes->getRef(col)->minWidthIntrinsic; + extremes->maxWidth += colExtremes->getRef(col)->maxWidth; + extremes->maxWidthIntrinsic += + colExtremes->getRef(col)->maxWidthIntrinsic; + } } - _MSG(" Table::getExtremesImpl, {%d, %d} numCols=%d\n", - extremes->minWidth, extremes->maxWidth, numCols); + correctExtremes (extremes); + + DBG_OBJ_LEAVE (); } void Table::sizeAllocateImpl (core::Allocation *allocation) { - calcCellSizes (); + DBG_OBJ_ENTER0 ("resize", 0, "sizeAllocateImpl"); + + calcCellSizes (true); /** * \bug Baselines are not regarded here. @@ -167,8 +166,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 +190,8 @@ void Table::sizeAllocateImpl (core::Allocation *allocation) x += colWidths->get (col) + getStyle()->hBorderSpacing; } + + DBG_OBJ_LEAVE (); } void Table::resizeDrawImpl () @@ -202,30 +202,147 @@ void Table::resizeDrawImpl () redrawY = getHeight (); } -void Table::setWidth (int width) +int Table::getAvailWidthOfChild (Widget *child, bool forceValue) { - // If limitTextWidth is set, a queueResize may also be necessary. - if (availWidth != width || limitTextWidth) { - _MSG(" Table::setWidth %d\n", width); - availWidth = width; - queueResize (0, false); + DBG_OBJ_ENTER ("resize", 0, "getAvailWidthOfChild", "%p, %s", + child, forceValue ? "true" : "false"); + + int width; + + // Unlike other containers, the table widget sometimes narrows + // columns to a width less than specified by CSS (see + // forceCalcCellSizes). For this reason, the column widths have to + // be calculated in all cases. + if (forceValue) { + calcCellSizes (false); + width = calcAvailWidthForDescendant (child); + } else + width = -1; + + DBG_OBJ_MSGF ("resize", 1, "=> %d", width); + DBG_OBJ_LEAVE (); + return width; +} + +void Table::correctRequisitionOfChild (core::Widget *child, + core::Requisition *requisition, + void (*splitHeightFun) (int, int*, int*)) +{ + // TODO Same comments as in Widget::correctRequisitionOfChild may + // apply here. + + DBG_OBJ_ENTER ("resize", 0, "correctRequisitionOfChild", + "%p, %d * (%d + %d), ...)", + child, requisition->width, requisition->ascent, + requisition->descent); + + if (child->getStyle()->width != core::style::LENGTH_AUTO) { + calcCellSizes (false); + // The requisition is always the width of the column; the table + // widget is special in inforcing this, based on extremes, which + // may again be corrected again by CSS attributes. + requisition->width = calcAvailWidthForDescendant (child); } + + correctReqHeightOfChild (child, requisition, splitHeightFun); + + DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)", + requisition->width, requisition->ascent, + requisition->descent); + DBG_OBJ_LEAVE (); } -void Table::setAscent (int ascent) +int Table::calcAvailWidthForDescendant (Widget *child) { - if (availAscent != ascent) { - availAscent = ascent; - queueResize (0, false); + DBG_OBJ_ENTER ("resize", 0, "calcAvailWidthForDescendant", "%p", child); + + // "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?) + int width = -1; + for (int row = numRows - 1; width == -1 && row >= 0; row--) { + for (int col = 0; width == -1 && col < numCols; col++) { + int n = row * numCols + col; + if (childDefined (n) && + children->get(n)->cell.widget == actualChild) { + DBG_OBJ_MSGF ("resize", 1, "calculated from column %d", col); + width = (children->get(n)->cell.colspanEff - 1) + * getStyle()->hBorderSpacing; + for (int i = 0; i < children->get(n)->cell.colspanEff; i++) + width += colWidths->get (col + i); + width = misc::max (width, 0); + } + } } + + assert (width != -1); + + DBG_OBJ_MSGF ("resize", 1, "=> %d", width); + DBG_OBJ_LEAVE (); + return width; +} + +int Table::applyPerWidth (int containerWidth, core::style::Length perWidth) +{ + return core::style::multiplyWithPerLength (containerWidth, perWidth); } -void Table::setDescent (int descent) +int Table::applyPerHeight (int containerHeight, core::style::Length perHeight) { - if (availDescent != descent) { - availDescent = descent; - queueResize (0, false); + return core::style::multiplyWithPerLength (containerHeight, perHeight); +} + +void Table::containerSizeChangedForChildren () +{ + DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren"); + + for (int col = 0; col < numCols; col++) { + for (int row = 0; row < numRows; row++) { + int n = row * numCols + col; + if (childDefined (n)) + children->get(n)->cell.widget->containerSizeChanged (); + } } + + DBG_OBJ_LEAVE (); +} + +bool Table::affectsSizeChangeContainerChild (core::Widget *child) +{ + DBG_OBJ_ENTER ("resize", 0, "affectsSizeChangeContainerChild", "%p", child); + + bool ret; + + // This is a bit more complicated, as compared to the standard + // implementation (Widget::affectsSizeChangeContainerChild). + // Height would handled the same way, but width is more + // complicated: we would have to track numerous values here. Always + // returning true is correct in all cases, but generally + // inefficient. + + // TODO Better solution? + + ret = true; + + DBG_OBJ_MSGF ("resize", 1, "=> %s", ret ? "true" : "false"); + DBG_OBJ_LEAVE (); + return ret; +} + +bool Table::usesAvailWidth () +{ + return true; +} + +bool Table::isBlockLevel () +{ + return true; } void Table::draw (core::View *view, core::Rectangle *area) @@ -272,6 +389,9 @@ core::Iterator *Table::iterator (core::Content::Type mask, bool atEnd) void Table::addCell (Widget *widget, int colspan, int rowspan) { + DBG_OBJ_ENTER ("resize", 0, "addCell", "%p, %d, %d", + widget, colspan, rowspan); + const int maxspan = 100; Child *child; int colspanEff; @@ -373,6 +493,8 @@ void Table::addCell (Widget *widget, int colspan, int rowspan) } MSG("\n"); #endif + + DBG_OBJ_LEAVE (); } void Table::addRow (core::style::Style *style) @@ -393,7 +515,7 @@ void Table::addRow (core::style::Style *style) rowClosed = false; } -TableCell *Table::getCellRef () +AlignedTableCell *Table::getCellRef () { core::Widget *child; @@ -401,14 +523,93 @@ TableCell *Table::getCellRef () int n = curCol + row * numCols; if (childDefined (n)) { child = children->get(n)->cell.widget; - if (child->instanceOf (TableCell::CLASS_ID)) - return (TableCell*)child; + if (child->instanceOf (AlignedTableCell::CLASS_ID)) + return (AlignedTableCell*)child; } } return NULL; } +const char *Table::getExtrModName (ExtrMod mod) +{ + switch (mod) { + case MIN: + return "MIN"; + + case MIN_INTR: + return "MIN_INTR"; + + case MIN_MIN: + return "MIN_MIN"; + + case MAX_MIN: + return "MAX_MIN"; + + case MAX: + return "MAX"; + + case MAX_INTR: + return "MAX_INTR"; + + default: + misc::assertNotReached (); + return NULL; + } +} + +int Table::getExtreme (core::Extremes *extremes, ExtrMod mod) +{ + switch (mod) { + case MIN: + return extremes->minWidth; + + case MIN_INTR: + return extremes->minWidthIntrinsic; + + case MIN_MIN: + return misc::min (extremes->minWidth, extremes->minWidthIntrinsic); + + case MAX_MIN: + return misc::max (extremes->minWidth, extremes->minWidthIntrinsic); + + case MAX: + return extremes->maxWidth; + + case MAX_INTR: + return extremes->maxWidthIntrinsic; + + default: + misc::assertNotReached (); return 0; + } +} + +void Table::setExtreme (core::Extremes *extremes, ExtrMod mod, int value) +{ + switch (mod) { + case MIN: + extremes->minWidth = value; + break; + + case MIN_INTR: + extremes->minWidthIntrinsic = value; + break; + + // MIN_MIN and MAX_MIN not supported here. + + case MAX: + extremes->maxWidth = value; + break; + + case MAX_INTR: + extremes->maxWidthIntrinsic = value; + break; + + default: + misc::assertNotReached (); + } +} + void Table::reallocChildren (int newNumCols, int newNumRows) { assert (newNumCols >= numCols); @@ -476,107 +677,171 @@ void Table::reallocChildren (int newNumCols, int newNumRows) numCols = newNumCols; numRows = newNumRows; + + DBG_OBJ_SET_NUM ("numCols", numCols); + DBG_OBJ_SET_NUM ("numRows", numCols); } // ---------------------------------------------------------------------- -void Table::calcCellSizes () +void Table::calcCellSizes (bool calcHeights) { - if (needsResize () || resizeQueued ()) - forceCalcCellSizes (); + DBG_OBJ_ENTER ("resize", 0, "calcCellSizes", "%s", + calcHeights ? "true" : "false"); + + bool sizeChanged = needsResize () || resizeQueued (); + bool extremesChanges = extremesChanged () || extremesQueued (); + + if (calcHeights ? (extremesChanges || sizeChanged) : + (extremesChanges || !colWidthsUpToDateWidthColExtremes)) + forceCalcCellSizes (calcHeights); + + DBG_OBJ_LEAVE (); } -void Table::forceCalcCellSizes () +void Table::forceCalcCellSizes (bool calcHeights) { - int totalWidth = 0, childHeight, forceTotalWidth = 1; + DBG_OBJ_ENTER0 ("resize", 0, "forceCalcCellSizes"); + + int childHeight; core::Extremes extremes; // Will also call calcColumnExtremes(), when needed. getExtremes (&extremes); - if (core::style::isAbsLength (getStyle()->width)) { - totalWidth = core::style::absLengthVal (getStyle()->width); - } else if (core::style::isPerLength (getStyle()->width)) { - /* - * If the width is > 100%, we use 100%, this prevents ugly - * results. (May be changed in future, when a more powerful - * rendering is implemented, to handle fixed positions etc., - * as defined by CSS2.) - */ - totalWidth = - misc::min (core::style::multiplyWithPerLength (availWidth, - getStyle()->width), - availWidth); - } else if (getStyle()->width == core::style::LENGTH_AUTO) { - totalWidth = availWidth; - forceTotalWidth = 0; - } - - _MSG(" availWidth = %d\n", availWidth); - _MSG(" totalWidth1 = %d\n", totalWidth); - - if (totalWidth < extremes.minWidth) - totalWidth = extremes.minWidth; - totalWidth = totalWidth - - (numCols + 1) * getStyle()->hBorderSpacing - - getStyle()->boxDiffWidth (); - - _MSG(" totalWidth2 = %d curCol=%d\n", totalWidth,curCol); + int availWidth = getAvailWidth (true); + int totalWidth = availWidth - + ((numCols + 1) * getStyle()->hBorderSpacing + boxDiffWidth ()); + DBG_OBJ_MSGF ("resize", 1, + "totalWidth = %d - ((%d - 1) * %d + %d) = <b>%d</b>", + availWidth, numCols, getStyle()->hBorderSpacing, + boxDiffWidth (), totalWidth); colWidths->setSize (numCols, 0); cumHeight->setSize (numRows + 1, 0); rowSpanCells->setSize (0); baseline->setSize (numRows); - _MSG(" extremes = %d,%d\n", extremes.minWidth, extremes.maxWidth); - _MSG(" getStyle()->boxDiffWidth() = %d\n", getStyle()->boxDiffWidth()); - _MSG(" getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing); + misc::SimpleVector<int> *oldColWidths = colWidths; + colWidths = new misc::SimpleVector <int> (8); + int minWidth = 0; + for (int col = 0; col < colExtremes->size(); col++) + minWidth += getColExtreme (col, MIN); + + DBG_OBJ_MSGF ("resize", 1, "minWidth (= %d) > totalWidth (= %d)?", + minWidth, totalWidth); + + if (minWidth > totalWidth) + // The sum of all column minima is larger than the available + // width, so we narrow the columns (see also CSS2 spec, + // section 17.5, #6). We use a similar apportioning, but not + // bases on minimal and maximal widths, but on intrinsic minimal + // widths and corrected minimal widths. This way, intrinsic + // extremes are preferred (so avoiding columns too narrow for + // the actual contents), at the expenses of corrected ones + // (which means that sometimes CSS values are handled + // incorrectly). + + apportion2 (totalWidth, 0, colExtremes->size() - 1, MIN_MIN, MAX_MIN, + colWidths, 0); + else { + // Normal apportioning. + int width; + if (getStyle()->width == core::style::LENGTH_AUTO) { + // Do not force width, when maximal width is smaller. + int maxWidth = 0; + for (int col = 0; col < colExtremes->size(); col++) + maxWidth += getColExtreme (col, MAX); + width = misc::min (totalWidth, maxWidth); + DBG_OBJ_MSGF ("resize", 1, "width = min (%d, %d) = %d", + totalWidth, maxWidth, width); + } else + // CSS 'width' defined: force this width. + width = totalWidth; - apportion_percentages2 (totalWidth, forceTotalWidth); - if (!hasColPercent) - apportion2 (totalWidth, forceTotalWidth); + apportion2 (width, 0, colExtremes->size() - 1, MIN, MAX, colWidths, 0); + } - setCumHeight (0, 0); - for (int row = 0; row < numRows; row++) { - /** - * \bug dw::Table::baseline is not filled. - */ - int rowHeight = 0; + // TODO: Adapted from old inline function "setColWidth". But (i) is + // this anyway correct (col width is is not x)? And does the + // performance gain actually play a role? + for (int col = 0; col < colExtremes->size(); col++) { + if (colWidths->get (col) != oldColWidths->get (col)) + redrawX = lout::misc::min (redrawX, colWidths->get (col)); + } + + DBG_IF_RTFL { + DBG_OBJ_SET_NUM ("colWidths.size", colWidths->size ()); + for (int i = 0; i < colWidths->size (); i++) + DBG_OBJ_ARRSET_NUM ("colWidths", i, colWidths->get (i)); + } - for (int col = 0; col < numCols; col++) { - int n = row * numCols + col; - if (childDefined (n)) { - int width = (children->get(n)->cell.colspanEff - 1) - * getStyle()->hBorderSpacing; - for (int i = 0; i < children->get(n)->cell.colspanEff; i++) - width += colWidths->get (col + i); + colWidthsUpToDateWidthColExtremes = true; + DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes", + colWidthsUpToDateWidthColExtremes); - core::Requisition childRequisition; - children->get(n)->cell.widget->setWidth (width); - children->get(n)->cell.widget->sizeRequest (&childRequisition); - childHeight = childRequisition.ascent + childRequisition.descent; - if (children->get(n)->cell.rowspan == 1) { - rowHeight = misc::max (rowHeight, childHeight); - } else { - rowSpanCells->increase(); - rowSpanCells->set(rowSpanCells->size()-1, n); - } + for (int col = 0; col < numCols; col++) { + if (col >= oldColWidths->size () || col >= colWidths->size () || + oldColWidths->get (col) != colWidths->get (col)) { + // Column width has changed, tell children about this. + for (int row = 0; row < numRows; row++) { + int n = row * numCols + col; + // TODO: Columns spanning several rows are only regarded + // when the first column is affected. + if (childDefined (n)) + children->get(n)->cell.widget->containerSizeChanged (); } - }/*for col*/ + } + } + + delete oldColWidths; - setCumHeight (row + 1, - cumHeight->get (row) + rowHeight + getStyle()->vBorderSpacing); + if (calcHeights) { + setCumHeight (0, 0); + for (int row = 0; row < numRows; row++) { + /** + * \bug dw::Table::baseline is not filled. + */ + int rowHeight = 0; + + for (int col = 0; col < numCols; col++) { + int n = row * numCols + col; + if (childDefined (n)) { + int width = (children->get(n)->cell.colspanEff - 1) + * getStyle()->hBorderSpacing; + for (int i = 0; i < children->get(n)->cell.colspanEff; i++) + width += colWidths->get (col + i); + + core::Requisition childRequisition; + //children->get(n)->cell.widget->setWidth (width); + children->get(n)->cell.widget->sizeRequest (&childRequisition); + childHeight = childRequisition.ascent + childRequisition.descent; + if (children->get(n)->cell.rowspan == 1) { + rowHeight = misc::max (rowHeight, childHeight); + } else { + rowSpanCells->increase(); + rowSpanCells->set(rowSpanCells->size()-1, n); + } + } + } // for col + + setCumHeight (row + 1, + cumHeight->get (row) + rowHeight + getStyle()->vBorderSpacing); + } // for row - }/*for row*/ + apportionRowSpan (); + } - apportionRowSpan (); + DBG_OBJ_LEAVE (); } void Table::apportionRowSpan () { + DBG_OBJ_ENTER0 ("resize", 0, "apportionRowSpan"); + int *rowHeight = NULL; for (int c = 0; c < rowSpanCells->size(); ++c) { @@ -630,6 +895,8 @@ void Table::apportionRowSpan () setCumHeight (i+1, cumHeight->get(i) + rowHeight[i]); } delete[] rowHeight; + + DBG_OBJ_LEAVE (); } @@ -640,8 +907,12 @@ void Table::apportionRowSpan () */ void Table::calcColumnExtremes () { + DBG_OBJ_ENTER0 ("resize", 0, "calcColumnExtremes"); + if (extremesChanged () || extremesQueued ()) forceCalcColumnExtremes (); + + DBG_OBJ_LEAVE (); } @@ -650,570 +921,282 @@ void Table::calcColumnExtremes () */ void Table::forceCalcColumnExtremes () { - _MSG(" Table::forceCalcColumnExtremes numCols=%d\n", numCols); - - if (numCols == 0) - return; + DBG_OBJ_ENTER0 ("resize", 0, "forceCalcColumnExtremes"); - colExtremes->setSize (numCols); - colPercents->setSize (numCols); - colSpanCells->setSize (0); - /* 1. cells with colspan = 1 */ - for (int col = 0; col < numCols; col++) { - colExtremes->getRef(col)->minWidth = 0; - colExtremes->getRef(col)->maxWidth = 0; - colPercents->set(col, core::style::LENGTH_AUTO); + if (numCols > 0) { + lout::misc::SimpleVector<int> colSpanCells (8); + colExtremes->setSize (numCols); - for (int row = 0; row < numRows; row++) { - int n = row * numCols + col; - if (!childDefined (n)) - continue; - if (children->get(n)->cell.colspanEff == 1) { - core::Extremes cellExtremes; - int cellMinW, cellMaxW, pbm; - core::style::Length width = - children->get(n)->cell.widget->getStyle()->width; - pbm = (numCols + 1) * getStyle()->hBorderSpacing - + children->get(n)->cell.widget->getStyle()->boxDiffWidth (); - children->get(n)->cell.widget->getExtremes (&cellExtremes); - if (core::style::isAbsLength (width)) { - // Fixed lengths include table padding, border and margin. - cellMinW = cellExtremes.minWidth; - cellMaxW = misc::max (cellMinW, - core::style::absLengthVal(width) - pbm); - } else { - cellMinW = cellExtremes.minWidth; - cellMaxW = cellExtremes.maxWidth; + // 1. cells with colspan = 1 + for (int col = 0; col < numCols; col++) { + DBG_OBJ_MSGF ("resize", 1, "column %d", col); + DBG_OBJ_MSG_START (); + + colExtremes->getRef(col)->minWidth = 0; + colExtremes->getRef(col)->minWidthIntrinsic = 0; + colExtremes->getRef(col)->maxWidth = 0; + colExtremes->getRef(col)->maxWidthIntrinsic = 0; + + for (int row = 0; row < numRows; row++) { + DBG_OBJ_MSGF ("resize", 1, "row %d", row); + DBG_OBJ_MSG_START (); + + int n = row * numCols + col; + + if (childDefined (n)) { + if (children->get(n)->cell.colspanEff == 1) { + core::Extremes cellExtremes; + children->get(n)->cell.widget->getExtremes (&cellExtremes); + + DBG_OBJ_MSGF ("resize", 1, "child: %d / %d", + cellExtremes.minWidth, cellExtremes.maxWidth); + + colExtremes->getRef(col)->minWidthIntrinsic = + misc::max (colExtremes->getRef(col)->minWidthIntrinsic, + cellExtremes.minWidthIntrinsic); + colExtremes->getRef(col)->maxWidthIntrinsic = + misc::max (colExtremes->getRef(col)->minWidthIntrinsic, + colExtremes->getRef(col)->maxWidthIntrinsic, + cellExtremes.maxWidthIntrinsic); + + colExtremes->getRef(col)->minWidth = + misc::max (colExtremes->getRef(col)->minWidth, + cellExtremes.minWidth); + colExtremes->getRef(col)->maxWidth = + misc::max (colExtremes->getRef(col)->minWidth, + colExtremes->getRef(col)->maxWidth, + cellExtremes.maxWidth); + + DBG_OBJ_MSGF ("resize", 1, "column: %d / %d (%d / %d)", + colExtremes->getRef(col)->minWidth, + colExtremes->getRef(col)->maxWidth, + colExtremes->getRef(col)->minWidthIntrinsic, + colExtremes->getRef(col)->maxWidthIntrinsic); + } else { + colSpanCells.increase (); + colSpanCells.setLast (n); + } } - _MSG("FCCE, col%d colMin,colMax,cellMin,cellMax = %d,%d,%d,%d\n", - col, - colExtremes->getRef(col)->minWidth, - colExtremes->getRef(col)->maxWidth, - cellMinW, cellMaxW); - - colExtremes->getRef(col)->minWidth = - misc::max (colExtremes->getRef(col)->minWidth, cellMinW); - colExtremes->getRef(col)->maxWidth = - misc::max (colExtremes->getRef(col)->minWidth, misc::max ( - colExtremes->getRef(col)->maxWidth, - cellMaxW)); - - // Also fill the colPercents array in this pass - if (core::style::isPerLength (width)) { - hasColPercent = 1; - if (colPercents->get(col) == core::style::LENGTH_AUTO) - colPercents->set(col, width); - } else if (core::style::isAbsLength (width)) { - // We treat LEN_ABS as a special case of LEN_AUTO. - /* - * if (colPercents->get(col) == LEN_AUTO) - * colPercents->set(col, LEN_ABS); - * - * (Hint: that's old code!) - */ - } - } else { - colSpanCells->increase(); - colSpanCells->set(colSpanCells->size()-1, n); + DBG_OBJ_MSG_END (); } - } - } - /* 2. cells with colspan > 1 */ - /* If needed, here we set proportionally apportioned col maximums */ - for (int c = 0; c < colSpanCells->size(); ++c) { - core::Extremes cellExtremes; - int cellMinW, cellMaxW, pbm; - int n = colSpanCells->get(c); - int col = n % numCols; - int cs = children->get(n)->cell.colspanEff; - core::style::Length width = - children->get(n)->cell.widget->getStyle()->width; - pbm = (numCols + 1) * getStyle()->hBorderSpacing - + children->get(n)->cell.widget->getStyle()->boxDiffWidth (); - children->get(n)->cell.widget->getExtremes (&cellExtremes); - if (core::style::isAbsLength (width)) { - // Fixed lengths include table padding, border and margin. - cellMinW = cellExtremes.minWidth; - cellMaxW = - misc::max (cellMinW, core::style::absLengthVal(width) - pbm); - } else { - cellMinW = cellExtremes.minWidth; - cellMaxW = cellExtremes.maxWidth; + DBG_OBJ_MSG_END (); } - int minSumCols = 0, maxSumCols = 0; - for (int i = 0; i < cs; ++i) { - minSumCols += colExtremes->getRef(col+i)->minWidth; - maxSumCols += colExtremes->getRef(col+i)->maxWidth; - } - - _MSG("cs=%d spanWidth=%d,%d sumCols=%d,%d\n", - cs,cellMinW,cellMaxW,minSumCols,maxSumCols); - if (minSumCols >= cellMinW && maxSumCols >= cellMaxW) - continue; + // 2. cells with colspan > 1 - // 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; - } - } - - // 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; - } - } + // TODO: Is this old comment still relevant? "If needed, here we + // set proportionally apportioned col maximums." - 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; + for (int i = 0; i < colSpanCells.size(); i++) { + int n = colSpanCells.get (i); + int col = n % numCols; + int cs = children->get(n)->cell.colspanEff; - _MSG("i=%d, wMin=%d wMax=%d cumMaxWold=%d\n", - i,wMin,wMax,cumMaxWold); + core::Extremes cellExtremes; + children->get(n)->cell.widget->getExtremes (&cellExtremes); + calcExtremesSpanMulteCols (col, cs, &cellExtremes, MIN, MAX); + calcExtremesSpanMulteCols (col, cs, &cellExtremes, MIN_INTR, MAX_INTR); } -#ifdef DBG - MSG("col min,max: ["); - for (int i = 0; i < numCols; i++) - MSG("%d,%d ", - colExtremes->getRef(i)->minWidth, - colExtremes->getRef(i)->maxWidth); - MSG("]\n"); - MSG("getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing); -#endif } -} -/** - * \brief Apportionment function for AUTO-length columns. - * 'extremes' comes filled, 'result' comes defined for percentage columns. - */ -void Table::apportion2 (int totalWidth, int forceTotalWidth) -{ - if (colExtremes->size() == 0) - return; -#ifdef DBG - MSG("app2, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n", - availWidth, totalWidth, forceTotalWidth); - MSG("app2, extremes: ( "); - for (int i = 0; i < colExtremes->size (); i++) - MSG("%d,%d ", - colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth); - MSG(")\n"); -#endif - int minAutoWidth = 0, maxAutoWidth = 0, availAutoWidth = totalWidth; - for (int col = 0; col < numCols; col++) { - if (core::style::isAbsLength (colPercents->get(col))) { - // set absolute lengths - setColWidth (col, colExtremes->get(col).minWidth); + DBG_IF_RTFL { + DBG_OBJ_SET_NUM ("colExtremes.size", colExtremes->size ()); + for (int i = 0; i < colExtremes->size (); i++) { + DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "minWidth", + colExtremes->get(i).minWidth); + DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "minWidthIntrinsic", + colExtremes->get(i).minWidthIntrinsic); + DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "maxWidth", + colExtremes->get(i).maxWidth); + DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "maxWidthIntrinsic", + colExtremes->get(i).maxWidthIntrinsic); } - if (colPercents->get(col) == core::style::LENGTH_AUTO) { - maxAutoWidth += colExtremes->get(col).maxWidth; - minAutoWidth += colExtremes->get(col).minWidth; - } else - availAutoWidth -= colWidths->get(col); - } - - if (!maxAutoWidth) // no core::style::LENGTH_AUTO cols! - return; - - colWidths->setSize (colExtremes->size (), 0); - - 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); + colWidthsUpToDateWidthColExtremes = false; + DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes", + colWidthsUpToDateWidthColExtremes); - 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_LEAVE (); } -void Table::apportion_percentages2(int totalWidth, int forceTotalWidth) +void Table::calcExtremesSpanMulteCols (int col, int cs, + core::Extremes *cellExtremes, + ExtrMod minExtrMod, ExtrMod maxExtrMod) { - int hasTablePercent = core::style::isPerLength (getStyle()->width) ? 1 : 0; - - if (colExtremes->size() == 0 || (!hasTablePercent && !hasColPercent)) - return; - - // If there's a table-wide percentage, totalWidth comes already scaled. - _MSG("APP_P, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n", - availWidth, totalWidth, forceTotalWidth); + DBG_OBJ_ENTER ("resize", 0, "calcExtremesSpanMulteCols", + "%d, %d, ..., %s, %s", + col, cs, getExtrModName (minExtrMod), + getExtrModName (maxExtrMod)); + + int cellMin = getExtreme (cellExtremes, minExtrMod); + int cellMax = getExtreme (cellExtremes, maxExtrMod); + + int minSumCols = 0, maxSumCols = 0; + + for (int j = 0; j < cs; j++) { + minSumCols += getColExtreme (col + j, minExtrMod); + maxSumCols += getColExtreme (col + j, maxExtrMod); + } - if (!hasColPercent) { -#ifdef DBG - MSG("APP_P, only a table-wide percentage\n"); - MSG("APP_P, extremes = { "); - for (int col = 0; col < numCols; col++) - MSG("%d,%d ", colExtremes->getRef(col)->minWidth, - colExtremes->getRef(col)->maxWidth); - MSG("}\n"); -#endif - // It has only a table-wide percentage. Apportion non-absolute widths. - int sumMaxWidth = 0, perAvailWidth = totalWidth; - for (int col = 0; col < numCols; col++) { - if (core::style::isAbsLength (colPercents->get(col))) - perAvailWidth -= colExtremes->getRef(col)->maxWidth; - else - sumMaxWidth += colExtremes->getRef(col)->maxWidth; + DBG_OBJ_MSGF ("resize", 1, "cs = %d, cell: %d / %d, sum: %d / %d\n", + cs, cellMin, cellMax, minSumCols, maxSumCols); + + bool changeMin = cellMin > minSumCols; + bool changeMax = cellMax > maxSumCols; + if (changeMin || changeMax) { + // TODO This differs from the documentation? Should work, anyway. + misc::SimpleVector<int> newMin, newMax; + if (changeMin) + apportion2 (cellMin, col, col + cs - 1, MIN, MAX, &newMin, 0); + if (changeMax) + apportion2 (cellMax, col, col + cs - 1, MIN, MAX, &newMax, 0); + + for (int j = 0; j < cs; j++) { + if (changeMin) + setColExtreme (col + j, minExtrMod, newMin.get (j)); + if (changeMax) + setColExtreme (col + j, maxExtrMod, newMax.get (j)); + + // For cases where min and max are somewhat confused: + setColExtreme (col + j, maxExtrMod, + misc::max (getColExtreme (col + j, minExtrMod), + getColExtreme (col + j, maxExtrMod))); } + } - _MSG("APP_P, perAvailWidth=%d, sumMaxWidth=%d\n", - perAvailWidth, sumMaxWidth); - - for (int col = 0; col < numCols; col++) { - int max_wi = colExtremes->getRef(col)->maxWidth, new_wi; - if (!core::style::isAbsLength (colPercents->get(col))) { - new_wi = - misc::max (colExtremes->getRef(col)->minWidth, - (int)((float)max_wi * perAvailWidth/sumMaxWidth)); - setColWidth (col, new_wi); - perAvailWidth -= new_wi; - sumMaxWidth -= max_wi; - } - } -#ifdef DBG - MSG("APP_P, result = { "); - for (int col = 0; col < numCols; col++) - MSG("%d ", colWidths->get(col)); - MSG("}\n"); -#endif + DBG_OBJ_LEAVE (); +} - } else { - // we'll have to apportion... - _MSG("APP_P, we'll have to apportion...\n"); +/** + * \brief Actual apportionment function. + */ +void Table::apportion2 (int totalWidth, int firstCol, int lastCol, + ExtrMod minExtrMod, ExtrMod maxExtrMod, + misc::SimpleVector<int> *dest, int destOffset) +{ + DBG_OBJ_ENTER ("resize", 0, "apportion2", "%d, %d, %d, %s, %s, ..., %d", + totalWidth, firstCol, lastCol, getExtrModName (minExtrMod), + getExtrModName (maxExtrMod), destOffset); - // 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; + if (lastCol >= firstCol) { + dest->setSize (destOffset + lastCol - firstCol + 1, 0); - _MSG("APP_P, col %d minWidth=%d maxWidth=%d\n", col, - colExtremes->getRef(col)->minWidth, - colExtremes->getRef(col)->maxWidth); + int totalMin = 0, totalMax = 0; + for (int col = firstCol; col <= lastCol; col++) { + totalMin += getColExtreme (col, minExtrMod); + totalMax += getColExtreme (col, maxExtrMod); } - int oldTotalWidth = totalWidth; - if (!forceTotalWidth) { - if (sumMaxNonPer == 0 || cumPercent < 0.99f) { - // only percentage columns, or cumPercent < 100% => restrict width - int totW = (int)(sumMaxNonPer / (1.0f - cumPercent)); - for (int col = 0; col < numCols; col++) { - totW = misc::max - (totW, - (int)(colExtremes->getRef(col)->maxWidth - / core::style::perLengthVal (colPercents->get(col)))); - } - totalWidth = misc::min (totW, totalWidth); + + DBG_OBJ_MSGF ("resize", 1, + "totalWidth = %d, totalMin = %d, totalMax = %d", + totalWidth, totalMin, totalMax); + + // The actual calculation is rather simple, the ith value is: + // + // + // (max[i] - min[i]) * (totalMax - totalMin) + // width[i] = totalMin + ----------------------------------------- + // (totalWidth - totalMin) + // + // (Regard "total" as "sum".) With the following general + // definitions (for both the list and sums): + // + // diffExtr = max - min + // diffWidth = width - min + // + // it is simplified to: + // + // diffExtr[i] * totalDiffWidth + // diffWidth[i] = ---------------------------- + // totalDiffExtr + // + // Of course, if totalDiffExtr is 0, this is not defined; + // instead, we apportion according to the minima: + // + // min[i] * totalWidth + // width[i] = ------------------- + // totalMin + // + // Since min[i] <= max[i] for all i, totalMin == totalMax + // implies that min[i] == max[i] for all i. + // + // Third, it totalMin == 0 (which also implies min[i] = max[i] = 0), + // the result is + // + // width[i] = totalWidth / n + + int totalDiffExtr = totalMax - totalMin; + if (totalDiffExtr != 0) { + // Normal case. The algorithm described in + // "rounding-errors.doc" is used, with: + // + // x[i] = diffExtr[i] + // y[i] = diffWidth[i] + // a = totalDiffWidth + // b = totalDiffExtr + + DBG_OBJ_MSG ("resize", 1, "normal case"); + + int totalDiffWidth = totalWidth - totalMin; + int cumDiffExtr = 0, cumDiffWidth = 0; + + for (int col = firstCol; col <= lastCol; col++) { + int min = getColExtreme (col, minExtrMod); + int max = getColExtreme (col, maxExtrMod); + int diffExtr = max - min; + + cumDiffExtr += diffExtr; + int diffWidth = + (cumDiffExtr * totalDiffWidth) / totalDiffExtr - cumDiffWidth; + cumDiffWidth += diffWidth; + + dest->set (destOffset - firstCol + col, diffWidth + min); } - } - - // make sure there's enough space - totalWidth = misc::max (totalWidth, sumMinWidth); - // extraWidth is always >= 0 - int extraWidth = totalWidth - sumMinWidth; - int sumMinWidthPer = sumMinWidth - sumMinNonPer; - int curPerWidth = sumMinWidthPer; - // percentages refer to workingWidth - int workingWidth = totalWidth - sumMinNonPer; - if (cumPercent < 0.99f) { - // In this case, use the whole table width - workingWidth = totalWidth; - curPerWidth = sumMinWidth; - } - - _MSG("APP_P, oldTotalWidth=%d totalWidth=%d" - " workingWidth=%d extraWidth=%d sumMinNonPer=%d\n", - oldTotalWidth,totalWidth,workingWidth,extraWidth,sumMinNonPer); - - for (int col = 0; col < numCols; col++) { - int colMinWidth = colExtremes->getRef(col)->minWidth; - if (core::style::isPerLength (colPercents->get(col))) { - int w = core::style::multiplyWithPerLength (workingWidth, - colPercents->get(col)); - if (w < colMinWidth) - w = colMinWidth; - else if (curPerWidth - colMinWidth + w > workingWidth) - w = colMinWidth + extraWidth; - extraWidth -= (w - colMinWidth); - curPerWidth += (w - colMinWidth); - setColWidth (col, w); - } else { - setColWidth (col, colMinWidth); + } else if (totalMin != 0) { + // Special case. Again, same algorithm, with + // + // x[i] = min[i] + // y[i] = width[i] + // a = totalWidth + // b = totalMin + + DBG_OBJ_MSG ("resize", 1, "special case 1"); + + int cumMin = 0, cumWidth = 0; + for (int col = firstCol; col <= lastCol; col++) { + int min = getColExtreme (col, minExtrMod); + cumMin += min; + int width = (cumMin * totalWidth) / totalMin - cumWidth; + cumWidth += width; + + dest->set (destOffset - firstCol + col, width); } - } - - if (cumPercent < 0.99f) { - // Will have to apportion the other columns -#ifdef DBG - MSG("APP_P, extremes: ( "); - for (int i = 0; i < colExtremes->size (); i++) - MSG("%d,%d ", - colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth); - MSG(")\n"); -#endif - curPerWidth -= sumMinNonPer; - int perWidth = (int)(curPerWidth/cumPercent); - totalWidth = misc::max (totalWidth, perWidth); - totalWidth = misc::min (totalWidth, oldTotalWidth); - - _MSG("APP_P, curPerWidth=%d perWidth=%d, totalWidth=%d\n", - curPerWidth, perWidth, totalWidth); - - if (hasAutoCol == 0) { - // Special case, cumPercent < 100% and no other columns to expand. - // We'll honor totalWidth by expanding the percentage cols. - int extraWidth = totalWidth - curPerWidth - sumMinNonPer; - for (int col = 0; col < numCols; col++) { - if (core::style::isPerLength (colPercents->get(col))) { - // This could cause rounding errors: - // - // int d = - // core::dw::multiplyWithPerLength (extraWidth, - // colPercents->get(col)) - // / cumPercent; - // - // Thus the "old" way: - int d = - (int)(extraWidth * - core::style::perLengthVal (colPercents->get(col)) - / cumPercent); - setColWidth (col, colWidths->get(col) + d); - } - } + } else { // if (totalMin == 0) + // Last special case. Ssame algorithm, with + // + // x[i] = 1 (so cumX = i = col - firstCol + 1) + // y[i] = width[i] + // a = totalWidth + // b = n = lastCol - firstCol + 1 + + DBG_OBJ_MSG ("resize", 1, "special case 2"); + + int cumWidth = 0, n = (lastCol - firstCol + 1); + for (int col = firstCol; col <= lastCol; col++) { + int i = (col - firstCol + 1); + int width = (i * totalWidth) / n - cumWidth; + cumWidth += width; + + dest->set (destOffset - firstCol + col, width); } } -#ifdef DBG - MSG("APP_P, result ={ "); - for (int col = 0; col < numCols; col++) - MSG("%d ", colWidths->get(col)); - MSG("}\n"); -#endif - apportion2 (totalWidth, 2); - -#ifdef DBG - MSG("APP_P, percent={"); - for (int col = 0; col < numCols; col++) - MSG("%f ", core::dw::perLengthVal (colPercents->get(col))); - MSG("}\n"); - MSG("APP_P, result ={ "); - for (int col = 0; col < numCols; col++) - MSG("%d ", colWidths->get(col)); - MSG("}\n"); -#endif - } -} - -// ---------------------------------------------------------------------- - -Table::TableIterator::TableIterator (Table *table, - core::Content::Type mask, bool atEnd): - core::Iterator (table, mask, atEnd) -{ - index = atEnd ? table->children->size () : -1; - content.type = atEnd ? core::Content::END : core::Content::START; -} - -Table::TableIterator::TableIterator (Table *table, - core::Content::Type mask, int index): - core::Iterator (table, mask, false) -{ - this->index = index; - - if (index < 0) - content.type = core::Content::START; - else if (index >= table->children->size ()) - content.type = core::Content::END; - else { - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - } -} - -object::Object *Table::TableIterator::clone() -{ - return new TableIterator ((Table*)getWidget(), getMask(), index); -} - -int Table::TableIterator::compareTo(object::Comparable *other) -{ - return index - ((TableIterator*)other)->index; -} - -bool Table::TableIterator::next () -{ - Table *table = (Table*)getWidget(); - - if (content.type == core::Content::END) - return false; - - // tables only contain widgets (in flow): - if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) { - content.type = core::Content::END; - return false; - } - - do { - index++; - if (index >= table->children->size ()) { - content.type = core::Content::END; - return false; - } - } while (table->children->get(index) == NULL || - table->children->get(index)->type != Child::CELL); - - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - return true; -} - -bool Table::TableIterator::prev () -{ - Table *table = (Table*)getWidget(); - - if (content.type == core::Content::START) - return false; - - // tables only contain widgets (in flow): - if ((getMask() & core::Content::WIDGET_IN_FLOW) == 0) { - content.type = core::Content::START; - return false; } - - do { - index--; - if (index < 0) { - content.type = core::Content::START; - return false; - } - } while (table->children->get(index) == NULL || - table->children->get(index)->type != Child::CELL); - - content.type = core::Content::WIDGET_IN_FLOW; - content.widget = table->children->get(index)->cell.widget; - return true; -} - -void Table::TableIterator::highlight (int start, int end, - core::HighlightLayer layer) -{ - /** todo Needs this an implementation? */ -} - -void Table::TableIterator::unhighlight (int direction, - core::HighlightLayer layer) -{ -} - -void Table::TableIterator::getAllocation (int start, int end, - core::Allocation *allocation) -{ - /** \bug Not implemented. */ + + DBG_OBJ_LEAVE (); } } // namespace dw |