]>
git.saurik.com Git - wxWidgets.git/blob - src/html/m_tables.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxHtml module for tables
4 // Author: Vaclav Slavik
6 // Copyright: (c) 1999 Vaclav Slavik
7 // Licence: wxWindows Licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation
14 #include "wx/wxprec.h"
17 #if wxUSE_HTML && wxUSE_STREAMS
28 1. This version of m_tables doesn't support auto-layout algorithm.
29 This means that all columns are of same width unless explicitly specified.
33 #include "wx/html/forcelnk.h"
34 #include "wx/html/m_templ.h"
36 #include "wx/html/htmlcell.h"
38 FORCE_LINK_ME(m_tables
)
41 #define TABLE_BORDER_CLR_1 wxColour(0xC5, 0xC2, 0xC5)
42 #define TABLE_BORDER_CLR_2 wxColour(0x62, 0x61, 0x62)
45 //-----------------------------------------------------------------------------
47 //-----------------------------------------------------------------------------
53 int leftpos
, pixwidth
, maxrealwidth
;
54 // temporary (depends on width of table)
64 wxHtmlContainerCell
*cont
;
66 int minheight
, valign
;
71 class wxHtmlTableCell
: public wxHtmlContainerCell
74 /* These are real attributes: */
76 // should we draw borders or not?
77 int m_NumCols
, m_NumRows
;
78 // number of columns; rows
79 colStruct
*m_ColsInfo
;
80 // array of column information
81 cellStruct
**m_CellInfo
;
82 // 2D array of all cells in the table : m_CellInfo[row][column]
84 // spaces between cells
86 // cells internal indentation
89 /* ...and these are valid only during parsing of table: */
90 int m_ActualCol
, m_ActualRow
;
91 // number of actual column (ranging from 0..m_NumCols)
93 // default values (for table and row):
94 wxColour m_tBkg
, m_rBkg
;
95 wxString m_tValign
, m_rValign
;
101 wxHtmlTableCell(wxHtmlContainerCell
*parent
, const wxHtmlTag
& tag
, double pixel_scale
= 1.0);
103 virtual void Layout(int w
);
105 void AddRow(const wxHtmlTag
& tag
);
106 void AddCell(wxHtmlContainerCell
*cell
, const wxHtmlTag
& tag
);
108 void ReallocCols(int cols
);
109 void ReallocRows(int rows
);
110 // reallocates memory to given number of cols/rows
111 // and changes m_NumCols/m_NumRows value to reflect this change
112 // NOTE! You CAN'T change m_NumCols/m_NumRows before calling this!!
117 wxHtmlTableCell::wxHtmlTableCell(wxHtmlContainerCell
*parent
, const wxHtmlTag
& tag
, double pixel_scale
)
118 : wxHtmlContainerCell(parent
)
120 m_PixelScale
= pixel_scale
;
122 (tag
.HasParam(wxT("BORDER")) && tag
.GetParam(wxT("BORDER")) != wxT("0"));
124 m_NumCols
= m_NumRows
= 0;
126 m_ActualCol
= m_ActualRow
= -1;
129 if (tag
.HasParam(wxT("BGCOLOR")))
130 tag
.GetParamAsColour(wxT("BGCOLOR"), &m_tBkg
);
131 if (tag
.HasParam(wxT("VALIGN")))
132 m_tValign
= tag
.GetParam(wxT("VALIGN"));
134 m_tValign
= wxEmptyString
;
135 if (!tag
.GetParamAsInt(wxT("CELLSPACING"), &m_Spacing
))
137 if (!tag
.GetParamAsInt(wxT("CELLPADDING"), &m_Padding
))
139 m_Spacing
= (int)(m_PixelScale
* (double)m_Spacing
);
140 m_Padding
= (int)(m_PixelScale
* (double)m_Padding
);
143 SetBorder(TABLE_BORDER_CLR_1
, TABLE_BORDER_CLR_2
);
148 wxHtmlTableCell::~wxHtmlTableCell()
150 if (m_ColsInfo
) free(m_ColsInfo
);
153 for (int i
= 0; i
< m_NumRows
; i
++)
161 void wxHtmlTableCell::ReallocCols(int cols
)
165 for (i
= 0; i
< m_NumRows
; i
++)
167 m_CellInfo
[i
] = (cellStruct
*) realloc(m_CellInfo
[i
], sizeof(cellStruct
) * cols
);
168 for (j
= m_NumCols
; j
< cols
; j
++)
169 m_CellInfo
[i
][j
].flag
= cellFree
;
172 m_ColsInfo
= (colStruct
*) realloc(m_ColsInfo
, sizeof(colStruct
) * cols
);
173 for (j
= m_NumCols
; j
< cols
; j
++)
175 m_ColsInfo
[j
].width
= 0;
176 m_ColsInfo
[j
].units
= wxHTML_UNITS_PERCENT
;
184 void wxHtmlTableCell::ReallocRows(int rows
)
186 m_CellInfo
= (cellStruct
**) realloc(m_CellInfo
, sizeof(cellStruct
*) * rows
);
187 for (int row
= m_NumRows
; row
< rows
; row
++)
190 m_CellInfo
[row
] = NULL
;
193 m_CellInfo
[row
] = (cellStruct
*) malloc(sizeof(cellStruct
) * m_NumCols
);
194 for (int col
= 0; col
< m_NumCols
; col
++)
195 m_CellInfo
[row
][col
].flag
= cellFree
;
202 void wxHtmlTableCell::AddRow(const wxHtmlTag
& tag
)
205 // VS: real allocation of row entry is done in AddCell in order
206 // to correctly handle empty rows (i.e. "<tr></tr>")
207 // m_ActualCol == -1 indicates that AddCell has to allocate new row.
211 if (tag
.HasParam(wxT("BGCOLOR")))
212 tag
.GetParamAsColour(wxT("BGCOLOR"), &m_rBkg
);
213 if (tag
.HasParam(wxT("VALIGN")))
214 m_rValign
= tag
.GetParam(wxT("VALIGN"));
216 m_rValign
= m_tValign
;
221 void wxHtmlTableCell::AddCell(wxHtmlContainerCell
*cell
, const wxHtmlTag
& tag
)
223 // Is this cell in new row?
224 // VS: we can't do it in AddRow, see my comment there
225 if (m_ActualCol
== -1)
227 if (m_ActualRow
+ 1 > m_NumRows
- 1)
228 ReallocRows(m_ActualRow
+ 2);
236 } while ((m_ActualCol
< m_NumCols
) &&
237 (m_CellInfo
[m_ActualRow
][m_ActualCol
].flag
!= cellFree
));
239 if (m_ActualCol
> m_NumCols
- 1)
240 ReallocCols(m_ActualCol
+ 1);
242 int r
= m_ActualRow
, c
= m_ActualCol
;
244 m_CellInfo
[r
][c
].cont
= cell
;
245 m_CellInfo
[r
][c
].colspan
= 1;
246 m_CellInfo
[r
][c
].rowspan
= 1;
247 m_CellInfo
[r
][c
].flag
= cellUsed
;
248 m_CellInfo
[r
][c
].minheight
= 0;
249 m_CellInfo
[r
][c
].valign
= wxHTML_ALIGN_TOP
;
251 /* scan for parameters: */
255 if (tag
.HasParam(wxT("WIDTH")))
257 wxString wd
= tag
.GetParam(wxT("WIDTH"));
259 if (wd
[wd
.Length()-1] == wxT('%'))
261 wxSscanf(wd
.c_str(), wxT("%i%%"), &m_ColsInfo
[c
].width
);
262 m_ColsInfo
[c
].units
= wxHTML_UNITS_PERCENT
;
266 wxSscanf(wd
.c_str(), wxT("%i"), &m_ColsInfo
[c
].width
);
267 m_ColsInfo
[c
].width
= (int)(m_PixelScale
* (double)m_ColsInfo
[c
].width
);
268 m_ColsInfo
[c
].units
= wxHTML_UNITS_PIXELS
;
276 tag
.GetParamAsInt(wxT("COLSPAN"), &m_CellInfo
[r
][c
].colspan
);
277 tag
.GetParamAsInt(wxT("ROWSPAN"), &m_CellInfo
[r
][c
].rowspan
);
278 if ((m_CellInfo
[r
][c
].colspan
!= 1) || (m_CellInfo
[r
][c
].rowspan
!= 1))
282 if (r
+ m_CellInfo
[r
][c
].rowspan
> m_NumRows
)
283 ReallocRows(r
+ m_CellInfo
[r
][c
].rowspan
);
284 if (c
+ m_CellInfo
[r
][c
].colspan
> m_NumCols
)
285 ReallocCols(c
+ m_CellInfo
[r
][c
].colspan
);
286 for (i
= r
; i
< r
+ m_CellInfo
[r
][c
].rowspan
; i
++)
287 for (j
= c
; j
< c
+ m_CellInfo
[r
][c
].colspan
; j
++)
288 m_CellInfo
[i
][j
].flag
= cellSpan
;
289 m_CellInfo
[r
][c
].flag
= cellUsed
;
295 wxColour bk
= m_rBkg
;
296 if (tag
.HasParam(wxT("BGCOLOR")))
297 tag
.GetParamAsColour(wxT("BGCOLOR"), &bk
);
299 cell
->SetBackgroundColour(bk
);
302 cell
->SetBorder(TABLE_BORDER_CLR_2
, TABLE_BORDER_CLR_1
);
304 // vertical alignment:
307 if (tag
.HasParam(wxT("VALIGN")))
308 valign
= tag
.GetParam(wxT("VALIGN"));
312 if (valign
== wxT("TOP"))
313 m_CellInfo
[r
][c
].valign
= wxHTML_ALIGN_TOP
;
314 else if (valign
== wxT("BOTTOM"))
315 m_CellInfo
[r
][c
].valign
= wxHTML_ALIGN_BOTTOM
;
316 else m_CellInfo
[r
][c
].valign
= wxHTML_ALIGN_CENTER
;
319 cell
->SetIndent(m_Padding
, wxHTML_INDENT_ALL
, wxHTML_UNITS_PIXELS
);
326 void wxHtmlTableCell::Layout(int w
)
334 if (m_WidthFloatUnits
== wxHTML_UNITS_PERCENT
)
336 if (m_WidthFloat
< 0) m_Width
= (100 + m_WidthFloat
) * w
/ 100;
337 else m_Width
= m_WidthFloat
* w
/ 100;
341 if (m_WidthFloat
< 0) m_Width
= w
+ m_WidthFloat
;
342 else m_Width
= m_WidthFloat
;
352 /* 1. setup columns widths: */
354 int wpix
= m_Width
- (m_NumCols
+ 1) * m_Spacing
;
358 // 1a. setup fixed-width columns:
359 for (i
= 0; i
< m_NumCols
; i
++)
360 if (m_ColsInfo
[i
].units
== wxHTML_UNITS_PIXELS
)
361 wpix
-= (m_ColsInfo
[i
].pixwidth
= m_ColsInfo
[i
].width
);
363 // 1b. setup floating-width columns:
364 for (i
= 0; i
< m_NumCols
; i
++)
365 if ((m_ColsInfo
[i
].units
== wxHTML_UNITS_PERCENT
) && (m_ColsInfo
[i
].width
!= 0))
366 wtemp
+= (m_ColsInfo
[i
].pixwidth
= m_ColsInfo
[i
].width
* wpix
/ 100);
369 // 1c. setup defalut columns (no width specification supplied):
370 // NOTE! This algorithm doesn't conform to HTML standard : it assigns equal widths
371 // instead of optimal
372 for (i
= j
= 0; i
< m_NumCols
; i
++)
373 if (m_ColsInfo
[i
].width
== 0) j
++;
374 for (i
= 0; i
< m_NumCols
; i
++)
375 if (m_ColsInfo
[i
].width
== 0)
376 m_ColsInfo
[i
].pixwidth
= wpix
/ j
;
379 /* 2. compute positions of columns: */
381 int wpos
= m_Spacing
;
382 for (int i
= 0; i
< m_NumCols
; i
++)
384 m_ColsInfo
[i
].leftpos
= wpos
;
385 wpos
+= m_ColsInfo
[i
].pixwidth
+ m_Spacing
;
389 /* 3. sub-layout all cells: */
391 int *ypos
= new int[m_NumRows
+ 1];
395 wxHtmlContainerCell
*actcell
;
398 for (actrow
= 1; actrow
<= m_NumRows
; actrow
++) ypos
[actrow
] = -1;
399 for (actrow
= 0; actrow
< m_NumRows
; actrow
++)
401 if (ypos
[actrow
] == -1) ypos
[actrow
] = ypos
[actrow
-1];
402 // 3a. sub-layout and detect max height:
404 for (actcol
= 0; actcol
< m_NumCols
; actcol
++) {
405 if (m_CellInfo
[actrow
][actcol
].flag
!= cellUsed
) continue;
406 actcell
= m_CellInfo
[actrow
][actcol
].cont
;
408 for (int i
= actcol
; i
< m_CellInfo
[actrow
][actcol
].colspan
+ actcol
; i
++)
409 fullwid
+= m_ColsInfo
[i
].pixwidth
;
410 fullwid
+= (m_CellInfo
[actrow
][actcol
].colspan
- 1) * m_Spacing
;
411 actcell
->SetMinHeight(m_CellInfo
[actrow
][actcol
].minheight
, m_CellInfo
[actrow
][actcol
].valign
);
412 actcell
->Layout(fullwid
);
414 if (ypos
[actrow
] + actcell
->GetHeight() + m_CellInfo
[actrow
][actcol
].rowspan
* m_Spacing
> ypos
[actrow
+ m_CellInfo
[actrow
][actcol
].rowspan
])
415 ypos
[actrow
+ m_CellInfo
[actrow
][actcol
].rowspan
] =
416 ypos
[actrow
] + actcell
->GetHeight() + m_CellInfo
[actrow
][actcol
].rowspan
* m_Spacing
;
420 for (actrow
= 0; actrow
< m_NumRows
; actrow
++)
422 // 3b. place cells in row & let'em all have same height:
424 for (actcol
= 0; actcol
< m_NumCols
; actcol
++)
426 if (m_CellInfo
[actrow
][actcol
].flag
!= cellUsed
) continue;
427 actcell
= m_CellInfo
[actrow
][actcol
].cont
;
428 actcell
->SetMinHeight(
429 ypos
[actrow
+ m_CellInfo
[actrow
][actcol
].rowspan
] - ypos
[actrow
] - m_Spacing
,
430 m_CellInfo
[actrow
][actcol
].valign
);
432 for (int i
= actcol
; i
< m_CellInfo
[actrow
][actcol
].colspan
+ actcol
; i
++)
433 fullwid
+= m_ColsInfo
[i
].pixwidth
;
434 fullwid
+= (m_CellInfo
[actrow
][actcol
].colspan
- 1) * m_Spacing
;
435 actcell
->Layout(fullwid
);
436 actcell
->SetPos(m_ColsInfo
[actcol
].leftpos
, ypos
[actrow
]);
439 m_Height
= ypos
[m_NumRows
];
449 //-----------------------------------------------------------------------------
450 // The tables handler:
451 //-----------------------------------------------------------------------------
454 TAG_HANDLER_BEGIN(TABLE
, "TABLE,TR,TD,TH")
457 wxHtmlTableCell
* m_Table
;
458 wxString m_tAlign
, m_rAlign
;
461 TAG_HANDLER_CONSTR(TABLE
)
464 m_tAlign
= m_rAlign
= wxEmptyString
;
465 m_OldAlign
= wxHTML_ALIGN_LEFT
;
469 TAG_HANDLER_PROC(tag
)
471 wxHtmlContainerCell
*c
;
473 // new table started, backup upper-level table (if any) and create new:
474 if (tag
.GetName() == wxT("TABLE"))
476 wxHtmlTableCell
*oldt
= m_Table
;
477 wxHtmlContainerCell
*oldcont
;
480 oldcont
= c
= m_WParser
->OpenContainer();
482 c
->SetWidthFloat(tag
, m_WParser
->GetPixelScale());
483 m_Table
= new wxHtmlTableCell(c
, tag
, m_WParser
->GetPixelScale());
484 m_OldAlign
= m_WParser
->GetAlign();
485 m_tAlign
= wxEmptyString
;
486 if (tag
.HasParam(wxT("ALIGN")))
487 m_tAlign
= tag
.GetParam(wxT("ALIGN"));
491 m_WParser
->SetAlign(m_OldAlign
);
492 m_WParser
->SetContainer(oldcont
);
493 m_WParser
->CloseContainer();
499 else if (m_Table
&& !tag
.IsEnding())
502 if (tag
.GetName() == wxT("TR"))
504 m_Table
->AddRow(tag
);
506 if (tag
.HasParam(wxT("ALIGN")))
507 m_rAlign
= tag
.GetParam(wxT("ALIGN"));
513 m_WParser
->SetAlign(m_OldAlign
);
514 c
= m_WParser
->SetContainer(new wxHtmlContainerCell(m_Table
));
515 m_Table
->AddCell(c
, tag
);
517 m_WParser
->OpenContainer();
519 if (tag
.GetName() == wxT("TH")) /*header style*/
521 m_WParser
->SetAlign(wxHTML_ALIGN_CENTER
);
528 if (tag
.HasParam(wxT("ALIGN")))
529 als
= tag
.GetParam(wxT("ALIGN"));
531 if (als
== wxT("RIGHT"))
532 m_WParser
->SetAlign(wxHTML_ALIGN_RIGHT
);
533 else if (als
== wxT("CENTER"))
534 m_WParser
->SetAlign(wxHTML_ALIGN_CENTER
);
536 m_WParser
->OpenContainer();
542 TAG_HANDLER_END(TABLE
)
548 TAGS_MODULE_BEGIN(Tables
)
550 TAGS_MODULE_ADD(TABLE
)
552 TAGS_MODULE_END(Tables
)