1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/html/m_tables.cpp
3 // Purpose: wxHtml module for tables
4 // Author: Vaclav Slavik
6 // Copyright: (c) 1999 Vaclav Slavik
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #include "wx/wxprec.h"
16 #if wxUSE_HTML && wxUSE_STREAMS
19 #include "wx/wxcrtvararg.h"
23 #include "wx/html/forcelnk.h"
24 #include "wx/html/m_templ.h"
26 #include "wx/html/htmlcell.h"
28 FORCE_LINK_ME(m_tables
)
31 #define TABLE_BORDER_CLR_1 wxColour(0xC5, 0xC2, 0xC5)
32 #define TABLE_BORDER_CLR_2 wxColour(0x62, 0x61, 0x62)
35 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
43 // width of the column either in pixels or percents
44 // ('width' is the number, 'units' determines its meaning)
45 int minWidth
, maxWidth
;
46 // minimal/maximal column width. This is needed by HTML 4.0
47 // layout algorithm and can be determined by trying to
48 // layout table cells with width=1 and width=infinity
49 int leftpos
, pixwidth
, maxrealwidth
;
50 // temporary (depends on actual width of table)
62 wxHtmlContainerCell
*cont
;
64 int minheight
, valign
;
70 class wxHtmlTableCell
: public wxHtmlContainerCell
73 /* These are real attributes: */
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
83 // cells internal indentation
87 /* ...and these are valid only when parsing the table: */
89 // number of actual column (ranging from 0..m_NumCols)
90 int m_ActualCol
, m_ActualRow
;
92 // default values (for table and row):
93 wxColour m_tBkg
, m_rBkg
;
94 wxString m_tValign
, m_rValign
;
100 wxHtmlTableCell(wxHtmlContainerCell
*parent
, const wxHtmlTag
& tag
, double pixel_scale
= 1.0);
101 virtual ~wxHtmlTableCell();
103 virtual void RemoveExtraSpacing(bool top
, bool bottom
);
105 virtual void Layout(int w
);
107 void AddRow(const wxHtmlTag
& tag
);
108 void AddCell(wxHtmlContainerCell
*cell
, const wxHtmlTag
& tag
);
110 const wxColour
& GetRowDefaultBackgroundColour() const { return m_rBkg
; }
113 // Reallocates memory to given number of cols/rows
114 // and changes m_NumCols/m_NumRows value to reflect this change
115 // NOTE! You CAN'T change m_NumCols/m_NumRows before calling this!!
116 void ReallocCols(int cols
);
117 void ReallocRows(int rows
);
119 // Computes minimal and maximal widths of columns. Needs to be called
120 // only once, before first Layout().
121 void ComputeMinMaxWidths();
123 wxDECLARE_NO_COPY_CLASS(wxHtmlTableCell
);
128 wxHtmlTableCell::wxHtmlTableCell(wxHtmlContainerCell
*parent
, const wxHtmlTag
& tag
, double pixel_scale
)
129 : wxHtmlContainerCell(parent
)
131 m_PixelScale
= pixel_scale
;
133 m_NumCols
= m_NumRows
= 0;
135 m_ActualCol
= m_ActualRow
= -1;
138 if (tag
.HasParam(wxT("BGCOLOR")))
140 tag
.GetParamAsColour(wxT("BGCOLOR"), &m_tBkg
);
142 SetBackgroundColour(m_tBkg
);
144 if (tag
.HasParam(wxT("VALIGN")))
145 m_tValign
= tag
.GetParam(wxT("VALIGN"));
147 m_tValign
= wxEmptyString
;
148 if (!tag
.GetParamAsInt(wxT("CELLSPACING"), &m_Spacing
))
150 if (!tag
.GetParamAsInt(wxT("CELLPADDING"), &m_Padding
))
152 m_Spacing
= (int)(m_PixelScale
* (double)m_Spacing
);
153 m_Padding
= (int)(m_PixelScale
* (double)m_Padding
);
155 if(tag
.HasParam(wxT("BORDER")))
157 if(tag
.GetParam("BORDER").IsEmpty())
160 tag
.GetParamAsInt(wxT("BORDER"), &m_Border
);
163 SetBorder(TABLE_BORDER_CLR_1
, TABLE_BORDER_CLR_2
, m_Border
); // special case see wxHtmlContainerCell::Draw
164 else if (m_Border
> 0)
165 SetBorder(TABLE_BORDER_CLR_1
, TABLE_BORDER_CLR_2
, (int)(m_PixelScale
* (double)m_Border
));
173 wxHtmlTableCell::~wxHtmlTableCell()
175 if (m_ColsInfo
) free(m_ColsInfo
);
178 for (int i
= 0; i
< m_NumRows
; i
++)
185 void wxHtmlTableCell::RemoveExtraSpacing(bool WXUNUSED(top
),
186 bool WXUNUSED(bottom
))
188 // Don't remove any spacing in the table -- it's always desirable,
189 // because it's part of table's definition.
190 // (If wxHtmlContainerCell::RemoveExtraSpacing() was applied to tables,
191 // then upper left cell of a table would be positioned above other cells
192 // if the table was the first element on the page.)
195 void wxHtmlTableCell::ReallocCols(int cols
)
199 for (i
= 0; i
< m_NumRows
; i
++)
201 m_CellInfo
[i
] = (cellStruct
*) realloc(m_CellInfo
[i
], sizeof(cellStruct
) * cols
);
202 for (j
= m_NumCols
; j
< cols
; j
++)
203 m_CellInfo
[i
][j
].flag
= cellFree
;
206 m_ColsInfo
= (colStruct
*) realloc(m_ColsInfo
, sizeof(colStruct
) * cols
);
207 for (j
= m_NumCols
; j
< cols
; j
++)
209 m_ColsInfo
[j
].width
= 0;
210 m_ColsInfo
[j
].units
= wxHTML_UNITS_PERCENT
;
211 m_ColsInfo
[j
].minWidth
= m_ColsInfo
[j
].maxWidth
= -1;
219 void wxHtmlTableCell::ReallocRows(int rows
)
221 m_CellInfo
= (cellStruct
**) realloc(m_CellInfo
, sizeof(cellStruct
*) * rows
);
222 for (int row
= m_NumRows
; row
< rows
; row
++)
225 m_CellInfo
[row
] = NULL
;
228 m_CellInfo
[row
] = (cellStruct
*) malloc(sizeof(cellStruct
) * m_NumCols
);
229 for (int col
= 0; col
< m_NumCols
; col
++)
230 m_CellInfo
[row
][col
].flag
= cellFree
;
237 void wxHtmlTableCell::AddRow(const wxHtmlTag
& tag
)
240 // VS: real allocation of row entry is done in AddCell in order
241 // to correctly handle empty rows (i.e. "<tr></tr>")
242 // m_ActualCol == -1 indicates that AddCell has to allocate new row.
246 if (tag
.HasParam(wxT("BGCOLOR")))
247 tag
.GetParamAsColour(wxT("BGCOLOR"), &m_rBkg
);
248 if (tag
.HasParam(wxT("VALIGN")))
249 m_rValign
= tag
.GetParam(wxT("VALIGN"));
251 m_rValign
= m_tValign
;
256 void wxHtmlTableCell::AddCell(wxHtmlContainerCell
*cell
, const wxHtmlTag
& tag
)
258 // Is this cell in new row?
259 // VS: we can't do it in AddRow, see my comment there
260 if (m_ActualCol
== -1)
262 if (m_ActualRow
+ 1 > m_NumRows
- 1)
263 ReallocRows(m_ActualRow
+ 2);
271 } while ((m_ActualCol
< m_NumCols
) &&
272 (m_CellInfo
[m_ActualRow
][m_ActualCol
].flag
!= cellFree
));
274 if (m_ActualCol
> m_NumCols
- 1)
275 ReallocCols(m_ActualCol
+ 1);
277 int r
= m_ActualRow
, c
= m_ActualCol
;
279 m_CellInfo
[r
][c
].cont
= cell
;
280 m_CellInfo
[r
][c
].colspan
= 1;
281 m_CellInfo
[r
][c
].rowspan
= 1;
282 m_CellInfo
[r
][c
].flag
= cellUsed
;
283 m_CellInfo
[r
][c
].minheight
= 0;
284 m_CellInfo
[r
][c
].valign
= wxHTML_ALIGN_TOP
;
286 /* scan for parameters: */
290 if (tag
.HasParam(wxT("WIDTH")))
292 wxString wd
= tag
.GetParam(wxT("WIDTH"));
294 if (!wd
.empty() && wd
[wd
.length()-1] == wxT('%'))
296 if ( wxSscanf(wd
.c_str(), wxT("%i%%"), &m_ColsInfo
[c
].width
) == 1 )
298 m_ColsInfo
[c
].units
= wxHTML_UNITS_PERCENT
;
304 if ( wd
.ToLong(&width
) )
306 m_ColsInfo
[c
].width
= (int)(m_PixelScale
* (double)width
);
307 m_ColsInfo
[c
].units
= wxHTML_UNITS_PIXELS
;
316 tag
.GetParamAsInt(wxT("COLSPAN"), &m_CellInfo
[r
][c
].colspan
);
317 tag
.GetParamAsInt(wxT("ROWSPAN"), &m_CellInfo
[r
][c
].rowspan
);
319 // VS: the standard says this about col/rowspan:
320 // "This attribute specifies the number of rows spanned by the
321 // current cell. The default value of this attribute is one ("1").
322 // The value zero ("0") means that the cell spans all rows from the
323 // current row to the last row of the table." All mainstream
324 // browsers act as if 0==1, though, and so does wxHTML.
325 if (m_CellInfo
[r
][c
].colspan
< 1)
326 m_CellInfo
[r
][c
].colspan
= 1;
327 if (m_CellInfo
[r
][c
].rowspan
< 1)
328 m_CellInfo
[r
][c
].rowspan
= 1;
330 if ((m_CellInfo
[r
][c
].colspan
> 1) || (m_CellInfo
[r
][c
].rowspan
> 1))
334 if (r
+ m_CellInfo
[r
][c
].rowspan
> m_NumRows
)
335 ReallocRows(r
+ m_CellInfo
[r
][c
].rowspan
);
336 if (c
+ m_CellInfo
[r
][c
].colspan
> m_NumCols
)
337 ReallocCols(c
+ m_CellInfo
[r
][c
].colspan
);
338 for (i
= r
; i
< r
+ m_CellInfo
[r
][c
].rowspan
; i
++)
339 for (j
= c
; j
< c
+ m_CellInfo
[r
][c
].colspan
; j
++)
340 m_CellInfo
[i
][j
].flag
= cellSpan
;
341 m_CellInfo
[r
][c
].flag
= cellUsed
;
347 wxColour bk
= m_rBkg
;
348 if (tag
.HasParam(wxT("BGCOLOR")))
349 tag
.GetParamAsColour(wxT("BGCOLOR"), &bk
);
351 cell
->SetBackgroundColour(bk
);
354 cell
->SetBorder(TABLE_BORDER_CLR_2
, TABLE_BORDER_CLR_1
);
356 // vertical alignment:
359 if (tag
.HasParam(wxT("VALIGN")))
360 valign
= tag
.GetParam(wxT("VALIGN"));
364 if (valign
== wxT("TOP"))
365 m_CellInfo
[r
][c
].valign
= wxHTML_ALIGN_TOP
;
366 else if (valign
== wxT("BOTTOM"))
367 m_CellInfo
[r
][c
].valign
= wxHTML_ALIGN_BOTTOM
;
368 else m_CellInfo
[r
][c
].valign
= wxHTML_ALIGN_CENTER
;
372 if (tag
.HasParam(wxT("NOWRAP")))
373 m_CellInfo
[r
][c
].nowrap
= true;
375 m_CellInfo
[r
][c
].nowrap
= false;
377 cell
->SetIndent(m_Padding
, wxHTML_INDENT_ALL
, wxHTML_UNITS_PIXELS
);
380 void wxHtmlTableCell::ComputeMinMaxWidths()
382 if (m_NumCols
== 0 || m_ColsInfo
[0].minWidth
!= wxDefaultCoord
) return;
386 for (int c
= 0; c
< m_NumCols
; c
++)
388 for (int r
= 0; r
< m_NumRows
; r
++)
390 cellStruct
& cell
= m_CellInfo
[r
][c
];
391 if (cell
.flag
== cellUsed
)
393 cell
.cont
->Layout(2*m_Padding
+ 1);
394 int maxWidth
= cell
.cont
->GetMaxTotalWidth();
395 int width
= cell
.nowrap
?maxWidth
:cell
.cont
->GetWidth();
396 width
-= (cell
.colspan
-1) * m_Spacing
;
397 maxWidth
-= (cell
.colspan
-1) * m_Spacing
;
398 // HTML 4.0 says it is acceptable to distribute min/max
399 width
/= cell
.colspan
;
400 maxWidth
/= cell
.colspan
;
401 for (int j
= 0; j
< cell
.colspan
; j
++) {
402 if (width
> m_ColsInfo
[c
+j
].minWidth
)
403 m_ColsInfo
[c
+j
].minWidth
= width
;
404 if (maxWidth
> m_ColsInfo
[c
+j
].maxWidth
)
405 m_ColsInfo
[c
+j
].maxWidth
= maxWidth
;
409 // Calculate maximum table width, required for nested tables
410 if (m_ColsInfo
[c
].units
== wxHTML_UNITS_PIXELS
)
411 m_MaxTotalWidth
+= wxMax(m_ColsInfo
[c
].width
, m_ColsInfo
[c
].minWidth
);
412 else if ((m_ColsInfo
[c
].units
== wxHTML_UNITS_PERCENT
) && (m_ColsInfo
[c
].width
!= 0))
413 percentage
+= m_ColsInfo
[c
].width
;
415 m_MaxTotalWidth
+= m_ColsInfo
[c
].maxWidth
;
418 if (percentage
>= 100)
420 // Table would have infinite length
421 // Make it ridiculous large
422 m_MaxTotalWidth
= 0xFFFFFF;
425 m_MaxTotalWidth
= m_MaxTotalWidth
* 100 / (100 - percentage
);
427 m_MaxTotalWidth
+= (m_NumCols
+ 1) * m_Spacing
+ 2 * m_Border
;
430 void wxHtmlTableCell::Layout(int w
)
432 ComputeMinMaxWidths();
434 wxHtmlCell::Layout(w
);
442 if (m_WidthFloatUnits
== wxHTML_UNITS_PERCENT
)
444 if (m_WidthFloat
< 0)
446 if (m_WidthFloat
< -100)
448 m_Width
= (100 + m_WidthFloat
) * w
/ 100;
452 if (m_WidthFloat
> 100)
454 m_Width
= m_WidthFloat
* w
/ 100;
459 if (m_WidthFloat
< 0) m_Width
= w
+ m_WidthFloat
;
460 else m_Width
= m_WidthFloat
;
470 /* 1. setup columns widths:
472 The algorithm tries to keep the table size less than w if possible.
475 int wpix
= m_Width
- (m_NumCols
+ 1) * m_Spacing
- 2 * m_Border
; // Available space for cell content
478 // 1a. setup fixed-width columns:
479 for (i
= 0; i
< m_NumCols
; i
++)
480 if (m_ColsInfo
[i
].units
== wxHTML_UNITS_PIXELS
)
482 m_ColsInfo
[i
].pixwidth
= wxMax(m_ColsInfo
[i
].width
,
483 m_ColsInfo
[i
].minWidth
);
484 wpix
-= m_ColsInfo
[i
].pixwidth
;
487 // 1b. Calculate maximum possible width if line wrapping would be disabled
488 // Recalculate total width if m_WidthFloat is zero to keep tables as small
491 for (i
= 0; i
< m_NumCols
; i
++)
492 if (m_ColsInfo
[i
].width
== 0)
494 maxWidth
+= m_ColsInfo
[i
].maxWidth
;
499 // Recalculate table width since no table width was initially given
500 int newWidth
= m_Width
- wpix
+ maxWidth
;
502 // Make sure that floating-width columns will have the right size.
503 // Calculate sum of all floating-width columns
505 for (i
= 0; i
< m_NumCols
; i
++)
506 if ((m_ColsInfo
[i
].units
== wxHTML_UNITS_PERCENT
) && (m_ColsInfo
[i
].width
!= 0))
507 percentage
+= m_ColsInfo
[i
].width
;
509 if (percentage
>= 100)
512 newWidth
= newWidth
* 100 / (100 - percentage
);
514 newWidth
= wxMin(newWidth
, w
- (m_NumCols
+ 1) * m_Spacing
- 2 * m_Border
);
515 wpix
-= m_Width
- newWidth
;
520 // 1c. setup floating-width columns:
522 for (i
= 0; i
< m_NumCols
; i
++)
523 if ((m_ColsInfo
[i
].units
== wxHTML_UNITS_PERCENT
) && (m_ColsInfo
[i
].width
!= 0))
525 m_ColsInfo
[i
].pixwidth
= wxMin(m_ColsInfo
[i
].width
, 100) * wpix
/ 100;
527 // Make sure to leave enough space for the other columns
528 int minRequired
= m_Border
;
529 for (j
= 0; j
< m_NumCols
; j
++)
531 if ((m_ColsInfo
[j
].units
== wxHTML_UNITS_PERCENT
&& j
> i
) ||
532 !m_ColsInfo
[j
].width
)
533 minRequired
+= m_ColsInfo
[j
].minWidth
;
535 m_ColsInfo
[i
].pixwidth
= wxMax(wxMin(wtemp
- minRequired
, m_ColsInfo
[i
].pixwidth
), m_ColsInfo
[i
].minWidth
);
537 wtemp
-= m_ColsInfo
[i
].pixwidth
;
539 wpix
= wtemp
; // minimum cells width
541 // 1d. setup default columns (no width specification supplied):
542 // The algorithm assigns calculates the maximum possible width if line
543 // wrapping would be disabled and assigns column width as a fraction
544 // based upon the maximum width of a column
545 // FIXME: I'm not sure if this algorithm is conform to HTML standard,
546 // though it seems to be much better than the old one
548 for (i
= j
= 0; i
< m_NumCols
; i
++)
549 if (m_ColsInfo
[i
].width
== 0) j
++;
554 for (i
= 0; i
< m_NumCols
; i
++)
555 if (m_ColsInfo
[i
].width
== 0)
557 // Assign with, make sure not to drop below minWidth
559 m_ColsInfo
[i
].pixwidth
= (int)(wpix
* (m_ColsInfo
[i
].maxWidth
/ (float)maxWidth
) + 0.5);
561 m_ColsInfo
[i
].pixwidth
= wpix
/ j
;
563 // Make sure to leave enough space for the other columns
566 for (r
= i
+ 1; r
< m_NumCols
; r
++)
568 if (!m_ColsInfo
[r
].width
)
569 minRequired
+= m_ColsInfo
[r
].minWidth
;
571 m_ColsInfo
[i
].pixwidth
= wxMax(wxMin(wpix
- minRequired
, m_ColsInfo
[i
].pixwidth
), m_ColsInfo
[i
].minWidth
);
575 if (m_ColsInfo
[i
].pixwidth
> (wpix
* (m_ColsInfo
[i
].maxWidth
/ (float)maxWidth
) + 0.5))
577 int diff
= (int)(m_ColsInfo
[i
].pixwidth
- (wpix
* m_ColsInfo
[i
].maxWidth
/ (float)maxWidth
+ 0.5));
578 maxWidth
+= diff
- m_ColsInfo
[i
].maxWidth
;
581 maxWidth
-= m_ColsInfo
[i
].maxWidth
;
583 wpix
-= m_ColsInfo
[i
].pixwidth
;
587 /* 2. compute positions of columns: */
589 int wpos
= m_Spacing
+ m_Border
;
590 for (int i
= 0; i
< m_NumCols
; i
++)
592 m_ColsInfo
[i
].leftpos
= wpos
;
593 wpos
+= m_ColsInfo
[i
].pixwidth
+ m_Spacing
;
596 // add the remaining space to the last column
597 if (m_NumCols
> 0 && wpos
< m_Width
- m_Border
)
598 m_ColsInfo
[m_NumCols
-1].pixwidth
+= m_Width
- wpos
- m_Border
;
601 /* 3. sub-layout all cells: */
603 int *ypos
= new int[m_NumRows
+ 1];
607 wxHtmlContainerCell
*actcell
;
609 ypos
[0] = m_Spacing
+ m_Border
;
610 for (actrow
= 1; actrow
<= m_NumRows
; actrow
++) ypos
[actrow
] = -1;
611 for (actrow
= 0; actrow
< m_NumRows
; actrow
++)
613 if (ypos
[actrow
] == -1) ypos
[actrow
] = ypos
[actrow
-1];
614 // 3a. sub-layout and detect max height:
616 for (actcol
= 0; actcol
< m_NumCols
; actcol
++) {
617 if (m_CellInfo
[actrow
][actcol
].flag
!= cellUsed
) continue;
618 actcell
= m_CellInfo
[actrow
][actcol
].cont
;
620 for (int i
= actcol
; i
< m_CellInfo
[actrow
][actcol
].colspan
+ actcol
; i
++)
621 fullwid
+= m_ColsInfo
[i
].pixwidth
;
622 fullwid
+= (m_CellInfo
[actrow
][actcol
].colspan
- 1) * m_Spacing
;
623 actcell
->SetMinHeight(m_CellInfo
[actrow
][actcol
].minheight
, m_CellInfo
[actrow
][actcol
].valign
);
624 actcell
->Layout(fullwid
);
626 if (ypos
[actrow
] + actcell
->GetHeight() + m_CellInfo
[actrow
][actcol
].rowspan
* m_Spacing
> ypos
[actrow
+ m_CellInfo
[actrow
][actcol
].rowspan
])
627 ypos
[actrow
+ m_CellInfo
[actrow
][actcol
].rowspan
] =
628 ypos
[actrow
] + actcell
->GetHeight() + m_CellInfo
[actrow
][actcol
].rowspan
* m_Spacing
;
632 for (actrow
= 0; actrow
< m_NumRows
; actrow
++)
634 // 3b. place cells in row & let'em all have same height:
636 for (actcol
= 0; actcol
< m_NumCols
; actcol
++)
638 if (m_CellInfo
[actrow
][actcol
].flag
!= cellUsed
) continue;
639 actcell
= m_CellInfo
[actrow
][actcol
].cont
;
640 actcell
->SetMinHeight(
641 ypos
[actrow
+ m_CellInfo
[actrow
][actcol
].rowspan
] - ypos
[actrow
] - m_Spacing
,
642 m_CellInfo
[actrow
][actcol
].valign
);
644 for (int i
= actcol
; i
< m_CellInfo
[actrow
][actcol
].colspan
+ actcol
; i
++)
645 fullwid
+= m_ColsInfo
[i
].pixwidth
;
646 fullwid
+= (m_CellInfo
[actrow
][actcol
].colspan
- 1) * m_Spacing
;
647 actcell
->Layout(fullwid
);
648 actcell
->SetPos(m_ColsInfo
[actcol
].leftpos
, ypos
[actrow
]);
651 m_Height
= ypos
[m_NumRows
] + m_Border
;
655 /* 4. adjust table's width if it was too small: */
658 int twidth
= m_ColsInfo
[m_NumCols
-1].leftpos
+
659 m_ColsInfo
[m_NumCols
-1].pixwidth
+ m_Spacing
+ m_Border
;
660 if (twidth
> m_Width
)
670 //-----------------------------------------------------------------------------
671 // The tables handler:
672 //-----------------------------------------------------------------------------
675 TAG_HANDLER_BEGIN(TABLE
, "TABLE,TR,TD,TH")
678 wxHtmlTableCell
* m_Table
;
679 wxString m_tAlign
, m_rAlign
;
680 wxHtmlContainerCell
*m_enclosingContainer
;
682 // Call ParseInner() preserving background colour and mode after any
683 // changes done by it.
684 void CallParseInnerWithBg(const wxHtmlTag
& tag
, const wxColour
& colBg
)
686 const wxColour oldbackclr
= m_WParser
->GetActualBackgroundColor();
687 const int oldbackmode
= m_WParser
->GetActualBackgroundMode();
690 m_WParser
->SetActualBackgroundColor(colBg
);
691 m_WParser
->SetActualBackgroundMode(wxBRUSHSTYLE_SOLID
);
692 m_WParser
->GetContainer()->InsertCell(
693 new wxHtmlColourCell(colBg
, wxHTML_CLR_BACKGROUND
)
699 if ( oldbackmode
!= m_WParser
->GetActualBackgroundMode() ||
700 oldbackclr
!= m_WParser
->GetActualBackgroundColor() )
702 m_WParser
->SetActualBackgroundMode(oldbackmode
);
703 m_WParser
->SetActualBackgroundColor(oldbackclr
);
704 m_WParser
->GetContainer()->InsertCell(
705 new wxHtmlColourCell(oldbackclr
,
706 oldbackmode
== wxBRUSHSTYLE_TRANSPARENT
707 ? wxHTML_CLR_TRANSPARENT_BACKGROUND
708 : wxHTML_CLR_BACKGROUND
)
713 TAG_HANDLER_CONSTR(TABLE
)
716 m_enclosingContainer
= NULL
;
717 m_tAlign
= m_rAlign
= wxEmptyString
;
721 TAG_HANDLER_PROC(tag
)
723 wxHtmlContainerCell
*c
;
725 // new table started, backup upper-level table (if any) and create new:
726 if (tag
.GetName() == wxT("TABLE"))
728 wxHtmlTableCell
*oldt
= m_Table
;
730 wxHtmlContainerCell
*oldEnclosing
= m_enclosingContainer
;
731 m_enclosingContainer
= c
= m_WParser
->OpenContainer();
733 m_Table
= new wxHtmlTableCell(c
, tag
, m_WParser
->GetPixelScale());
737 if (tag
.HasParam(wxT("WIDTH")))
740 bool wpercent
= false;
741 if (tag
.GetParamAsIntOrPercent(wxT("WIDTH"), &width
, wpercent
))
745 m_Table
->SetWidthFloat(width
, wxHTML_UNITS_PERCENT
);
749 m_Table
->SetWidthFloat((int)(m_WParser
->GetPixelScale() * width
), wxHTML_UNITS_PIXELS
);
754 m_Table
->SetWidthFloat(0, wxHTML_UNITS_PIXELS
);
756 int oldAlign
= m_WParser
->GetAlign();
757 m_tAlign
= wxEmptyString
;
758 if (tag
.HasParam(wxT("ALIGN")))
759 m_tAlign
= tag
.GetParam(wxT("ALIGN"));
761 CallParseInnerWithBg(tag
, m_Table
->GetBackgroundColour());
763 m_WParser
->SetAlign(oldAlign
);
764 m_WParser
->SetContainer(m_enclosingContainer
);
765 m_WParser
->CloseContainer();
768 m_enclosingContainer
= oldEnclosing
;
770 return true; // ParseInner() called
777 if (tag
.GetName() == wxT("TR"))
779 m_Table
->AddRow(tag
);
781 if (tag
.HasParam(wxT("ALIGN")))
782 m_rAlign
= tag
.GetParam(wxT("ALIGN"));
788 c
= m_WParser
->SetContainer(new wxHtmlContainerCell(m_Table
));
789 m_Table
->AddCell(c
, tag
);
791 m_WParser
->OpenContainer();
793 const bool isHeader
= tag
.GetName() == wxT("TH");
796 if (tag
.HasParam(wxT("ALIGN")))
797 als
= tag
.GetParam(wxT("ALIGN"));
802 if (als
== wxT("RIGHT"))
803 m_WParser
->SetAlign(wxHTML_ALIGN_RIGHT
);
804 else if (als
== wxT("LEFT"))
805 m_WParser
->SetAlign(wxHTML_ALIGN_LEFT
);
806 else if (als
== wxT("CENTER"))
807 m_WParser
->SetAlign(wxHTML_ALIGN_CENTER
);
808 else // use default alignment
809 m_WParser
->SetAlign(isHeader
? wxHTML_ALIGN_CENTER
810 : wxHTML_ALIGN_LEFT
);
812 m_WParser
->OpenContainer();
814 // the header should be rendered in bold by default
818 boldOld
= m_WParser
->GetFontBold();
819 m_WParser
->SetFontBold(true);
820 m_WParser
->GetContainer()->InsertCell(
821 new wxHtmlFontCell(m_WParser
->CreateCurrentFont()));
825 if ( !tag
.GetParamAsColour(wxT("BGCOLOR"), &bgCol
) )
826 bgCol
= m_Table
->GetRowDefaultBackgroundColour();
828 CallParseInnerWithBg(tag
, bgCol
);
832 m_WParser
->SetFontBold(boldOld
);
833 m_WParser
->GetContainer()->InsertCell(
834 new wxHtmlFontCell(m_WParser
->CreateCurrentFont()));
837 // set the current container back to the enclosing one so that
838 // text outside of <th> and <td> isn't included in any cell
839 // (this happens often enough in practice because it's common
840 // to use whitespace between </td> and the next <td>):
841 m_WParser
->SetContainer(m_enclosingContainer
);
843 return true; // ParseInner() called
850 TAG_HANDLER_END(TABLE
)
856 TAGS_MODULE_BEGIN(Tables
)
858 TAGS_MODULE_ADD(TABLE
)
860 TAGS_MODULE_END(Tables
)