]> git.saurik.com Git - wxWidgets.git/blame - src/html/m_tables.cpp
fixed a design flaw in wxFontMapper that prevented automatic creation of wxConfig...
[wxWidgets.git] / src / html / m_tables.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
c88293a4 2// Name: m_tables.cpp
5526e819
VS
3// Purpose: wxHtml module for tables
4// Author: Vaclav Slavik
69941f05 5// RCS-ID: $Id$
5526e819
VS
6// Copyright: (c) 1999 Vaclav Slavik
7// Licence: wxWindows Licence
8/////////////////////////////////////////////////////////////////////////////
9
3364ab79
RS
10#ifdef __GNUG__
11#pragma implementation
12#endif
13
3096bd2f 14#include "wx/wxprec.h"
3364ab79 15
314260fb 16#include "wx/defs.h"
f6bcfd97 17#if wxUSE_HTML && wxUSE_STREAMS
3364ab79
RS
18#ifdef __BORDLANDC__
19#pragma hdrstop
20#endif
21
22#ifndef WXPRECOMP
3364ab79
RS
23#endif
24
5526e819
VS
25
26/*
27REMARKS:
c88293a4 28 1. This version of m_tables doesn't support auto-layout algorithm.
5526e819
VS
29 This means that all columns are of same width unless explicitly specified.
30*/
31
32
69941f05
VS
33#include "wx/html/forcelnk.h"
34#include "wx/html/m_templ.h"
5526e819 35
69941f05 36#include "wx/html/htmlcell.h"
5526e819 37
c88293a4 38FORCE_LINK_ME(m_tables)
5526e819
VS
39
40
41#define TABLE_BORDER_CLR_1 wxColour(0xC5, 0xC2, 0xC5)
42#define TABLE_BORDER_CLR_2 wxColour(0x62, 0x61, 0x62)
43
44
45//-----------------------------------------------------------------------------
46// wxHtmlTableCell
47//-----------------------------------------------------------------------------
48
49
50typedef struct {
04dbb646 51 int width, units;
8bd72d90 52 // universal
04dbb646 53 int leftpos, pixwidth, maxrealwidth;
8bd72d90 54 // temporary (depends on width of table)
5526e819
VS
55 } colStruct;
56
57typedef enum {
58 cellSpan,
59 cellUsed,
60 cellFree
61 } cellState;
62
63typedef struct {
64 wxHtmlContainerCell *cont;
65 int colspan, rowspan;
66 int minheight, valign;
67 cellState flag;
68 } cellStruct;
69
70
71class wxHtmlTableCell : public wxHtmlContainerCell
72{
73 protected:
74 /* These are real attributes: */
75 bool m_HasBorders;
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]
83 int m_Spacing;
84 // spaces between cells
85 int m_Padding;
86 // cells internal indentation
87
88 private:
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)
92
93 // default values (for table and row):
8bd72d90 94 wxColour m_tBkg, m_rBkg;
5526e819
VS
95 wxString m_tValign, m_rValign;
96
edbd0635
VS
97 double m_PixelScale;
98
5526e819
VS
99
100 public:
edbd0635 101 wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag, double pixel_scale = 1.0);
5526e819
VS
102 ~wxHtmlTableCell();
103 virtual void Layout(int w);
104
105 void AddRow(const wxHtmlTag& tag);
106 void AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag);
107 private:
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!!
113};
114
115
116
edbd0635 117wxHtmlTableCell::wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag, double pixel_scale)
5526e819
VS
118 : wxHtmlContainerCell(parent)
119{
edbd0635 120 m_PixelScale = pixel_scale;
8bd72d90 121 m_HasBorders = (tag.GetParam(wxT("BORDER")) != wxT("0"));
5526e819
VS
122 m_ColsInfo = NULL;
123 m_NumCols = m_NumRows = 0;
124 m_CellInfo = NULL;
125 m_ActualCol = m_ActualRow = -1;
126
127 /* scan params: */
04dbb646 128 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90 129 tag.GetParamAsColour(wxT("BGCOLOR"), &m_tBkg);
04dbb646
VZ
130 if (tag.HasParam(wxT("VALIGN")))
131 m_tValign = tag.GetParam(wxT("VALIGN"));
132 else
8bd72d90
VS
133 m_tValign = wxEmptyString;
134 if (!tag.GetParamAsInt(wxT("CELLSPACING"), &m_Spacing))
135 m_Spacing = 2;
136 if (!tag.GetParamAsInt(wxT("CELLPADDING"), &m_Padding))
137 m_Padding = 3;
edbd0635
VS
138 m_Spacing = (int)(m_PixelScale * (double)m_Spacing);
139 m_Padding = (int)(m_PixelScale * (double)m_Padding);
5526e819
VS
140
141 if (m_HasBorders)
142 SetBorder(TABLE_BORDER_CLR_1, TABLE_BORDER_CLR_2);
143}
144
145
146
147wxHtmlTableCell::~wxHtmlTableCell()
148{
149 if (m_ColsInfo) free(m_ColsInfo);
04dbb646 150 if (m_CellInfo)
4f9297b0 151 {
5526e819
VS
152 for (int i = 0; i < m_NumRows; i++)
153 free(m_CellInfo[i]);
154 free(m_CellInfo);
155 }
156}
157
158
159
160void wxHtmlTableCell::ReallocCols(int cols)
161{
162 int i,j;
163
04dbb646 164 for (i = 0; i < m_NumRows; i++)
4f9297b0 165 {
5526e819
VS
166 m_CellInfo[i] = (cellStruct*) realloc(m_CellInfo[i], sizeof(cellStruct) * cols);
167 for (j = m_NumCols; j < cols; j++)
168 m_CellInfo[i][j].flag = cellFree;
169 }
170
171 m_ColsInfo = (colStruct*) realloc(m_ColsInfo, sizeof(colStruct) * cols);
04dbb646 172 for (j = m_NumCols; j < cols; j++)
4f9297b0 173 {
5526e819 174 m_ColsInfo[j].width = 0;
efba2b89 175 m_ColsInfo[j].units = wxHTML_UNITS_PERCENT;
5526e819
VS
176 }
177
178 m_NumCols = cols;
179}
180
181
182
183void wxHtmlTableCell::ReallocRows(int rows)
184{
185 m_CellInfo = (cellStruct**) realloc(m_CellInfo, sizeof(cellStruct*) * rows);
04dbb646 186 for (int row = m_NumRows; row < rows ; row++)
80eab469 187 {
04dbb646 188 if (m_NumCols == 0)
80eab469 189 m_CellInfo[row] = NULL;
04dbb646 190 else
80eab469
VS
191 {
192 m_CellInfo[row] = (cellStruct*) malloc(sizeof(cellStruct) * m_NumCols);
193 for (int col = 0; col < m_NumCols; col++)
194 m_CellInfo[row][col].flag = cellFree;
195 }
5526e819 196 }
5526e819
VS
197 m_NumRows = rows;
198}
199
200
5526e819
VS
201void wxHtmlTableCell::AddRow(const wxHtmlTag& tag)
202{
5526e819 203 m_ActualCol = -1;
d361bbff
VS
204 // VS: real allocation of row entry is done in AddCell in order
205 // to correctly handle empty rows (i.e. "<tr></tr>")
206 // m_ActualCol == -1 indicates that AddCell has to allocate new row.
5526e819 207
d361bbff 208 // scan params:
5526e819 209 m_rBkg = m_tBkg;
04dbb646 210 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90 211 tag.GetParamAsColour(wxT("BGCOLOR"), &m_rBkg);
04dbb646
VZ
212 if (tag.HasParam(wxT("VALIGN")))
213 m_rValign = tag.GetParam(wxT("VALIGN"));
214 else
d361bbff 215 m_rValign = m_tValign;
5526e819
VS
216}
217
218
219
220void wxHtmlTableCell::AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag)
221{
d361bbff
VS
222 // Is this cell in new row?
223 // VS: we can't do it in AddRow, see my comment there
224 if (m_ActualCol == -1)
225 {
226 if (m_ActualRow + 1 > m_NumRows - 1)
227 ReallocRows(m_ActualRow + 2);
228 m_ActualRow++;
229 }
230
231 // cells & columns:
04dbb646 232 do
4f9297b0 233 {
5526e819 234 m_ActualCol++;
04dbb646 235 } while ((m_ActualCol < m_NumCols) &&
8bd72d90 236 (m_CellInfo[m_ActualRow][m_ActualCol].flag != cellFree));
04dbb646 237
5526e819
VS
238 if (m_ActualCol > m_NumCols - 1)
239 ReallocCols(m_ActualCol + 1);
240
241 int r = m_ActualRow, c = m_ActualCol;
242
243 m_CellInfo[r][c].cont = cell;
244 m_CellInfo[r][c].colspan = 1;
245 m_CellInfo[r][c].rowspan = 1;
246 m_CellInfo[r][c].flag = cellUsed;
247 m_CellInfo[r][c].minheight = 0;
efba2b89 248 m_CellInfo[r][c].valign = wxHTML_ALIGN_TOP;
5526e819
VS
249
250 /* scan for parameters: */
251
252 // width:
253 {
8bd72d90 254 if (tag.HasParam(wxT("WIDTH")))
2fa3b707 255 {
8bd72d90 256 wxString wd = tag.GetParam(wxT("WIDTH"));
5526e819 257
8bd72d90 258 if (wd[wd.Length()-1] == wxT('%'))
2fa3b707 259 {
66a77a74 260 wxSscanf(wd.c_str(), wxT("%i%%"), &m_ColsInfo[c].width);
efba2b89 261 m_ColsInfo[c].units = wxHTML_UNITS_PERCENT;
5526e819 262 }
04dbb646 263 else
2fa3b707 264 {
66a77a74 265 wxSscanf(wd.c_str(), wxT("%i"), &m_ColsInfo[c].width);
edbd0635 266 m_ColsInfo[c].width = (int)(m_PixelScale * (double)m_ColsInfo[c].width);
efba2b89 267 m_ColsInfo[c].units = wxHTML_UNITS_PIXELS;
5526e819
VS
268 }
269 }
270 }
271
272
273 // spanning:
274 {
8bd72d90
VS
275 tag.GetParamAsInt(wxT("COLSPAN"), &m_CellInfo[r][c].colspan);
276 tag.GetParamAsInt(wxT("ROWSPAN"), &m_CellInfo[r][c].rowspan);
04dbb646 277 if ((m_CellInfo[r][c].colspan != 1) || (m_CellInfo[r][c].rowspan != 1))
2fa3b707 278 {
5526e819
VS
279 int i, j;
280
04dbb646 281 if (r + m_CellInfo[r][c].rowspan > m_NumRows)
8bd72d90 282 ReallocRows(r + m_CellInfo[r][c].rowspan);
04dbb646 283 if (c + m_CellInfo[r][c].colspan > m_NumCols)
8bd72d90 284 ReallocCols(c + m_CellInfo[r][c].colspan);
5526e819
VS
285 for (i = r; i < r + m_CellInfo[r][c].rowspan; i++)
286 for (j = c; j < c + m_CellInfo[r][c].colspan; j++)
287 m_CellInfo[i][j].flag = cellSpan;
288 m_CellInfo[r][c].flag = cellUsed;
289 }
290 }
291
292 //background color:
293 {
8bd72d90 294 wxColour bk = m_rBkg;
04dbb646 295 if (tag.HasParam(wxT("BGCOLOR")))
8bd72d90
VS
296 tag.GetParamAsColour(wxT("BGCOLOR"), &bk);
297 if (bk.Ok())
298 cell->SetBackgroundColour(bk);
5526e819
VS
299 }
300 if (m_HasBorders)
4f9297b0 301 cell->SetBorder(TABLE_BORDER_CLR_2, TABLE_BORDER_CLR_1);
5526e819
VS
302
303 // vertical alignment:
304 {
305 wxString valign;
04dbb646
VZ
306 if (tag.HasParam(wxT("VALIGN")))
307 valign = tag.GetParam(wxT("VALIGN"));
308 else
8bd72d90 309 valign = m_tValign;
5526e819 310 valign.MakeUpper();
04dbb646 311 if (valign == wxT("TOP"))
8bd72d90 312 m_CellInfo[r][c].valign = wxHTML_ALIGN_TOP;
04dbb646 313 else if (valign == wxT("BOTTOM"))
8bd72d90 314 m_CellInfo[r][c].valign = wxHTML_ALIGN_BOTTOM;
efba2b89 315 else m_CellInfo[r][c].valign = wxHTML_ALIGN_CENTER;
5526e819
VS
316 }
317
4f9297b0 318 cell->SetIndent(m_Padding, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
5526e819
VS
319}
320
321
322
323
324
325void wxHtmlTableCell::Layout(int w)
326{
327 /*
328
329 WIDTH ADJUSTING :
330
331 */
332
04dbb646 333 if (m_WidthFloatUnits == wxHTML_UNITS_PERCENT)
4f9297b0 334 {
5526e819
VS
335 if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100;
336 else m_Width = m_WidthFloat * w / 100;
337 }
04dbb646 338 else
4f9297b0 339 {
5526e819
VS
340 if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
341 else m_Width = m_WidthFloat;
342 }
343
344
345 /*
346
347 LAYOUTING :
348
349 */
350
351 /* 1. setup columns widths: */
352 {
353 int wpix = m_Width - (m_NumCols + 1) * m_Spacing;
354 int i, j;
355 int wtemp = 0;
356
357 // 1a. setup fixed-width columns:
358 for (i = 0; i < m_NumCols; i++)
efba2b89 359 if (m_ColsInfo[i].units == wxHTML_UNITS_PIXELS)
5526e819
VS
360 wpix -= (m_ColsInfo[i].pixwidth = m_ColsInfo[i].width);
361
362 // 1b. setup floating-width columns:
363 for (i = 0; i < m_NumCols; i++)
efba2b89 364 if ((m_ColsInfo[i].units == wxHTML_UNITS_PERCENT) && (m_ColsInfo[i].width != 0))
5526e819
VS
365 wtemp += (m_ColsInfo[i].pixwidth = m_ColsInfo[i].width * wpix / 100);
366 wpix -= wtemp;
367
368 // 1c. setup defalut columns (no width specification supplied):
369 // NOTE! This algorithm doesn't conform to HTML standard : it assigns equal widths
370 // instead of optimal
371 for (i = j = 0; i < m_NumCols; i++)
372 if (m_ColsInfo[i].width == 0) j++;
373 for (i = 0; i < m_NumCols; i++)
374 if (m_ColsInfo[i].width == 0)
375 m_ColsInfo[i].pixwidth = wpix / j;
376 }
377
378 /* 2. compute positions of columns: */
379 {
380 int wpos = m_Spacing;
04dbb646 381 for (int i = 0; i < m_NumCols; i++)
2fa3b707 382 {
5526e819
VS
383 m_ColsInfo[i].leftpos = wpos;
384 wpos += m_ColsInfo[i].pixwidth + m_Spacing;
385 }
386 }
387
388 /* 3. sub-layout all cells: */
389 {
2776d7c3 390 int *ypos = new int[m_NumRows + 1];
5526e819
VS
391
392 int actcol, actrow;
393 int fullwid;
394 wxHtmlContainerCell *actcell;
395
2fa3b707
VS
396 ypos[0] = m_Spacing;
397 for (actrow = 1; actrow <= m_NumRows; actrow++) ypos[actrow] = -1;
04dbb646 398 for (actrow = 0; actrow < m_NumRows; actrow++)
2fa3b707
VS
399 {
400 if (ypos[actrow] == -1) ypos[actrow] = ypos[actrow-1];
5526e819
VS
401 // 3a. sub-layout and detect max height:
402
403 for (actcol = 0; actcol < m_NumCols; actcol++) {
404 if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
405 actcell = m_CellInfo[actrow][actcol].cont;
406 fullwid = 0;
407 for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
408 fullwid += m_ColsInfo[i].pixwidth;
a97a264f 409 fullwid += (m_CellInfo[actrow][actcol].colspan - 1) * m_Spacing;
4f9297b0
VS
410 actcell->SetMinHeight(m_CellInfo[actrow][actcol].minheight, m_CellInfo[actrow][actcol].valign);
411 actcell->Layout(fullwid);
5526e819 412
4f9297b0 413 if (ypos[actrow] + actcell->GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing > ypos[actrow + m_CellInfo[actrow][actcol].rowspan])
5526e819 414 ypos[actrow + m_CellInfo[actrow][actcol].rowspan] =
4f9297b0 415 ypos[actrow] + actcell->GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing;
5526e819
VS
416 }
417 }
418
04dbb646 419 for (actrow = 0; actrow < m_NumRows; actrow++)
2fa3b707 420 {
5526e819
VS
421 // 3b. place cells in row & let'em all have same height:
422
04dbb646 423 for (actcol = 0; actcol < m_NumCols; actcol++)
2fa3b707 424 {
5526e819
VS
425 if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
426 actcell = m_CellInfo[actrow][actcol].cont;
4f9297b0 427 actcell->SetMinHeight(
a97a264f 428 ypos[actrow + m_CellInfo[actrow][actcol].rowspan] - ypos[actrow] - m_Spacing,
5526e819
VS
429 m_CellInfo[actrow][actcol].valign);
430 fullwid = 0;
431 for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
432 fullwid += m_ColsInfo[i].pixwidth;
a97a264f 433 fullwid += (m_CellInfo[actrow][actcol].colspan - 1) * m_Spacing;
4f9297b0
VS
434 actcell->Layout(fullwid);
435 actcell->SetPos(m_ColsInfo[actcol].leftpos, ypos[actrow]);
5526e819 436 }
5526e819
VS
437 }
438 m_Height = ypos[m_NumRows];
2776d7c3 439 delete[] ypos;
5526e819
VS
440 }
441}
442
443
444
445
446
447
448//-----------------------------------------------------------------------------
449// The tables handler:
450//-----------------------------------------------------------------------------
451
452
453TAG_HANDLER_BEGIN(TABLE, "TABLE,TR,TD,TH")
454
455 TAG_HANDLER_VARS
456 wxHtmlTableCell* m_Table;
457 wxString m_tAlign, m_rAlign;
458 int m_OldAlign;
459
460 TAG_HANDLER_CONSTR(TABLE)
461 {
462 m_Table = NULL;
01325161
VS
463 m_tAlign = m_rAlign = wxEmptyString;
464 m_OldAlign = wxHTML_ALIGN_LEFT;
5526e819
VS
465 }
466
467
468 TAG_HANDLER_PROC(tag)
469 {
470 wxHtmlContainerCell *c;
471
472 // new table started, backup upper-level table (if any) and create new:
04dbb646 473 if (tag.GetName() == wxT("TABLE"))
2fa3b707 474 {
5526e819
VS
475 wxHtmlTableCell *oldt = m_Table;
476 wxHtmlContainerCell *oldcont;
477 int m_OldAlign;
478
4f9297b0 479 oldcont = c = m_WParser->OpenContainer();
5526e819 480
4f9297b0
VS
481 c->SetWidthFloat(tag, m_WParser->GetPixelScale());
482 m_Table = new wxHtmlTableCell(c, tag, m_WParser->GetPixelScale());
483 m_OldAlign = m_WParser->GetAlign();
5526e819 484 m_tAlign = wxEmptyString;
8bd72d90
VS
485 if (tag.HasParam(wxT("ALIGN")))
486 m_tAlign = tag.GetParam(wxT("ALIGN"));
5526e819
VS
487
488 ParseInner(tag);
489
4f9297b0
VS
490 m_WParser->SetAlign(m_OldAlign);
491 m_WParser->SetContainer(oldcont);
492 m_WParser->CloseContainer();
5526e819
VS
493 m_Table = oldt;
494 return TRUE;
495 }
496
497
04dbb646 498 else if (m_Table && !tag.IsEnding())
2fa3b707 499 {
5526e819 500 // new row in table
04dbb646 501 if (tag.GetName() == wxT("TR"))
2fa3b707 502 {
4f9297b0 503 m_Table->AddRow(tag);
5526e819 504 m_rAlign = m_tAlign;
04dbb646 505 if (tag.HasParam(wxT("ALIGN")))
8bd72d90 506 m_rAlign = tag.GetParam(wxT("ALIGN"));
5526e819
VS
507 }
508
509 // new cell
04dbb646 510 else
2fa3b707 511 {
4f9297b0
VS
512 m_WParser->SetAlign(m_OldAlign);
513 c = m_WParser->SetContainer(new wxHtmlContainerCell(m_Table));
514 m_Table->AddCell(c, tag);
5526e819 515
4f9297b0 516 m_WParser->OpenContainer();
5526e819 517
04dbb646 518 if (tag.GetName() == wxT("TH")) /*header style*/
2fa3b707 519 {
4f9297b0 520 m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
5526e819
VS
521 }
522
523 {
524 wxString als;
525
526 als = m_rAlign;
04dbb646 527 if (tag.HasParam(wxT("ALIGN")))
8bd72d90 528 als = tag.GetParam(wxT("ALIGN"));
5526e819 529 als.MakeUpper();
04dbb646 530 if (als == wxT("RIGHT"))
8bd72d90 531 m_WParser->SetAlign(wxHTML_ALIGN_RIGHT);
04dbb646 532 else if (als == wxT("CENTER"))
8bd72d90 533 m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
5526e819 534 }
4f9297b0 535 m_WParser->OpenContainer();
5526e819
VS
536 }
537 }
538 return FALSE;
539 }
540
541TAG_HANDLER_END(TABLE)
542
543
544
545
546
547TAGS_MODULE_BEGIN(Tables)
548
549 TAGS_MODULE_ADD(TABLE)
550
551TAGS_MODULE_END(Tables)
552
553
554#endif