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