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