Dillo v3.1.1-14-g8f67d6e0
Loading...
Searching...
No Matches
table.cc
Go to the documentation of this file.
1/*
2 * Dillo Widget
3 *
4 * Copyright 2005-2007, 2014 Sebastian Geerken <sgeerken@dillo.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20//#define DBG
21
22#include "table.hh"
23#include "../lout/msg.h"
24#include "../lout/misc.hh"
25#include "../lout/debug.hh"
26
27using namespace lout;
28
29namespace dw {
30
32int Table::CLASS_ID = -1;
33
34Table::Table(bool limitTextWidth)
35{
36 DBG_OBJ_CREATE ("dw::Table");
37 registerName ("dw::Table", &CLASS_ID);
38 setButtonSensitive(false);
39
40 this->limitTextWidth = limitTextWidth;
41
42 rowClosed = false;
43
44 numRows = 0;
45 numCols = 0;
46 curRow = -1;
47 curCol = 0;
48
49 DBG_OBJ_SET_NUM ("numCols", numCols);
50 DBG_OBJ_SET_NUM ("numRows", numCols);
51
52 children = new misc::SimpleVector <Child*> (16);
56 colWidths = new misc::SimpleVector <int> (8);
57 cumHeight = new misc::SimpleVector <int> (8);
58 rowSpanCells = new misc::SimpleVector <int> (8);
59 baseline = new misc::SimpleVector <int> (8);
60 rowStyle = new misc::SimpleVector <core::style::Style*> (8);
61
63 DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes",
65
68
69 redrawX = 0;
70 redrawY = 0;
71}
72
74{
75 for (int i = 0; i < children->size (); i++) {
76 if (children->get(i)) {
77 switch (children->get(i)->type) {
78 case Child::CELL:
79 delete children->get(i)->cell.widget;
80 break;
82 break;
83 }
84
85 delete children->get(i);
86 }
87 }
88
89 for (int i = 0; i < rowStyle->size (); i++)
90 if (rowStyle->get (i))
91 rowStyle->get(i)->unref ();
92
93 delete children;
94 delete colExtremes;
95 delete colWidthSpecified;
96 delete colWidthPercentage;
97 delete colWidths;
98 delete cumHeight;
99 delete rowSpanCells;
100 delete baseline;
101 delete rowStyle;
102
104}
105
107{
108 DBG_OBJ_ENTER0 ("resize", 0, "sizeRequestImpl");
109
110 forceCalcCellSizes (true);
111
117 for (int col = 0; col < numCols; col++)
118 requisition->width += colWidths->get (col);
119
122 requisition->descent = 0;
123
125 false);
126
127 // For the order, see similar reasoning for dw::Textblock.
129
130 DBG_OBJ_LEAVE ();
131}
132
134{
135 DBG_OBJ_ENTER0 ("resize", 0, "getExtremesImpl");
136
137 if (numCols == 0)
140 boxDiffWidth ();
141 else {
143
147 for (int col = 0; col < numCols; col++) {
148 extremes->minWidth += colExtremes->getRef(col)->minWidth;
150 colExtremes->getRef(col)->minWidthIntrinsic;
151 extremes->maxWidth += colExtremes->getRef(col)->maxWidth;
153 colExtremes->getRef(col)->maxWidthIntrinsic;
154 extremes->adjustmentWidth += colExtremes->getRef(col)->adjustmentWidth;
155 }
156 }
157
159
160 // For the order, see similar reasoning for dw::Textblock.
162
163 DBG_OBJ_LEAVE ();
164}
165
167{
168 DBG_OBJ_ENTER ("resize", 0, "sizeAllocateImpl", "%d, %d; %d * (%d + %d)",
171
173
174 calcCellSizes (true);
175
180 int offy = allocation->y + boxOffsetY () + getStyle()->vBorderSpacing;
181 int x = allocation->x + boxOffsetX () + getStyle()->hBorderSpacing;
182
183 for (int col = 0; col < numCols; col++) {
184 for (int row = 0; row < numRows; row++) {
185 int n = row * numCols + col;
186 if (childDefined (n)) {
187 int width = (children->get(n)->cell.colspanEff - 1)
189 for (int i = 0; i < children->get(n)->cell.colspanEff; i++)
190 width += colWidths->get (col + i);
191
192 core::Allocation childAllocation;
193 core::Requisition childRequisition;
194
195 children->get(n)->cell.widget->sizeRequest (&childRequisition);
196
197 childAllocation.x = x;
198 childAllocation.y = cumHeight->get (row) + offy;
199 childAllocation.width = width;
200 childAllocation.ascent = childRequisition.ascent;
201 childAllocation.descent =
202 cumHeight->get (row + children->get(n)->cell.rowspan)
204 - childRequisition.ascent;
205 children->get(n)->cell.widget->sizeAllocate (&childAllocation);
206 }
207 }
208
209 x += colWidths->get (col) + getStyle()->hBorderSpacing;
210 }
211
213
214 DBG_OBJ_LEAVE ();
215}
216
224
225int Table::getAvailWidthOfChild (Widget *child, bool forceValue)
226{
227 DBG_OBJ_ENTER ("resize", 0, "getAvailWidthOfChild", "%p, %s",
228 child, forceValue ? "true" : "false");
229
230 int width;
231 oof::OutOfFlowMgr *oofm;
232
233 if (isWidgetOOF(child) && (oofm = getWidgetOutOfFlowMgr(child)) &&
234 oofm->dealingWithSizeOfChild (child))
235 width = oofm->getAvailWidthOfChild (child, forceValue);
236 else {
237 // We do not calculate the column widths at this point, because
238 // this tends to be rather inefficient for tables with many
239 // cells:
240 //
241 // For each of the n cells, some text is added (say, only one word
242 // per cell). Textblock::addText will eventually (via addText0
243 // etc.) call this method, Table::getAvailWidthOfChild. If
244 // calcCellSizes() is called here, this will call
245 // forceCalcCellSizes(), since the last call, sizes have to be
246 // re-calculated (because cells have been added). This will
247 // calculate the extremes for each existing cell, so
248 // Widget::getExtremes is called n * (n + 1) / 2 times. Even if the
249 // extremes are cached (so that getExtremesImpl does not have to be
250 // called in each case), this would make rendering tables with more
251 // than a few hundred cells unacceptably slow.
252 //
253 // Instead, column widths are calculated in Table::sizeRequestImpl.
254 //
255 // An alternative would be incremental resizing for tables; this
256 // approach resembles the behaviour before GROWS.
257
258 // TODO Does it still make sence to return -1 when forceValue is
259 // set?
260 if (forceValue)
261 width = calcAvailWidthForDescendant (child);
262 else
263 width = -1;
264 }
265
266 DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
267 DBG_OBJ_LEAVE ();
268 return width;
269}
270
272{
273 DBG_OBJ_ENTER ("resize", 0, "calcAvailWidthForDescendant", "%p", child);
274
275 // "child" is not a direct child, but a direct descendant. Search
276 // for the actual childs.
277 Widget *actualChild = child;
278 while (actualChild != NULL && actualChild->getParent () != this)
279 actualChild = actualChild->getParent ();
280
281 assert (actualChild != NULL);
282
283 // ActualChild->parentRef contains (indirectly) the position in the
284 // children array (see addCell()), so the column can be easily
285 // determined.
286 int childNo = getParentRefInFlowSubRef (actualChild->parentRef);
287 int col = childNo % numCols;
288 DBG_OBJ_MSGF ("resize", 1, "actualChild = %p, "
289 "childNo = getParentRefInFlowSubRef (%d) = %d, "
290 "column = %d %% %d = %d",
291 actualChild, actualChild->parentRef, childNo, childNo,
292 numCols, col);
293 int colspanEff = children->get(childNo)->cell.colspanEff;
294 DBG_OBJ_MSGF ("resize", 1, "calculated from column %d, colspanEff = %d",
295 col, colspanEff);
296
297 int width = (colspanEff - 1) * getStyle()->hBorderSpacing;
298 for (int i = 0; i < colspanEff; i++)
299 width += colWidths->get (col + i);
300 width = misc::max (width, 0);
301
302 if (child != actualChild) {
303 // For table cells (direct children: child == actualChild), CSS
304 // 'width' is already regarded in the column calculation.
305 // However, for children of the table cells, CSS 'width' must be
306 // regarded here.
307
308 int corrWidth = width;
309 child->calcFinalWidth (child->getStyle(), -1, this, 0, true, &corrWidth);
310
311 // But better not exceed it ... (TODO: Only here?)
312 width = misc::min (width, corrWidth);
313 }
314
315 DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
316 DBG_OBJ_LEAVE ();
317 return width;
318}
319
320int Table::applyPerWidth (int containerWidth, core::style::Length perWidth)
321{
322 return core::style::multiplyWithPerLength (containerWidth, perWidth);
323}
324
325int Table::applyPerHeight (int containerHeight, core::style::Length perHeight)
326{
327 return core::style::multiplyWithPerLength (containerHeight, perHeight);
328}
329
331{
332 DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
333
334 for (int col = 0; col < numCols; col++) {
335 for (int row = 0; row < numRows; row++) {
336 int n = row * numCols + col;
337 if (childDefined (n))
338 children->get(n)->cell.widget->containerSizeChanged ();
339 }
340 }
341
343
344 DBG_OBJ_LEAVE ();
345}
346
348{
349 DBG_OBJ_ENTER ("resize", 0, "affectsSizeChangeContainerChild", "%p", child);
350
351 bool ret;
352
353 // This is a bit more complicated, as compared to the standard
354 // implementation (Widget::affectsSizeChangeContainerChild).
355 // Height would handled the same way, but width is more
356 // complicated: we would have to track numerous values here. Always
357 // returning true is correct in all cases, but generally
358 // inefficient.
359
360 // TODO Better solution?
361
362 ret = true;
363
364 DBG_OBJ_MSGF ("resize", 1, "=> %s", ret ? "true" : "false");
365 DBG_OBJ_LEAVE ();
366 return ret;
367}
368
370{
371 return true;
372}
373
375{
376 return true;
377}
378
379void Table::drawLevel (core::View *view, core::Rectangle *area, int level,
380 core::DrawingContext *context)
381{
382 DBG_OBJ_ENTER ("draw", 0, "Table::drawLevel", "[%d, %d, %d * %d], %s",
383 area->x, area->y, area->width, area->height,
384 stackingLevelText (level));
385
386#if 0
387 // This old code belongs perhaps to the background. Check when reactivated.
388 int offx = getStyle()->boxOffsetX () + getStyle()->hBorderSpacing;
389 int offy = getStyle()->boxOffsetY () + getStyle()->vBorderSpacing;
390 int width = getContentWidth ();
391
392 // This part seems unnecessary. It also segfaulted sometimes when
393 // cumHeight size was less than numRows. --jcid
394 for (int row = 0; row < numRows; row++) {
395 if (rowStyle->get (row))
396 drawBox (view, rowStyle->get (row), area,
397 offx, offy + cumHeight->get (row),
398 width - 2*getStyle()->hBorderSpacing,
399 cumHeight->get (row + 1) - cumHeight->get (row)
400 - getStyle()->vBorderSpacing, false);
401 }
402#endif
403
404 switch (level) {
405 case SL_IN_FLOW:
406 for (int i = 0; i < children->size (); i++) {
407 if (childDefined (i)) {
408 Widget *child = children->get(i)->cell.widget;
409 core::Rectangle childArea;
411 && child->intersects (this, area, &childArea))
412 child->draw (view, &childArea, context);
413 }
414 }
415 break;
416
417 default:
418 OOFAwareWidget::drawLevel (view, area, level, context);
419 break;
420 }
421
422 DBG_OBJ_LEAVE ();
423}
424
427 *context)
428{
429 DBG_OBJ_ENTER ("events", 0, "Table::getWidgetAtPointLevel", "%d, %d, %s",
430 x, y, stackingLevelText (level));
431
432 Widget *widgetAtPoint = NULL;
433
434 switch (level) {
435 case SL_IN_FLOW:
436 for (int i = children->size () - 1; widgetAtPoint == NULL && i >= 0;
437 i--) {
438 if (childDefined (i)) {
439 Widget *child = children->get(i)->cell.widget;
441 widgetAtPoint = child->getWidgetAtPoint (x, y, context);
442 }
443 }
444 break;
445
446 default:
447 widgetAtPoint =
448 OOFAwareWidget::getWidgetAtPointLevel (x, y, level, context);
449 break;
450 }
451
452 DBG_OBJ_MSGF ("events", 1, "=> %p", widgetAtPoint);
453 DBG_OBJ_LEAVE ();
454
455 return widgetAtPoint;
456}
457
458void Table::removeChild (Widget *child)
459{
461}
462
464{
465 return new TableIterator (this, mask, atEnd);
466}
467
468void Table::addCell (Widget *widget, int colspan, int rowspan)
469{
470 DBG_OBJ_ENTER ("resize", 0, "addCell", "%p, %d, %d",
471 widget, colspan, rowspan);
472
473 const int maxspan = 100;
474 Child *child;
475 int colspanEff;
476
477 // We limit the values for colspan and rowspan to avoid
478 // attacks by malicious web pages.
479 if (colspan > maxspan || colspan < 0) {
480 MSG_WARN("colspan = %d is set to %d.\n", colspan, maxspan);
481 colspan = maxspan;
482 }
483 if (rowspan > maxspan || rowspan <= 0) {
484 MSG_WARN("rowspan = %d is set to %d.\n", rowspan, maxspan);
485 rowspan = maxspan;
486 }
487
488 if (numRows == 0) {
489 // to prevent a crash
490 MSG("addCell: cell without row.\n");
491 addRow (NULL);
492 }
493
494 if (rowClosed) {
495 MSG_WARN("Last cell had colspan=0.\n");
496 addRow (NULL);
497 }
498
499 if (colspan == 0) {
500 colspanEff = misc::max (numCols - curCol, 1);
501 rowClosed = true;
502 } else
503 colspanEff = colspan;
504
505 // Find next free cell-
506 while (curCol < numCols &&
507 (child = children->get(curRow * numCols + curCol)) != NULL &&
508 child->type == Child::SPAN_SPACE)
509 curCol++;
510
511 _MSG("Table::addCell numCols=%d,curCol=%d,colspan=%d,colspanEff=%d\n",
512 numCols, curCol, colspan, colspanEff);
513
514 // Increase children array, when necessary.
515 if (curRow + rowspan > numRows)
516 reallocChildren (numCols, curRow + rowspan);
517 if (curCol + colspanEff > numCols)
518 reallocChildren (curCol + colspanEff, numRows);
519
520 // Fill span space.
521 for (int col = 0; col < colspanEff; col++)
522 for (int row = 0; row < rowspan; row++)
523 if (!(col == 0 && row == 0)) {
524 int i = (curRow + row) * numCols + curCol + col;
525
526 child = children->get(i);
527 if (child) {
528 MSG("Overlapping spans in table.\n");
529 assert(child->type == Child::SPAN_SPACE);
530 delete child;
531 }
532 child = new Child ();
533 child->type = Child::SPAN_SPACE;
534 child->spanSpace.startCol = curCol;
535 child->spanSpace.startRow = curRow;
536 children->set (i, child);
537 }
538
539 // Set the "root" cell.
540 child = new Child ();
541 child->type = Child::CELL;
542 child->cell.widget = widget;
543 child->cell.colspanOrig = colspan;
544 child->cell.colspanEff = colspanEff;
545 child->cell.rowspan = rowspan;
546 children->set (curRow * numCols + curCol, child);
547
548 // The position in the children array is (indirectly) assigned to parentRef,
549 // although incremental resizing is not implemented. Useful, e. g., in
550 // calcAvailWidthForDescendant(). See also reallocChildren().
551 widget->parentRef = makeParentRefInFlow (curRow * numCols + curCol);
552 DBG_OBJ_SET_NUM_O (widget, "parentRef", widget->parentRef);
553
554 curCol += colspanEff;
555
556 widget->setParent (this);
557 if (rowStyle->get (curRow))
558 widget->setBgColor (rowStyle->get(curRow)->backgroundColor);
559 queueResize (0, true);
560
561#if 0
562 // show table structure in stdout
563 for (int row = 0; row < numRows; row++) {
564 for (int col = 0; col < numCols; col++) {
565 int n = row * numCols + col;
566 if (!(child = children->get (n))) {
567 MSG("[null ] ");
568 } else if (children->get(n)->type == Child::CELL) {
569 MSG("[CELL rs=%d] ", child->cell.rowspan);
570 } else if (children->get(n)->type == Child::SPAN_SPACE) {
571 MSG("[SPAN rs=%d] ", child->cell.rowspan);
572 } else {
573 MSG("[Unk. ] ");
574 }
575 }
576 MSG("\n");
577 }
578 MSG("\n");
579#endif
580
581 DBG_OBJ_LEAVE ();
582}
583
585{
586 curRow++;
587
588 if (curRow >= numRows)
590
591 if (rowStyle->get (curRow))
592 rowStyle->get(curRow)->unref ();
593
594 rowStyle->set (curRow, style);
595 if (style)
596 style->ref ();
597
598 curCol = 0;
599 rowClosed = false;
600}
601
603{
604 core::Widget *child;
605
606 for (int row = 0; row <= numRows; row++) {
607 int n = curCol + row * numCols;
608 if (childDefined (n)) {
609 child = children->get(n)->cell.widget;
611 return (AlignedTableCell*)child;
612 }
613 }
614
615 return NULL;
616}
617
619{
620 switch (mod) {
621 case MIN:
622 return "MIN";
623
624 case MIN_INTR:
625 return "MIN_INTR";
626
627 case MIN_MIN:
628 return "MIN_MIN";
629
630 case MAX_MIN:
631 return "MAX_MIN";
632
633 case MAX:
634 return "MAX";
635
636 case MAX_INTR:
637 return "MAX_INTR";
638
639 case DATA:
640 return "DATA";
641
642 default:
644 return NULL;
645 }
646}
647
649{
650 switch (mod) {
651 case MIN:
652 return extremes->minWidth;
653
654 case MIN_INTR:
656
657 case MIN_MIN:
659
660 case MAX_MIN:
662
663 case MAX:
664 return extremes->maxWidth;
665
666 case MAX_INTR:
668
669 default:
671 return 0;
672 }
673}
674
675void Table::setExtreme (core::Extremes *extremes, ExtrMod mod, int value)
676{
677 switch (mod) {
678 case MIN:
679 extremes->minWidth = value;
680 break;
681
682 case MIN_INTR:
684 break;
685
686 // MIN_MIN and MAX_MIN not supported here.
687
688 case MAX:
689 extremes->maxWidth = value;
690 break;
691
692 case MAX_INTR:
694 break;
695
696 default:
698 }
699}
700
701int Table::getColExtreme (int col, ExtrMod mod, void *data)
702{
703 switch (mod) {
704 case DATA:
705 return ((misc::SimpleVector<int>*)data)->get (col);
706
707 default:
708 return getExtreme (colExtremes->getRef(col), mod);
709 }
710}
711
712void Table::setColExtreme (int col, ExtrMod mod, void *data, int value)
713{
714 switch (mod) {
715 case DATA:
716 ((misc::SimpleVector<int>*)data)->set (col, value);
717
718 default:
719 setExtreme (colExtremes->getRef(col), mod, value);
720 }
721}
722
723void Table::reallocChildren (int newNumCols, int newNumRows)
724{
725 assert (newNumCols >= numCols);
726 assert (newNumRows >= numRows);
727
728 children->setSize (newNumCols * newNumRows);
729
730 if (newNumCols > numCols) {
731 // Complicated case, array got also wider.
732 for (int row = newNumRows - 1; row >= 0; row--) {
733 int colspan0Col = -1, colspan0Row = -1;
734
735 // Copy old part.
736 for (int col = numCols - 1; col >= 0; col--) {
737 int n = row * newNumCols + col;
738 children->set (n, children->get (row * numCols + col));
739 if (children->get (n)) {
740 switch (children->get(n)->type) {
741 case Child::CELL:
742 if (children->get(n)->cell.colspanOrig == 0) {
743 colspan0Col = col;
744 colspan0Row = row;
745 children->get(n)->cell.colspanEff = newNumCols - col;
746 }
747 break;
749 if (children->get(children->get(n)->spanSpace.startRow
750 * numCols +
751 children->get(n)->spanSpace.startCol)
752 ->cell.colspanOrig == 0) {
753 colspan0Col = children->get(n)->spanSpace.startCol;
754 colspan0Row = children->get(n)->spanSpace.startRow;
755 }
756 break;
757 }
758 }
759 }
760
761 // Fill rest of the column.
762 if (colspan0Col == -1) {
763 for (int col = numCols; col < newNumCols; col++)
764 children->set (row * newNumCols + col, NULL);
765 } else {
766 for (int col = numCols; col < newNumCols; col++) {
767 Child *child = new Child ();
768 child->type = Child::SPAN_SPACE;
769 child->spanSpace.startCol = colspan0Col;
770 child->spanSpace.startRow = colspan0Row;
771 children->set (row * newNumCols + col, child);
772 }
773 }
774 }
775 }
776
777 // Bottom part of the children array.
778 for (int row = numRows; row < newNumRows; row++)
779 for (int col = 0; col < newNumCols; col++)
780 children->set (row * newNumCols + col, NULL);
781
782 // Simple arrays.
783 rowStyle->setSize (newNumRows);
784 for (int row = numRows; row < newNumRows; row++)
785 rowStyle->set (row, NULL);
786 // Rest is increased, when needed.
787
788 if (newNumCols > numCols) {
789 // Re-calculate parentRef. See addCell().
790 for (int row = 1; row < newNumRows; row++)
791 for (int col = 0; col < newNumCols; col++) {
792 int n = row * newNumCols + col;
793 Child *child = children->get (n);
794 if (child != NULL && child->type == Child::CELL) {
796 DBG_OBJ_SET_NUM_O (child->cell.widget, "parentRef",
797 child->cell.widget->parentRef);
798 }
799 }
800 }
801
802 numCols = newNumCols;
803 numRows = newNumRows;
804
805 // We initiate the column widths with a random value, to have a
806 // defined available width for the children before the column
807 // widths are actually calculated.
808
809 colWidths->setSize (numCols, 100);
810
812 DBG_OBJ_SET_NUM ("colWidths.size", colWidths->size ());
813 for (int i = 0; i < colWidths->size (); i++)
814 DBG_OBJ_ARRSET_NUM ("colWidths", i, colWidths->get (i));
815 }
816
817 DBG_OBJ_SET_NUM ("numCols", numCols);
818 DBG_OBJ_SET_NUM ("numRows", numCols);
819}
820
821// ----------------------------------------------------------------------
822
823void Table::calcCellSizes (bool calcHeights)
824{
825 DBG_OBJ_ENTER ("resize", 0, "calcCellSizes", "%s",
826 calcHeights ? "true" : "false");
827
828 bool sizeChanged = needsResize () || resizeQueued ();
829 bool extremesChanget = extremesChanged () || extremesQueued ();
830
831 if (calcHeights ? (extremesChanget || sizeChanged) :
832 (extremesChanget || !colWidthsUpToDateWidthColExtremes))
833 forceCalcCellSizes (calcHeights);
834
835 DBG_OBJ_LEAVE ();
836}
837
838
839void Table::forceCalcCellSizes (bool calcHeights)
840{
841 DBG_OBJ_ENTER ("resize", 0, "forceCalcCellSizes", "%s",
842 calcHeights ? "true" : "false");
843
844 // Since Table::getAvailWidthOfChild does not calculate the column
845 // widths, and so initially a random value (100) is returned, a
846 // correction is necessary. The old values are temporary preserved
847 // ...
848
849 lout::misc::SimpleVector<int> oldColWidths (8);
850 oldColWidths.setSize (colWidths->size ());
851 colWidths->copyTo (&oldColWidths);
852
853 actuallyCalcCellSizes (calcHeights);
854
855 // ... and then compared to the new ones. In case of a difference,
856 // the cell is told about this.
857
858 for (int col = 0; col < colWidths->size (); col++) {
859 if (oldColWidths.get (col) != colWidths->get (col)) {
860 for (int row = 0; row < numRows; row++) {
861 int n = row * numCols + col, col2;
862 Child *child = children->get(n);
863 if (child) {
864 Widget *cell;
865 switch (child->type) {
866 case Child::CELL:
867 cell = child->cell.widget;
868 break;
869
871 // TODO Are Child::spanSpace::startRow and
872 // Child::spanSpace::startCol not defined?
873
874 // Search for actual cell. If not found, this means
875 // that a cell is spanning multiple columns *and*
876 // rows; in this case it has been processed before.
877
878 cell = NULL;
879 for (col2 = col - 1; col2 >= 0 && cell == NULL; col2--) {
880 int n2 = row * numCols + col2;
881 Child *child2 = children->get(n2);
882 if (child2 != NULL && child2->type == Child::CELL)
883 cell = child2->cell.widget;
884 }
885 break;
886
887 default:
889 cell = NULL;
890 }
891
892 if (cell)
893 cell->containerSizeChanged ();
894 }
895 }
896 }
897 }
898
899 DBG_OBJ_LEAVE ();
900}
901
902void Table::actuallyCalcCellSizes (bool calcHeights)
903{
904 DBG_OBJ_ENTER ("resize", 0, "actuallyCalcCellSizes", "%s",
905 calcHeights ? "true" : "false");
906
907 int childHeight;
909
910 // Will also call forceCalcColumnExtremes(), when needed.
912
913 int availWidth = getAvailWidth (true);
914 // When adjust_table_min_width is set, use perhaps the adjustment
915 // width for correction. (TODO: Is this necessary?)
916 int corrWidth =
918 int totalWidth = misc::max (availWidth, corrWidth)
919 - ((numCols + 1) * getStyle()->hBorderSpacing + boxDiffWidth ());
920
921 DBG_OBJ_MSGF ("resize", 1,
922 "totalWidth = max (%d, %d) - ((%d - 1) * %d + %d) = <b>%d</b>",
923 availWidth, corrWidth, numCols, getStyle()->hBorderSpacing,
924 boxDiffWidth (), totalWidth);
925
926 assert (colWidths->size () == numCols); // This is set in addCell.
927 cumHeight->setSize (numRows + 1, 0);
930
931 misc::SimpleVector<int> *oldColWidths = colWidths;
932 colWidths = new misc::SimpleVector <int> (8);
934
935 int minWidth = 0, minWidthIntrinsic = 0, maxWidth = 0;
936 for (int col = 0; col < colExtremes->size(); col++) {
937 minWidth += colExtremes->getRef(col)->minWidth;
938 minWidthIntrinsic += colExtremes->getRef(col)->minWidthIntrinsic;
939 maxWidth += colExtremes->getRef(col)->maxWidth;
940 }
941
942 // CSS 'width' defined and effective?
943 bool totalWidthSpecified = false;
944 if (getStyle()->width != core::style::LENGTH_AUTO) {
945 // Even if 'width' is defined, it may not have a defined value. We try
946 // this trick (should perhaps be replaced by a cleaner solution):
947 core::Requisition testReq = { -1, -1, -1 };
949 false);
950 if (testReq.width != -1)
951 totalWidthSpecified = true;
952 }
953
954 DBG_OBJ_MSGF ("resize", 1,
955 "minWidth = %d, minWidthIntrinsic = %d, maxWidth %d, "
956 "totalWidth = %d, %s",
957 minWidth, minWidthIntrinsic, maxWidth, totalWidth,
958 totalWidthSpecified ? "specified" : "not specified");
959
960 if (minWidth > totalWidth) {
961 DBG_OBJ_MSG ("resize", 1, "case 1: minWidth > totalWidth");
962
963 // The sum of all column minima is larger than the available
964 // width, so we narrow the columns (see also CSS2 spec,
965 // section 17.5, #6). We use a similar apportioning, but not
966 // bases on minimal and maximal widths, but on intrinsic minimal
967 // widths and corrected minimal widths. This way, intrinsic
968 // extremes are preferred (so avoiding columns too narrow for
969 // the actual contents), at the expenses of corrected ones
970 // (which means that sometimes CSS values are handled
971 // incorrectly).
972
973 // A special case is a table with columns whose widths are
974 // defined by percentage values. In this case, all other columns
975 // are applied the intrinsic minimal width, while larger values
976 // are applied to the columns with percentage width (but not
977 // larger than the corrected width). The left columns are
978 // preferred, but it is ensured that no column is narrower than
979 // the intrinsic minimum.
980 //
981 // Example two columns with both "width: 70%" will be displayed like
982 // this:
983 //
984 // --------------------------------------------------
985 // | | |
986 // --------------------------------------------------
987 //
988 // The first gets indeed 70% of the total width, the second only
989 // the rest.
990 //
991 // This somewhat strange behaviour tries to mimic the somewhat
992 // strange behaviour of Firefox and Chromium.
993
994 if (numColWidthPercentage == 0 || minWidthIntrinsic >= totalWidth) {
995 // Latter case (minWidthIntrinsic >= totalWidth): special treating
996 // of percentage values would not make sense.
997
998 DBG_OBJ_MSG ("resize", 1, "case 1a: simple apportioning");
999
1000 apportion2 (totalWidth, 0, colExtremes->size() - 1, MIN_MIN, MAX_MIN,
1001 NULL, colWidths, 0);
1002 } else {
1003 DBG_OBJ_MSG ("resize", 1, "case 1b: treat percentages specially");
1004
1005 // Keep track of the width which is apportioned to the rest
1006 // of the columns with percentage width (widthPartPer), and
1007 // the minimal width (intrinsic minimum) which is needed for
1008 // the rest of these columns (minWidthIntrinsicPer).
1009
1010 int widthPartPer = totalWidth, minWidthIntrinsicPer = 0;
1011 for (int col = 0; col < colExtremes->size(); col++)
1012 if (colWidthPercentage->get (col))
1013 minWidthIntrinsicPer +=
1014 colExtremes->getRef(col)->minWidthIntrinsic;
1015 else
1016 // Columns without percentage width get only the
1017 // intrinsic mininal, so subtract this from the width for the
1018 // columns *with* percentage
1019 widthPartPer -=
1020 colExtremes->getRef(col)->minWidthIntrinsic;
1021
1022 DBG_OBJ_MSGF ("resize", 1,
1023 "widthPartPer = %d, minWidthIntrinsicPer = %d",
1024 widthPartPer, minWidthIntrinsicPer);
1025
1026 for (int col = 0; col < colExtremes->size(); col++)
1027 if (colWidthPercentage->get (col)) {
1028 int colWidth = colExtremes->getRef(col)->minWidth;
1029 int minIntr = colExtremes->getRef(col)->minWidthIntrinsic;
1030
1031 minWidthIntrinsicPer -= minIntr;
1032
1033 if (colWidth > widthPartPer - minWidthIntrinsicPer)
1034 colWidth = widthPartPer - minWidthIntrinsicPer;
1035
1036 colWidths->set (col, colWidth);
1037 widthPartPer -= colWidth;
1038
1039 DBG_OBJ_MSGF ("resize", 1,
1040 "#%d: colWidth = %d ... widthPartPer = %d, "
1041 "minWidthIntrinsicPer = %d",
1042 col, colWidth, widthPartPer, minWidthIntrinsicPer);
1043
1044 } else
1045 colWidths->set (col,
1046 colExtremes->getRef(col)->minWidthIntrinsic);
1047
1048 }
1049 } else if (totalWidthSpecified && totalWidth > maxWidth) {
1050 DBG_OBJ_MSG ("resize", 1,
1051 "case 2: totalWidthSpecified && totalWidth > maxWidth");
1052
1053 // The width is specified (and so enforced), but all maxima sum
1054 // up to less than this specified width. The columns will have
1055 // there maximal width, and the extra space is apportioned
1056 // according to the column widths, and so to the column
1057 // maxima. This is done by simply passing MAX twice to the
1058 // apportioning function.
1059
1060 // When column widths are specified (numColWidthSpecified > 0,
1061 // as calculated in forceCalcColumnExtremes()), they are treated
1062 // specially and excluded from the apportioning, so that the
1063 // specified column widths are enforced. An exception is when
1064 // all columns are specified: in this case they must be
1065 // enlargened to fill the whole table width.
1066
1067 if (numColWidthSpecified == 0 ||
1068 numColWidthSpecified == colExtremes->size()) {
1069 DBG_OBJ_MSG ("resize", 1,
1070 "subcase 2a: no or all columns with specified width");
1071 apportion2 (totalWidth, 0, colExtremes->size() - 1, MAX, MAX, NULL,
1072 colWidths, 0);
1073 } else {
1074 DBG_OBJ_MSGF ("resize", 1,
1075 "subcase 2b: %d column(s) with specified width",
1077
1078 // Seperate columns with specified and unspecified width, and
1079 // apply apportion2() only to the latter.
1080
1081 int numNotSpecified = colExtremes->size() - numColWidthSpecified;
1082
1083 misc::SimpleVector<int> widthsNotSpecified (numNotSpecified);
1084 widthsNotSpecified.setSize (numNotSpecified);
1085 misc::SimpleVector<int> apportionDest (numNotSpecified);
1086
1087 int totalWidthNotSpecified = totalWidth, indexNotSpecified = 0;
1088 for (int col = 0; col < colExtremes->size(); col++)
1089 if (colWidthSpecified->get (col))
1090 totalWidthNotSpecified -= colExtremes->getRef(col)->maxWidth;
1091 else {
1092 widthsNotSpecified.set (indexNotSpecified,
1093 colExtremes->getRef(col)->maxWidth);
1094 indexNotSpecified++;
1095 }
1096
1097 DBG_IF_RTFL {
1098 DBG_OBJ_MSGF ("resize", 1, "totalWidthNotSpecified = %d",
1099 totalWidthNotSpecified);
1100
1101 DBG_OBJ_MSG ("resize", 1, "widthsNotSpecified:");
1103
1104 for (int i = 0; i < widthsNotSpecified.size (); i++)
1105 DBG_OBJ_MSGF ("resize", 1, "#%d: %d",
1106 i, widthsNotSpecified.get (i));
1107
1108 DBG_OBJ_MSG_END ();
1109 }
1110
1111 apportion2 (totalWidthNotSpecified, 0, numNotSpecified - 1, DATA, DATA,
1112 (void*)&widthsNotSpecified, &apportionDest, 0);
1113
1114 DBG_IF_RTFL {
1115 DBG_OBJ_MSG ("resize", 1, "apportionDest:");
1117
1118 for (int i = 0; i < apportionDest.size (); i++)
1119 DBG_OBJ_MSGF ("resize", 1, "#%d: %d", i, apportionDest.get (i));
1120
1121 DBG_OBJ_MSG_END ();
1122 }
1123
1124 DBG_OBJ_MSG ("resize", 1, "finally setting column widths:");
1126
1127 indexNotSpecified = 0;
1128 for (int col = 0; col < colExtremes->size(); col++)
1129 if (colWidthSpecified->get (col)) {
1130 DBG_OBJ_MSGF ("resize", 1, "#%d: specified, gets maximum %d",
1131 col, colExtremes->getRef(col)->maxWidth);
1132 colWidths->set (col, colExtremes->getRef(col)->maxWidth);
1133 } else {
1134 DBG_OBJ_MSGF ("resize", 1, "#%d: not specified, gets value %d "
1135 "at position %d from temporary list",
1136 col, apportionDest.get (indexNotSpecified),
1137 indexNotSpecified);
1138 colWidths->set (col, apportionDest.get (indexNotSpecified));
1139 indexNotSpecified++;
1140 }
1141
1142 DBG_OBJ_MSG_END ();
1143 }
1144 } else {
1145 // Normal apportioning.
1146 int width =
1147 totalWidthSpecified ? totalWidth : misc::min (totalWidth, maxWidth);
1148 DBG_OBJ_MSGF ("resize", 1, "case 3: else; width = %d", width);
1149 apportion2 (width, 0, colExtremes->size() - 1, MIN, MAX, NULL, colWidths,
1150 0);
1151 }
1152
1153 // TODO: Adapted from old inline function "setColWidth". But (i) is
1154 // this anyway correct (col width is is not x)? And does the
1155 // performance gain actually play a role?
1156 for (int col = 0; col < colExtremes->size(); col++) {
1157 if (colWidths->get (col) != oldColWidths->get (col))
1159 }
1160
1161 DBG_IF_RTFL {
1162 DBG_OBJ_SET_NUM ("colWidths.size", colWidths->size ());
1163 for (int i = 0; i < colWidths->size (); i++)
1164 DBG_OBJ_ARRSET_NUM ("colWidths", i, colWidths->get (i));
1165 }
1166
1168 DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes",
1170
1171 for (int col = 0; col < numCols; col++) {
1172 if (col >= oldColWidths->size () || col >= colWidths->size () ||
1173 oldColWidths->get (col) != colWidths->get (col)) {
1174 // Column width has changed, tell children about this.
1175 for (int row = 0; row < numRows; row++) {
1176 int n = row * numCols + col;
1177 // TODO: Columns spanning several rows are only regarded
1178 // when the first column is affected.
1179 if (childDefined (n))
1180 children->get(n)->cell.widget->containerSizeChanged ();
1181 }
1182 }
1183 }
1184
1185 delete oldColWidths;
1186
1187 if (calcHeights) {
1188 setCumHeight (0, 0);
1189 for (int row = 0; row < numRows; row++) {
1193 int rowHeight = 0;
1194
1195 for (int col = 0; col < numCols; col++) {
1196 int n = row * numCols + col;
1197 if (childDefined (n)) {
1198 int width = (children->get(n)->cell.colspanEff - 1)
1200 for (int i = 0; i < children->get(n)->cell.colspanEff; i++)
1201 width += colWidths->get (col + i);
1202
1203 core::Requisition childRequisition;
1204 //children->get(n)->cell.widget->setWidth (width);
1205 children->get(n)->cell.widget->sizeRequest (&childRequisition);
1206 childHeight = childRequisition.ascent + childRequisition.descent;
1207 if (children->get(n)->cell.rowspan == 1) {
1208 rowHeight = misc::max (rowHeight, childHeight);
1209 } else {
1212 }
1213 }
1214 } // for col
1215
1216 setCumHeight (row + 1,
1217 cumHeight->get (row) + rowHeight + getStyle()->vBorderSpacing);
1218 } // for row
1219
1221 }
1222
1223 DBG_OBJ_LEAVE ();
1224}
1225
1227{
1228 DBG_OBJ_ENTER0 ("resize", 0, "apportionRowSpan");
1229
1230 int *rowHeight = NULL;
1231
1232 for (int c = 0; c < rowSpanCells->size(); ++c) {
1233 int n = rowSpanCells->get(c);
1234 int row = n / numCols;
1235 int rs = children->get(n)->cell.rowspan;
1236 int sumRows = cumHeight->get(row+rs) - cumHeight->get(row);
1237 core::Requisition childRequisition;
1238 children->get(n)->cell.widget->sizeRequest (&childRequisition);
1239 int spanHeight = childRequisition.ascent + childRequisition.descent
1241 if (sumRows >= spanHeight)
1242 continue;
1243
1244 // Cell size is too small.
1245 _MSG("Short cell %d, sumRows=%d spanHeight=%d\n",
1246 n,sumRows,spanHeight);
1247
1248 // Fill height array
1249 if (!rowHeight) {
1250 rowHeight = new int[numRows];
1251 for (int i = 0; i < numRows; i++)
1252 rowHeight[i] = cumHeight->get(i+1) - cumHeight->get(i);
1253 }
1254#ifdef DBG
1255 MSG(" rowHeight { ");
1256 for (int i = 0; i < numRows; i++)
1257 MSG("%d ", rowHeight[i]);
1258 MSG("}\n");
1259#endif
1260
1261 // Calc new row sizes for this span.
1262 int cumHnew_i = 0, cumh_i = 0, hnew_i;
1263 for (int i = row; i < row + rs; ++i) {
1264 hnew_i =
1265 sumRows == 0 ? (int)((float)(spanHeight-cumHnew_i)/(row+rs-i)) :
1266 (sumRows-cumh_i) <= 0 ? 0 :
1267 (int)((float)(spanHeight-cumHnew_i)*rowHeight[i]/(sumRows-cumh_i));
1268
1269 _MSG(" i=%-3d h=%d hnew_i=%d =%d*%d/%d cumh_i=%d cumHnew_i=%d\n",
1270 i,rowHeight[i],hnew_i,
1271 spanHeight-cumHnew_i,rowHeight[i],sumRows-cumh_i,
1272 cumh_i, cumHnew_i);
1273
1274 cumHnew_i += hnew_i;
1275 cumh_i += rowHeight[i];
1276 rowHeight[i] = hnew_i;
1277 }
1278 // Update cumHeight
1279 for (int i = 0; i < numRows; ++i)
1280 setCumHeight (i+1, cumHeight->get(i) + rowHeight[i]);
1281 }
1282 delete[] rowHeight;
1283
1284 DBG_OBJ_LEAVE ();
1285}
1286
1287
1292{
1293 DBG_OBJ_ENTER0 ("resize", 0, "forceCalcColumnExtremes");
1294
1295 if (numCols > 0) {
1296 lout::misc::SimpleVector<int> colSpanCells (8);
1297 colExtremes->setSize (numCols);
1300
1301 // 1. cells with colspan = 1
1302 for (int col = 0; col < numCols; col++) {
1303 DBG_OBJ_MSGF ("resize", 1, "column %d", col);
1305
1306 colWidthSpecified->set (col, false);
1307 colWidthPercentage->set (col, false);
1308
1309 colExtremes->getRef(col)->minWidth = 0;
1310 colExtremes->getRef(col)->minWidthIntrinsic = 0;
1311 colExtremes->getRef(col)->maxWidth = 0;
1312 colExtremes->getRef(col)->maxWidthIntrinsic = 0;
1313 colExtremes->getRef(col)->adjustmentWidth = 0;
1314
1315 for (int row = 0; row < numRows; row++) {
1316 DBG_OBJ_MSGF ("resize", 1, "row %d", row);
1318
1319 int n = row * numCols + col;
1320
1321 if (childDefined (n)) {
1322 if (children->get(n)->cell.colspanEff == 1) {
1323 core::Extremes cellExtremes;
1324 children->get(n)->cell.widget->getExtremes (&cellExtremes);
1325
1326 DBG_OBJ_MSGF ("resize", 1, "child: %d / %d",
1327 cellExtremes.minWidth, cellExtremes.maxWidth);
1328
1329 colExtremes->getRef(col)->minWidthIntrinsic =
1330 misc::max (colExtremes->getRef(col)->minWidthIntrinsic,
1331 cellExtremes.minWidthIntrinsic);
1332 colExtremes->getRef(col)->maxWidthIntrinsic =
1333 misc::max (colExtremes->getRef(col)->minWidthIntrinsic,
1334 colExtremes->getRef(col)->maxWidthIntrinsic,
1335 cellExtremes.maxWidthIntrinsic);
1336
1337 colExtremes->getRef(col)->minWidth =
1338 misc::max (colExtremes->getRef(col)->minWidth,
1339 cellExtremes.minWidth);
1340 colExtremes->getRef(col)->maxWidth =
1341 misc::max (colExtremes->getRef(col)->minWidth,
1342 colExtremes->getRef(col)->maxWidth,
1343 cellExtremes.maxWidth);
1344
1345 colExtremes->getRef(col)->adjustmentWidth =
1346 misc::max (colExtremes->getRef(col)->adjustmentWidth,
1347 cellExtremes.adjustmentWidth);
1348
1349 core::style::Length childWidth =
1350 children->get(n)->cell.widget->getStyle()->width;
1351 if (childWidth != core::style::LENGTH_AUTO) {
1352 colWidthSpecified->set (col, true);
1353 if (core::style::isPerLength (childWidth))
1354 colWidthPercentage->set (col, true);
1355 }
1356
1357 DBG_OBJ_MSGF ("resize", 1, "column: %d / %d (%d / %d)",
1358 colExtremes->getRef(col)->minWidth,
1359 colExtremes->getRef(col)->maxWidth,
1360 colExtremes->getRef(col)->minWidthIntrinsic,
1361 colExtremes->getRef(col)->maxWidthIntrinsic);
1362 } else {
1363 colSpanCells.increase ();
1364 colSpanCells.setLast (n);
1365 }
1366 }
1367
1368 DBG_OBJ_MSG_END ();
1369 }
1370
1371 DBG_OBJ_MSG_END ();
1372 }
1373
1374 // 2. cells with colspan > 1
1375
1376 // TODO: Is this old comment still relevant? "If needed, here we
1377 // set proportionally apportioned col maximums."
1378
1379 for (int i = 0; i < colSpanCells.size(); i++) {
1380 int n = colSpanCells.get (i);
1381 int col = n % numCols;
1382 int cs = children->get(n)->cell.colspanEff;
1383
1384 core::Extremes cellExtremes;
1385 children->get(n)->cell.widget->getExtremes (&cellExtremes);
1386
1387 calcExtremesSpanMultiCols (col, cs, &cellExtremes, MIN, MAX, NULL);
1388 calcExtremesSpanMultiCols (col, cs, &cellExtremes, MIN_INTR, MAX_INTR,
1389 NULL);
1390 calcAdjustmentWidthSpanMultiCols (col, cs, &cellExtremes);
1391
1392 core::style::Length childWidth =
1393 children->get(n)->cell.widget->getStyle()->width;
1394 if (childWidth != core::style::LENGTH_AUTO) {
1395 for (int j = 0; j < cs; j++)
1396 colWidthSpecified->set (col + j, true);
1397 if (core::style::isPerLength (childWidth))
1398 for (int j = 0; j < cs; j++)
1399 colWidthPercentage->set (col + j, true);
1400 }
1401 }
1402 }
1403
1406 for (int i = 0; i < colExtremes->size (); i++) {
1407 if (colWidthSpecified->get (i))
1409 if (colWidthPercentage->get (i))
1411 }
1412
1413 DBG_IF_RTFL {
1414 DBG_OBJ_SET_NUM ("colExtremes.size", colExtremes->size ());
1415 for (int i = 0; i < colExtremes->size (); i++) {
1416 DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "minWidth",
1417 colExtremes->get(i).minWidth);
1418 DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "minWidthIntrinsic",
1419 colExtremes->get(i).minWidthIntrinsic);
1420 DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "maxWidth",
1421 colExtremes->get(i).maxWidth);
1422 DBG_OBJ_ARRATTRSET_NUM ("colExtremes", i, "maxWidthIntrinsic",
1423 colExtremes->get(i).maxWidthIntrinsic);
1424 }
1425
1426 DBG_OBJ_SET_NUM ("colWidthSpecified.size", colWidthSpecified->size ());
1427 for (int i = 0; i < colWidthSpecified->size (); i++)
1428 DBG_OBJ_ARRSET_BOOL ("colWidthSpecified", i,
1430 DBG_OBJ_SET_NUM ("numColWidthSpecified", numColWidthSpecified);
1431
1432 DBG_OBJ_SET_NUM ("colWidthPercentage.size", colWidthPercentage->size ());
1433 for (int i = 0; i < colWidthPercentage->size (); i++)
1434 DBG_OBJ_ARRSET_BOOL ("colWidthPercentage", i,
1436 DBG_OBJ_SET_NUM ("numColWidthPercentage", numColWidthPercentage);
1437 }
1438
1440 DBG_OBJ_SET_BOOL ("colWidthsUpToDateWidthColExtremes",
1442
1443 DBG_OBJ_LEAVE ();
1444}
1445
1447 core::Extremes *cellExtremes,
1448 ExtrMod minExtrMod, ExtrMod maxExtrMod,
1449 void *extrData)
1450{
1451 DBG_OBJ_ENTER ("resize", 0, "calcExtremesSpanMulteCols",
1452 "%d, %d, ..., %s, %s, ...",
1453 col, cs, getExtrModName (minExtrMod),
1454 getExtrModName (maxExtrMod));
1455
1456 int cellMin = getExtreme (cellExtremes, minExtrMod);
1457 int cellMax = getExtreme (cellExtremes, maxExtrMod);
1458
1459 int minSumCols = 0, maxSumCols = 0;
1460
1461 for (int j = 0; j < cs; j++) {
1462 minSumCols += getColExtreme (col + j, minExtrMod, extrData);
1463 maxSumCols += getColExtreme (col + j, maxExtrMod, extrData);
1464 }
1465
1466 DBG_OBJ_MSGF ("resize", 1, "cs = %d, cell: %d / %d, sum: %d / %d\n",
1467 cs, cellMin, cellMax, minSumCols, maxSumCols);
1468
1469 bool changeMin = cellMin > minSumCols;
1470 bool changeMax = cellMax > maxSumCols;
1471 if (changeMin || changeMax) {
1472 // TODO This differs from the documentation? Should work, anyway.
1473 misc::SimpleVector<int> newMin, newMax;
1474 if (changeMin)
1475 apportion2 (cellMin, col, col + cs - 1, MIN, MAX, NULL, &newMin, 0);
1476 if (changeMax)
1477 apportion2 (cellMax, col, col + cs - 1, MIN, MAX, NULL, &newMax, 0);
1478
1479 for (int j = 0; j < cs; j++) {
1480 if (changeMin)
1481 setColExtreme (col + j, minExtrMod, extrData, newMin.get (j));
1482 if (changeMax)
1483 setColExtreme (col + j, maxExtrMod, extrData, newMax.get (j));
1484
1485 // For cases where min and max are somewhat confused:
1486 setColExtreme (col + j, maxExtrMod, extrData,
1487 misc::max (getColExtreme (col + j, minExtrMod,
1488 extrData),
1489 getColExtreme (col + j, maxExtrMod,
1490 extrData)));
1491 }
1492 }
1493
1494 DBG_OBJ_LEAVE ();
1495}
1496
1498 core::Extremes *cellExtremes)
1499{
1500 DBG_OBJ_ENTER ("resize", 0, "calcAdjustmentWidthSpanMultiCols",
1501 "%d, %d, ...", col, cs);
1502
1503 int sumAdjustmentWidth = 0;
1504 for (int j = 0; j < cs; j++)
1505 sumAdjustmentWidth += colExtremes->getRef(col + j)->adjustmentWidth;
1506
1507 if (cellExtremes->adjustmentWidth > sumAdjustmentWidth) {
1508 misc::SimpleVector<int> newAdjustmentWidth;
1509 apportion2 (cellExtremes->adjustmentWidth, col, col + cs - 1, MIN, MAX,
1510 NULL, &newAdjustmentWidth, 0);
1511 for (int j = 0; j < cs; j++)
1512 colExtremes->getRef(col + j)->adjustmentWidth =
1513 newAdjustmentWidth.get (j);
1514 }
1515
1516 DBG_OBJ_LEAVE ();
1517}
1518
1522void Table::apportion2 (int totalWidth, int firstCol, int lastCol,
1523 ExtrMod minExtrMod, ExtrMod maxExtrMod, void *extrData,
1524 misc::SimpleVector<int> *dest, int destOffset)
1525{
1526 DBG_OBJ_ENTER ("resize", 0, "apportion2", "%d, %d, %d, %s, %s, ..., %d",
1527 totalWidth, firstCol, lastCol, getExtrModName (minExtrMod),
1528 getExtrModName (maxExtrMod), destOffset);
1529
1530 if (lastCol >= firstCol) {
1531 dest->setSize (destOffset + lastCol - firstCol + 1, 0);
1532
1533 int totalMin = 0, totalMax = 0;
1534 for (int col = firstCol; col <= lastCol; col++) {
1535 totalMin += getColExtreme (col, minExtrMod, extrData);
1536 totalMax += getColExtreme (col, maxExtrMod, extrData);
1537 }
1538
1539 DBG_OBJ_MSGF ("resize", 1,
1540 "totalWidth = %d, totalMin = %d, totalMax = %d",
1541 totalWidth, totalMin, totalMax);
1542
1543 // The actual calculation is rather simple, the ith value is:
1544 //
1545 //
1546 // (max[i] - min[i]) * (totalMax - totalMin)
1547 // width[i] = min[i] + -----------------------------------------
1548 // (totalWidth - totalMin)
1549 //
1550 // (Regard "total" as "sum".) With the following general
1551 // definitions (for both the list and sums):
1552 //
1553 // diffExtr = max - min
1554 // diffWidth = width - min
1555 //
1556 // it is simplified to:
1557 //
1558 // diffExtr[i] * totalDiffWidth
1559 // diffWidth[i] = ----------------------------
1560 // totalDiffExtr
1561 //
1562 // Of course, if totalDiffExtr is 0, this is not defined;
1563 // instead, we apportion according to the minima:
1564 //
1565 // min[i] * totalWidth
1566 // width[i] = -------------------
1567 // totalMin
1568 //
1569 // Since min[i] <= max[i] for all i, totalMin == totalMax
1570 // implies that min[i] == max[i] for all i.
1571 //
1572 // Third, it totalMin == 0 (which also implies min[i] = max[i] = 0),
1573 // the result is
1574 //
1575 // width[i] = totalWidth / n
1576
1577 int totalDiffExtr = totalMax - totalMin;
1578 if (totalDiffExtr != 0) {
1579 // Normal case. The algorithm described in
1580 // "rounding-errors.doc" is used, with:
1581 //
1582 // x[i] = diffExtr[i]
1583 // y[i] = diffWidth[i]
1584 // a = totalDiffWidth
1585 // b = totalDiffExtr
1586
1587 DBG_OBJ_MSG ("resize", 1, "normal case");
1588
1589 int totalDiffWidth = totalWidth - totalMin;
1590 int cumDiffExtr = 0, cumDiffWidth = 0;
1591
1592 for (int col = firstCol; col <= lastCol; col++) {
1593 int min = getColExtreme (col, minExtrMod, extrData);
1594 int max = getColExtreme (col, maxExtrMod, extrData);
1595 int diffExtr = max - min;
1596
1597 cumDiffExtr += diffExtr;
1598 int diffWidth =
1599 (cumDiffExtr * totalDiffWidth) / totalDiffExtr - cumDiffWidth;
1600 cumDiffWidth += diffWidth;
1601
1602 dest->set (destOffset - firstCol + col, diffWidth + min);
1603 }
1604 } else if (totalMin != 0) {
1605 // Special case. Again, same algorithm, with
1606 //
1607 // x[i] = min[i]
1608 // y[i] = width[i]
1609 // a = totalWidth
1610 // b = totalMin
1611
1612 DBG_OBJ_MSG ("resize", 1, "special case 1");
1613
1614 int cumMin = 0, cumWidth = 0;
1615 for (int col = firstCol; col <= lastCol; col++) {
1616 int min = getColExtreme (col, minExtrMod, extrData);
1617 cumMin += min;
1618 int width = (cumMin * totalWidth) / totalMin - cumWidth;
1619 cumWidth += width;
1620
1621 dest->set (destOffset - firstCol + col, width);
1622 }
1623 } else { // if (totalMin == 0)
1624 // Last special case. Ssame algorithm, with
1625 //
1626 // x[i] = 1 (so cumX = i = col - firstCol + 1)
1627 // y[i] = width[i]
1628 // a = totalWidth
1629 // b = n = lastCol - firstCol + 1
1630
1631 DBG_OBJ_MSG ("resize", 1, "special case 2");
1632
1633 int cumWidth = 0, n = (lastCol - firstCol + 1);
1634 for (int col = firstCol; col <= lastCol; col++) {
1635 int i = (col - firstCol + 1);
1636 int width = (i * totalWidth) / n - cumWidth;
1637 cumWidth += width;
1638
1639 dest->set (destOffset - firstCol + col, width);
1640 }
1641 }
1642 }
1643
1644 DBG_OBJ_LEAVE ();
1645}
1646
1647} // namespace dw
#define _MSG(...)
Definition bookmarks.c:45
#define MSG(...)
Definition bookmarks.c:46
AlignedTableCell * getCellRef()
Definition table.cc:602
void drawLevel(core::View *view, core::Rectangle *area, int level, core::DrawingContext *context)
Definition table.cc:379
int getExtreme(core::Extremes *extremes, ExtrMod mod)
Definition table.cc:648
void setCumHeight(int row, int value)
Definition table.hh:455
~Table()
Definition table.cc:73
lout::misc::SimpleVector< core::style::Style * > * rowStyle
Definition table.hh:416
int calcAvailWidthForDescendant(Widget *child)
Definition table.cc:271
Table(bool limitTextWidth)
Definition table.cc:34
void calcAdjustmentWidthSpanMultiCols(int col, int cs, core::Extremes *cellExtremes)
Definition table.cc:1497
void apportionRowSpan()
Definition table.cc:1226
int getColExtreme(int col, ExtrMod mod, void *data)
Definition table.cc:701
lout::misc::SimpleVector< int > * baseline
Definition table.hh:414
void calcExtremesSpanMultiCols(int col, int cs, core::Extremes *cellExtremes, ExtrMod minExtrMod, ExtrMod maxExtrMod, void *extrData)
Definition table.cc:1446
void forceCalcColumnExtremes()
Fills dw::Table::colExtremes in all cases.
Definition table.cc:1291
void calcCellSizes(bool calcHeights)
Definition table.cc:823
void forceCalcCellSizes(bool calcHeights)
Definition table.cc:839
lout::misc::SimpleVector< int > * colWidths
The widths of all columns.
Definition table.hh:402
int applyPerWidth(int containerWidth, core::style::Length perWidth)
Definition table.cc:320
int getAvailWidthOfChild(Widget *child, bool forceValue)
Definition table.cc:225
void resizeDrawImpl()
Called after sizeAllocateImpl() to redraw necessary areas.
Definition table.cc:217
bool affectsSizeChangeContainerChild(Widget *child)
Definition table.cc:347
void addCell(Widget *widget, int colspan, int rowspan)
Definition table.cc:468
void getExtremesSimpl(core::Extremes *extremes)
Simple variant, to be implemented by widgets with extremes not depending on positions.
Definition table.cc:133
int numCols
Definition table.hh:367
int redrawX
Definition table.hh:370
@ MIN_INTR
Definition table.hh:420
@ MAX_MIN
Definition table.hh:420
@ MIN_MIN
Definition table.hh:420
@ MAX_INTR
Definition table.hh:420
int curRow
Definition table.hh:367
void containerSizeChangedForChildren()
Definition table.cc:330
void addRow(core::style::Style *style)
Definition table.cc:584
bool usesAvailWidth()
Must be implemengted by a method returning true, when getAvailWidth() is called.
Definition table.cc:369
bool isBlockLevel()
Definition table.cc:374
int numRows
Definition table.hh:367
lout::misc::SimpleVector< core::Extremes > * colExtremes
The extremes of all columns.
Definition table.hh:375
lout::misc::SimpleVector< int > * rowSpanCells
If a Cell has rowspan > 1, it goes into this array.
Definition table.hh:413
int curCol
Definition table.hh:367
lout::misc::SimpleVector< Child * > * children
Definition table.hh:368
void actuallyCalcCellSizes(bool calcHeights)
Definition table.cc:902
void sizeAllocateImpl(core::Allocation *allocation)
See Sizes of Dillo Widgets.
Definition table.cc:166
bool colWidthsUpToDateWidthColExtremes
Definition table.hh:418
bool limitTextWidth
Definition table.hh:365
void sizeRequestSimpl(core::Requisition *requisition)
Simple variant, to be implemented by widgets with sizes not depending on positions.
Definition table.cc:106
void removeChild(Widget *child)
Definition table.cc:458
int numColWidthPercentage
Definition table.hh:397
core::Iterator * iterator(core::Content::Type mask, bool atEnd)
Return an iterator for this widget.
Definition table.cc:463
void setColExtreme(int col, ExtrMod mod, void *data, int value)
Definition table.cc:712
static bool getAdjustTableMinWidth()
Definition table.hh:497
lout::misc::SimpleVector< int > * cumHeight
Row cumulative height array: cumHeight->size() is numRows + 1, cumHeight->get(0) is 0,...
Definition table.hh:409
void setExtreme(core::Extremes *extremes, ExtrMod mod, int value)
Definition table.cc:675
lout::misc::SimpleVector< bool > * colWidthPercentage
Wether the column itself (in the future?) or at least one cell in this column or spanning over this c...
Definition table.hh:396
void reallocChildren(int newNumCols, int newNumRows)
Definition table.cc:723
void apportion2(int totalWidth, int firstCol, int lastCol, ExtrMod minExtrMod, ExtrMod maxExtrMod, void *extrData, lout::misc::SimpleVector< int > *dest, int destOffset)
Actual apportionment function.
Definition table.cc:1522
bool rowClosed
Definition table.hh:365
bool childDefined(int n)
Definition table.hh:428
int applyPerHeight(int containerHeight, core::style::Length perHeight)
Definition table.cc:325
int numColWidthSpecified
Definition table.hh:386
Widget * getWidgetAtPointLevel(int x, int y, int level, core::GettingWidgetAtPointContext *context)
Definition table.cc:425
lout::misc::SimpleVector< bool > * colWidthSpecified
Wether the column itself (in the future?) or at least one cell in this column or spanning over this c...
Definition table.hh:385
static bool adjustTableMinWidth
Definition table.hh:363
const char * getExtrModName(ExtrMod mod)
Definition table.cc:618
static int CLASS_ID
Definition table.hh:492
int redrawY
Definition table.hh:370
Set at the top when drawing.
Definition types.hh:295
Set at the top when getting the widget at the point.
Definition types.hh:313
Iterators are used to iterate through the contents of a widget.
Definition iterator.hh:20
dw::core::Shape implemtation for simple rectangles.
Definition types.hh:70
void draw(core::View *view, core::style::Style *style, int x, int y)
Definition types.cc:41
static bool handledByStackingContextMgr(Widget *widget)
An interface to encapsulate platform dependent drawing.
Definition view.hh:17
The base class of all dillo widgets.
Definition widget.hh:24
Extremes extremes
Analogue to dw::core::Widget::requisition.
Definition widget.hh:146
Allocation allocation
The current allocation: size and position, always relative to the canvas.
Definition widget.hh:183
void setButtonSensitive(bool buttonSensitive)
Definition widget.cc:1468
int boxDiffWidth()
Definition widget.hh:461
int parentRef
This value is defined by the parent widget, and used for incremential resizing.
Definition widget.hh:175
int getAvailWidth(bool forceValue)
Return available width including margin/border/padding (extraSpace?), not only the content width.
Definition widget.cc:649
void correctRequisition(Requisition *requisition, void(*splitHeightFun)(int, int *, int *), bool allowDecreaseWidth, bool allowDecreaseHeight)
Definition widget.cc:744
style::Style * getStyle()
Definition widget.hh:448
bool resizeQueued()
Definition widget.hh:435
Requisition requisition
Size_request() stores the result of the last call of size_request_impl().
Definition widget.hh:140
void queueDrawArea(int x, int y, int width, int height)
Definition widget.cc:285
bool extremesQueued()
Definition widget.hh:436
bool extremesChanged()
Definition widget.hh:440
bool needsResize()
Definition widget.hh:437
style::Style * style
Definition widget.hh:130
void queueResize(int ref, bool extremesChanged, bool fast)
This method should be called, when a widget changes its size.
Definition widget.cc:309
int boxDiffHeight()
Definition widget.hh:466
void correctExtremes(Extremes *extremes, bool useAdjustmentWidth)
Definition widget.cc:821
void getExtremes(Extremes *extremes, int numPos=0, Widget **references=NULL, int *x=NULL, int *y=NULL)
Wrapper for Widget::getExtremesImpl().
Definition widget.cc:1014
void drawBox(View *view, style::Style *style, Rectangle *area, int x, int y, int width, int height, bool inverse)
Draw borders and background of a widget part, which allocation is given by (x, y, width,...
Definition widget.cc:1371
int getContentWidth()
Definition widget.hh:186
int getParentRefInFlowSubRef(int parentRef)
void sizeAllocateStart(core::Allocation *allocation)
bool isWidgetOOF(Widget *widget)
static const char * stackingLevelText(int level)
oof::OutOfFlowMgr * getWidgetOutOfFlowMgr(Widget *widget)
void correctRequisitionByOOF(core::Requisition *requisition, void(*splitHeightFun)(int, int *, int *))
void correctExtremesByOOF(core::Extremes *extremes)
int makeParentRefInFlow(int inFlowSubRef)
Represents additional data for OOF containers.
virtual int getAvailWidthOfChild(core::Widget *child, bool forceValue)=0
virtual bool dealingWithSizeOfChild(core::Widget *child)=0
bool instanceOf(int otherClassId)
Returns, whether this class is an instance of the class, given by otherClassId, or of a sub class of ...
Definition identity.cc:105
void registerName(const char *className, int *classId)
This method must be called in the constructor for the sub class.
Definition identity.cc:83
Simple (simpler than container::untyped::Vector and container::typed::Vector) template based vector.
Definition misc.hh:94
void setSize(int newSize)
Set the size explicitly.
Definition misc.hh:167
void increase()
Increase the vector size by one.
Definition misc.hh:160
void copyTo(SimpleVector< T > *dest, int thisStart=0, int thisLast=-1, int destStart=0)
Copies some elements into another vector of the same type.
Definition misc.hh:266
void set(int i, T t)
Store an object in the vector.
Definition misc.hh:246
T get(int i) const
Return the one element, explicitly.
Definition misc.hh:201
int size() const
Return the number of elements put into this vector.
Definition misc.hh:141
void setLast(T t)
Store an object at the end of the vector.
Definition misc.hh:254
#define DBG_IF_RTFL
Definition debug.hh:73
#define DBG_OBJ_ENTER0(aspect, prio, funname)
#define DBG_OBJ_ARRSET_BOOL(var, ind, val)
#define DBG_OBJ_DELETE()
#define DBG_OBJ_CREATE(klass)
#define DBG_OBJ_SET_BOOL(var, val)
#define DBG_OBJ_MSG_END()
#define DBG_OBJ_MSGF(aspect, prio, fmt,...)
#define DBG_OBJ_SET_NUM(var, val)
#define DBG_OBJ_MSG(aspect, prio, msg)
#define DBG_OBJ_ARRSET_NUM(var, ind, val)
#define DBG_OBJ_ENTER(aspect, prio, funname, fmt,...)
#define DBG_OBJ_LEAVE()
#define DBG_OBJ_MSG_START()
#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val)
#define DBG_OBJ_SET_NUM_O(obj, var, val)
#define MSG_WARN(...)
Definition msg.h:26
int multiplyWithPerLength(int x, Length l)
Multiply an int with a percentage length, returning int.
Definition style.hh:473
int Length
Type for representing all lengths within dw::core::style.
Definition style.hh:428
bool isPerLength(Length l)
Returns true if l is a percentage.
Definition style.hh:445
@ LENGTH_AUTO
Represents "auto" lengths.
Definition style.hh:494
void splitHeightPreserveDescent(int height, int *ascent, int *descent)
Definition widget.cc:2024
Dw is in this namespace, or sub namespaces of this one.
T min(T a, T b)
Definition misc.hh:19
T max(T a, T b)
Definition misc.hh:20
void assertNotReached()
Definition misc.hh:35
struct dw::Table::Child::@23::@25 cell
enum dw::Table::Child::@22 type
struct dw::Table::Child::@23::@26 spanSpace
core::Widget * widget
Definition table.hh:336
Represents the allocation, i.e.
Definition types.hh:164