]> git.saurik.com Git - wxWidgets.git/blob - src/html/htmlcell.cpp
3fbef604ee1b3a6d8a7bc71183286c0ba3881be7
[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 "htmlcell.h"
12 #endif
13
14 #include "wx/wxprec.h"
15
16 #include "wx/defs.h"
17
18 #if wxUSE_HTML && wxUSE_STREAMS
19
20 #ifdef __BORLANDC__
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 "wx/settings.h"
33 #include <stdlib.h>
34
35 //-----------------------------------------------------------------------------
36 // Helper classes
37 //-----------------------------------------------------------------------------
38
39 void wxHtmlSelection::Set(const wxPoint& fromPos, wxHtmlCell *fromCell,
40 const wxPoint& toPos, wxHtmlCell *toCell)
41 {
42 m_fromCell = fromCell;
43 m_toCell = toCell;
44 m_fromPos = fromPos;
45 m_toPos = toPos;
46 }
47
48 void wxHtmlSelection::Set(wxHtmlCell *fromCell, wxHtmlCell *toCell)
49 {
50 wxPoint p1 = fromCell ? fromCell->GetAbsPos() : wxDefaultPosition;
51 wxPoint p2 = toCell ? toCell->GetAbsPos() : wxDefaultPosition;
52 if ( toCell )
53 {
54 p2.x += toCell->GetWidth()-1;
55 p2.y += toCell->GetHeight()-1;
56 }
57 Set(p1, fromCell, p2, toCell);
58 }
59
60 wxColour wxDefaultHtmlRenderingStyle::GetSelectedTextColour(
61 const wxColour& clr)
62 {
63 return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
64 }
65
66 wxColour wxDefaultHtmlRenderingStyle::GetSelectedTextBgColour(
67 const wxColour& WXUNUSED(clr))
68 {
69 return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
70 }
71
72
73 //-----------------------------------------------------------------------------
74 // wxHtmlCell
75 //-----------------------------------------------------------------------------
76
77 wxHtmlCell::wxHtmlCell() : wxObject()
78 {
79 m_Next = NULL;
80 m_Parent = NULL;
81 m_Width = m_Height = m_Descent = 0;
82 m_CanLiveOnPagebreak = TRUE;
83 m_Link = NULL;
84 }
85
86 wxHtmlCell::~wxHtmlCell()
87 {
88 delete m_Link;
89 }
90
91
92 void wxHtmlCell::OnMouseClick(wxWindow *parent, int x, int y,
93 const wxMouseEvent& event)
94 {
95 wxHtmlLinkInfo *lnk = GetLink(x, y);
96 if (lnk != NULL)
97 {
98 wxHtmlLinkInfo lnk2(*lnk);
99 lnk2.SetEvent(&event);
100 lnk2.SetHtmlCell(this);
101
102 // note : this cast is legal because parent is *always* wxHtmlWindow
103 wxStaticCast(parent, wxHtmlWindow)->OnLinkClicked(lnk2);
104 }
105 }
106
107
108
109 bool wxHtmlCell::AdjustPagebreak(int *pagebreak, int* WXUNUSED(known_pagebreaks), int WXUNUSED(number_of_pages)) const
110 {
111 if ((!m_CanLiveOnPagebreak) &&
112 m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak)
113 {
114 *pagebreak = m_PosY;
115 return TRUE;
116 }
117
118 return FALSE;
119 }
120
121
122
123 void wxHtmlCell::SetLink(const wxHtmlLinkInfo& link)
124 {
125 if (m_Link) delete m_Link;
126 m_Link = NULL;
127 if (link.GetHref() != wxEmptyString)
128 m_Link = new wxHtmlLinkInfo(link);
129 }
130
131
132
133 void wxHtmlCell::Layout(int WXUNUSED(w))
134 {
135 SetPos(0, 0);
136 }
137
138
139
140 void wxHtmlCell::GetHorizontalConstraints(int *left, int *right) const
141 {
142 if (left)
143 *left = m_PosX;
144 if (right)
145 *right = m_PosX + m_Width;
146 }
147
148
149
150 const wxHtmlCell* wxHtmlCell::Find(int WXUNUSED(condition), const void* WXUNUSED(param)) const
151 {
152 return NULL;
153 }
154
155
156 wxHtmlCell *wxHtmlCell::FindCellByPos(wxCoord x, wxCoord y,
157 unsigned flags) const
158 {
159 if ( x >= 0 && x < m_Width && y >= 0 && y < m_Height )
160 {
161 return wxConstCast(this, wxHtmlCell);
162 }
163 else
164 {
165 if ((flags & wxHTML_FIND_NEAREST_AFTER) &&
166 (y < 0 || (y == 0 && x <= 0)))
167 return wxConstCast(this, wxHtmlCell);
168 else if ((flags & wxHTML_FIND_NEAREST_BEFORE) &&
169 (y > m_Height-1 || (y == m_Height-1 && x >= m_Width)))
170 return wxConstCast(this, wxHtmlCell);
171 else
172 return NULL;
173 }
174 }
175
176
177 wxPoint wxHtmlCell::GetAbsPos() const
178 {
179 wxPoint p(m_PosX, m_PosY);
180 for (wxHtmlCell *parent = m_Parent; parent; parent = parent->m_Parent)
181 {
182 p.x += parent->m_PosX;
183 p.y += parent->m_PosY;
184 }
185 return p;
186 }
187
188 unsigned wxHtmlCell::GetDepth() const
189 {
190 unsigned d = 0;
191 for (wxHtmlCell *p = m_Parent; p; p = p->m_Parent)
192 d++;
193 return d;
194 }
195
196 bool wxHtmlCell::IsBefore(wxHtmlCell *cell) const
197 {
198 const wxHtmlCell *c1 = this;
199 const wxHtmlCell *c2 = cell;
200 unsigned d1 = GetDepth();
201 unsigned d2 = cell->GetDepth();
202
203 if ( d1 > d2 )
204 for (; d1 != d2; d1-- )
205 c1 = c1->m_Parent;
206 else if ( d1 < d2 )
207 for (; d1 != d2; d2-- )
208 c2 = c2->m_Parent;
209
210 if ( cell == this )
211 return true;
212
213 while ( c1 && c2 )
214 {
215 if ( c1->m_Parent == c2->m_Parent )
216 {
217 while ( c1 )
218 {
219 if ( c1 == c2 )
220 return true;
221 c1 = c1->GetNext();
222 }
223 return false;
224 }
225 else
226 {
227 c1 = c1->m_Parent;
228 c2 = c2->m_Parent;
229 }
230 }
231
232 wxFAIL_MSG(_T("Cells are in different trees"));
233 return false;
234 }
235
236
237 //-----------------------------------------------------------------------------
238 // wxHtmlWordCell
239 //-----------------------------------------------------------------------------
240
241 wxHtmlWordCell::wxHtmlWordCell(const wxString& word, wxDC& dc) : wxHtmlCell()
242 {
243 m_Word = word;
244 dc.GetTextExtent(m_Word, &m_Width, &m_Height, &m_Descent);
245 SetCanLiveOnPagebreak(FALSE);
246 }
247
248
249 // Splits m_Word into up to three parts according to selection, returns
250 // substring before, in and after selection and the points (in relative coords)
251 // where s2 and s3 start:
252 void wxHtmlWordCell::Split(wxDC& dc,
253 const wxPoint& selFrom, const wxPoint& selTo,
254 unsigned& pos1, unsigned& pos2) const
255 {
256 wxPoint pt1 = (selFrom == wxDefaultPosition) ?
257 wxDefaultPosition : selFrom - GetAbsPos();
258 wxPoint pt2 = (selTo == wxDefaultPosition) ?
259 wxPoint(m_Width, -1) : selTo - GetAbsPos();
260
261 wxCoord charW, charH;
262 unsigned len = m_Word.length();
263 unsigned i = 0;
264 pos1 = 0;
265
266 // before selection:
267 while ( pt1.x > 0 && i < len )
268 {
269 dc.GetTextExtent(m_Word[i], &charW, &charH);
270 pt1.x -= charW;
271 if ( pt1.x >= 0 )
272 {
273 pos1 += charW;
274 i++;
275 }
276 }
277
278 // in selection:
279 unsigned j = i;
280 pos2 = pos1;
281 pt2.x -= pos2;
282 while ( pt2.x > 0 && j < len )
283 {
284 dc.GetTextExtent(m_Word[j], &charW, &charH);
285 pt2.x -= charW;
286 if ( pt2.x >= 0 )
287 {
288 pos2 += charW;
289 j++;
290 }
291 }
292
293 pos1 = i;
294 pos2 = j;
295 }
296
297 void wxHtmlWordCell::SetSelectionPrivPos(wxDC& dc, wxHtmlSelection *s) const
298 {
299 unsigned p1, p2;
300
301 Split(dc,
302 this == s->GetFromCell() ? s->GetFromPos() : wxDefaultPosition,
303 this == s->GetToCell() ? s->GetToPos() : wxDefaultPosition,
304 p1, p2);
305
306 wxPoint p(0, m_Word.length());
307
308 if ( this == s->GetFromCell() )
309 p.x = p1; // selection starts here
310 if ( this == s->GetToCell() )
311 p.y = p2; // selection ends here
312
313 if ( this == s->GetFromCell() )
314 s->SetFromPrivPos(p);
315 if ( this == s->GetToCell() )
316 s->SetToPrivPos(p);
317 }
318
319
320 static void SwitchSelState(wxDC& dc, wxHtmlRenderingInfo& info,
321 bool toSelection)
322 {
323 wxColour fg = info.GetState().GetFgColour();
324 wxColour bg = info.GetState().GetBgColour();
325
326 if ( toSelection )
327 {
328 dc.SetBackgroundMode(wxSOLID);
329 dc.SetTextForeground(info.GetStyle().GetSelectedTextColour(fg));
330 dc.SetTextBackground(info.GetStyle().GetSelectedTextBgColour(bg));
331 }
332 else
333 {
334 dc.SetBackgroundMode(wxTRANSPARENT);
335 dc.SetTextForeground(fg);
336 dc.SetTextBackground(bg);
337 }
338 }
339
340
341 void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
342 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
343 wxHtmlRenderingInfo& info)
344 {
345 #if 0 // useful for debugging
346 dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width,m_Height);
347 #endif
348
349 if ( info.GetState().GetSelectionState() == wxHTML_SEL_CHANGING )
350 {
351 // Selection changing, we must draw the word piecewise:
352 wxHtmlSelection *s = info.GetSelection();
353 wxString txt;
354 int w, h;
355 int ofs = 0;
356
357 wxPoint priv = (this == s->GetFromCell()) ?
358 s->GetFromPrivPos() : s->GetToPrivPos();
359 int part1 = priv.x;
360 int part2 = priv.y;
361
362 if ( part1 > 0 )
363 {
364 txt = m_Word.Mid(0, part1);
365 dc.DrawText(txt, x + m_PosX, y + m_PosY);
366 dc.GetTextExtent(txt, &w, &h);
367 ofs += w;
368 }
369
370 SwitchSelState(dc, info, true);
371
372 txt = m_Word.Mid(part1, part2-part1);
373 dc.DrawText(txt, ofs + x + m_PosX, y + m_PosY);
374
375 if ( (size_t)part2 < m_Word.length() )
376 {
377 dc.GetTextExtent(txt, &w, &h);
378 ofs += w;
379 SwitchSelState(dc, info, false);
380 txt = m_Word.Mid(part2);
381 dc.DrawText(txt, ofs + x + m_PosX, y + m_PosY);
382 }
383 }
384 else
385 {
386 // Not changing selection state, draw the word in single mode:
387
388 if ( info.GetState().GetSelectionState() != wxHTML_SEL_OUT &&
389 dc.GetBackgroundMode() != wxSOLID )
390 {
391 SwitchSelState(dc, info, true);
392 }
393 else if ( info.GetState().GetSelectionState() == wxHTML_SEL_OUT &&
394 dc.GetBackgroundMode() == wxSOLID )
395 {
396 SwitchSelState(dc, info, false);
397 }
398 dc.DrawText(m_Word, x + m_PosX, y + m_PosY);
399 }
400 }
401
402
403 wxString wxHtmlWordCell::ConvertToText(wxHtmlSelection *s) const
404 {
405 if ( s && (this == s->GetFromCell() || this == s->GetToCell()) )
406 {
407 wxPoint priv = (this == s->GetFromCell()) ?
408 s->GetFromPrivPos() : s->GetToPrivPos();
409 int part1 = priv.x;
410 int part2 = priv.y;
411 return m_Word.Mid(part1, part2-part1);
412 }
413 else
414 return m_Word;
415 }
416
417
418
419 //-----------------------------------------------------------------------------
420 // wxHtmlContainerCell
421 //-----------------------------------------------------------------------------
422
423
424 wxHtmlContainerCell::wxHtmlContainerCell(wxHtmlContainerCell *parent) : wxHtmlCell()
425 {
426 m_Cells = m_LastCell = NULL;
427 m_Parent = parent;
428 if (m_Parent) m_Parent->InsertCell(this);
429 m_AlignHor = wxHTML_ALIGN_LEFT;
430 m_AlignVer = wxHTML_ALIGN_BOTTOM;
431 m_IndentLeft = m_IndentRight = m_IndentTop = m_IndentBottom = 0;
432 m_WidthFloat = 100; m_WidthFloatUnits = wxHTML_UNITS_PERCENT;
433 m_UseBkColour = FALSE;
434 m_UseBorder = FALSE;
435 m_MinHeight = 0;
436 m_MinHeightAlign = wxHTML_ALIGN_TOP;
437 m_LastLayout = -1;
438 }
439
440 wxHtmlContainerCell::~wxHtmlContainerCell()
441 {
442 wxHtmlCell *cell = m_Cells;
443 while ( cell )
444 {
445 wxHtmlCell *cellNext = cell->GetNext();
446 delete cell;
447 cell = cellNext;
448 }
449 }
450
451
452
453 void wxHtmlContainerCell::SetIndent(int i, int what, int units)
454 {
455 int val = (units == wxHTML_UNITS_PIXELS) ? i : -i;
456 if (what & wxHTML_INDENT_LEFT) m_IndentLeft = val;
457 if (what & wxHTML_INDENT_RIGHT) m_IndentRight = val;
458 if (what & wxHTML_INDENT_TOP) m_IndentTop = val;
459 if (what & wxHTML_INDENT_BOTTOM) m_IndentBottom = val;
460 m_LastLayout = -1;
461 }
462
463
464
465 int wxHtmlContainerCell::GetIndent(int ind) const
466 {
467 if (ind & wxHTML_INDENT_LEFT) return m_IndentLeft;
468 else if (ind & wxHTML_INDENT_RIGHT) return m_IndentRight;
469 else if (ind & wxHTML_INDENT_TOP) return m_IndentTop;
470 else if (ind & wxHTML_INDENT_BOTTOM) return m_IndentBottom;
471 else return -1; /* BUG! Should not be called... */
472 }
473
474
475
476
477 int wxHtmlContainerCell::GetIndentUnits(int ind) const
478 {
479 bool p = FALSE;
480 if (ind & wxHTML_INDENT_LEFT) p = m_IndentLeft < 0;
481 else if (ind & wxHTML_INDENT_RIGHT) p = m_IndentRight < 0;
482 else if (ind & wxHTML_INDENT_TOP) p = m_IndentTop < 0;
483 else if (ind & wxHTML_INDENT_BOTTOM) p = m_IndentBottom < 0;
484 if (p) return wxHTML_UNITS_PERCENT;
485 else return wxHTML_UNITS_PIXELS;
486 }
487
488
489
490 bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak, int* known_pagebreaks, int number_of_pages) const
491 {
492 if (!m_CanLiveOnPagebreak)
493 return wxHtmlCell::AdjustPagebreak(pagebreak, known_pagebreaks, number_of_pages);
494
495 else
496 {
497 wxHtmlCell *c = GetFirstChild();
498 bool rt = FALSE;
499 int pbrk = *pagebreak - m_PosY;
500
501 while (c)
502 {
503 if (c->AdjustPagebreak(&pbrk, known_pagebreaks, number_of_pages))
504 rt = TRUE;
505 c = c->GetNext();
506 }
507 if (rt)
508 *pagebreak = pbrk + m_PosY;
509 return rt;
510 }
511 }
512
513
514
515 void wxHtmlContainerCell::Layout(int w)
516 {
517 wxHtmlCell::Layout(w);
518
519 if (m_LastLayout == w) return;
520
521 // VS: Any attempt to layout with negative or zero width leads to hell,
522 // but we can't ignore such attempts completely, since it sometimes
523 // happen (e.g. when trying how small a table can be). The best thing we
524 // can do is to set the width of child cells to zero
525 if (w < 1)
526 {
527 m_Width = 0;
528 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
529 cell->Layout(0);
530 // this does two things: it recursively calls this code on all
531 // child contrainers and resets children's position to (0,0)
532 return;
533 }
534
535 wxHtmlCell *cell = m_Cells, *line = m_Cells;
536 long xpos = 0, ypos = m_IndentTop;
537 int xdelta = 0, ybasicpos = 0, ydiff;
538 int s_width, s_indent;
539 int ysizeup = 0, ysizedown = 0;
540 int MaxLineWidth = 0;
541 int xcnt = 0;
542
543
544 /*
545
546 WIDTH ADJUSTING :
547
548 */
549
550 if (m_WidthFloatUnits == wxHTML_UNITS_PERCENT)
551 {
552 if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100;
553 else m_Width = m_WidthFloat * w / 100;
554 }
555 else
556 {
557 if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
558 else m_Width = m_WidthFloat;
559 }
560
561 if (m_Cells)
562 {
563 int l = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
564 int r = (m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight;
565 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
566 cell->Layout(m_Width - (l + r));
567 }
568
569 /*
570
571 LAYOUTING :
572
573 */
574
575 // adjust indentation:
576 s_indent = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
577 s_width = m_Width - s_indent - ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
578
579 // my own layouting:
580 while (cell != NULL)
581 {
582 switch (m_AlignVer)
583 {
584 case wxHTML_ALIGN_TOP : ybasicpos = 0; break;
585 case wxHTML_ALIGN_BOTTOM : ybasicpos = - cell->GetHeight(); break;
586 case wxHTML_ALIGN_CENTER : ybasicpos = - cell->GetHeight() / 2; break;
587 }
588 ydiff = cell->GetHeight() + ybasicpos;
589
590 if (cell->GetDescent() + ydiff > ysizedown) ysizedown = cell->GetDescent() + ydiff;
591 if (ybasicpos + cell->GetDescent() < -ysizeup) ysizeup = - (ybasicpos + cell->GetDescent());
592
593 cell->SetPos(xpos, ybasicpos + cell->GetDescent());
594 xpos += cell->GetWidth();
595 cell = cell->GetNext();
596 xcnt++;
597
598 // force new line if occured:
599 if ((cell == NULL) || (xpos + cell->GetWidth() > s_width))
600 {
601 if (xpos > MaxLineWidth) MaxLineWidth = xpos;
602 if (ysizeup < 0) ysizeup = 0;
603 if (ysizedown < 0) ysizedown = 0;
604 switch (m_AlignHor) {
605 case wxHTML_ALIGN_LEFT :
606 case wxHTML_ALIGN_JUSTIFY :
607 xdelta = 0;
608 break;
609 case wxHTML_ALIGN_RIGHT :
610 xdelta = 0 + (s_width - xpos);
611 break;
612 case wxHTML_ALIGN_CENTER :
613 xdelta = 0 + (s_width - xpos) / 2;
614 break;
615 }
616 if (xdelta < 0) xdelta = 0;
617 xdelta += s_indent;
618
619 ypos += ysizeup;
620
621 if (m_AlignHor != wxHTML_ALIGN_JUSTIFY || cell == NULL)
622 while (line != cell)
623 {
624 line->SetPos(line->GetPosX() + xdelta,
625 ypos + line->GetPosY());
626 line = line->GetNext();
627 }
628 else
629 {
630 int counter = 0;
631 int step = (s_width - xpos);
632 if (step < 0) step = 0;
633 xcnt--;
634 if (xcnt > 0) while (line != cell)
635 {
636 line->SetPos(line->GetPosX() + s_indent +
637 (counter++ * step / xcnt),
638 ypos + line->GetPosY());
639 line = line->GetNext();
640 }
641 xcnt++;
642 }
643
644 ypos += ysizedown;
645 xpos = xcnt = 0;
646 ysizeup = ysizedown = 0;
647 line = cell;
648 }
649 }
650
651 // setup height & width, depending on container layout:
652 m_Height = ypos + (ysizedown + ysizeup) + m_IndentBottom;
653
654 if (m_Height < m_MinHeight)
655 {
656 if (m_MinHeightAlign != wxHTML_ALIGN_TOP)
657 {
658 int diff = m_MinHeight - m_Height;
659 if (m_MinHeightAlign == wxHTML_ALIGN_CENTER) diff /= 2;
660 cell = m_Cells;
661 while (cell)
662 {
663 cell->SetPos(cell->GetPosX(), cell->GetPosY() + diff);
664 cell = cell->GetNext();
665 }
666 }
667 m_Height = m_MinHeight;
668 }
669
670 MaxLineWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
671 if (m_Width < MaxLineWidth) m_Width = MaxLineWidth;
672
673 m_LastLayout = w;
674 }
675
676 void wxHtmlContainerCell::UpdateRenderingStatePre(wxHtmlRenderingInfo& info,
677 wxHtmlCell *cell) const
678 {
679 wxHtmlSelection *s = info.GetSelection();
680 if (!s) return;
681 if (s->GetFromCell() == cell || s->GetToCell() == cell)
682 {
683 info.GetState().SetSelectionState(wxHTML_SEL_CHANGING);
684 }
685 }
686
687 void wxHtmlContainerCell::UpdateRenderingStatePost(wxHtmlRenderingInfo& info,
688 wxHtmlCell *cell) const
689 {
690 wxHtmlSelection *s = info.GetSelection();
691 if (!s) return;
692 if (s->GetToCell() == cell)
693 info.GetState().SetSelectionState(wxHTML_SEL_OUT);
694 else if (s->GetFromCell() == cell)
695 info.GetState().SetSelectionState(wxHTML_SEL_IN);
696 }
697
698 #define mMin(a, b) (((a) < (b)) ? (a) : (b))
699 #define mMax(a, b) (((a) < (b)) ? (b) : (a))
700
701 void wxHtmlContainerCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
702 wxHtmlRenderingInfo& info)
703 {
704 // container visible, draw it:
705 if ((y + m_PosY <= view_y2) && (y + m_PosY + m_Height > view_y1))
706 {
707 if (m_UseBkColour)
708 {
709 wxBrush myb = wxBrush(m_BkColour, wxSOLID);
710
711 int real_y1 = mMax(y + m_PosY, view_y1);
712 int real_y2 = mMin(y + m_PosY + m_Height - 1, view_y2);
713
714 dc.SetBrush(myb);
715 dc.SetPen(*wxTRANSPARENT_PEN);
716 dc.DrawRectangle(x + m_PosX, real_y1, m_Width, real_y2 - real_y1 + 1);
717 }
718
719 if (m_UseBorder)
720 {
721 wxPen mypen1(m_BorderColour1, 1, wxSOLID);
722 wxPen mypen2(m_BorderColour2, 1, wxSOLID);
723
724 dc.SetPen(mypen1);
725 dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX, y + m_PosY + m_Height - 1);
726 dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX + m_Width, y + m_PosY);
727 dc.SetPen(mypen2);
728 dc.DrawLine(x + m_PosX + m_Width - 1, y + m_PosY, x + m_PosX + m_Width - 1, y + m_PosY + m_Height - 1);
729 dc.DrawLine(x + m_PosX, y + m_PosY + m_Height - 1, x + m_PosX + m_Width, y + m_PosY + m_Height - 1);
730 }
731
732 if (m_Cells)
733 {
734 // draw container's contents:
735 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
736 {
737 UpdateRenderingStatePre(info, cell);
738 cell->Draw(dc,
739 x + m_PosX, y + m_PosY, view_y1, view_y2,
740 info);
741 UpdateRenderingStatePost(info, cell);
742 }
743 }
744 }
745 // container invisible, just proceed font+color changing:
746 else
747 {
748 DrawInvisible(dc, x, y, info);
749 }
750 }
751
752
753
754 void wxHtmlContainerCell::DrawInvisible(wxDC& dc, int x, int y,
755 wxHtmlRenderingInfo& info)
756 {
757 if (m_Cells)
758 {
759 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
760 {
761 UpdateRenderingStatePre(info, cell);
762 cell->DrawInvisible(dc, x + m_PosX, y + m_PosY, info);
763 UpdateRenderingStatePost(info, cell);
764 }
765 }
766 }
767
768
769 wxColour wxHtmlContainerCell::GetBackgroundColour()
770 {
771 if (m_UseBkColour)
772 return m_BkColour;
773 else
774 return wxNullColour;
775 }
776
777
778
779 wxHtmlLinkInfo *wxHtmlContainerCell::GetLink(int x, int y) const
780 {
781 wxHtmlCell *cell = FindCellByPos(x, y);
782
783 // VZ: I don't know if we should pass absolute or relative coords to
784 // wxHtmlCell::GetLink()? As the base class version just ignores them
785 // anyhow, it hardly matters right now but should still be clarified
786 return cell ? cell->GetLink(x, y) : NULL;
787 }
788
789
790
791 void wxHtmlContainerCell::InsertCell(wxHtmlCell *f)
792 {
793 if (!m_Cells) m_Cells = m_LastCell = f;
794 else
795 {
796 m_LastCell->SetNext(f);
797 m_LastCell = f;
798 if (m_LastCell) while (m_LastCell->GetNext()) m_LastCell = m_LastCell->GetNext();
799 }
800 f->SetParent(this);
801 m_LastLayout = -1;
802 }
803
804
805
806 void wxHtmlContainerCell::SetAlign(const wxHtmlTag& tag)
807 {
808 if (tag.HasParam(wxT("ALIGN")))
809 {
810 wxString alg = tag.GetParam(wxT("ALIGN"));
811 alg.MakeUpper();
812 if (alg == wxT("CENTER"))
813 SetAlignHor(wxHTML_ALIGN_CENTER);
814 else if (alg == wxT("LEFT"))
815 SetAlignHor(wxHTML_ALIGN_LEFT);
816 else if (alg == wxT("JUSTIFY"))
817 SetAlignHor(wxHTML_ALIGN_JUSTIFY);
818 else if (alg == wxT("RIGHT"))
819 SetAlignHor(wxHTML_ALIGN_RIGHT);
820 m_LastLayout = -1;
821 }
822 }
823
824
825
826 void wxHtmlContainerCell::SetWidthFloat(const wxHtmlTag& tag, double pixel_scale)
827 {
828 if (tag.HasParam(wxT("WIDTH")))
829 {
830 int wdi;
831 wxString wd = tag.GetParam(wxT("WIDTH"));
832
833 if (wd[wd.Length()-1] == wxT('%'))
834 {
835 wxSscanf(wd.c_str(), wxT("%i%%"), &wdi);
836 SetWidthFloat(wdi, wxHTML_UNITS_PERCENT);
837 }
838 else
839 {
840 wxSscanf(wd.c_str(), wxT("%i"), &wdi);
841 SetWidthFloat((int)(pixel_scale * (double)wdi), wxHTML_UNITS_PIXELS);
842 }
843 m_LastLayout = -1;
844 }
845 }
846
847
848
849 const wxHtmlCell* wxHtmlContainerCell::Find(int condition, const void* param) const
850 {
851 if (m_Cells)
852 {
853 const wxHtmlCell *r = NULL;
854
855 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
856 {
857 r = cell->Find(condition, param);
858 if (r) return r;
859 }
860 }
861 return NULL;
862 }
863
864
865 wxHtmlCell *wxHtmlContainerCell::FindCellByPos(wxCoord x, wxCoord y,
866 unsigned flags) const
867 {
868 if ( flags & wxHTML_FIND_EXACT )
869 {
870 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
871 {
872 int cx = cell->GetPosX(),
873 cy = cell->GetPosY();
874
875 if ( (cx <= x) && (cx + cell->GetWidth() > x) &&
876 (cy <= y) && (cy + cell->GetHeight() > y) )
877 {
878 return cell->FindCellByPos(x - cx, y - cy, flags);
879 }
880 }
881 }
882 else if ( flags & wxHTML_FIND_NEAREST_AFTER )
883 {
884 wxHtmlCell *c;
885 int y2;
886 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
887 {
888 y2 = cell->GetPosY() + cell->GetHeight() - 1;
889 if (y2 < y || (y2 == y && cell->GetPosX()+cell->GetWidth()-1 < x))
890 continue;
891 c = cell->FindCellByPos(x - cell->GetPosX(), y - cell->GetPosY(),
892 flags);
893 if (c) return c;
894 }
895 }
896 else if ( flags & wxHTML_FIND_NEAREST_BEFORE )
897 {
898 wxHtmlCell *c2, *c = NULL;
899 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
900 {
901 if (cell->GetPosY() > y ||
902 (cell->GetPosY() == y && cell->GetPosX() > x))
903 break;
904 c2 = cell->FindCellByPos(x - cell->GetPosX(), y - cell->GetPosY(),
905 flags);
906 if (c2)
907 c = c2;
908 }
909 if (c) return c;
910 }
911
912 return NULL;
913 }
914
915
916 void wxHtmlContainerCell::OnMouseClick(wxWindow *parent, int x, int y, const wxMouseEvent& event)
917 {
918 wxHtmlCell *cell = FindCellByPos(x, y);
919 if ( cell )
920 cell->OnMouseClick(parent, x, y, event);
921 }
922
923
924
925 void wxHtmlContainerCell::GetHorizontalConstraints(int *left, int *right) const
926 {
927 int cleft = m_PosX + m_Width, cright = m_PosX; // worst case
928 int l, r;
929
930 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
931 {
932 cell->GetHorizontalConstraints(&l, &r);
933 if (l < cleft)
934 cleft = l;
935 if (r > cright)
936 cright = r;
937 }
938
939 cleft -= (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
940 cright += (m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight;
941
942 if (left)
943 *left = cleft;
944 if (right)
945 *right = cright;
946 }
947
948
949 wxHtmlCell *wxHtmlContainerCell::GetFirstTerminal() const
950 {
951 if ( m_Cells )
952 {
953 wxHtmlCell *c2;
954 for (wxHtmlCell *c = m_Cells; c; c = c->GetNext())
955 {
956 c2 = c->GetFirstTerminal();
957 if ( c2 )
958 return c2;
959 }
960 }
961 return NULL;
962 }
963
964 wxHtmlCell *wxHtmlContainerCell::GetLastTerminal() const
965 {
966 if ( m_Cells )
967 {
968 // most common case first:
969 wxHtmlCell *c = m_LastCell->GetLastTerminal();
970 if ( c )
971 return c;
972
973 wxHtmlCell *c2 = NULL;
974 for (c = m_Cells; c; c = c->GetNext())
975 c2 = c->GetLastTerminal();
976 return c2;
977 }
978 else
979 return NULL;
980 }
981
982
983
984
985 // --------------------------------------------------------------------------
986 // wxHtmlColourCell
987 // --------------------------------------------------------------------------
988
989 void wxHtmlColourCell::Draw(wxDC& dc,
990 int x, int y,
991 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
992 wxHtmlRenderingInfo& info)
993 {
994 DrawInvisible(dc, x, y, info);
995 }
996
997 void wxHtmlColourCell::DrawInvisible(wxDC& dc,
998 int WXUNUSED(x), int WXUNUSED(y),
999 wxHtmlRenderingInfo& info)
1000 {
1001 wxHtmlRenderingState& state = info.GetState();
1002 if (m_Flags & wxHTML_CLR_FOREGROUND)
1003 {
1004 state.SetFgColour(m_Colour);
1005 if (state.GetSelectionState() != wxHTML_SEL_IN)
1006 dc.SetTextForeground(m_Colour);
1007 else
1008 dc.SetTextForeground(
1009 info.GetStyle().GetSelectedTextColour(m_Colour));
1010 }
1011 if (m_Flags & wxHTML_CLR_BACKGROUND)
1012 {
1013 state.SetBgColour(m_Colour);
1014 if (state.GetSelectionState() != wxHTML_SEL_IN)
1015 dc.SetTextBackground(m_Colour);
1016 else
1017 dc.SetTextBackground(
1018 info.GetStyle().GetSelectedTextBgColour(m_Colour));
1019 dc.SetBackground(wxBrush(m_Colour, wxSOLID));
1020 }
1021 }
1022
1023
1024
1025
1026 // ---------------------------------------------------------------------------
1027 // wxHtmlFontCell
1028 // ---------------------------------------------------------------------------
1029
1030 void wxHtmlFontCell::Draw(wxDC& dc,
1031 int WXUNUSED(x), int WXUNUSED(y),
1032 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
1033 wxHtmlRenderingInfo& WXUNUSED(info))
1034 {
1035 dc.SetFont(m_Font);
1036 }
1037
1038 void wxHtmlFontCell::DrawInvisible(wxDC& dc, int WXUNUSED(x), int WXUNUSED(y),
1039 wxHtmlRenderingInfo& WXUNUSED(info))
1040 {
1041 dc.SetFont(m_Font);
1042 }
1043
1044
1045
1046
1047
1048
1049
1050
1051 // ---------------------------------------------------------------------------
1052 // wxHtmlWidgetCell
1053 // ---------------------------------------------------------------------------
1054
1055 wxHtmlWidgetCell::wxHtmlWidgetCell(wxWindow *wnd, int w)
1056 {
1057 int sx, sy;
1058 m_Wnd = wnd;
1059 m_Wnd->GetSize(&sx, &sy);
1060 m_Width = sx, m_Height = sy;
1061 m_WidthFloat = w;
1062 }
1063
1064
1065 void wxHtmlWidgetCell::Draw(wxDC& WXUNUSED(dc),
1066 int WXUNUSED(x), int WXUNUSED(y),
1067 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
1068 wxHtmlRenderingInfo& WXUNUSED(info))
1069 {
1070 int absx = 0, absy = 0, stx, sty;
1071 wxHtmlCell *c = this;
1072
1073 while (c)
1074 {
1075 absx += c->GetPosX();
1076 absy += c->GetPosY();
1077 c = c->GetParent();
1078 }
1079
1080 ((wxScrolledWindow*)(m_Wnd->GetParent()))->GetViewStart(&stx, &sty);
1081 m_Wnd->SetSize(absx - wxHTML_SCROLL_STEP * stx, absy - wxHTML_SCROLL_STEP * sty, m_Width, m_Height);
1082 }
1083
1084
1085
1086 void wxHtmlWidgetCell::DrawInvisible(wxDC& WXUNUSED(dc),
1087 int WXUNUSED(x), int WXUNUSED(y),
1088 wxHtmlRenderingInfo& WXUNUSED(info))
1089 {
1090 int absx = 0, absy = 0, stx, sty;
1091 wxHtmlCell *c = this;
1092
1093 while (c)
1094 {
1095 absx += c->GetPosX();
1096 absy += c->GetPosY();
1097 c = c->GetParent();
1098 }
1099
1100 ((wxScrolledWindow*)(m_Wnd->GetParent()))->GetViewStart(&stx, &sty);
1101 m_Wnd->SetSize(absx - wxHTML_SCROLL_STEP * stx, absy - wxHTML_SCROLL_STEP * sty, m_Width, m_Height);
1102 }
1103
1104
1105
1106 void wxHtmlWidgetCell::Layout(int w)
1107 {
1108 if (m_WidthFloat != 0)
1109 {
1110 m_Width = (w * m_WidthFloat) / 100;
1111 m_Wnd->SetSize(m_Width, m_Height);
1112 }
1113
1114 wxHtmlCell::Layout(w);
1115 }
1116
1117
1118
1119 // ----------------------------------------------------------------------------
1120 // wxHtmlTerminalCellsInterator
1121 // ----------------------------------------------------------------------------
1122
1123 const wxHtmlCell* wxHtmlTerminalCellsInterator::operator++()
1124 {
1125 if ( !m_pos )
1126 return NULL;
1127
1128 do
1129 {
1130 if ( m_pos == m_to )
1131 {
1132 m_pos = NULL;
1133 return NULL;
1134 }
1135
1136 if ( m_pos->GetNext() )
1137 m_pos = m_pos->GetNext();
1138 else
1139 {
1140 // we must go up the hierarchy until we reach container where this
1141 // is not the last child, and then go down to first terminal cell:
1142 while ( m_pos->GetNext() == NULL )
1143 {
1144 m_pos = m_pos->GetParent();
1145 if ( !m_pos )
1146 return NULL;
1147 }
1148 m_pos = m_pos->GetNext();
1149 }
1150 while ( m_pos->GetFirstChild() != NULL )
1151 m_pos = m_pos->GetFirstChild();
1152 } while ( !m_pos->IsTerminalCell() );
1153
1154 return m_pos;
1155 }
1156
1157 #endif