]> git.saurik.com Git - wxWidgets.git/blob - src/html/htmlcell.cpp
new wxHTML printing code ; parser now supports scaling
[wxWidgets.git] / src / html / htmlcell.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: htmlcell.cpp
3 // Purpose: wxHtmlCell - basic element of HTML output
4 // Author: Vaclav Slavik
5 // RCS-ID: $Id$
6 // Copyright: (c) 1999 Vaclav Slavik
7 // Licence: wxWindows Licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation
12 #endif
13
14 #include "wx/wxprec.h"
15
16 #include "wx/defs.h"
17 #if wxUSE_HTML
18
19 #ifdef __BORDLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WXPRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #include "wx/html/htmlcell.h"
28 #include "wx/html/htmlwin.h"
29 #include <stdlib.h>
30
31
32 //-----------------------------------------------------------------------------
33 // wxHtmlCell
34 //-----------------------------------------------------------------------------
35
36
37 void wxHtmlCell::OnMouseClick(wxWindow *parent, int x, int y,
38 bool WXUNUSED(left),
39 bool WXUNUSED(middle),
40 bool WXUNUSED(right))
41 {
42 wxString lnk = GetLink(x, y);
43 if (lnk != wxEmptyString)
44 ((wxHtmlWindow*)parent) -> OnLinkClicked(lnk);
45 // note : this overcasting is legal because parent is *always* wxHtmlWindow
46 }
47
48
49
50 bool wxHtmlCell::AdjustPagebreak(int *pagebreak)
51 {
52
53 if ((!m_CanLiveOnPagebreak) &&
54 m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak) {
55 *pagebreak = m_PosY;
56 if (m_Next != NULL) m_Next -> AdjustPagebreak(pagebreak);
57 return TRUE;
58 }
59
60 else {
61 if (m_Next != NULL) return m_Next -> AdjustPagebreak(pagebreak);
62 else return FALSE;
63 }
64 }
65
66
67
68
69 //-----------------------------------------------------------------------------
70 // wxHtmlWordCell
71 //-----------------------------------------------------------------------------
72
73 wxHtmlWordCell::wxHtmlWordCell(const wxString& word, wxDC& dc) : wxHtmlCell()
74 {
75 m_Word = word;
76
77 if (m_Word.Find(wxT('&')) != -1)
78 {
79 static wxChar* substitutions[][3] =
80 {
81 { wxT("&nbsp;"), wxT("&nbsp "), wxT(" ") },
82 { wxT("&copy;"), wxT("&copy "), wxT("(c)") },
83 { wxT("&quot;"), wxT("&quot "), wxT("\"") },
84 { wxT("&lt;"), wxT("&lt "), wxT("<") },
85 { wxT("&gt;"), wxT("&gt "), wxT(">") },
86 { wxT("&amp;"), wxT("&amp "), wxT("&") /*this one should be last one*/ },
87 { NULL, NULL, NULL }
88 };
89
90 for (int i = 0; substitutions[i][0] != NULL; i++)
91 {
92 m_Word.Replace(substitutions[i][0], substitutions[i][2], TRUE);
93 m_Word.Replace(substitutions[i][1], substitutions[i][2], TRUE);
94 }
95 }
96
97 dc.GetTextExtent(m_Word, &m_Width, &m_Height, &m_Descent);
98 SetCanLiveOnPagebreak(FALSE);
99 }
100
101
102
103 void wxHtmlWordCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2)
104 {
105 dc.DrawText(m_Word, x + m_PosX, y + m_PosY);
106 wxHtmlCell::Draw(dc, x, y, view_y1, view_y2);
107 }
108
109
110
111 //-----------------------------------------------------------------------------
112 // wxHtmlContainerCell
113 //-----------------------------------------------------------------------------
114
115
116 wxHtmlContainerCell::wxHtmlContainerCell(wxHtmlContainerCell *parent) : wxHtmlCell()
117 {
118 m_Cells = m_LastCell = NULL;
119 m_Parent = parent;
120 if (m_Parent) m_Parent -> InsertCell(this);
121 m_AlignHor = wxHTML_ALIGN_LEFT;
122 m_AlignVer = wxHTML_ALIGN_BOTTOM;
123 m_IndentLeft = m_IndentRight = m_IndentTop = m_IndentBottom = 0;
124 m_WidthFloat = 100; m_WidthFloatUnits = wxHTML_UNITS_PERCENT;
125 m_UseBkColour = FALSE;
126 m_UseBorder = FALSE;
127 m_MinHeight = m_MaxLineWidth = 0;
128 m_MinHeightAlign = wxHTML_ALIGN_TOP;
129 }
130
131
132
133 void wxHtmlContainerCell::SetIndent(int i, int what, int units)
134 {
135 int val = (units == wxHTML_UNITS_PIXELS) ? i : -i;
136 if (what & wxHTML_INDENT_LEFT) m_IndentLeft = val;
137 if (what & wxHTML_INDENT_RIGHT) m_IndentRight = val;
138 if (what & wxHTML_INDENT_TOP) m_IndentTop = val;
139 if (what & wxHTML_INDENT_BOTTOM) m_IndentBottom = val;
140 }
141
142
143
144 int wxHtmlContainerCell::GetIndent(int ind) const
145 {
146 if (ind & wxHTML_INDENT_LEFT) return m_IndentLeft;
147 else if (ind & wxHTML_INDENT_RIGHT) return m_IndentRight;
148 else if (ind & wxHTML_INDENT_TOP) return m_IndentTop;
149 else if (ind & wxHTML_INDENT_BOTTOM) return m_IndentBottom;
150 else return -1; /* BUG! Should not be called... */
151 }
152
153
154
155
156 int wxHtmlContainerCell::GetIndentUnits(int ind) const
157 {
158 bool p = FALSE;
159 if (ind & wxHTML_INDENT_LEFT) p = m_IndentLeft < 0;
160 else if (ind & wxHTML_INDENT_RIGHT) p = m_IndentRight < 0;
161 else if (ind & wxHTML_INDENT_TOP) p = m_IndentTop < 0;
162 else if (ind & wxHTML_INDENT_BOTTOM) p = m_IndentBottom < 0;
163 if (p) return wxHTML_UNITS_PERCENT;
164 else return wxHTML_UNITS_PIXELS;
165 }
166
167
168
169 bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak)
170 {
171 if (!m_CanLiveOnPagebreak)
172 return wxHtmlCell::AdjustPagebreak(pagebreak);
173
174 else {
175 wxHtmlCell *c = GetFirstCell();
176 bool rt = FALSE;
177 int pbrk = *pagebreak - m_PosY;
178
179 while (c) {
180 if (c -> AdjustPagebreak(&pbrk)) rt = TRUE;
181 c = c -> GetNext();
182 }
183 if (rt) *pagebreak = pbrk + m_PosY;
184 return rt;
185 }
186 }
187
188
189
190 void wxHtmlContainerCell::Layout(int w)
191 {
192 wxHtmlCell *cell = m_Cells, *line = m_Cells;
193 long xpos = 0, ypos = m_IndentTop;
194 int xdelta = 0, ybasicpos = 0, ydiff;
195 int s_width, s_indent;
196 int ysizeup = 0, ysizedown = 0;
197
198 /*
199
200 WIDTH ADJUSTING :
201
202 */
203
204 if (m_WidthFloatUnits == wxHTML_UNITS_PERCENT) {
205 if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100;
206 else m_Width = m_WidthFloat * w / 100;
207 }
208 else {
209 if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
210 else m_Width = m_WidthFloat;
211 }
212
213 if (m_Cells) {
214 int l = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
215 int r = (m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight;
216 m_Cells -> Layout(m_Width - (l + r));
217 }
218
219 /*
220
221 LAYOUTING :
222
223 */
224
225 // adjust indentation:
226 s_indent = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
227 s_width = m_Width - s_indent - ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
228
229 m_MaxLineWidth = 0;
230
231 // my own layouting:
232 while (cell != NULL) {
233 switch (m_AlignVer) {
234 case wxHTML_ALIGN_TOP : ybasicpos = 0; break;
235 case wxHTML_ALIGN_BOTTOM : ybasicpos = - cell -> GetHeight(); break;
236 case wxHTML_ALIGN_CENTER : ybasicpos = - cell -> GetHeight() / 2; break;
237 }
238 ydiff = cell -> GetHeight() + ybasicpos;
239
240 if (cell -> GetDescent() + ydiff > ysizedown) ysizedown = cell -> GetDescent() + ydiff;
241 if (ybasicpos + cell -> GetDescent() < -ysizeup) ysizeup = - (ybasicpos + cell -> GetDescent());
242
243 cell -> SetPos(xpos, ybasicpos + cell -> GetDescent());
244 xpos += cell -> GetWidth();
245 cell = cell -> GetNext();
246
247 // force new line if occured:
248 if ((cell == NULL) || (xpos + cell -> GetWidth() > s_width)) {
249 if (xpos > m_MaxLineWidth) m_MaxLineWidth = xpos;
250 if (ysizeup < 0) ysizeup = 0;
251 if (ysizedown < 0) ysizedown = 0;
252 switch (m_AlignHor) {
253 case wxHTML_ALIGN_LEFT : xdelta = 0; break;
254 case wxHTML_ALIGN_RIGHT : xdelta = 0 + (s_width - xpos); break;
255 case wxHTML_ALIGN_CENTER : xdelta = 0 + (s_width - xpos) / 2; break;
256 }
257 if (xdelta < 0) xdelta = 0;
258 xdelta += s_indent;
259
260 ypos += ysizeup;
261 while (line != cell) {
262 line -> SetPos(line -> GetPosX() + xdelta, ypos + line -> GetPosY());
263 line = line -> GetNext();
264 }
265
266 ypos += ysizedown;
267 xpos = 0;
268 ysizeup = ysizedown = 0;
269 line = cell;
270 }
271 }
272
273 // setup height & width, depending on container layout:
274 m_Height = ypos + (ysizedown + ysizeup) + m_IndentBottom;
275
276 if (m_Height < m_MinHeight) {
277 if (m_MinHeightAlign != wxHTML_ALIGN_TOP) {
278 int diff = m_MinHeight - m_Height;
279 if (m_MinHeightAlign == wxHTML_ALIGN_CENTER) diff /= 2;
280 cell = m_Cells;
281 while (cell) {
282 cell -> SetPos(cell -> GetPosX(), cell -> GetPosY() + diff);
283 cell = cell -> GetNext();
284 }
285 }
286 m_Height = m_MinHeight;
287 }
288
289 m_MaxLineWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
290 if (m_Width < m_MaxLineWidth) m_Width = m_MaxLineWidth;
291
292 wxHtmlCell::Layout(w);
293 }
294
295
296 #define mMin(a, b) (((a) < (b)) ? (a) : (b))
297 #define mMax(a, b) (((a) < (b)) ? (b) : (a))
298
299 void wxHtmlContainerCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2)
300 {
301 // container visible, draw it:
302 if ((y + m_PosY < view_y2) && (y + m_PosY + m_Height > view_y1)) {
303
304 if (m_UseBkColour) {
305 wxBrush myb = wxBrush(m_BkColour, wxSOLID);
306
307 int real_y1 = mMax(y + m_PosY, view_y1);
308 int real_y2 = mMin(y + m_PosY + m_Height - 1, view_y2);
309
310 dc.SetBrush(myb);
311 dc.SetPen(*wxTRANSPARENT_PEN);
312 dc.DrawRectangle(x + m_PosX, real_y1, m_Width, real_y2 - real_y1 + 1);
313 }
314
315 if (m_UseBorder) {
316 wxPen mypen1(m_BorderColour1, 1, wxSOLID);
317 wxPen mypen2(m_BorderColour2, 1, wxSOLID);
318
319 dc.SetPen(mypen1);
320 dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX, y + m_PosY + m_Height - 1);
321 dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX + m_Width - 1, y + m_PosY);
322 dc.SetPen(mypen2);
323 dc.DrawLine(x + m_PosX + m_Width - 1, y + m_PosY, x + m_PosX + m_Width - 1, y + m_PosY + m_Height - 1);
324 dc.DrawLine(x + m_PosX, y + m_PosY + m_Height - 1, x + m_PosX + m_Width - 1, y + m_PosY + m_Height - 1);
325 }
326
327 if (m_Cells) m_Cells -> Draw(dc, x + m_PosX, y + m_PosY, view_y1, view_y2);
328 }
329 // container invisible, just proceed font+color changing:
330 else {
331 if (m_Cells) m_Cells -> DrawInvisible(dc, x + m_PosX, y + m_PosY);
332 }
333
334 wxHtmlCell::Draw(dc, x, y, view_y1, view_y2);
335 }
336
337
338
339 void wxHtmlContainerCell::DrawInvisible(wxDC& dc, int x, int y)
340 {
341 if (m_Cells) m_Cells -> DrawInvisible(dc, x + m_PosX, y + m_PosY);
342 wxHtmlCell::DrawInvisible(dc, x, y);
343 }
344
345
346
347 wxString wxHtmlContainerCell::GetLink(int x, int y) const
348 {
349 wxHtmlCell *c = m_Cells;
350 int cx, cy, cw, ch;
351
352 while (c) {
353 cx = c -> GetPosX(), cy = c -> GetPosY();
354 cw = c -> GetWidth(), ch = c -> GetHeight();
355 if ((x >= cx) && (x < cx + cw) && (y >= cy) && (y < cy + ch))
356 return c -> GetLink(x - cx, y - cy);
357 c = c -> GetNext();
358 }
359 return wxEmptyString;
360 }
361
362
363
364 void wxHtmlContainerCell::InsertCell(wxHtmlCell *f)
365 {
366 if (!m_Cells) m_Cells = m_LastCell = f;
367 else {
368 m_LastCell -> SetNext(f);
369 m_LastCell = f;
370 if (m_LastCell) while (m_LastCell -> GetNext()) m_LastCell = m_LastCell -> GetNext();
371 }
372 f -> SetParent(this);
373 }
374
375
376
377 void wxHtmlContainerCell::SetAlign(const wxHtmlTag& tag)
378 {
379 if (tag.HasParam("ALIGN")) {
380 wxString alg = tag.GetParam("ALIGN");
381 alg.MakeUpper();
382 if (alg == "CENTER")
383 SetAlignHor(wxHTML_ALIGN_CENTER);
384 else if (alg == "LEFT")
385 SetAlignHor(wxHTML_ALIGN_LEFT);
386 else if (alg == "RIGHT")
387 SetAlignHor(wxHTML_ALIGN_RIGHT);
388 }
389 }
390
391
392
393 void wxHtmlContainerCell::SetWidthFloat(const wxHtmlTag& tag, double pixel_scale)
394 {
395 if (tag.HasParam("WIDTH")) {
396 int wdi;
397 wxString wd = tag.GetParam("WIDTH");
398
399 if (wd[wd.Length()-1] == '%') {
400 wxSscanf(wd.c_str(), wxT("%i%%"), &wdi);
401 SetWidthFloat(wdi, wxHTML_UNITS_PERCENT);
402 }
403 else {
404 wxSscanf(wd.c_str(), wxT("%i"), &wdi);
405 SetWidthFloat((int)(pixel_scale * (double)wdi), wxHTML_UNITS_PIXELS);
406 }
407 }
408 }
409
410
411
412 const wxHtmlCell* wxHtmlContainerCell::Find(int condition, const void* param) const
413 {
414 const wxHtmlCell *r = NULL;
415
416 if (m_Cells) {
417 r = m_Cells -> Find(condition, param);
418 if (r) return r;
419 }
420
421 return wxHtmlCell::Find(condition, param);
422 }
423
424
425
426 void wxHtmlContainerCell::OnMouseClick(wxWindow *parent, int x, int y, bool left, bool middle, bool right)
427 {
428 if (m_Cells) {
429 wxHtmlCell *c = m_Cells;
430 while (c) {
431 if ( (c -> GetPosX() <= x) &&
432 (c -> GetPosY() <= y) &&
433 (c -> GetPosX() + c -> GetWidth() > x) &&
434 (c -> GetPosY() + c -> GetHeight() > y)) {
435 c -> OnMouseClick(parent, x - c -> GetPosX(), y - c -> GetPosY(), left, middle, right);
436 break;
437 }
438 c = c -> GetNext();
439 }
440 }
441 }
442
443
444
445
446
447 //--------------------------------------------------------------------------------
448 // wxHtmlColourCell
449 //--------------------------------------------------------------------------------
450
451 void wxHtmlColourCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2)
452 {
453 if (m_Flags & wxHTML_CLR_FOREGROUND)
454 dc.SetTextForeground(m_Colour);
455 if (m_Flags & wxHTML_CLR_BACKGROUND) {
456 dc.SetBackground(wxBrush(m_Colour, wxSOLID));
457 dc.SetTextBackground(m_Colour);
458 }
459 wxHtmlCell::Draw(dc, x, y, view_y1, view_y2);
460 }
461
462 void wxHtmlColourCell::DrawInvisible(wxDC& dc, int x, int y)
463 {
464 if (m_Flags & wxHTML_CLR_FOREGROUND)
465 dc.SetTextForeground(m_Colour);
466 if (m_Flags & wxHTML_CLR_BACKGROUND) {
467 dc.SetBackground(wxBrush(m_Colour, wxSOLID));
468 dc.SetTextBackground(m_Colour);
469 }
470 wxHtmlCell::DrawInvisible(dc, x, y);
471 }
472
473
474
475
476 //--------------------------------------------------------------------------------
477 // wxHtmlFontCell
478 //--------------------------------------------------------------------------------
479
480 void wxHtmlFontCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2)
481 {
482 dc.SetFont(*m_Font);
483 wxHtmlCell::Draw(dc, x, y, view_y1, view_y2);
484 }
485
486 void wxHtmlFontCell::DrawInvisible(wxDC& dc, int x, int y)
487 {
488 dc.SetFont(*m_Font);
489 wxHtmlCell::DrawInvisible(dc, x, y);
490 }
491
492
493
494
495
496
497
498
499 //--------------------------------------------------------------------------------
500 // wxHtmlWidgetCell
501 //--------------------------------------------------------------------------------
502
503 wxHtmlWidgetCell::wxHtmlWidgetCell(wxWindow *wnd, int w)
504 {
505 int sx, sy;
506 m_Wnd = wnd;
507 m_Wnd -> GetSize(&sx, &sy);
508 m_Width = sx, m_Height = sy;
509 m_WidthFloat = w;
510 }
511
512
513 void wxHtmlWidgetCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2)
514 {
515 int absx = 0, absy = 0, stx, sty;
516 wxHtmlCell *c = this;
517
518 while (c) {
519 absx += c -> GetPosX();
520 absy += c -> GetPosY();
521 c = c -> GetParent();
522 }
523
524 ((wxScrolledWindow*)(m_Wnd -> GetParent())) -> ViewStart(&stx, &sty);
525 m_Wnd -> SetSize(absx - wxHTML_SCROLL_STEP * stx, absy - wxHTML_SCROLL_STEP * sty, m_Width, m_Height);
526
527 wxHtmlCell::Draw(dc, x, y, view_y1, view_y2);
528 }
529
530
531
532 void wxHtmlWidgetCell::DrawInvisible(wxDC& dc, int x, int y)
533 {
534 int absx = 0, absy = 0, stx, sty;
535 wxHtmlCell *c = this;
536
537 while (c) {
538 absx += c -> GetPosX();
539 absy += c -> GetPosY();
540 c = c -> GetParent();
541 }
542
543 ((wxScrolledWindow*)(m_Wnd -> GetParent())) -> ViewStart(&stx, &sty);
544 m_Wnd -> SetSize(absx - wxHTML_SCROLL_STEP * stx, absy - wxHTML_SCROLL_STEP * sty, m_Width, m_Height);
545
546 wxHtmlCell::DrawInvisible(dc, x, y);
547 }
548
549
550
551 void wxHtmlWidgetCell::Layout(int w)
552 {
553 if (m_WidthFloat != 0) {
554 m_Width = (w * m_WidthFloat) / 100;
555 m_Wnd -> SetSize(m_Width, m_Height);
556 }
557
558 wxHtmlCell::Layout(w);
559 }
560
561 #endif