dillo  3.0.5
About: dillo is a small, fast, extensible Web browser particularly suitable for older or smaller computers and embedded systems (but only limited or no support for frames, CSS, JavaScript, Java).
  Fossies Dox: dillo-3.0.5.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

table.cc
Go to the documentation of this file.
1 /*
2  * Dillo Widget
3  *
4  * Copyright 2005-2007 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 
27 using namespace lout;
28 
29 namespace dw {
30 
31 int Table::CLASS_ID = -1;
32 
33 Table::Table(bool limitTextWidth)
34 {
35  DBG_OBJ_CREATE ("dw::Table");
36  registerName ("dw::Table", &CLASS_ID);
37  setFlags (BLOCK_LEVEL);
38  setFlags (USES_HINTS);
39  setButtonSensitive(false);
40 
41  this->limitTextWidth = limitTextWidth;
42 
43  rowClosed = false;
44 
45  // random values
46  availWidth = 100;
47  availAscent = 100;
48  availDescent = 0;
49 
50  numRows = 0;
51  numCols = 0;
52  curRow = -1;
53  curCol = 0;
54 
55  children = new misc::SimpleVector <Child*> (16);
56  colExtremes = new misc::SimpleVector<core::Extremes> (8);
57  colWidths = new misc::SimpleVector <int> (8);
58  cumHeight = new misc::SimpleVector <int> (8);
59  rowSpanCells = new misc::SimpleVector <int> (8);
60  colSpanCells = new misc::SimpleVector <int> (8);
61  baseline = new misc::SimpleVector <int> (8);
63 
64  hasColPercent = 0;
65  colPercents = new misc::SimpleVector <core::style::Length> (8);
66 
67  redrawX = 0;
68  redrawY = 0;
69 }
70 
71 
72 Table::~Table()
73 {
74  for (int i = 0; i < children->size (); i++) {
75  if (children->get(i)) {
76  switch (children->get(i)->type) {
77  case Child::CELL:
78  delete children->get(i)->cell.widget;
79  break;
80  case Child::SPAN_SPACE:
81  break;
82  }
83 
84  delete children->get(i);
85  }
86  }
87 
88  for (int i = 0; i < rowStyle->size (); i++)
89  if (rowStyle->get (i))
90  rowStyle->get(i)->unref ();
91 
92  delete children;
93  delete colExtremes;
94  delete colWidths;
95  delete cumHeight;
96  delete rowSpanCells;
97  delete colSpanCells;
98  delete baseline;
99  delete rowStyle;
100  delete colPercents;
101 
102  DBG_OBJ_DELETE ();
103 }
104 
105 void Table::sizeRequestImpl (core::Requisition *requisition)
106 {
107  forceCalcCellSizes ();
108 
112  requisition->width = getStyle()->boxDiffWidth ()
113  + (numCols + 1) * getStyle()->hBorderSpacing;
114  for (int col = 0; col < numCols; col++)
115  requisition->width += colWidths->get (col);
116 
117  requisition->ascent =
118  getStyle()->boxDiffHeight () + cumHeight->get (numRows)
119  + getStyle()->vBorderSpacing;
120  requisition->descent = 0;
121 
122 }
123 
124 void Table::getExtremesImpl (core::Extremes *extremes)
125 {
126  if (numCols == 0) {
127  extremes->minWidth = extremes->maxWidth = 0;
128  return;
129  }
130 
131  forceCalcColumnExtremes ();
132 
133  extremes->minWidth = extremes->maxWidth =
134  (numCols + 1) * getStyle()->hBorderSpacing
135  + getStyle()->boxDiffWidth ();
136  for (int col = 0; col < numCols; col++) {
137  extremes->minWidth += colExtremes->getRef(col)->minWidth;
138  extremes->maxWidth += colExtremes->getRef(col)->maxWidth;
139  }
140  if (core::style::isAbsLength (getStyle()->width)) {
141  extremes->minWidth =
142  misc::max (extremes->minWidth,
143  core::style::absLengthVal(getStyle()->width));
144  extremes->maxWidth =
145  misc::max (extremes->maxWidth,
146  core::style::absLengthVal(getStyle()->width));
147  }
148 
149  _MSG(" Table::getExtremesImpl, {%d, %d} numCols=%d\n",
150  extremes->minWidth, extremes->maxWidth, numCols);
151 }
152 
153 void Table::sizeAllocateImpl (core::Allocation *allocation)
154 {
155  calcCellSizes ();
156 
161  int offy =
162  allocation->y + getStyle()->boxOffsetY () + getStyle()->vBorderSpacing;
163  int x =
164  allocation->x + getStyle()->boxOffsetX () + getStyle()->hBorderSpacing;
165 
166  for (int col = 0; col < numCols; col++) {
167  for (int row = 0; row < numRows; row++) {
168  int n = row * numCols + col;
169  if (childDefined (n)) {
170  int width =
171  (children->get(n)->cell.colspanEff - 1)
172  * getStyle()->hBorderSpacing;
173  for (int i = 0; i < children->get(n)->cell.colspanEff; i++)
174  width += colWidths->get (col + i);
175 
176  core::Allocation childAllocation;
177  core::Requisition childRequisition;
178 
179  children->get(n)->cell.widget->sizeRequest (&childRequisition);
180 
181  childAllocation.x = x;
182  childAllocation.y = cumHeight->get (row) + offy;
183  childAllocation.width = width;
184  childAllocation.ascent = childRequisition.ascent;
185  childAllocation.descent =
186  cumHeight->get (row + children->get(n)->cell.rowspan)
187  - cumHeight->get (row) - getStyle()->vBorderSpacing
188  - childRequisition.ascent;
189  children->get(n)->cell.widget->sizeAllocate (&childAllocation);
190  }
191  }
192 
193  x += colWidths->get (col) + getStyle()->hBorderSpacing;
194  }
195 }
196 
197 void Table::resizeDrawImpl ()
198 {
199  queueDrawArea (redrawX, 0, allocation.width - redrawX, getHeight ());
200  queueDrawArea (0, redrawY, allocation.width, getHeight () - redrawY);
201  redrawX = allocation.width;
202  redrawY = getHeight ();
203 }
204 
205 void Table::setWidth (int width)
206 {
207  // If limitTextWidth is set, a queueResize may also be necessary.
208  if (availWidth != width || limitTextWidth) {
209  _MSG(" Table::setWidth %d\n", width);
210  availWidth = width;
211  queueResize (0, false);
212  }
213 }
214 
215 void Table::setAscent (int ascent)
216 {
217  if (availAscent != ascent) {
218  availAscent = ascent;
219  queueResize (0, false);
220  }
221 }
222 
223 void Table::setDescent (int descent)
224 {
225  if (availDescent != descent) {
226  availDescent = descent;
227  queueResize (0, false);
228  }
229 }
230 
231 void Table::draw (core::View *view, core::Rectangle *area)
232 {
233  // Can be optimized, by iterating on the lines in area.
234  drawWidgetBox (view, area, false);
235 
236 #if 0
237  int offx = getStyle()->boxOffsetX () + getStyle()->hBorderSpacing;
238  int offy = getStyle()->boxOffsetY () + getStyle()->vBorderSpacing;
239  int width = getContentWidth ();
240 
241  // This part seems unnecessary. It also segfaulted sometimes when
242  // cumHeight size was less than numRows. --jcid
243  for (int row = 0; row < numRows; row++) {
244  if (rowStyle->get (row))
245  drawBox (view, rowStyle->get (row), area,
246  offx, offy + cumHeight->get (row),
247  width - 2*getStyle()->hBorderSpacing,
248  cumHeight->get (row + 1) - cumHeight->get (row)
249  - getStyle()->vBorderSpacing, false);
250  }
251 #endif
252 
253  for (int i = 0; i < children->size (); i++) {
254  if (childDefined (i)) {
255  Widget *child = children->get(i)->cell.widget;
256  core::Rectangle childArea;
257  if (child->intersects (area, &childArea))
258  child->draw (view, &childArea);
259  }
260  }
261 }
262 
263 void Table::removeChild (Widget *child)
264 {
266 }
267 
268 core::Iterator *Table::iterator (core::Content::Type mask, bool atEnd)
269 {
270  return new TableIterator (this, mask, atEnd);
271 }
272 
273 void Table::addCell (Widget *widget, int colspan, int rowspan)
274 {
275  const int maxspan = 100;
276  Child *child;
277  int colspanEff;
278 
279  // We limit the values for colspan and rowspan to avoid
280  // attacks by malicious web pages.
281  if (colspan > maxspan || colspan < 0) {
282  MSG_WARN("colspan = %d is set to %d.\n", colspan, maxspan);
283  colspan = maxspan;
284  }
285  if (rowspan > maxspan || rowspan <= 0) {
286  MSG_WARN("rowspan = %d is set to %d.\n", rowspan, maxspan);
287  rowspan = maxspan;
288  }
289 
290  if (numRows == 0) {
291  // to prevent a crash
292  MSG("addCell: cell without row.\n");
293  addRow (NULL);
294  }
295 
296  if (rowClosed) {
297  MSG_WARN("Last cell had colspan=0.\n");
298  addRow (NULL);
299  }
300 
301  if (colspan == 0) {
302  colspanEff = misc::max (numCols - curCol, 1);
303  rowClosed = true;
304  } else
305  colspanEff = colspan;
306 
307  // Find next free cell-
308  while (curCol < numCols &&
309  (child = children->get(curRow * numCols + curCol)) != NULL &&
310  child->type == Child::SPAN_SPACE)
311  curCol++;
312 
313  _MSG("Table::addCell numCols=%d,curCol=%d,colspan=%d,colspanEff=%d\n",
314  numCols, curCol, colspan, colspanEff);
315 
316  // Increase children array, when necessary.
317  if (curRow + rowspan > numRows)
318  reallocChildren (numCols, curRow + rowspan);
319  if (curCol + colspanEff > numCols)
320  reallocChildren (curCol + colspanEff, numRows);
321 
322  // Fill span space.
323  for (int col = 0; col < colspanEff; col++)
324  for (int row = 0; row < rowspan; row++)
325  if (!(col == 0 && row == 0)) {
326  int i = (curRow + row) * numCols + curCol + col;
327 
328  child = children->get(i);
329  if (child) {
330  MSG("Overlapping spans in table.\n");
331  assert(child->type == Child::SPAN_SPACE);
332  delete child;
333  }
334  child = new Child ();
335  child->type = Child::SPAN_SPACE;
336  child->spanSpace.startCol = curCol;
337  child->spanSpace.startRow = curRow;
338  children->set (i, child);
339  }
340 
341  // Set the "root" cell.
342  child = new Child ();
343  child->type = Child::CELL;
344  child->cell.widget = widget;
345  child->cell.colspanOrig = colspan;
346  child->cell.colspanEff = colspanEff;
347  child->cell.rowspan = rowspan;
348  children->set (curRow * numCols + curCol, child);
349 
350  curCol += colspanEff;
351 
352  widget->setParent (this);
353  if (rowStyle->get (curRow))
354  widget->setBgColor (rowStyle->get(curRow)->backgroundColor);
355  queueResize (0, true);
356 
357 #if 0
358  // show table structure in stdout
359  for (int row = 0; row < numRows; row++) {
360  for (int col = 0; col < numCols; col++) {
361  int n = row * numCols + col;
362  if (!(child = children->get (n))) {
363  MSG("[null ] ");
364  } else if (children->get(n)->type == Child::CELL) {
365  MSG("[CELL rs=%d] ", child->cell.rowspan);
366  } else if (children->get(n)->type == Child::SPAN_SPACE) {
367  MSG("[SPAN rs=%d] ", child->cell.rowspan);
368  } else {
369  MSG("[Unk. ] ");
370  }
371  }
372  MSG("\n");
373  }
374  MSG("\n");
375 #endif
376 }
377 
378 void Table::addRow (core::style::Style *style)
379 {
380  curRow++;
381 
382  if (curRow >= numRows)
383  reallocChildren (numCols, curRow + 1);
384 
385  if (rowStyle->get (curRow))
386  rowStyle->get(curRow)->unref ();
387 
388  rowStyle->set (curRow, style);
389  if (style)
390  style->ref ();
391 
392  curCol = 0;
393  rowClosed = false;
394 }
395 
396 TableCell *Table::getCellRef ()
397 {
398  core::Widget *child;
399 
400  for (int row = 0; row <= numRows; row++) {
401  int n = curCol + row * numCols;
402  if (childDefined (n)) {
403  child = children->get(n)->cell.widget;
404  if (child->instanceOf (TableCell::CLASS_ID))
405  return (TableCell*)child;
406  }
407  }
408 
409  return NULL;
410 }
411 
412 void Table::reallocChildren (int newNumCols, int newNumRows)
413 {
414  assert (newNumCols >= numCols);
415  assert (newNumRows >= numRows);
416 
417  children->setSize (newNumCols * newNumRows);
418 
419  if (newNumCols > numCols) {
420  // Complicated case, array got also wider.
421  for (int row = newNumRows - 1; row >= 0; row--) {
422  int colspan0Col = -1, colspan0Row = -1;
423 
424  // Copy old part.
425  for (int col = numCols - 1; col >= 0; col--) {
426  int n = row * newNumCols + col;
427  children->set (n, children->get (row * numCols + col));
428  if (children->get (n)) {
429  switch (children->get(n)->type) {
430  case Child::CELL:
431  if (children->get(n)->cell.colspanOrig == 0) {
432  colspan0Col = col;
433  colspan0Row = row;
434  children->get(n)->cell.colspanEff = newNumCols - col;
435  }
436  break;
437  case Child::SPAN_SPACE:
438  if (children->get(children->get(n)->spanSpace.startRow
439  * numCols +
440  children->get(n)->spanSpace.startCol)
441  ->cell.colspanOrig == 0) {
442  colspan0Col = children->get(n)->spanSpace.startCol;
443  colspan0Row = children->get(n)->spanSpace.startRow;
444  }
445  break;
446  }
447  }
448  }
449 
450  // Fill rest of the column.
451  if (colspan0Col == -1) {
452  for (int col = numCols; col < newNumCols; col++)
453  children->set (row * newNumCols + col, NULL);
454  } else {
455  for (int col = numCols; col < newNumCols; col++) {
456  Child *child = new Child ();
457  child->type = Child::SPAN_SPACE;
458  child->spanSpace.startCol = colspan0Col;
459  child->spanSpace.startRow = colspan0Row;
460  children->set (row * newNumCols + col, child);
461  }
462  }
463  }
464  }
465 
466  // Bottom part of the children array.
467  for (int row = numRows; row < newNumRows; row++)
468  for (int col = 0; col < newNumCols; col++)
469  children->set (row * newNumCols + col, NULL);
470 
471  // Simple arrays.
472  rowStyle->setSize (newNumRows);
473  for (int row = numRows; row < newNumRows; row++)
474  rowStyle->set (row, NULL);
475  // Rest is increased, when needed.
476 
477  numCols = newNumCols;
478  numRows = newNumRows;
479 }
480 
481 // ----------------------------------------------------------------------
482 
483 void Table::calcCellSizes ()
484 {
485  if (needsResize ())
486  forceCalcCellSizes ();
487 }
488 
489 
490 void Table::forceCalcCellSizes ()
491 {
492  int totalWidth = 0, childHeight, forceTotalWidth = 1;
493  core::Extremes extremes;
494 
495  // Will also call calcColumnExtremes(), when needed.
496  getExtremes (&extremes);
497 
498  if (core::style::isAbsLength (getStyle()->width)) {
499  totalWidth = core::style::absLengthVal (getStyle()->width);
500  } else if (core::style::isPerLength (getStyle()->width)) {
501  /*
502  * If the width is > 100%, we use 100%, this prevents ugly
503  * results. (May be changed in future, when a more powerful
504  * rendering is implemented, to handle fixed positions etc.,
505  * as defined by CSS2.)
506  */
507  totalWidth =
509  getStyle()->width),
510  availWidth);
511  } else if (getStyle()->width == core::style::LENGTH_AUTO) {
512  totalWidth = availWidth;
513  forceTotalWidth = 0;
514  }
515 
516  _MSG(" availWidth = %d\n", availWidth);
517  _MSG(" totalWidth1 = %d\n", totalWidth);
518 
519  if (totalWidth < extremes.minWidth)
520  totalWidth = extremes.minWidth;
521  totalWidth = totalWidth
522  - (numCols + 1) * getStyle()->hBorderSpacing
523  - getStyle()->boxDiffWidth ();
524 
525  _MSG(" totalWidth2 = %d curCol=%d\n", totalWidth,curCol);
526 
527 
528  colWidths->setSize (numCols, 0);
529  cumHeight->setSize (numRows + 1, 0);
530  rowSpanCells->setSize (0);
531  baseline->setSize (numRows);
532 
533  _MSG(" extremes = %d,%d\n", extremes.minWidth, extremes.maxWidth);
534  _MSG(" getStyle()->boxDiffWidth() = %d\n", getStyle()->boxDiffWidth());
535  _MSG(" getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
536 
537 
538  apportion_percentages2 (totalWidth, forceTotalWidth);
539  if (!hasColPercent)
540  apportion2 (totalWidth, forceTotalWidth);
541 
542  setCumHeight (0, 0);
543  for (int row = 0; row < numRows; row++) {
547  int rowHeight = 0;
548 
549  for (int col = 0; col < numCols; col++) {
550  int n = row * numCols + col;
551  if (childDefined (n)) {
552  int width = (children->get(n)->cell.colspanEff - 1)
553  * getStyle()->hBorderSpacing;
554  for (int i = 0; i < children->get(n)->cell.colspanEff; i++)
555  width += colWidths->get (col + i);
556 
557  core::Requisition childRequisition;
558  children->get(n)->cell.widget->setWidth (width);
559  children->get(n)->cell.widget->sizeRequest (&childRequisition);
560  childHeight = childRequisition.ascent + childRequisition.descent;
561  if (children->get(n)->cell.rowspan == 1) {
562  rowHeight = misc::max (rowHeight, childHeight);
563  } else {
564  rowSpanCells->increase();
565  rowSpanCells->set(rowSpanCells->size()-1, n);
566  }
567  }
568  }/*for col*/
569 
570  setCumHeight (row + 1,
571  cumHeight->get (row) + rowHeight + getStyle()->vBorderSpacing);
572 
573  }/*for row*/
574 
575  apportionRowSpan ();
576 }
577 
578 void Table::apportionRowSpan ()
579 {
580  int *rowHeight = NULL;
581 
582  for (int c = 0; c < rowSpanCells->size(); ++c) {
583  int n = rowSpanCells->get(c);
584  int row = n / numCols;
585  int rs = children->get(n)->cell.rowspan;
586  int sumRows = cumHeight->get(row+rs) - cumHeight->get(row);
587  core::Requisition childRequisition;
588  children->get(n)->cell.widget->sizeRequest (&childRequisition);
589  int spanHeight = childRequisition.ascent + childRequisition.descent
590  + getStyle()->vBorderSpacing;
591  if (sumRows >= spanHeight)
592  continue;
593 
594  // Cell size is too small.
595  _MSG("Short cell %d, sumRows=%d spanHeight=%d\n",
596  n,sumRows,spanHeight);
597 
598  // Fill height array
599  if (!rowHeight) {
600  rowHeight = new int[numRows];
601  for (int i = 0; i < numRows; i++)
602  rowHeight[i] = cumHeight->get(i+1) - cumHeight->get(i);
603  }
604 #ifdef DBG
605  MSG(" rowHeight { ");
606  for (int i = 0; i < numRows; i++)
607  MSG("%d ", rowHeight[i]);
608  MSG("}\n");
609 #endif
610 
611  // Calc new row sizes for this span.
612  int cumHnew_i = 0, cumh_i = 0, hnew_i;
613  for (int i = row; i < row + rs; ++i) {
614  hnew_i =
615  sumRows == 0 ? (int)((float)(spanHeight-cumHnew_i)/(row+rs-i)) :
616  (sumRows-cumh_i) <= 0 ? 0 :
617  (int)((float)(spanHeight-cumHnew_i)*rowHeight[i]/(sumRows-cumh_i));
618 
619  _MSG(" i=%-3d h=%d hnew_i=%d =%d*%d/%d cumh_i=%d cumHnew_i=%d\n",
620  i,rowHeight[i],hnew_i,
621  spanHeight-cumHnew_i,rowHeight[i],sumRows-cumh_i,
622  cumh_i, cumHnew_i);
623 
624  cumHnew_i += hnew_i;
625  cumh_i += rowHeight[i];
626  rowHeight[i] = hnew_i;
627  }
628  // Update cumHeight
629  for (int i = 0; i < numRows; ++i)
630  setCumHeight (i+1, cumHeight->get(i) + rowHeight[i]);
631  }
632  delete[] rowHeight;
633 }
634 
635 
641 void Table::calcColumnExtremes ()
642 {
643  if (extremesChanged ())
644  forceCalcColumnExtremes ();
645 }
646 
647 
651 void Table::forceCalcColumnExtremes ()
652 {
653  _MSG(" Table::forceCalcColumnExtremes numCols=%d\n", numCols);
654 
655  if (numCols == 0)
656  return;
657 
658  colExtremes->setSize (numCols);
659  colPercents->setSize (numCols);
660  colSpanCells->setSize (0);
661  /* 1. cells with colspan = 1 */
662  for (int col = 0; col < numCols; col++) {
663  colExtremes->getRef(col)->minWidth = 0;
664  colExtremes->getRef(col)->maxWidth = 0;
665  colPercents->set(col, core::style::LENGTH_AUTO);
666 
667  for (int row = 0; row < numRows; row++) {
668  int n = row * numCols + col;
669  if (!childDefined (n))
670  continue;
671  if (children->get(n)->cell.colspanEff == 1) {
672  core::Extremes cellExtremes;
673  int cellMinW, cellMaxW, pbm;
674  core::style::Length width =
675  children->get(n)->cell.widget->getStyle()->width;
676  pbm = (numCols + 1) * getStyle()->hBorderSpacing
677  + children->get(n)->cell.widget->getStyle()->boxDiffWidth ();
678  children->get(n)->cell.widget->getExtremes (&cellExtremes);
679  if (core::style::isAbsLength (width)) {
680  // Fixed lengths include table padding, border and margin.
681  cellMinW = cellExtremes.minWidth;
682  cellMaxW = misc::max (cellMinW,
683  core::style::absLengthVal(width) - pbm);
684  } else {
685  cellMinW = cellExtremes.minWidth;
686  cellMaxW = cellExtremes.maxWidth;
687  }
688 
689  _MSG("FCCE, col%d colMin,colMax,cellMin,cellMax = %d,%d,%d,%d\n",
690  col,
691  colExtremes->getRef(col)->minWidth,
692  colExtremes->getRef(col)->maxWidth,
693  cellMinW, cellMaxW);
694 
695  colExtremes->getRef(col)->minWidth =
696  misc::max (colExtremes->getRef(col)->minWidth, cellMinW);
697  colExtremes->getRef(col)->maxWidth =
698  misc::max (colExtremes->getRef(col)->minWidth, misc::max (
699  colExtremes->getRef(col)->maxWidth,
700  cellMaxW));
701 
702  // Also fill the colPercents array in this pass
703  if (core::style::isPerLength (width)) {
704  hasColPercent = 1;
705  if (colPercents->get(col) == core::style::LENGTH_AUTO)
706  colPercents->set(col, width);
707  } else if (core::style::isAbsLength (width)) {
708  // We treat LEN_ABS as a special case of LEN_AUTO.
709  /*
710  * if (colPercents->get(col) == LEN_AUTO)
711  * colPercents->set(col, LEN_ABS);
712  *
713  * (Hint: that's old code!)
714  */
715  }
716  } else {
717  colSpanCells->increase();
718  colSpanCells->set(colSpanCells->size()-1, n);
719  }
720  }
721  }
722 
723  /* 2. cells with colspan > 1 */
724  /* If needed, here we set proportionally apportioned col maximums */
725  for (int c = 0; c < colSpanCells->size(); ++c) {
726  core::Extremes cellExtremes;
727  int cellMinW, cellMaxW, pbm;
728  int n = colSpanCells->get(c);
729  int col = n % numCols;
730  int cs = children->get(n)->cell.colspanEff;
731  core::style::Length width =
732  children->get(n)->cell.widget->getStyle()->width;
733  pbm = (numCols + 1) * getStyle()->hBorderSpacing
734  + children->get(n)->cell.widget->getStyle()->boxDiffWidth ();
735  children->get(n)->cell.widget->getExtremes (&cellExtremes);
736  if (core::style::isAbsLength (width)) {
737  // Fixed lengths include table padding, border and margin.
738  cellMinW = cellExtremes.minWidth;
739  cellMaxW =
740  misc::max (cellMinW, core::style::absLengthVal(width) - pbm);
741  } else {
742  cellMinW = cellExtremes.minWidth;
743  cellMaxW = cellExtremes.maxWidth;
744  }
745  int minSumCols = 0, maxSumCols = 0;
746  for (int i = 0; i < cs; ++i) {
747  minSumCols += colExtremes->getRef(col+i)->minWidth;
748  maxSumCols += colExtremes->getRef(col+i)->maxWidth;
749  }
750 
751  _MSG("cs=%d spanWidth=%d,%d sumCols=%d,%d\n",
752  cs,cellMinW,cellMaxW,minSumCols,maxSumCols);
753 
754  if (minSumCols >= cellMinW && maxSumCols >= cellMaxW)
755  continue;
756 
757  // Cell size is too small; apportion {min,max} for this colspan.
758  int spanMinW = misc::max (misc::max (cs, minSumCols),
759  cellMinW - (cs-1) * getStyle()->hBorderSpacing),
760  spanMaxW = misc::max (misc::max (cs, maxSumCols),
761  cellMaxW - (cs-1) * getStyle()->hBorderSpacing);
762 
763  if (minSumCols == 0) {
764  // No single cells defined for this span => pre-apportion equally
765  minSumCols = spanMinW; maxSumCols = spanMaxW;
766  int minW = spanMinW, maxW = spanMaxW;
767  for (int i = 0; i < cs; ++i) {
768  colExtremes->getRef(col+i)->minWidth = minW / (cs - i);
769  colExtremes->getRef(col+i)->maxWidth = maxW / (cs - i);
770  minW -= colExtremes->getRef(col+i)->minWidth;
771  maxW -= colExtremes->getRef(col+i)->maxWidth;
772  }
773  }
774 
775  // These values will help if the span has percents.
776  int spanHasColPercent = 0;
777  int availSpanMinW = spanMinW;
778  float cumSpanPercent = 0.0f;
779  for (int i = col; i < col + cs; ++i) {
780  if (core::style::isPerLength (colPercents->get(i))) {
781  cumSpanPercent += core::style::perLengthVal (colPercents->get(i));
782  ++spanHasColPercent;
783  } else
784  availSpanMinW -= colExtremes->getRef(i)->minWidth;
785  }
786 
787  // Calculate weighted-apportion columns for this span.
788  int wMin = 0, wMax;
789  int cumMaxWnew = 0, cumMaxWold = 0, goalMaxW = spanMaxW;
790  int curAppW = maxSumCols;
791  int curExtraW = spanMinW - minSumCols;
792  for (int i = col; i < col + cs; ++i) {
793 
794  if (!spanHasColPercent) {
795  int d_a = colExtremes->getRef(i)->maxWidth;
796  int d_w = curAppW > 0 ? (int)((float)curExtraW * d_a/curAppW) : 0;
797  if (d_a < 0||d_w < 0) {
798  MSG("d_a=%d d_w=%d\n",d_a,d_w);
799  exit(1);
800  }
801  wMin = colExtremes->getRef(i)->minWidth + d_w;
802  colExtremes->getRef(i)->minWidth = wMin;
803  curExtraW -= d_w;
804  curAppW -= d_a;
805  } else {
806  if (core::style::isPerLength (colPercents->get(i))) {
807  // multiplyWithPerLength would cause rounding errors,
808  // therefore the deprecated way, using perLengthVal:
809  wMin = misc::max (colExtremes->getRef(i)->minWidth,
810  (int)(availSpanMinW *
812  (colPercents->get (i))
813  / cumSpanPercent));
814  colExtremes->getRef(i)->minWidth = wMin;
815  }
816  }
817 
818  wMax = (goalMaxW-cumMaxWnew <= 0) ? 0 :
819  (int)((float)(goalMaxW-cumMaxWnew)
820  * colExtremes->getRef(i)->maxWidth
821  / (maxSumCols-cumMaxWold));
822  wMax = misc::max (wMin, wMax);
823  cumMaxWnew += wMax;
824  cumMaxWold += colExtremes->getRef(i)->maxWidth;
825  colExtremes->getRef(i)->maxWidth = wMax;
826 
827  _MSG("i=%d, wMin=%d wMax=%d cumMaxWold=%d\n",
828  i,wMin,wMax,cumMaxWold);
829 
830  }
831 #ifdef DBG
832  MSG("col min,max: [");
833  for (int i = 0; i < numCols; i++)
834  MSG("%d,%d ",
835  colExtremes->getRef(i)->minWidth,
836  colExtremes->getRef(i)->maxWidth);
837  MSG("]\n");
838  MSG("getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
839 #endif
840  }
841 }
842 
847 void Table::apportion2 (int totalWidth, int forceTotalWidth)
848 {
849  if (colExtremes->size() == 0)
850  return;
851 #ifdef DBG
852  MSG("app2, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
853  availWidth, totalWidth, forceTotalWidth);
854  MSG("app2, extremes: ( ");
855  for (int i = 0; i < colExtremes->size (); i++)
856  MSG("%d,%d ",
857  colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
858  MSG(")\n");
859 #endif
860  int minAutoWidth = 0, maxAutoWidth = 0, availAutoWidth = totalWidth;
861  for (int col = 0; col < numCols; col++) {
862  if (core::style::isAbsLength (colPercents->get(col))) {
863  // set absolute lengths
864  setColWidth (col, colExtremes->get(col).minWidth);
865  }
866  if (colPercents->get(col) == core::style::LENGTH_AUTO) {
867  maxAutoWidth += colExtremes->get(col).maxWidth;
868  minAutoWidth += colExtremes->get(col).minWidth;
869  } else
870  availAutoWidth -= colWidths->get(col);
871  }
872 
873  if (!maxAutoWidth) // no core::style::LENGTH_AUTO cols!
874  return;
875 
876  colWidths->setSize (colExtremes->size (), 0);
877 
878  if (!forceTotalWidth && maxAutoWidth < availAutoWidth) {
879  // Enough space for the maximum table, don't widen past max.
880  availAutoWidth = maxAutoWidth;
881  }
882 
883  // General case.
884  int curTargetWidth = misc::max (availAutoWidth, minAutoWidth);
885  int curExtraWidth = curTargetWidth - minAutoWidth;
886  int curMaxWidth = maxAutoWidth;
887  int curNewWidth = minAutoWidth;
888  for (int col = 0; col < numCols; col++) {
889  _MSG("app2, col %d, minWidth=%d maxWidth=%d\n",
890  col, colExtremes->getRef(col)->minWidth,
891  colExtremes->get(col).maxWidth);
892 
893  if (colPercents->get(col) != core::style::LENGTH_AUTO)
894  continue;
895 
896  int colMinWidth = colExtremes->getRef(col)->minWidth;
897  int colMaxWidth = colExtremes->getRef(col)->maxWidth;
898  int w = (curMaxWidth <= 0) ? 0 :
899  (int)((float)curTargetWidth * colMaxWidth/curMaxWidth);
900 
901  _MSG("app2, curTargetWidth=%d colMaxWidth=%d curMaxWidth=%d "
902  "curNewWidth=%d ",
903  curTargetWidth, colMaxWidth,curMaxWidth,curNewWidth);
904  _MSG("w = %d, ", w);
905 
906  if (w <= colMinWidth)
907  w = colMinWidth;
908  else if (curNewWidth - colMinWidth + w > curTargetWidth)
909  w = colMinWidth + curExtraWidth;
910 
911  _MSG("w = %d\n", w);
912 
913  curNewWidth -= colMinWidth;
914  curMaxWidth -= colMaxWidth;
915  curExtraWidth -= (w - colMinWidth);
916  curTargetWidth -= w;
917  setColWidth (col, w);
918  }
919 #ifdef DBG
920  MSG("app2, result: ( ");
921  for (int i = 0; i < colWidths->size (); i++)
922  MSG("%d ", colWidths->get (i));
923  MSG(")\n");
924 #endif
925 }
926 
927 void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
928 {
929  int hasTablePercent = core::style::isPerLength (getStyle()->width) ? 1 : 0;
930 
931  if (colExtremes->size() == 0 || (!hasTablePercent && !hasColPercent))
932  return;
933 
934  // If there's a table-wide percentage, totalWidth comes already scaled.
935  _MSG("APP_P, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
936  availWidth, totalWidth, forceTotalWidth);
937 
938  if (!hasColPercent) {
939 #ifdef DBG
940  MSG("APP_P, only a table-wide percentage\n");
941  MSG("APP_P, extremes = { ");
942  for (int col = 0; col < numCols; col++)
943  MSG("%d,%d ", colExtremes->getRef(col)->minWidth,
944  colExtremes->getRef(col)->maxWidth);
945  MSG("}\n");
946 #endif
947  // It has only a table-wide percentage. Apportion non-absolute widths.
948  int sumMaxWidth = 0, perAvailWidth = totalWidth;
949  for (int col = 0; col < numCols; col++) {
950  if (core::style::isAbsLength (colPercents->get(col)))
951  perAvailWidth -= colExtremes->getRef(col)->maxWidth;
952  else
953  sumMaxWidth += colExtremes->getRef(col)->maxWidth;
954  }
955 
956  _MSG("APP_P, perAvailWidth=%d, sumMaxWidth=%d\n",
957  perAvailWidth, sumMaxWidth);
958 
959  for (int col = 0; col < numCols; col++) {
960  int max_wi = colExtremes->getRef(col)->maxWidth, new_wi;
961  if (!core::style::isAbsLength (colPercents->get(col))) {
962  new_wi =
963  misc::max (colExtremes->getRef(col)->minWidth,
964  (int)((float)max_wi * perAvailWidth/sumMaxWidth));
965  setColWidth (col, new_wi);
966  perAvailWidth -= new_wi;
967  sumMaxWidth -= max_wi;
968  }
969  }
970 #ifdef DBG
971  MSG("APP_P, result = { ");
972  for (int col = 0; col < numCols; col++)
973  MSG("%d ", colWidths->get(col));
974  MSG("}\n");
975 #endif
976 
977  } else {
978  // we'll have to apportion...
979  _MSG("APP_P, we'll have to apportion...\n");
980 
981  // Calculate cumPercent and available space
982  float cumPercent = 0.0f;
983  int hasAutoCol = 0;
984  int sumMinWidth = 0, sumMaxWidth = 0, sumMinNonPer = 0, sumMaxNonPer = 0;
985  for (int col = 0; col < numCols; col++) {
986  if (core::style::isPerLength (colPercents->get(col))) {
987  cumPercent += core::style::perLengthVal (colPercents->get(col));
988  } else {
989  sumMinNonPer += colExtremes->getRef(col)->minWidth;
990  sumMaxNonPer += colExtremes->getRef(col)->maxWidth;
991  if (colPercents->get(col) == core::style::LENGTH_AUTO)
992  hasAutoCol++;
993  }
994  sumMinWidth += colExtremes->getRef(col)->minWidth;
995  sumMaxWidth += colExtremes->getRef(col)->maxWidth;
996 
997  _MSG("APP_P, col %d minWidth=%d maxWidth=%d\n", col,
998  colExtremes->getRef(col)->minWidth,
999  colExtremes->getRef(col)->maxWidth);
1000  }
1001  int oldTotalWidth = totalWidth;
1002  if (!forceTotalWidth) {
1003  if (sumMaxNonPer == 0 || cumPercent < 0.99f) {
1004  // only percentage columns, or cumPercent < 100% => restrict width
1005  int totW = (int)(sumMaxNonPer / (1.0f - cumPercent));
1006  for (int col = 0; col < numCols; col++) {
1007  totW = misc::max
1008  (totW,
1009  (int)(colExtremes->getRef(col)->maxWidth
1010  / core::style::perLengthVal (colPercents->get(col))));
1011  }
1012  totalWidth = misc::min (totW, totalWidth);
1013  }
1014  }
1015 
1016  // make sure there's enough space
1017  totalWidth = misc::max (totalWidth, sumMinWidth);
1018  // extraWidth is always >= 0
1019  int extraWidth = totalWidth - sumMinWidth;
1020  int sumMinWidthPer = sumMinWidth - sumMinNonPer;
1021  int curPerWidth = sumMinWidthPer;
1022  // percentages refer to workingWidth
1023  int workingWidth = totalWidth - sumMinNonPer;
1024  if (cumPercent < 0.99f) {
1025  // In this case, use the whole table width
1026  workingWidth = totalWidth;
1027  curPerWidth = sumMinWidth;
1028  }
1029 
1030  _MSG("APP_P, oldTotalWidth=%d totalWidth=%d"
1031  " workingWidth=%d extraWidth=%d sumMinNonPer=%d\n",
1032  oldTotalWidth,totalWidth,workingWidth,extraWidth,sumMinNonPer);
1033 
1034  for (int col = 0; col < numCols; col++) {
1035  int colMinWidth = colExtremes->getRef(col)->minWidth;
1036  if (core::style::isPerLength (colPercents->get(col))) {
1037  int w = core::style::multiplyWithPerLength (workingWidth,
1038  colPercents->get(col));
1039  if (w < colMinWidth)
1040  w = colMinWidth;
1041  else if (curPerWidth - colMinWidth + w > workingWidth)
1042  w = colMinWidth + extraWidth;
1043  extraWidth -= (w - colMinWidth);
1044  curPerWidth += (w - colMinWidth);
1045  setColWidth (col, w);
1046  } else {
1047  setColWidth (col, colMinWidth);
1048  }
1049  }
1050 
1051  if (cumPercent < 0.99f) {
1052  // Will have to apportion the other columns
1053 #ifdef DBG
1054  MSG("APP_P, extremes: ( ");
1055  for (int i = 0; i < colExtremes->size (); i++)
1056  MSG("%d,%d ",
1057  colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
1058  MSG(")\n");
1059 #endif
1060  curPerWidth -= sumMinNonPer;
1061  int perWidth = (int)(curPerWidth/cumPercent);
1062  totalWidth = misc::max (totalWidth, perWidth);
1063  totalWidth = misc::min (totalWidth, oldTotalWidth);
1064 
1065  _MSG("APP_P, curPerWidth=%d perWidth=%d, totalWidth=%d\n",
1066  curPerWidth, perWidth, totalWidth);
1067 
1068  if (hasAutoCol == 0) {
1069  // Special case, cumPercent < 100% and no other columns to expand.
1070  // We'll honor totalWidth by expanding the percentage cols.
1071  int extraWidth = totalWidth - curPerWidth - sumMinNonPer;
1072  for (int col = 0; col < numCols; col++) {
1073  if (core::style::isPerLength (colPercents->get(col))) {
1074  // This could cause rounding errors:
1075  //
1076  // int d =
1077  // core::dw::multiplyWithPerLength (extraWidth,
1078  // colPercents->get(col))
1079  // / cumPercent;
1080  //
1081  // Thus the "old" way:
1082  int d =
1083  (int)(extraWidth *
1084  core::style::perLengthVal (colPercents->get(col))
1085  / cumPercent);
1086  setColWidth (col, colWidths->get(col) + d);
1087  }
1088  }
1089  }
1090  }
1091 #ifdef DBG
1092  MSG("APP_P, result ={ ");
1093  for (int col = 0; col < numCols; col++)
1094  MSG("%d ", colWidths->get(col));
1095  MSG("}\n");
1096 #endif
1097  apportion2 (totalWidth, 2);
1098 
1099 #ifdef DBG
1100  MSG("APP_P, percent={");
1101  for (int col = 0; col < numCols; col++)
1102  MSG("%f ", core::dw::perLengthVal (colPercents->get(col)));
1103  MSG("}\n");
1104  MSG("APP_P, result ={ ");
1105  for (int col = 0; col < numCols; col++)
1106  MSG("%d ", colWidths->get(col));
1107  MSG("}\n");
1108 #endif
1109  }
1110 }
1111 
1112 // ----------------------------------------------------------------------
1113 
1114 Table::TableIterator::TableIterator (Table *table,
1115  core::Content::Type mask, bool atEnd):
1116  core::Iterator (table, mask, atEnd)
1117 {
1118  index = atEnd ? table->children->size () : -1;
1120 }
1121 
1123  core::Content::Type mask, int index):
1124  core::Iterator (table, mask, false)
1125 {
1126  this->index = index;
1127 
1128  if (index < 0)
1130  else if (index >= table->children->size ())
1132  else {
1134  content.widget = table->children->get(index)->cell.widget;
1135  }
1136 }
1137 
1139 {
1140  return new TableIterator ((Table*)getWidget(), getMask(), index);
1141 }
1142 
1144 {
1145  return index - ((TableIterator*)other)->index;
1146 }
1147 
1149 {
1150  Table *table = (Table*)getWidget();
1151 
1152  if (content.type == core::Content::END)
1153  return false;
1154 
1155  // tables only contain widgets:
1156  if ((getMask() & core::Content::WIDGET) == 0) {
1157  content.type = core::Content::END;
1158  return false;
1159  }
1160 
1161  do {
1162  index++;
1163  if (index >= table->children->size ()) {
1164  content.type = core::Content::END;
1165  return false;
1166  }
1167  } while (table->children->get(index) == NULL ||
1168  table->children->get(index)->type != Child::CELL);
1169 
1170  content.type = core::Content::WIDGET;
1171  content.widget = table->children->get(index)->cell.widget;
1172  return true;
1173 }
1174 
1176 {
1177  Table *table = (Table*)getWidget();
1178 
1179  if (content.type == core::Content::START)
1180  return false;
1181 
1182  // tables only contain widgets:
1183  if ((getMask() & core::Content::WIDGET) == 0) {
1184  content.type = core::Content::START;
1185  return false;
1186  }
1187 
1188  do {
1189  index--;
1190  if (index < 0) {
1191  content.type = core::Content::START;
1192  return false;
1193  }
1194  } while (table->children->get(index) == NULL ||
1195  table->children->get(index)->type != Child::CELL);
1196 
1197  content.type = core::Content::WIDGET;
1198  content.widget = table->children->get(index)->cell.widget;
1199  return true;
1200 }
1201 
1202 void Table::TableIterator::highlight (int start, int end,
1203  core::HighlightLayer layer)
1204 {
1206 }
1207 
1209  core::HighlightLayer layer)
1210 {
1211 }
1212 
1213 void Table::TableIterator::getAllocation (int start, int end,
1215 {
1217 }
1218 
1219 } // namespace dw
DBG_OBJ_DELETE
#define DBG_OBJ_DELETE()
Definition: debug.hh:176
dw::Table::TableIterator::next
bool next()
Move iterator forward and store content it.
Definition: table.cc:1148
dw::Table
A Widget for rendering tables.
Definition: table.hh:316
dw::core::Allocation::y
int y
Definition: types.hh:166
dw::core::style::isPerLength
bool isPerLength(Length l)
Returns true if l is a percentage.
Definition: style.hh:406
dw::core::Allocation::x
int x
Definition: types.hh:165
dw::core::style::absLengthVal
int absLengthVal(Length l)
Returns the value of a length in pixels, as an integer.
Definition: style.hh:412
dw::core::Extremes::maxWidth
int maxWidth
Definition: types.hh:182
dw::core::style::Style::ref
void ref()
Definition: style.hh:598
dw::core::HighlightLayer
HighlightLayer
Definition: types.hh:42
DBG_OBJ_CREATE
#define DBG_OBJ_CREATE(klass)
Definition: debug.hh:175
MSG
#define MSG(...)
Definition: bookmarks.c:45
dw::core::Requisition
Definition: types.hh:172
dw::TableCell
Definition: tablecell.hh:9
dw::core::style::LENGTH_AUTO
Represents "auto" lengths.
Definition: style.hh:454
dw::core::Requisition::descent
int descent
Definition: types.hh:176
dw::Table::TableIterator::clone
lout::object::Object * clone()
Return an exact copy of the object.
Definition: table.cc:1138
dw::core::Rectangle::draw
void draw(core::View *view, core::style::Style *style, int x, int y)
Definition: types.cc:41
dw::core::Extremes::minWidth
int minWidth
Definition: types.hh:181
dw::core::Content::Type
Type
Definition: types.hh:187
dw::Table::TableIterator::prev
bool prev()
Move iterator backward and store content it.
Definition: table.cc:1175
dw::core::Iterator
Iterators are used to iterate through the contents of a widget.
Definition: iterator.hh:19
dw::Table::Child::spanSpace
struct dw::Table::Child::@16::@19 spanSpace
dw::Table::Child::type
enum dw::Table::Child::@15 type
dw::core::Allocation
Represents the allocation, i.e. actual position and size of a dw::core::Widget.
Definition: types.hh:163
dw::Table::TableIterator::unhighlight
void unhighlight(int direction, core::HighlightLayer layer)
Shrink highlighted region to no longer contain the current content.
Definition: table.cc:1208
dw::core::style::multiplyWithPerLength
int multiplyWithPerLength(int x, Length l)
Multiply an int with a percentage length, returning int.
Definition: style.hh:433
dw::core::Iterator::getWidget
Widget * getWidget()
Definition: iterator.hh:35
dw::Table::TableIterator::index
int index
Definition: table.hh:340
dw::Table::children
lout::misc::SimpleVector< Child * > * children
Definition: table.hh:362
dw::Table::TableIterator::getAllocation
void getAllocation(int start, int end, core::Allocation *allocation)
Return the shape, which a part of the item, the iterator points on, allocates.
Definition: table.cc:1213
lout::misc::max
T max(T a, T b)
Definition: misc.hh:20
lout::misc::min
T min(T a, T b)
Definition: misc.hh:19
dw::core::Allocation::descent
int descent
Definition: types.hh:169
lout::object::Object
This is the base class for many other classes, which defines very common virtual methods.
Definition: object.hh:24
dw::core::style::perLengthVal
double perLengthVal(Length l)
Returns the value of a percentage, relative to 1, as a double.
Definition: style.hh:419
table.hh
dw::core::Requisition::ascent
int ascent
Definition: types.hh:175
lout
Definition: container.cc:26
dw::Table::TableIterator::compareTo
int compareTo(lout::object::Comparable *other)
Compare two objects c1 and c2.
Definition: table.cc:1143
dw::core::style::isAbsLength
bool isAbsLength(Length l)
Returns true if l is an absolute length.
Definition: style.hh:403
dw::core::Iterator::getMask
Content::Type getMask()
Definition: iterator.hh:37
dw::core::Requisition::width
int width
Definition: types.hh:174
dw::Table::TableIterator::highlight
void highlight(int start, int end, core::HighlightLayer layer)
Extend highlighted region to contain part of the current content.
Definition: table.cc:1202
dw::Table::TableIterator::TableIterator
TableIterator(Table *table, core::Content::Type mask, bool atEnd)
Definition: table.cc:1114
dw::core::Content::WIDGET
Definition: types.hh:191
dw::core::Rectangle
dw::core::Shape implemtation for simple rectangles.
Definition: types.hh:69
dw::core::Iterator::content
Content content
Definition: iterator.hh:26
dw::core::Extremes
Definition: types.hh:179
dw::core::View
An interface to encapsulate platform dependent drawing.
Definition: view.hh:16
dw::Table::Child::CELL
Definition: table.hh:323
dw::core::Content::widget
Widget * widget
Definition: types.hh:205
dw::core::Content::END
Definition: types.hh:189
dw::core::style::Length
int Length
Type for representing all lengths within dw::core::style.
Definition: style.hh:389
dw::core::Allocation::ascent
int ascent
Definition: types.hh:168
lout::object::Comparable
Instances of a sub class of may be compared (less, greater).
Definition: object.hh:41
_MSG
#define _MSG(...)
Definition: bookmarks.c:44
dw::Table::Child::cell
struct dw::Table::Child::@16::@18 cell
dw::Table::Child
Definition: table.hh:320
dw::core::Widget
The base class of all dillo widgets.
Definition: widget.hh:23
dw::core::Widget::allocation
Allocation allocation
The current allocation: size and position, always relative to the canvas.
Definition: widget.hh:151
MSG_WARN
#define MSG_WARN(...)
Definition: msg.h:27
dw
Dw is in this namespace, or sub namespaces of this one.
Definition: alignedtextblock.cc:26
dw::core::Content::type
short type
Definition: types.hh:201
lout::misc::SimpleVector
Simple (simpler than container::untyped::Vector and container::typed::Vector) template based vector.
Definition: misc.hh:71
dw::core::style::Style
Definition: style.hh:571
lout::identity::IdentifiableObject::instanceOf
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:88
dw::core::Allocation::width
int width
Definition: types.hh:167
dw::core::Content::START
Definition: types.hh:188
dw::Table::TableIterator
Definition: table.hh:337