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