]> git.saurik.com Git - wxWidgets.git/blob - src/html/mod_tables.cpp
*** empty log message ***
[wxWidgets.git] / src / html / mod_tables.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mod_tables.cpp
3 // Purpose: wxHtml module for tables
4 // Author: Vaclav Slavik
5 // Copyright: (c) 1999 Vaclav Slavik
6 // Licence: wxWindows Licence
7 /////////////////////////////////////////////////////////////////////////////
8
9 #include "wx/defs.h"
10 #if wxUSE_HTML
11
12 /*
13 REMARKS:
14 1. This version of mod_tables doesn't support auto-layout algorithm.
15 This means that all columns are of same width unless explicitly specified.
16 */
17
18
19 #include <wx/html/forcelink.h>
20 #include <wx/html/mod_templ.h>
21
22 #include <wx/html/htmlcell.h>
23
24 FORCE_LINK_ME(mod_tables)
25
26
27 #define TABLE_BORDER_CLR_1 wxColour(0xC5, 0xC2, 0xC5)
28 #define TABLE_BORDER_CLR_2 wxColour(0x62, 0x61, 0x62)
29
30
31 //-----------------------------------------------------------------------------
32 // wxHtmlTableCell
33 //-----------------------------------------------------------------------------
34
35
36 typedef struct {
37 int width, units; // universal
38 int leftpos, pixwidth, maxrealwidth; // temporary (depends on width of table)
39 } colStruct;
40
41 typedef enum {
42 cellSpan,
43 cellUsed,
44 cellFree
45 } cellState;
46
47 typedef struct {
48 wxHtmlContainerCell *cont;
49 int colspan, rowspan;
50 int minheight, valign;
51 cellState flag;
52 } cellStruct;
53
54
55 class wxHtmlTableCell : public wxHtmlContainerCell
56 {
57 protected:
58 /* These are real attributes: */
59 bool m_HasBorders;
60 // should we draw borders or not?
61 int m_NumCols, m_NumRows;
62 // number of columns; rows
63 colStruct *m_ColsInfo;
64 // array of column information
65 cellStruct **m_CellInfo;
66 // 2D array of all cells in the table : m_CellInfo[row][column]
67 int m_Spacing;
68 // spaces between cells
69 int m_Padding;
70 // cells internal indentation
71
72 private:
73 /* ...and these are valid only during parsing of table: */
74 int m_ActualCol, m_ActualRow;
75 // number of actual column (ranging from 0..m_NumCols)
76
77 // default values (for table and row):
78 int m_tBkg, m_rBkg;
79 wxString m_tValign, m_rValign;
80
81
82 public:
83 wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag);
84 ~wxHtmlTableCell();
85 virtual void Layout(int w);
86
87 void AddRow(const wxHtmlTag& tag);
88 void AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag);
89 private:
90 void ReallocCols(int cols);
91 void ReallocRows(int rows);
92 // reallocates memory to given number of cols/rows
93 // and changes m_NumCols/m_NumRows value to reflect this change
94 // NOTE! You CAN'T change m_NumCols/m_NumRows before calling this!!
95 };
96
97
98
99 wxHtmlTableCell::wxHtmlTableCell(wxHtmlContainerCell *parent, const wxHtmlTag& tag)
100 : wxHtmlContainerCell(parent)
101 {
102 m_HasBorders = tag.HasParam("BORDER");
103 m_ColsInfo = NULL;
104 m_NumCols = m_NumRows = 0;
105 m_CellInfo = NULL;
106 m_ActualCol = m_ActualRow = -1;
107
108 /* scan params: */
109 m_tBkg = m_rBkg = -1;
110 if (tag.HasParam("BGCOLOR")) tag.ScanParam("BGCOLOR", "#%lX", &m_tBkg);
111 if (tag.HasParam("VALIGN")) m_tValign = tag.GetParam("VALIGN"); else m_tValign = wxEmptyString;
112 if (tag.HasParam("CELLSPACING")) tag.ScanParam("CELLSPACING", "%i", &m_Spacing); else m_Spacing = 2;
113 if (tag.HasParam("CELLPADDING")) tag.ScanParam("CELLPADDING", "%i", &m_Padding); else m_Padding = 3;
114
115 if (m_HasBorders)
116 SetBorder(TABLE_BORDER_CLR_1, TABLE_BORDER_CLR_2);
117 }
118
119
120
121 wxHtmlTableCell::~wxHtmlTableCell()
122 {
123 if (m_ColsInfo) free(m_ColsInfo);
124 if (m_CellInfo) {
125 for (int i = 0; i < m_NumRows; i++)
126 free(m_CellInfo[i]);
127 free(m_CellInfo);
128 }
129 }
130
131
132
133 void wxHtmlTableCell::ReallocCols(int cols)
134 {
135 int i,j;
136
137 for (i = 0; i < m_NumRows; i++) {
138 m_CellInfo[i] = (cellStruct*) realloc(m_CellInfo[i], sizeof(cellStruct) * cols);
139 for (j = m_NumCols; j < cols; j++)
140 m_CellInfo[i][j].flag = cellFree;
141 }
142
143 m_ColsInfo = (colStruct*) realloc(m_ColsInfo, sizeof(colStruct) * cols);
144 for (j = m_NumCols; j < cols; j++) {
145 m_ColsInfo[j].width = 0;
146 m_ColsInfo[j].units = HTML_UNITS_PERCENT;
147 }
148
149 m_NumCols = cols;
150 }
151
152
153
154 void wxHtmlTableCell::ReallocRows(int rows)
155 {
156 m_CellInfo = (cellStruct**) realloc(m_CellInfo, sizeof(cellStruct*) * rows);
157 if (m_NumCols != 0) {
158 int x = rows - 1;
159 m_CellInfo[x] = (cellStruct*) malloc(sizeof(cellStruct) * m_NumCols);
160 for (int i = 0; i < m_NumCols; i++)
161 m_CellInfo[x][i].flag = cellFree;
162 }
163 else
164 m_CellInfo[rows - 1] = NULL;
165 m_NumRows = rows;
166 }
167
168
169
170 void wxHtmlTableCell::AddRow(const wxHtmlTag& tag)
171 {
172 if (m_ActualRow + 1 > m_NumRows - 1)
173 ReallocRows(m_ActualRow + 2);
174 m_ActualRow++;
175 m_ActualCol = -1;
176
177 /* scan params: */
178 m_rBkg = m_tBkg;
179 if (tag.HasParam("BGCOLOR")) tag.ScanParam("BGCOLOR", "#%lX", &m_rBkg);
180 if (tag.HasParam("VALIGN")) m_rValign = tag.GetParam("VALIGN"); else m_rValign = m_tValign;
181 }
182
183
184
185 void wxHtmlTableCell::AddCell(wxHtmlContainerCell *cell, const wxHtmlTag& tag)
186 {
187 do {
188 m_ActualCol++;
189 } while ((m_ActualCol < m_NumCols) && (m_CellInfo[m_ActualRow][m_ActualCol].flag != cellFree));
190 if (m_ActualCol > m_NumCols - 1)
191 ReallocCols(m_ActualCol + 1);
192
193 int r = m_ActualRow, c = m_ActualCol;
194
195 m_CellInfo[r][c].cont = cell;
196 m_CellInfo[r][c].colspan = 1;
197 m_CellInfo[r][c].rowspan = 1;
198 m_CellInfo[r][c].flag = cellUsed;
199 m_CellInfo[r][c].minheight = 0;
200 m_CellInfo[r][c].valign = HTML_ALIGN_TOP;
201
202 /* scan for parameters: */
203
204 // width:
205 {
206 if (tag.HasParam("WIDTH")) {
207 wxString wd = tag.GetParam("WIDTH");
208
209 if (wd[wd.Length()-1] == '%') {
210 sscanf(wd.c_str(), "%i%%", &m_ColsInfo[c].width);
211 m_ColsInfo[c].units = HTML_UNITS_PERCENT;
212 }
213 else {
214 sscanf(wd.c_str(), "%i", &m_ColsInfo[c].width);
215 m_ColsInfo[c].units = HTML_UNITS_PIXELS;
216 }
217 }
218 }
219
220
221 // spanning:
222 {
223 if (tag.HasParam("COLSPAN")) tag.ScanParam("COLSPAN", "%i", &m_CellInfo[r][c].colspan);
224 if (tag.HasParam("ROWSPAN")) tag.ScanParam("ROWSPAN", "%i", &m_CellInfo[r][c].rowspan);
225 if ((m_CellInfo[r][c].colspan != 1) || (m_CellInfo[r][c].rowspan != 1)) {
226 int i, j;
227
228 if (r + m_CellInfo[r][c].rowspan > m_NumRows) ReallocRows(r + m_CellInfo[r][c].rowspan);
229 if (c + m_CellInfo[r][c].colspan > m_NumCols) ReallocCols(c + m_CellInfo[r][c].colspan);
230 for (i = r; i < r + m_CellInfo[r][c].rowspan; i++)
231 for (j = c; j < c + m_CellInfo[r][c].colspan; j++)
232 m_CellInfo[i][j].flag = cellSpan;
233 m_CellInfo[r][c].flag = cellUsed;
234 }
235 }
236
237 //background color:
238 {
239 int bk = m_rBkg;
240 if (tag.HasParam("BGCOLOR")) tag.ScanParam("BGCOLOR", "#%lX", &bk);
241 if (bk != -1) {
242 wxColour clr = wxColour((bk & 0xFF0000) >> 16 , (bk & 0x00FF00) >> 8, (bk & 0x0000FF));
243 cell -> SetBackgroundColour(clr);
244 }
245 }
246 if (m_HasBorders)
247 cell -> SetBorder(TABLE_BORDER_CLR_2, TABLE_BORDER_CLR_1);
248
249 // vertical alignment:
250 {
251 wxString valign;
252 if (tag.HasParam("VALIGN")) valign = tag.GetParam("VALIGN"); else valign = m_tValign;
253 valign.MakeUpper();
254 if (valign == "TOP") m_CellInfo[r][c].valign = HTML_ALIGN_TOP;
255 else if (valign == "BOTTOM") m_CellInfo[r][c].valign = HTML_ALIGN_BOTTOM;
256 else m_CellInfo[r][c].valign = HTML_ALIGN_CENTER;
257 }
258
259 cell -> SetIndent(m_Padding, HTML_INDENT_ALL, HTML_UNITS_PIXELS);
260 }
261
262
263
264
265
266 void wxHtmlTableCell::Layout(int w)
267 {
268 /*
269
270 WIDTH ADJUSTING :
271
272 */
273
274 if (m_WidthFloatUnits == HTML_UNITS_PERCENT) {
275 if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100;
276 else m_Width = m_WidthFloat * w / 100;
277 }
278 else {
279 if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
280 else m_Width = m_WidthFloat;
281 }
282
283
284 /*
285
286 LAYOUTING :
287
288 */
289
290 /* 1. setup columns widths: */
291 {
292 int wpix = m_Width - (m_NumCols + 1) * m_Spacing;
293 int i, j;
294 int wtemp = 0;
295
296 // 1a. setup fixed-width columns:
297 for (i = 0; i < m_NumCols; i++)
298 if (m_ColsInfo[i].units == HTML_UNITS_PIXELS)
299 wpix -= (m_ColsInfo[i].pixwidth = m_ColsInfo[i].width);
300
301 // 1b. setup floating-width columns:
302 for (i = 0; i < m_NumCols; i++)
303 if ((m_ColsInfo[i].units == HTML_UNITS_PERCENT) && (m_ColsInfo[i].width != 0))
304 wtemp += (m_ColsInfo[i].pixwidth = m_ColsInfo[i].width * wpix / 100);
305 wpix -= wtemp;
306
307 // 1c. setup defalut columns (no width specification supplied):
308 // NOTE! This algorithm doesn't conform to HTML standard : it assigns equal widths
309 // instead of optimal
310 for (i = j = 0; i < m_NumCols; i++)
311 if (m_ColsInfo[i].width == 0) j++;
312 for (i = 0; i < m_NumCols; i++)
313 if (m_ColsInfo[i].width == 0)
314 m_ColsInfo[i].pixwidth = wpix / j;
315 }
316
317 /* 2. compute positions of columns: */
318 {
319 int wpos = m_Spacing;
320 for (int i = 0; i < m_NumCols; i++) {
321 m_ColsInfo[i].leftpos = wpos;
322 wpos += m_ColsInfo[i].pixwidth + m_Spacing;
323 }
324 }
325
326 /* 3. sub-layout all cells: */
327 {
328 int *ypos = (int*) malloc(sizeof(int) * (m_NumRows + 1));
329
330 int actcol, actrow;
331 int fullwid;
332 wxHtmlContainerCell *actcell;
333
334 for (actrow = 0; actrow <= m_NumRows; actrow++) ypos[actrow] = m_Spacing;
335
336 for (actrow = 0; actrow < m_NumRows; actrow++) {
337
338 // 3a. sub-layout and detect max height:
339
340 for (actcol = 0; actcol < m_NumCols; actcol++) {
341 if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
342 actcell = m_CellInfo[actrow][actcol].cont;
343 fullwid = 0;
344 for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
345 fullwid += m_ColsInfo[i].pixwidth;
346 actcell -> SetMinHeight(m_CellInfo[actrow][actcol].minheight, m_CellInfo[actrow][actcol].valign);
347 actcell -> Layout(fullwid);
348
349 if (ypos[actrow] + actcell -> GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing > ypos[actrow + m_CellInfo[actrow][actcol].rowspan])
350 ypos[actrow + m_CellInfo[actrow][actcol].rowspan] =
351 ypos[actrow] + actcell -> GetHeight() + m_CellInfo[actrow][actcol].rowspan * m_Spacing;
352 }
353 }
354
355
356 for (actrow = 0; actrow < m_NumRows; actrow++) {
357
358 // 3b. place cells in row & let'em all have same height:
359
360 for (actcol = 0; actcol < m_NumCols; actcol++) {
361 if (m_CellInfo[actrow][actcol].flag != cellUsed) continue;
362 actcell = m_CellInfo[actrow][actcol].cont;
363 actcell -> SetMinHeight(
364 ypos[actrow + m_CellInfo[actrow][actcol].rowspan] - ypos[actrow] - m_CellInfo[actrow][actcol].rowspan * m_Spacing,
365 m_CellInfo[actrow][actcol].valign);
366 fullwid = 0;
367 for (int i = actcol; i < m_CellInfo[actrow][actcol].colspan + actcol; i++)
368 fullwid += m_ColsInfo[i].pixwidth;
369 actcell -> Layout(fullwid);
370 actcell -> SetPos(m_ColsInfo[actcol].leftpos, ypos[actrow]);
371 }
372
373 }
374 m_Height = ypos[m_NumRows];
375 free(ypos);
376 }
377 }
378
379
380
381
382
383
384 //-----------------------------------------------------------------------------
385 // The tables handler:
386 //-----------------------------------------------------------------------------
387
388
389 TAG_HANDLER_BEGIN(TABLE, "TABLE,TR,TD,TH")
390
391 TAG_HANDLER_VARS
392 wxHtmlTableCell* m_Table;
393 wxString m_tAlign, m_rAlign;
394 int m_OldAlign;
395
396 TAG_HANDLER_CONSTR(TABLE)
397 {
398 m_Table = NULL;
399 m_tAlign = m_rAlign = wxEmptyString;
400 m_OldAlign = HTML_ALIGN_LEFT;
401 }
402
403
404 TAG_HANDLER_PROC(tag)
405 {
406 wxHtmlContainerCell *c;
407
408 // new table started, backup upper-level table (if any) and create new:
409 if (tag.GetName() == "TABLE") {
410 wxHtmlTableCell *oldt = m_Table;
411 wxHtmlContainerCell *oldcont;
412 int m_OldAlign;
413
414 oldcont = c = m_WParser -> OpenContainer();
415
416 c -> SetWidthFloat(tag);
417 m_Table = new wxHtmlTableCell(c, tag);
418 m_OldAlign = m_WParser -> GetAlign();
419 m_tAlign = wxEmptyString;
420 if (tag.HasParam("ALIGN")) m_tAlign = tag.GetParam("ALIGN");
421
422 ParseInner(tag);
423
424 m_WParser -> SetAlign(m_OldAlign);
425 m_WParser -> SetContainer(oldcont);
426 m_WParser -> CloseContainer();
427 m_Table = oldt;
428 return TRUE;
429 }
430
431
432 else if (m_Table && !tag.IsEnding()) {
433 // new row in table
434 if (tag.GetName() == "TR") {
435 m_Table -> AddRow(tag);
436 m_rAlign = m_tAlign;
437 if (tag.HasParam("ALIGN")) m_rAlign = tag.GetParam("ALIGN");
438 }
439
440 // new cell
441 else {
442 m_WParser -> SetAlign(m_OldAlign);
443 c = m_WParser -> SetContainer(new wxHtmlContainerCell(m_Table));
444 m_Table -> AddCell(c, tag);
445
446 m_WParser -> OpenContainer();
447
448 if (tag.GetName() == "TH") /*header style*/ {
449 m_WParser -> SetAlign(HTML_ALIGN_CENTER);
450 }
451
452 {
453 wxString als;
454
455 als = m_rAlign;
456 if (tag.HasParam("ALIGN")) als = tag.GetParam("ALIGN");
457 als.MakeUpper();
458 if (als == "RIGHT") m_WParser -> SetAlign(HTML_ALIGN_RIGHT);
459 else if (als == "CENTER") m_WParser -> SetAlign(HTML_ALIGN_CENTER);
460 }
461 m_WParser -> OpenContainer();
462 }
463 }
464 return FALSE;
465 }
466
467 TAG_HANDLER_END(TABLE)
468
469
470
471
472
473 TAGS_MODULE_BEGIN(Tables)
474
475 TAGS_MODULE_ADD(TABLE)
476
477 TAGS_MODULE_END(Tables)
478
479
480 #endif