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