diff options
-rw-r--r-- | dw/table.cc | 108 | ||||
-rw-r--r-- | dw/table.hh | 1 | ||||
-rw-r--r-- | lout/misc.hh | 16 |
3 files changed, 114 insertions, 11 deletions
diff --git a/dw/table.cc b/dw/table.cc index 432f1ae5..0493c393 100644 --- a/dw/table.cc +++ b/dw/table.cc @@ -221,14 +221,32 @@ int Table::getAvailWidthOfChild (Widget *child, bool forceValue) 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); + // We do not calculate the column widths at this point, because + // this tends to be rather inefficient for tables with many + // cells: + // + // For each of the n cells, some text is added (say, only one word + // per cell). Textblock::addText will eventually (via addText0 + // etc.) call this method, Table::getAvailWidthOfChild. If + // calcCellSizes() is called here, this will call + // forceCalcCellSizes(), since the last call, sizes have to be + // re-calculated (because cells have been added). This will + // calculate the extremes for each existing cell, so + // Widget::getExtremes is called n * (n + 1) / 2 times. Even if the + // extremes are cached (so that getExtremesImpl does not have to be + // called in each case), this would make rendering tables with more + // than a few hundred cells unacceptably slow. + // + // Instead, column widths are calculated in Table::sizeRequestImpl. + // + // An alternative would be incremental resizing for tables; this + // approach resembles the behaviour before GROWS. + + // TODO Does it still make sence to return -1 when forceValue is + // set? + if (forceValue) width = calcAvailWidthForDescendant (child); - } else + else width = -1; DBG_OBJ_MSGF ("resize", 1, "=> %d", width); @@ -702,6 +720,18 @@ void Table::reallocChildren (int newNumCols, int newNumRows) numCols = newNumCols; numRows = newNumRows; + // We initiate the column widths with a random value, to have a + // defined available width for the children before the column + // widths are actually calculated. + + colWidths->setSize (numCols, 100); + + 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)); + } + DBG_OBJ_SET_NUM ("numCols", numCols); DBG_OBJ_SET_NUM ("numRows", numCols); } @@ -726,6 +756,64 @@ void Table::calcCellSizes (bool calcHeights) void Table::forceCalcCellSizes (bool calcHeights) { + // Since Table::getAvailWidthOfChild does not calculate the column + // widths, and so initially a random value (100) is returned, a + // correction is necessary. The old values are temporary preserved + // ... + + lout::misc::SimpleVector<int> oldColWidths (8); + oldColWidths.setSize (colWidths->size ()); + colWidths->copyTo (&oldColWidths); + + actuallyCalcCellSizes (calcHeights); + + // ... and then compared to the new ones. In case of a difference, + // the cell is told about this. + + for (int col = 0; col < colWidths->size (); col++) { + if (oldColWidths.get (col) != colWidths->get (col)) { + for (int row = 0; row < numRows; row++) { + int n = row * numCols + col, col2; + Child *child = children->get(n); + if (child) { + Widget *cell; + switch (child->type) { + case Child::CELL: + cell = child->cell.widget; + break; + + case Child::SPAN_SPACE: + // TODO Are Child::spanSpace::startRow and + // Child::spanSpace::startCol not defined? + + // Search for actual cell. If not found, this means + // that a cell is spanning multiple columns *and* + // rows; in this case it has been processed before. + + cell = NULL; + for (col2 = col - 1; col2 >= 0 && cell == NULL; col2--) { + int n2 = row * numCols + col2; + Child *child2 = children->get(n2); + if (child2->type == Child::CELL) + cell = child2->cell.widget; + } + break; + + default: + misc::assertNotReached (); + cell = NULL; + } + + if (cell) + cell->containerSizeChanged (); + } + } + } + } +} + +void Table::actuallyCalcCellSizes (bool calcHeights) +{ DBG_OBJ_ENTER0 ("resize", 0, "forceCalcCellSizes"); int childHeight; @@ -747,13 +835,14 @@ void Table::forceCalcCellSizes (bool calcHeights) availWidth, corrWidth, numCols, getStyle()->hBorderSpacing, boxDiffWidth (), totalWidth); - colWidths->setSize (numCols, 0); + assert (colWidths->size () == numCols); // This is set in addCell. cumHeight->setSize (numRows + 1, 0); rowSpanCells->setSize (0); baseline->setSize (numRows); misc::SimpleVector<int> *oldColWidths = colWidths; colWidths = new misc::SimpleVector <int> (8); + colWidths->setSize (numCols); int minWidth = 0, minWidthIntrinsic = 0, maxWidth = 0; for (int col = 0; col < colExtremes->size(); col++) { @@ -824,8 +913,6 @@ void Table::forceCalcCellSizes (bool calcHeights) } else { DBG_OBJ_MSG ("resize", 1, "case 1b: treat percentages specially"); - colWidths->setSize (colExtremes->size(), 0); - // Keep track of the width which is apportioned to the rest // of the columns with percentage width (widthPartPer), and // the minimal width (intrinsic minimum) which is needed for @@ -948,7 +1035,6 @@ void Table::forceCalcCellSizes (bool calcHeights) DBG_OBJ_MSG ("resize", 1, "finally setting column widths:"); DBG_OBJ_MSG_START (); - colWidths->setSize (colExtremes->size()); indexNotSpecified = 0; for (int col = 0; col < colExtremes->size(); col++) if (colWidthSpecified->get (col)) { diff --git a/dw/table.hh b/dw/table.hh index 9ea7056f..61e93e89 100644 --- a/dw/table.hh +++ b/dw/table.hh @@ -437,6 +437,7 @@ private: void calcCellSizes (bool calcHeights); void forceCalcCellSizes (bool calcHeights); + void actuallyCalcCellSizes (bool calcHeights); void apportionRowSpan (); void _unused_calcColumnExtremes (); diff --git a/lout/misc.hh b/lout/misc.hh index b362fc2f..a0beb1b6 100644 --- a/lout/misc.hh +++ b/lout/misc.hh @@ -231,6 +231,22 @@ public: assert (this->num > 0); this->array[this->num - 1] = t; } + + /** + * \brief Copies some elements into another vector of the same + * type. + * + * Cannot be used to copy elements within one vector. (For this, + * it would have to be extended to copy backwards in some cases.) + */ + inline void copyTo(SimpleVector<T> *dest, int thisStart = 0, + int thisLast = -1, int destStart = 0) { + assert (dest != this); + if (thisLast == -1) + thisLast = this->size () - 1; + for (int i = thisStart; i <= thisLast; i++) + dest->set (i - thisStart + destStart, get (i)); + } }; /** |