]> git.saurik.com Git - wxWidgets.git/blame - src/html/m_tables.cpp
added wxTimerEvent::GetTimer()
[wxWidgets.git] / src / html / m_tables.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
93763ad5 2// Name: src/html/m_tables.cpp
5526e819
VS
3// Purpose: wxHtml module for tables
4// Author: Vaclav Slavik
69941f05 5// RCS-ID: $Id$
5526e819 6// Copyright: (c) 1999 Vaclav Slavik
65571936 7// Licence: wxWindows licence
5526e819
VS
8/////////////////////////////////////////////////////////////////////////////
9
3096bd2f 10#include "wx/wxprec.h"
3364ab79 11
2b5f62a0 12#ifdef __BORLANDC__
93763ad5 13 #pragma hdrstop
3364ab79
RS
14#endif
15
93763ad5
WS
16#if wxUSE_HTML && wxUSE_STREAMS
17
b4f4d3dd 18#ifndef WX_PRECOMP
193d0c93 19 #include "wx/wxcrtvararg.h"
3364ab79
RS
20#endif
21
69941f05
VS
22#include "wx/html/forcelnk.h"
23#include "wx/html/m_templ.h"
5526e819 24
69941f05 25#include "wx/html/htmlcell.h"
5526e819 26
c88293a4 27FORCE_LINK_ME(m_tables)
5526e819
VS
28
29
30#define TABLE_BORDER_CLR_1 wxColour(0xC5, 0xC2, 0xC5)
31#define TABLE_BORDER_CLR_2 wxColour(0x62, 0x61, 0x62)
32
33
34//-----------------------------------------------------------------------------
35// wxHtmlTableCell
36//-----------------------------------------------------------------------------
37
38
79d6c018
VS
39struct colStruct
40{
41 int width, units;
42 // width of the column either in pixels or percents
43 // ('width' is the number, 'units' determines its meaning)
44 int minWidth, maxWidth;
45 // minimal/maximal column width. This is needed by HTML 4.0
46 // layouting algorithm and can be determined by trying to
47 // layout table cells with width=1 and width=infinity
48 int leftpos, pixwidth, maxrealwidth;
49 // temporary (depends on actual width of table)
50};
51
52enum cellState
53{
54 cellSpan,
55 cellUsed,
56 cellFree
57};
58
59struct cellStruct
60{
61 wxHtmlContainerCell *cont;
62 int colspan, rowspan;
63 int minheight, valign;
64 cellState flag;
ca16b7a9 65 bool nowrap;
79d6c018 66};
5526e819
VS
67
68
69class wxHtmlTableCell : public wxHtmlContainerCell
70{
79d6c018
VS
71protected:
72 /* These are real attributes: */
73
74 // should we draw borders or not?
75 bool m_HasBorders;
76 // number of columns; rows
77 int m_NumCols, m_NumRows;
78 // array of column information
79 colStruct *m_ColsInfo;
80 // 2D array of all cells in the table : m_CellInfo[row][column]
81 cellStruct **m_CellInfo;
82 // spaces between cells
83 int m_Spacing;
84 // cells internal indentation
85 int m_Padding;
86
87private:
88 /* ...and these are valid only when parsing the table: */
89
90 // number of actual column (ranging from 0..m_NumCols)
91 int m_ActualCol, m_ActualRow;
92
93 // default values (for table and row):
94 wxColour m_tBkg, m_rBkg;
95 wxString m_tValign, m_rValign;
96
97 double m_PixelScale;
98
99
100public:
101 wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag, double pixel_scale = 1.0);
d3c7fc99 102 virtual ~wxHtmlTableCell();
3bc7a423
VS
103
104 virtual void RemoveExtraSpacing(bool top, bool bottom);
105
79d6c018
VS
106 virtual void Layout(int w);
107
108 void AddRow(const wxHtmlTag& tag);
109 void AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag);
110
111private:
112 // Reallocates memory to given number of cols/rows
113 // and changes m_NumCols/m_NumRows value to reflect this change
114 // NOTE! You CAN'T change m_NumCols/m_NumRows before calling this!!
115 void ReallocCols(int cols);
116 void ReallocRows(int rows);
117
118 // Computes minimal and maximal widths of columns. Needs to be called
25c71ccc 119 // only once, before first Layout().
79d6c018 120 void ComputeMinMaxWidths();
22f3361e
VZ
121
122 DECLARE_NO_COPY_CLASS(wxHtmlTableCell)
5526e819
VS
123};
124
125
126
edbd0635 127wxHtmlTableCell::wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag, double pixel_scale)
5526e819
VS
128 : wxHtmlContainerCell(parent)
129{
edbd0635 130 m_PixelScale = pixel_scale;
25c71ccc 131 m_HasBorders =
b0bdbbfe 132 (tag.HasParam(wxT("BORDER")) && tag.GetParam(wxT("BORDER")) != wxT("0"));
5526e819
VS
133 m_ColsInfo = NULL;
134 m_NumCols = m_NumRows = 0;
135 m_CellInfo = NULL;
136 m_ActualCol = m_ActualRow = -1;
137
138 /* scan params: */
04dbb646 139 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90 140 tag.GetParamAsColour(wxT("BGCOLOR"), &m_tBkg);
04dbb646
VZ
141 if (tag.HasParam(wxT("VALIGN")))
142 m_tValign = tag.GetParam(wxT("VALIGN"));
143 else
8bd72d90
VS
144 m_tValign = wxEmptyString;
145 if (!tag.GetParamAsInt(wxT("CELLSPACING"), &m_Spacing))
146 m_Spacing = 2;
147 if (!tag.GetParamAsInt(wxT("CELLPADDING"), &m_Padding))
148 m_Padding = 3;
edbd0635
VS
149 m_Spacing = (int)(m_PixelScale * (double)m_Spacing);
150 m_Padding = (int)(m_PixelScale * (double)m_Padding);
5526e819
VS
151
152 if (m_HasBorders)
153 SetBorder(TABLE_BORDER_CLR_1, TABLE_BORDER_CLR_2);
154}
155
156
157
158wxHtmlTableCell::~wxHtmlTableCell()
159{
160 if (m_ColsInfo) free(m_ColsInfo);
04dbb646 161 if (m_CellInfo)
4f9297b0 162 {
5526e819
VS
163 for (int i = 0; i < m_NumRows; i++)
164 free(m_CellInfo[i]);
165 free(m_CellInfo);
166 }
167}
168
169
3bc7a423
VS
170void wxHtmlTableCell::RemoveExtraSpacing(bool WXUNUSED(top),
171 bool WXUNUSED(bottom))
172{
173 // Don't remove any spacing in the table -- it's always desirable,
174 // because it's part of table's definition.
175 // (If wxHtmlContainerCell::RemoveExtraSpacing() was applied to tables,
176 // then upper left cell of a table would be positioned above other cells
177 // if the table was the first element on the page.)
178}
5526e819
VS
179
180void wxHtmlTableCell::ReallocCols(int cols)
181{
182 int i,j;
183
04dbb646 184 for (i = 0; i < m_NumRows; i++)
4f9297b0 185 {
5526e819
VS
186 m_CellInfo[i] = (cellStruct*) realloc(m_CellInfo[i], sizeof(cellStruct) * cols);
187 for (j = m_NumCols; j < cols; j++)
188 m_CellInfo[i][j].flag = cellFree;
189 }
190
191 m_ColsInfo = (colStruct*) realloc(m_ColsInfo, sizeof(colStruct) * cols);
04dbb646 192 for (j = m_NumCols; j < cols; j++)
4f9297b0 193 {
5526e819 194 m_ColsInfo[j].width = 0;
efba2b89 195 m_ColsInfo[j].units = wxHTML_UNITS_PERCENT;
79d6c018 196 m_ColsInfo[j].minWidth = m_ColsInfo[j].maxWidth = -1;
5526e819
VS
197 }
198
199 m_NumCols = cols;
200}
201
202
203
204void wxHtmlTableCell::ReallocRows(int rows)
205{
206 m_CellInfo = (cellStruct**) realloc(m_CellInfo, sizeof(cellStruct*) * rows);
04dbb646 207 for (int row = m_NumRows; row < rows ; row++)
80eab469 208 {
04dbb646 209 if (m_NumCols == 0)
80eab469 210 m_CellInfo[row] = NULL;
04dbb646 211 else
80eab469
VS
212 {
213 m_CellInfo[row] = (cellStruct*) malloc(sizeof(cellStruct) * m_NumCols);
214 for (int col = 0; col < m_NumCols; col++)
215 m_CellInfo[row][col].flag = cellFree;
216 }
5526e819 217 }
5526e819
VS
218 m_NumRows = rows;
219}
220
221
5526e819
VS
222void wxHtmlTableCell::AddRow(const wxHtmlTag& tag)
223{
5526e819 224 m_ActualCol = -1;
d361bbff
VS
225 // VS: real allocation of row entry is done in AddCell in order
226 // to correctly handle empty rows (i.e. "<tr></tr>")
227 // m_ActualCol == -1 indicates that AddCell has to allocate new row.
5526e819 228
d361bbff 229 // scan params:
5526e819 230 m_rBkg = m_tBkg;
04dbb646 231 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90 232 tag.GetParamAsColour(wxT("BGCOLOR"), &m_rBkg);
04dbb646
VZ
233 if (tag.HasParam(wxT("VALIGN")))
234 m_rValign = tag.GetParam(wxT("VALIGN"));
235 else
d361bbff 236 m_rValign = m_tValign;
5526e819
VS
237}
238
239
240
241void wxHtmlTableCell::AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag)
242{
d361bbff
VS
243 // Is this cell in new row?
244 // VS: we can't do it in AddRow, see my comment there
245 if (m_ActualCol == -1)
246 {
247 if (m_ActualRow + 1 > m_NumRows - 1)
248 ReallocRows(m_ActualRow + 2);
249 m_ActualRow++;
250 }
251
252 // cells & columns:
04dbb646 253 do
4f9297b0 254 {
5526e819 255 m_ActualCol++;
04dbb646 256 } while ((m_ActualCol < m_NumCols) &&
8bd72d90 257 (m_CellInfo[m_ActualRow][m_ActualCol].flag != cellFree));
04dbb646 258
5526e819
VS
259 if (m_ActualCol > m_NumCols - 1)
260 ReallocCols(m_ActualCol + 1);
261
262 int r = m_ActualRow, c = m_ActualCol;
263
264 m_CellInfo[r][c].cont = cell;
265 m_CellInfo[r][c].colspan = 1;
266 m_CellInfo[r][c].rowspan = 1;
267 m_CellInfo[r][c].flag = cellUsed;
268 m_CellInfo[r][c].minheight = 0;
efba2b89 269 m_CellInfo[r][c].valign = wxHTML_ALIGN_TOP;
5526e819
VS
270
271 /* scan for parameters: */
272
273 // width:
274 {
8bd72d90 275 if (tag.HasParam(wxT("WIDTH")))
2fa3b707 276 {
8bd72d90 277 wxString wd = tag.GetParam(wxT("WIDTH"));
5526e819 278
93763ad5 279 if (wd[wd.length()-1] == wxT('%'))
2fa3b707 280 {
66a77a74 281 wxSscanf(wd.c_str(), wxT("%i%%"), &m_ColsInfo[c].width);
efba2b89 282 m_ColsInfo[c].units = wxHTML_UNITS_PERCENT;
5526e819 283 }
04dbb646 284 else
2fa3b707 285 {
66a77a74 286 wxSscanf(wd.c_str(), wxT("%i"), &m_ColsInfo[c].width);
edbd0635 287 m_ColsInfo[c].width = (int)(m_PixelScale * (double)m_ColsInfo[c].width);
efba2b89 288 m_ColsInfo[c].units = wxHTML_UNITS_PIXELS;
5526e819
VS
289 }
290 }
291 }
292
293
294 // spanning:
295 {
8bd72d90
VS
296 tag.GetParamAsInt(wxT("COLSPAN"), &m_CellInfo[r][c].colspan);
297 tag.GetParamAsInt(wxT("ROWSPAN"), &m_CellInfo[r][c].rowspan);
fbe77cea
VS
298
299 // VS: the standard says this about col/rowspan:
25c71ccc
VZ
300 // "This attribute specifies the number of rows spanned by the
301 // current cell. The default value of this attribute is one ("1").
302 // The value zero ("0") means that the cell spans all rows from the
303 // current row to the last row of the table." All mainstream
fbe77cea 304 // browsers act as if 0==1, though, and so does wxHTML.
25c71ccc 305 if (m_CellInfo[r][c].colspan < 1)
fbe77cea 306 m_CellInfo[r][c].colspan = 1;
25c71ccc 307 if (m_CellInfo[r][c].rowspan < 1)
fbe77cea
VS
308 m_CellInfo[r][c].rowspan = 1;
309
310 if ((m_CellInfo[r][c].colspan > 1) || (m_CellInfo[r][c].rowspan > 1))
2fa3b707 311 {
5526e819
VS
312 int i, j;
313
04dbb646 314 if (r + m_CellInfo[r][c].rowspan > m_NumRows)
8bd72d90 315 ReallocRows(r + m_CellInfo[r][c].rowspan);
04dbb646 316 if (c + m_CellInfo[r][c].colspan > m_NumCols)
8bd72d90 317 ReallocCols(c + m_CellInfo[r][c].colspan);
5526e819
VS
318 for (i = r; i < r + m_CellInfo[r][c].rowspan; i++)
319 for (j = c; j < c + m_CellInfo[r][c].colspan; j++)
320 m_CellInfo[i][j].flag = cellSpan;
321 m_CellInfo[r][c].flag = cellUsed;
322 }
323 }
324
325 //background color:
326 {
8bd72d90 327 wxColour bk = m_rBkg;
04dbb646 328 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90
VS
329 tag.GetParamAsColour(wxT("BGCOLOR"), &bk);
330 if (bk.Ok())
331 cell->SetBackgroundColour(bk);
5526e819
VS
332 }
333 if (m_HasBorders)
4f9297b0 334 cell->SetBorder(TABLE_BORDER_CLR_2, TABLE_BORDER_CLR_1);
5526e819
VS
335
336 // vertical alignment:
337 {
338 wxString valign;
04dbb646
VZ
339 if (tag.HasParam(wxT("VALIGN")))
340 valign = tag.GetParam(wxT("VALIGN"));
341 else
8bd72d90 342 valign = m_tValign;
5526e819 343 valign.MakeUpper();
04dbb646 344 if (valign == wxT("TOP"))
8bd72d90 345 m_CellInfo[r][c].valign = wxHTML_ALIGN_TOP;
04dbb646 346 else if (valign == wxT("BOTTOM"))
8bd72d90 347 m_CellInfo[r][c].valign = wxHTML_ALIGN_BOTTOM;
efba2b89 348 else m_CellInfo[r][c].valign = wxHTML_ALIGN_CENTER;
5526e819
VS
349 }
350
ca16b7a9
VS
351 // nowrap
352 if (tag.HasParam(wxT("NOWRAP")))
353 m_CellInfo[r][c].nowrap = true;
354 else
355 m_CellInfo[r][c].nowrap = false;
356
4f9297b0 357 cell->SetIndent(m_Padding, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
5526e819
VS
358}
359
79d6c018
VS
360void wxHtmlTableCell::ComputeMinMaxWidths()
361{
d1da8872 362 if (m_NumCols == 0 || m_ColsInfo[0].minWidth != wxDefaultCoord) return;
25c71ccc 363
ca16b7a9
VS
364 m_MaxTotalWidth = 0;
365 int percentage = 0;
79d6c018
VS
366 for (int c = 0; c < m_NumCols; c++)
367 {
368 for (int r = 0; r < m_NumRows; r++)
369 {
370 cellStruct& cell = m_CellInfo[r][c];
371 if (cell.flag == cellUsed)
372 {
026d1fac 373 cell.cont->Layout(2*m_Padding + 1);
ca16b7a9
VS
374 int maxWidth = cell.cont->GetMaxTotalWidth();
375 int width = cell.nowrap?maxWidth:cell.cont->GetWidth();
026d1fac 376 width -= (cell.colspan-1) * m_Spacing;
ca16b7a9 377 maxWidth -= (cell.colspan-1) * m_Spacing;
79d6c018 378 // HTML 4.0 says it is acceptable to distribute min/max
79d6c018 379 width /= cell.colspan;
ca16b7a9
VS
380 maxWidth /= cell.colspan;
381 for (int j = 0; j < cell.colspan; j++) {
79d6c018
VS
382 if (width > m_ColsInfo[c+j].minWidth)
383 m_ColsInfo[c+j].minWidth = width;
ca16b7a9
VS
384 if (maxWidth > m_ColsInfo[c+j].maxWidth)
385 m_ColsInfo[c+j].maxWidth = maxWidth;
386 }
79d6c018
VS
387 }
388 }
ca16b7a9
VS
389 // Calculate maximum table width, required for nested tables
390 if (m_ColsInfo[c].units == wxHTML_UNITS_PIXELS)
391 m_MaxTotalWidth += wxMax(m_ColsInfo[c].width, m_ColsInfo[c].minWidth);
392 else if ((m_ColsInfo[c].units == wxHTML_UNITS_PERCENT) && (m_ColsInfo[c].width != 0))
393 percentage += m_ColsInfo[c].width;
394 else
395 m_MaxTotalWidth += m_ColsInfo[c].maxWidth;
79d6c018 396 }
5526e819 397
ca16b7a9
VS
398 if (percentage >= 100)
399 {
400 // Table would have infinite length
401 // Make it ridiculous large
402 m_MaxTotalWidth = 0xFFFFFF;
403 }
404 else
405 m_MaxTotalWidth = m_MaxTotalWidth * 100 / (100 - percentage);
406
407 m_MaxTotalWidth += (m_NumCols + 1) * m_Spacing;
408}
5526e819
VS
409
410void wxHtmlTableCell::Layout(int w)
411{
79d6c018 412 ComputeMinMaxWidths();
25c71ccc 413
026d1fac 414 wxHtmlCell::Layout(w);
79d6c018 415
5526e819
VS
416 /*
417
418 WIDTH ADJUSTING :
419
420 */
421
04dbb646 422 if (m_WidthFloatUnits == wxHTML_UNITS_PERCENT)
4f9297b0 423 {
ca16b7a9
VS
424 if (m_WidthFloat < 0)
425 {
426 if (m_WidthFloat < -100)
427 m_WidthFloat = -100;
428 m_Width = (100 + m_WidthFloat) * w / 100;
429 }
25c71ccc 430 else
ca16b7a9
VS
431 {
432 if (m_WidthFloat > 100)
433 m_WidthFloat = 100;
434 m_Width = m_WidthFloat * w / 100;
435 }
5526e819 436 }
04dbb646 437 else
4f9297b0 438 {
5526e819
VS
439 if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
440 else m_Width = m_WidthFloat;
441 }
442
443
444 /*
445
446 LAYOUTING :
447
448 */
449
25c71ccc
VZ
450 /* 1. setup columns widths:
451
ca16b7a9
VS
452 The algorithm tries to keep the table size less than w if possible.
453 */
5526e819
VS
454 {
455 int wpix = m_Width - (m_NumCols + 1) * m_Spacing;
456 int i, j;
5526e819
VS
457
458 // 1a. setup fixed-width columns:
459 for (i = 0; i < m_NumCols; i++)
efba2b89 460 if (m_ColsInfo[i].units == wxHTML_UNITS_PIXELS)
79d6c018 461 {
25c71ccc 462 m_ColsInfo[i].pixwidth = wxMax(m_ColsInfo[i].width,
79d6c018
VS
463 m_ColsInfo[i].minWidth);
464 wpix -= m_ColsInfo[i].pixwidth;
465 }
5526e819 466
ca16b7a9
VS
467 // 1b. Calculate maximum possible width if line wrapping would be disabled
468 // Recalculate total width if m_WidthFloat is zero to keep tables as small
469 // as possible.
470 int maxWidth = 0;
471 for (i = 0; i < m_NumCols; i++)
472 if (m_ColsInfo[i].width == 0)
473 {
474 maxWidth += m_ColsInfo[i].maxWidth;
475 }
476
477 if (!m_WidthFloat)
478 {
479 // Recalculate table width since no table width was initially given
480 int newWidth = m_Width - wpix + maxWidth;
481
482 // Make sure that floating-width columns will have the right size.
483 // Calculate sum of all floating-width columns
484 int percentage = 0;
485 for (i = 0; i < m_NumCols; i++)
486 if ((m_ColsInfo[i].units == wxHTML_UNITS_PERCENT) && (m_ColsInfo[i].width != 0))
487 percentage += m_ColsInfo[i].width;
488
489 if (percentage >= 100)
490 newWidth = w;
491 else
492 newWidth = newWidth * 100 / (100 - percentage);
25c71ccc 493
ca16b7a9
VS
494 newWidth = wxMin(newWidth, w - (m_NumCols + 1) * m_Spacing);
495 wpix -= m_Width - newWidth;
496 m_Width = newWidth;
497 }
25c71ccc 498
ca16b7a9
VS
499
500 // 1c. setup floating-width columns:
501 int wtemp = wpix;
5526e819 502 for (i = 0; i < m_NumCols; i++)
efba2b89 503 if ((m_ColsInfo[i].units == wxHTML_UNITS_PERCENT) && (m_ColsInfo[i].width != 0))
79d6c018 504 {
ca16b7a9
VS
505 m_ColsInfo[i].pixwidth = wxMin(m_ColsInfo[i].width, 100) * wpix / 100;
506
507 // Make sure to leave enough space for the other columns
508 int minRequired = 0;
509 for (j = 0; j < m_NumCols; j++)
510 {
511 if ((m_ColsInfo[j].units == wxHTML_UNITS_PERCENT && j > i) ||
512 !m_ColsInfo[j].width)
513 minRequired += m_ColsInfo[j].minWidth;
514 }
515 m_ColsInfo[i].pixwidth = wxMax(wxMin(wtemp - minRequired, m_ColsInfo[i].pixwidth), m_ColsInfo[i].minWidth);
516
517 wtemp -= m_ColsInfo[i].pixwidth;
79d6c018 518 }
ca16b7a9
VS
519 wpix = wtemp;
520
521 // 1d. setup default columns (no width specification supplied):
522 // The algorithm assigns calculates the maximum possible width if line
523 // wrapping would be disabled and assigns column width as a fraction
524 // based upon the maximum width of a column
525 // FIXME: I'm not sure if this algorithm is conform to HTML standard,
526 // though it seems to be much better than the old one
5526e819 527
5526e819
VS
528 for (i = j = 0; i < m_NumCols; i++)
529 if (m_ColsInfo[i].width == 0) j++;
ca16b7a9
VS
530 if (wpix < 0)
531 wpix = 0;
532
533 // Assign widths
5526e819
VS
534 for (i = 0; i < m_NumCols; i++)
535 if (m_ColsInfo[i].width == 0)
8c571f46 536 {
ca16b7a9
VS
537 // Assign with, make sure not to drop below minWidth
538 if (maxWidth)
25c71ccc 539 m_ColsInfo[i].pixwidth = (int)(wpix * (m_ColsInfo[i].maxWidth / (float)maxWidth) + 0.5);
ca16b7a9
VS
540 else
541 m_ColsInfo[i].pixwidth = wpix / j;
25c71ccc 542
ca16b7a9
VS
543 // Make sure to leave enough space for the other columns
544 int minRequired = 0;
545 int r;
546 for (r = i + 1; r < m_NumCols; r++)
547 {
548 if (!m_ColsInfo[r].width)
549 minRequired += m_ColsInfo[r].minWidth;
550 }
551 m_ColsInfo[i].pixwidth = wxMax(wxMin(wpix - minRequired, m_ColsInfo[i].pixwidth), m_ColsInfo[i].minWidth);
552
553 if (maxWidth)
554 {
555 if (m_ColsInfo[i].pixwidth > (wpix * (m_ColsInfo[i].maxWidth / (float)maxWidth) + 0.5))
556 {
25c71ccc 557 int diff = (int)(m_ColsInfo[i].pixwidth - (wpix * m_ColsInfo[i].maxWidth / (float)maxWidth + 0.5));
ca16b7a9
VS
558 maxWidth += diff - m_ColsInfo[i].maxWidth;
559 }
560 else
561 maxWidth -= m_ColsInfo[i].maxWidth;
562 }
563 wpix -= m_ColsInfo[i].pixwidth;
8c571f46 564 }
5526e819
VS
565 }
566
567 /* 2. compute positions of columns: */
568 {
569 int wpos = m_Spacing;
04dbb646 570 for (int i = 0; i < m_NumCols; i++)
2fa3b707 571 {
5526e819
VS
572 m_ColsInfo[i].leftpos = wpos;
573 wpos += m_ColsInfo[i].pixwidth + m_Spacing;
574 }
575 }
576
577 /* 3. sub-layout all cells: */
578 {
2776d7c3 579 int *ypos = new int[m_NumRows + 1];
5526e819
VS
580
581 int actcol, actrow;
582 int fullwid;
583 wxHtmlContainerCell *actcell;
584
2fa3b707
VS
585 ypos[0] = m_Spacing;
586 for (actrow = 1; actrow <= m_NumRows; actrow++) ypos[actrow] = -1;
04dbb646 587 for (actrow = 0; actrow < m_NumRows; actrow++)
2fa3b707
VS
588 {
589 if (ypos[actrow] == -1) ypos[actrow] = ypos[actrow-1];
5526e819
VS
590 // 3a. sub-layout and detect max height:
591
592 for (actcol = 0; actcol < m_NumCols; actcol++) {
593 if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
594 actcell = m_CellInfo[actrow][actcol].cont;
595 fullwid = 0;
596 for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
597 fullwid += m_ColsInfo[i].pixwidth;
a97a264f 598 fullwid += (m_CellInfo[actrow][actcol].colspan - 1) * m_Spacing;
4f9297b0
VS
599 actcell->SetMinHeight(m_CellInfo[actrow][actcol].minheight, m_CellInfo[actrow][actcol].valign);
600 actcell->Layout(fullwid);
5526e819 601
4f9297b0 602 if (ypos[actrow] + actcell->GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing > ypos[actrow + m_CellInfo[actrow][actcol].rowspan])
5526e819 603 ypos[actrow + m_CellInfo[actrow][actcol].rowspan] =
4f9297b0 604 ypos[actrow] + actcell->GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing;
5526e819
VS
605 }
606 }
607
04dbb646 608 for (actrow = 0; actrow < m_NumRows; actrow++)
2fa3b707 609 {
5526e819
VS
610 // 3b. place cells in row & let'em all have same height:
611
04dbb646 612 for (actcol = 0; actcol < m_NumCols; actcol++)
2fa3b707 613 {
5526e819
VS
614 if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
615 actcell = m_CellInfo[actrow][actcol].cont;
4f9297b0 616 actcell->SetMinHeight(
a97a264f 617 ypos[actrow + m_CellInfo[actrow][actcol].rowspan] - ypos[actrow] - m_Spacing,
5526e819
VS
618 m_CellInfo[actrow][actcol].valign);
619 fullwid = 0;
620 for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
621 fullwid += m_ColsInfo[i].pixwidth;
a97a264f 622 fullwid += (m_CellInfo[actrow][actcol].colspan - 1) * m_Spacing;
4f9297b0
VS
623 actcell->Layout(fullwid);
624 actcell->SetPos(m_ColsInfo[actcol].leftpos, ypos[actrow]);
5526e819 625 }
5526e819
VS
626 }
627 m_Height = ypos[m_NumRows];
2776d7c3 628 delete[] ypos;
5526e819 629 }
8c571f46
VS
630
631 /* 4. adjust table's width if it was too small: */
632 if (m_NumCols > 0)
633 {
25c71ccc 634 int twidth = m_ColsInfo[m_NumCols-1].leftpos +
8c571f46
VS
635 m_ColsInfo[m_NumCols-1].pixwidth + m_Spacing;
636 if (twidth > m_Width)
637 m_Width = twidth;
638 }
5526e819
VS
639}
640
641
642
643
644
645
646//-----------------------------------------------------------------------------
647// The tables handler:
648//-----------------------------------------------------------------------------
649
650
651TAG_HANDLER_BEGIN(TABLE, "TABLE,TR,TD,TH")
652
653 TAG_HANDLER_VARS
654 wxHtmlTableCell* m_Table;
655 wxString m_tAlign, m_rAlign;
5526e819
VS
656
657 TAG_HANDLER_CONSTR(TABLE)
658 {
659 m_Table = NULL;
01325161 660 m_tAlign = m_rAlign = wxEmptyString;
5526e819
VS
661 }
662
663
664 TAG_HANDLER_PROC(tag)
665 {
666 wxHtmlContainerCell *c;
667
668 // new table started, backup upper-level table (if any) and create new:
04dbb646 669 if (tag.GetName() == wxT("TABLE"))
2fa3b707 670 {
5526e819
VS
671 wxHtmlTableCell *oldt = m_Table;
672 wxHtmlContainerCell *oldcont;
5526e819 673
4f9297b0 674 oldcont = c = m_WParser->OpenContainer();
5526e819 675
ca16b7a9
VS
676 m_Table = new wxHtmlTableCell(c, tag);
677
678 // width:
679 {
680 if (tag.HasParam(wxT("WIDTH")))
681 {
682 wxString wd = tag.GetParam(wxT("WIDTH"));
683
93763ad5 684 if (wd[wd.length()-1] == wxT('%'))
ca16b7a9
VS
685 {
686 int width = 0;
687 wxSscanf(wd.c_str(), wxT("%i%%"), &width);
688 m_Table->SetWidthFloat(width, wxHTML_UNITS_PERCENT);
689 }
690 else
691 {
692 int width = 0;
693 wxSscanf(wd.c_str(), wxT("%i"), &width);
25c71ccc 694 m_Table->SetWidthFloat((int)(m_WParser->GetPixelScale() * width), wxHTML_UNITS_PIXELS);
ca16b7a9
VS
695 }
696 }
697 else
698 m_Table->SetWidthFloat(0, wxHTML_UNITS_PIXELS);
699 }
2755d437 700 int oldAlign = m_WParser->GetAlign();
5526e819 701 m_tAlign = wxEmptyString;
8bd72d90
VS
702 if (tag.HasParam(wxT("ALIGN")))
703 m_tAlign = tag.GetParam(wxT("ALIGN"));
5526e819
VS
704
705 ParseInner(tag);
706
2755d437 707 m_WParser->SetAlign(oldAlign);
4f9297b0
VS
708 m_WParser->SetContainer(oldcont);
709 m_WParser->CloseContainer();
25c71ccc 710
5526e819 711 m_Table = oldt;
d1da8872 712 return true;
5526e819
VS
713 }
714
715
211dfedd 716 else if (m_Table)
2fa3b707 717 {
5526e819 718 // new row in table
04dbb646 719 if (tag.GetName() == wxT("TR"))
2fa3b707 720 {
4f9297b0 721 m_Table->AddRow(tag);
5526e819 722 m_rAlign = m_tAlign;
04dbb646 723 if (tag.HasParam(wxT("ALIGN")))
8bd72d90 724 m_rAlign = tag.GetParam(wxT("ALIGN"));
5526e819
VS
725 }
726
727 // new cell
04dbb646 728 else
2fa3b707 729 {
4f9297b0
VS
730 c = m_WParser->SetContainer(new wxHtmlContainerCell(m_Table));
731 m_Table->AddCell(c, tag);
5526e819 732
4f9297b0 733 m_WParser->OpenContainer();
5526e819 734
04dbb646 735 if (tag.GetName() == wxT("TH")) /*header style*/
4f9297b0 736 m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
2755d437
VS
737 else
738 m_WParser->SetAlign(wxHTML_ALIGN_LEFT);
739
740 wxString als;
741
742 als = m_rAlign;
743 if (tag.HasParam(wxT("ALIGN")))
744 als = tag.GetParam(wxT("ALIGN"));
745 als.MakeUpper();
746 if (als == wxT("RIGHT"))
747 m_WParser->SetAlign(wxHTML_ALIGN_RIGHT);
748 else if (als == wxT("LEFT"))
749 m_WParser->SetAlign(wxHTML_ALIGN_LEFT);
750 else if (als == wxT("CENTER"))
751 m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
752
4f9297b0 753 m_WParser->OpenContainer();
5526e819
VS
754 }
755 }
d1da8872 756 return false;
5526e819
VS
757 }
758
759TAG_HANDLER_END(TABLE)
760
761
762
763
764
765TAGS_MODULE_BEGIN(Tables)
766
767 TAGS_MODULE_ADD(TABLE)
768
769TAGS_MODULE_END(Tables)
770
771
772#endif