fixed selecting part of word from right to left in wxHTML (patch #1719530)
[wxWidgets.git] / src / html / htmlcell.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/html/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 #include "wx/wxprec.h"
11
12 #ifdef __BORLANDC__
13 #pragma hdrstop
14 #endif
15
16 #if wxUSE_HTML && wxUSE_STREAMS
17
18 #ifndef WX_PRECOMP
19 #include "wx/dynarray.h"
20 #include "wx/brush.h"
21 #include "wx/colour.h"
22 #include "wx/dc.h"
23 #include "wx/settings.h"
24 #include "wx/module.h"
25 #include "wx/wxcrtvararg.h"
26 #endif
27
28 #include "wx/html/htmlcell.h"
29 #include "wx/html/htmlwin.h"
30
31 #include <stdlib.h>
32
33 //-----------------------------------------------------------------------------
34 // Helper classes
35 //-----------------------------------------------------------------------------
36
37 void wxHtmlSelection::Set(const wxPoint& fromPos, const wxHtmlCell *fromCell,
38 const wxPoint& toPos, const wxHtmlCell *toCell)
39 {
40 m_fromCell = fromCell;
41 m_toCell = toCell;
42 m_fromPos = fromPos;
43 m_toPos = toPos;
44 }
45
46 void wxHtmlSelection::Set(const wxHtmlCell *fromCell, const wxHtmlCell *toCell)
47 {
48 wxPoint p1 = fromCell ? fromCell->GetAbsPos() : wxDefaultPosition;
49 wxPoint p2 = toCell ? toCell->GetAbsPos() : wxDefaultPosition;
50 if ( toCell )
51 {
52 p2.x += toCell->GetWidth();
53 p2.y += toCell->GetHeight();
54 }
55 Set(p1, fromCell, p2, toCell);
56 }
57
58 wxColour
59 wxDefaultHtmlRenderingStyle::
60 GetSelectedTextColour(const wxColour& WXUNUSED(clr))
61 {
62 return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
63 }
64
65 wxColour
66 wxDefaultHtmlRenderingStyle::
67 GetSelectedTextBgColour(const wxColour& WXUNUSED(clr))
68 {
69 return wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
70 }
71
72
73 //-----------------------------------------------------------------------------
74 // wxHtmlCell
75 //-----------------------------------------------------------------------------
76
77 IMPLEMENT_ABSTRACT_CLASS(wxHtmlCell, wxObject)
78
79 wxHtmlCell::wxHtmlCell() : wxObject()
80 {
81 m_Next = NULL;
82 m_Parent = NULL;
83 m_Width = m_Height = m_Descent = 0;
84 m_ScriptMode = wxHTML_SCRIPT_NORMAL; // <sub> or <sup> mode
85 m_ScriptBaseline = 0; // <sub> or <sup> baseline
86 m_CanLiveOnPagebreak = true;
87 m_Link = NULL;
88 }
89
90 wxHtmlCell::~wxHtmlCell()
91 {
92 delete m_Link;
93 }
94
95 // Update the descent value when whe are in a <sub> or <sup>.
96 // prevbase is the parent base
97 void wxHtmlCell::SetScriptMode(wxHtmlScriptMode mode, long previousBase)
98 {
99 m_ScriptMode = mode;
100
101 if (mode == wxHTML_SCRIPT_SUP)
102 m_ScriptBaseline = previousBase - (m_Height + 1) / 2;
103 else if (mode == wxHTML_SCRIPT_SUB)
104 m_ScriptBaseline = previousBase + (m_Height + 1) / 6;
105 else
106 m_ScriptBaseline = 0;
107
108 m_Descent += m_ScriptBaseline;
109 }
110
111 #if WXWIN_COMPATIBILITY_2_6
112
113 struct wxHtmlCellOnMouseClickCompatHelper;
114
115 static wxHtmlCellOnMouseClickCompatHelper *gs_helperOnMouseClick = NULL;
116
117 // helper for routing calls to new ProcessMouseClick() method to deprecated
118 // OnMouseClick() method
119 struct wxHtmlCellOnMouseClickCompatHelper
120 {
121 wxHtmlCellOnMouseClickCompatHelper(wxHtmlWindowInterface *window_,
122 const wxPoint& pos_,
123 const wxMouseEvent& event_)
124 : window(window_), pos(pos_), event(event_), retval(false)
125 {
126 }
127
128 bool CallOnMouseClick(wxHtmlCell *cell)
129 {
130 wxHtmlCellOnMouseClickCompatHelper *oldHelper = gs_helperOnMouseClick;
131 gs_helperOnMouseClick = this;
132 cell->OnMouseClick
133 (
134 window ? window->GetHTMLWindow() : NULL,
135 pos.x, pos.y,
136 event
137 );
138 gs_helperOnMouseClick = oldHelper;
139 return retval;
140 }
141
142 wxHtmlWindowInterface *window;
143 const wxPoint& pos;
144 const wxMouseEvent& event;
145 bool retval;
146 };
147 #endif // WXWIN_COMPATIBILITY_2_6
148
149 bool wxHtmlCell::ProcessMouseClick(wxHtmlWindowInterface *window,
150 const wxPoint& pos,
151 const wxMouseEvent& event)
152 {
153 wxCHECK_MSG( window, false, _T("window interface must be provided") );
154
155 #if WXWIN_COMPATIBILITY_2_6
156 // NB: this hack puts the body of ProcessMouseClick() into OnMouseClick()
157 // (for which it has to pass the arguments and return value via a
158 // helper variable because these two methods have different
159 // signatures), so that old code overriding OnMouseClick will continue
160 // to work
161 wxHtmlCellOnMouseClickCompatHelper compat(window, pos, event);
162 return compat.CallOnMouseClick(this);
163 }
164
165 void wxHtmlCell::OnMouseClick(wxWindow *, int, int, const wxMouseEvent& event)
166 {
167 wxCHECK_RET( gs_helperOnMouseClick, _T("unexpected call to OnMouseClick") );
168 wxHtmlWindowInterface *window = gs_helperOnMouseClick->window;
169 const wxPoint& pos = gs_helperOnMouseClick->pos;
170 #endif // WXWIN_COMPATIBILITY_2_6
171
172 wxHtmlLinkInfo *lnk = GetLink(pos.x, pos.y);
173 bool retval = false;
174
175 if (lnk)
176 {
177 wxHtmlLinkInfo lnk2(*lnk);
178 lnk2.SetEvent(&event);
179 lnk2.SetHtmlCell(this);
180
181 window->OnHTMLLinkClicked(lnk2);
182 retval = true;
183 }
184
185 #if WXWIN_COMPATIBILITY_2_6
186 gs_helperOnMouseClick->retval = retval;
187 #else
188 return retval;
189 #endif // WXWIN_COMPATIBILITY_2_6
190 }
191
192 #if WXWIN_COMPATIBILITY_2_6
193 wxCursor wxHtmlCell::GetCursor() const
194 {
195 return wxNullCursor;
196 }
197 #endif // WXWIN_COMPATIBILITY_2_6
198
199 wxCursor wxHtmlCell::GetMouseCursor(wxHtmlWindowInterface *window) const
200 {
201 #if WXWIN_COMPATIBILITY_2_6
202 // NB: Older versions of wx used GetCursor() virtual method in place of
203 // GetMouseCursor(interface). This code ensures that user code that
204 // overriden GetCursor() continues to work. The trick is that the base
205 // wxHtmlCell::GetCursor() method simply returns wxNullCursor, so we
206 // know that GetCursor() was overriden iff it returns valid cursor.
207 wxCursor cur = GetCursor();
208 if (cur.Ok())
209 return cur;
210 #endif // WXWIN_COMPATIBILITY_2_6
211
212 if ( GetLink() )
213 {
214 return window->GetHTMLCursor(wxHtmlWindowInterface::HTMLCursor_Link);
215 }
216 else
217 {
218 return window->GetHTMLCursor(wxHtmlWindowInterface::HTMLCursor_Default);
219 }
220 }
221
222
223 bool wxHtmlCell::AdjustPagebreak(int *pagebreak,
224 wxArrayInt& WXUNUSED(known_pagebreaks)) const
225 {
226 if ((!m_CanLiveOnPagebreak) &&
227 m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak)
228 {
229 *pagebreak = m_PosY;
230 return true;
231 }
232
233 return false;
234 }
235
236
237
238 void wxHtmlCell::SetLink(const wxHtmlLinkInfo& link)
239 {
240 if (m_Link) delete m_Link;
241 m_Link = NULL;
242 if (link.GetHref() != wxEmptyString)
243 m_Link = new wxHtmlLinkInfo(link);
244 }
245
246
247 void wxHtmlCell::Layout(int WXUNUSED(w))
248 {
249 SetPos(0, 0);
250 }
251
252
253
254 const wxHtmlCell* wxHtmlCell::Find(int WXUNUSED(condition), const void* WXUNUSED(param)) const
255 {
256 return NULL;
257 }
258
259
260 wxHtmlCell *wxHtmlCell::FindCellByPos(wxCoord x, wxCoord y,
261 unsigned flags) const
262 {
263 if ( x >= 0 && x < m_Width && y >= 0 && y < m_Height )
264 {
265 return wxConstCast(this, wxHtmlCell);
266 }
267 else
268 {
269 if ((flags & wxHTML_FIND_NEAREST_AFTER) &&
270 (y < 0 || (y < 0+m_Height && x < 0+m_Width)))
271 return wxConstCast(this, wxHtmlCell);
272 else if ((flags & wxHTML_FIND_NEAREST_BEFORE) &&
273 (y >= 0+m_Height || (y >= 0 && x >= 0)))
274 return wxConstCast(this, wxHtmlCell);
275 else
276 return NULL;
277 }
278 }
279
280
281 wxPoint wxHtmlCell::GetAbsPos(wxHtmlCell *rootCell) const
282 {
283 wxPoint p(m_PosX, m_PosY);
284 for (wxHtmlCell *parent = m_Parent; parent && parent != rootCell;
285 parent = parent->m_Parent)
286 {
287 p.x += parent->m_PosX;
288 p.y += parent->m_PosY;
289 }
290 return p;
291 }
292
293 wxHtmlCell *wxHtmlCell::GetRootCell() const
294 {
295 wxHtmlCell *c = wxConstCast(this, wxHtmlCell);
296 while ( c->m_Parent )
297 c = c->m_Parent;
298 return c;
299 }
300
301 unsigned wxHtmlCell::GetDepth() const
302 {
303 unsigned d = 0;
304 for (wxHtmlCell *p = m_Parent; p; p = p->m_Parent)
305 d++;
306 return d;
307 }
308
309 bool wxHtmlCell::IsBefore(wxHtmlCell *cell) const
310 {
311 const wxHtmlCell *c1 = this;
312 const wxHtmlCell *c2 = cell;
313 unsigned d1 = GetDepth();
314 unsigned d2 = cell->GetDepth();
315
316 if ( d1 > d2 )
317 for (; d1 != d2; d1-- )
318 c1 = c1->m_Parent;
319 else if ( d1 < d2 )
320 for (; d1 != d2; d2-- )
321 c2 = c2->m_Parent;
322
323 if ( cell == this )
324 return true;
325
326 while ( c1 && c2 )
327 {
328 if ( c1->m_Parent == c2->m_Parent )
329 {
330 while ( c1 )
331 {
332 if ( c1 == c2 )
333 return true;
334 c1 = c1->GetNext();
335 }
336 return false;
337 }
338 else
339 {
340 c1 = c1->m_Parent;
341 c2 = c2->m_Parent;
342 }
343 }
344
345 wxFAIL_MSG(_T("Cells are in different trees"));
346 return false;
347 }
348
349
350 //-----------------------------------------------------------------------------
351 // wxHtmlWordCell
352 //-----------------------------------------------------------------------------
353
354 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWordCell, wxHtmlCell)
355
356 wxHtmlWordCell::wxHtmlWordCell(const wxString& word, const wxDC& dc) : wxHtmlCell()
357 {
358 m_Word = word;
359 wxCoord w, h, d;
360 dc.GetTextExtent(m_Word, &w, &h, &d);
361 m_Width = w;
362 m_Height = h;
363 m_Descent = d;
364 SetCanLiveOnPagebreak(false);
365 m_allowLinebreak = true;
366 }
367
368 void wxHtmlWordCell::SetPreviousWord(wxHtmlWordCell *cell)
369 {
370 if ( cell && m_Parent == cell->m_Parent &&
371 !wxIsspace(cell->m_Word.Last()) && !wxIsspace(m_Word[0u]) )
372 {
373 m_allowLinebreak = false;
374 }
375 }
376
377 // Splits m_Word into up to three parts according to selection, returns
378 // substring before, in and after selection and the points (in relative coords)
379 // where s2 and s3 start:
380 void wxHtmlWordCell::Split(const wxDC& dc,
381 const wxPoint& selFrom, const wxPoint& selTo,
382 unsigned& pos1, unsigned& pos2) const
383 {
384 wxPoint pt1 = (selFrom == wxDefaultPosition) ?
385 wxDefaultPosition : selFrom - GetAbsPos();
386 wxPoint pt2 = (selTo == wxDefaultPosition) ?
387 wxPoint(m_Width, wxDefaultCoord) : selTo - GetAbsPos();
388
389 // if the selection is entirely within this cell, make sure pt1 < pt2 in
390 // order to make the rest of this function simpler:
391 if ( selFrom != wxDefaultPosition && selTo != wxDefaultPosition &&
392 selFrom.x > selTo.x )
393 {
394 wxPoint tmp = pt1;
395 pt1 = pt2;
396 pt2 = tmp;
397 }
398
399 unsigned len = m_Word.length();
400 unsigned i = 0;
401 pos1 = 0;
402
403 // adjust for cases when the start/end position is completely
404 // outside the cell:
405 if ( pt1.y < 0 )
406 pt1.x = 0;
407 if ( pt2.y >= m_Height )
408 pt2.x = m_Width;
409
410 // before selection:
411 #ifdef __WXMAC__
412 // implementation using PartialExtents to support fractional widths
413 wxArrayInt widths ;
414 dc.GetPartialTextExtents(m_Word,widths) ;
415 while( i < len && pt1.x >= widths[i] )
416 i++ ;
417 #else // __WXMAC__
418 wxCoord charW, charH;
419 while ( pt1.x > 0 && i < len )
420 {
421 dc.GetTextExtent(m_Word[i], &charW, &charH);
422 pt1.x -= charW;
423 if ( pt1.x >= 0 )
424 {
425 pos1 += charW;
426 i++;
427 }
428 }
429 #endif // __WXMAC__/!__WXMAC__
430
431 // in selection:
432 unsigned j = i;
433 #ifdef __WXMAC__
434 while( j < len && pt2.x >= widths[j] )
435 j++ ;
436 #else // __WXMAC__
437 pos2 = pos1;
438 pt2.x -= pos2;
439 while ( pt2.x > 0 && j < len )
440 {
441 dc.GetTextExtent(m_Word[j], &charW, &charH);
442 pt2.x -= charW;
443 if ( pt2.x >= 0 )
444 {
445 pos2 += charW;
446 j++;
447 }
448 }
449 #endif // __WXMAC__/!__WXMAC__
450
451 pos1 = i;
452 pos2 = j;
453 }
454
455 void wxHtmlWordCell::SetSelectionPrivPos(const wxDC& dc, wxHtmlSelection *s) const
456 {
457 unsigned p1, p2;
458
459 Split(dc,
460 this == s->GetFromCell() ? s->GetFromPos() : wxDefaultPosition,
461 this == s->GetToCell() ? s->GetToPos() : wxDefaultPosition,
462 p1, p2);
463
464 wxPoint p(0, m_Word.length());
465
466 if ( this == s->GetFromCell() )
467 p.x = p1; // selection starts here
468 if ( this == s->GetToCell() )
469 p.y = p2; // selection ends here
470
471 if ( this == s->GetFromCell() )
472 s->SetFromPrivPos(p);
473 if ( this == s->GetToCell() )
474 s->SetToPrivPos(p);
475 }
476
477
478 static void SwitchSelState(wxDC& dc, wxHtmlRenderingInfo& info,
479 bool toSelection)
480 {
481 wxColour fg = info.GetState().GetFgColour();
482 wxColour bg = info.GetState().GetBgColour();
483
484 if ( toSelection )
485 {
486 dc.SetBackgroundMode(wxSOLID);
487 dc.SetTextForeground(info.GetStyle().GetSelectedTextColour(fg));
488 dc.SetTextBackground(info.GetStyle().GetSelectedTextBgColour(bg));
489 dc.SetBackground(wxBrush(info.GetStyle().GetSelectedTextBgColour(bg),
490 wxSOLID));
491 }
492 else
493 {
494 dc.SetBackgroundMode(wxTRANSPARENT);
495 dc.SetTextForeground(fg);
496 dc.SetTextBackground(bg);
497 dc.SetBackground(wxBrush(bg, wxSOLID));
498 }
499 }
500
501
502 void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
503 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
504 wxHtmlRenderingInfo& info)
505 {
506 #if 0 // useful for debugging
507 dc.SetPen(*wxBLACK_PEN);
508 dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width /* VZ: +1? */ ,m_Height);
509 #endif
510
511 bool drawSelectionAfterCell = false;
512
513 if ( info.GetState().GetSelectionState() == wxHTML_SEL_CHANGING )
514 {
515 // Selection changing, we must draw the word piecewise:
516 wxHtmlSelection *s = info.GetSelection();
517 wxString txt;
518 int w, h;
519 int ofs = 0;
520
521 wxPoint priv = (this == s->GetFromCell()) ?
522 s->GetFromPrivPos() : s->GetToPrivPos();
523
524 // NB: this is quite a hack: in order to compute selection boundaries
525 // (in word's characters) we must know current font, which is only
526 // possible inside rendering code. Therefore we update the
527 // information here and store it in wxHtmlSelection so that
528 // ConvertToText can use it later:
529 if ( priv == wxDefaultPosition )
530 {
531 SetSelectionPrivPos(dc, s);
532 priv = (this == s->GetFromCell()) ?
533 s->GetFromPrivPos() : s->GetToPrivPos();
534 }
535
536 int part1 = priv.x;
537 int part2 = priv.y;
538
539 if ( part1 > 0 )
540 {
541 txt = m_Word.Mid(0, part1);
542 dc.DrawText(txt, x + m_PosX, y + m_PosY);
543 dc.GetTextExtent(txt, &w, &h);
544 ofs += w;
545 }
546
547 SwitchSelState(dc, info, true);
548
549 txt = m_Word.Mid(part1, part2-part1);
550 dc.DrawText(txt, ofs + x + m_PosX, y + m_PosY);
551
552 if ( (size_t)part2 < m_Word.length() )
553 {
554 dc.GetTextExtent(txt, &w, &h);
555 ofs += w;
556 SwitchSelState(dc, info, false);
557 txt = m_Word.Mid(part2);
558 dc.DrawText(txt, ofs + x + m_PosX, y + m_PosY);
559 }
560 else
561 drawSelectionAfterCell = true;
562 }
563 else
564 {
565 wxHtmlSelectionState selstate = info.GetState().GetSelectionState();
566 // Not changing selection state, draw the word in single mode:
567 if ( selstate != wxHTML_SEL_OUT &&
568 dc.GetBackgroundMode() != wxSOLID )
569 {
570 SwitchSelState(dc, info, true);
571 }
572 else if ( selstate == wxHTML_SEL_OUT &&
573 dc.GetBackgroundMode() == wxSOLID )
574 {
575 SwitchSelState(dc, info, false);
576 }
577 dc.DrawText(m_Word, x + m_PosX, y + m_PosY);
578 drawSelectionAfterCell = (selstate != wxHTML_SEL_OUT);
579 }
580
581 // NB: If the text is justified then there is usually some free space
582 // between adjacent cells and drawing the selection only onto cells
583 // would result in ugly unselected spaces. The code below detects
584 // this special case and renders the selection *outside* the sell,
585 // too.
586 if ( m_Parent->GetAlignHor() == wxHTML_ALIGN_JUSTIFY &&
587 drawSelectionAfterCell )
588 {
589 wxHtmlCell *nextCell = m_Next;
590 while ( nextCell && nextCell->IsFormattingCell() )
591 nextCell = nextCell->GetNext();
592 if ( nextCell )
593 {
594 int nextX = nextCell->GetPosX();
595 if ( m_PosX + m_Width < nextX )
596 {
597 dc.SetBrush(dc.GetBackground());
598 dc.SetPen(*wxTRANSPARENT_PEN);
599 dc.DrawRectangle(x + m_PosX + m_Width, y + m_PosY,
600 nextX - m_PosX - m_Width, m_Height);
601 }
602 }
603 }
604 }
605
606
607 wxString wxHtmlWordCell::ConvertToText(wxHtmlSelection *s) const
608 {
609 if ( s && (this == s->GetFromCell() || this == s->GetToCell()) )
610 {
611 wxPoint priv = this == s->GetFromCell() ? s->GetFromPrivPos()
612 : s->GetToPrivPos();
613
614 // VZ: we may be called before we had a chance to re-render ourselves
615 // and in this case GetFrom/ToPrivPos() is not set yet -- assume
616 // that this only happens in case of a double/triple click (which
617 // seems to be the case now) and so it makes sense to select the
618 // entire contents of the cell in this case
619 //
620 // TODO: but this really needs to be fixed in some better way later...
621 if ( priv != wxDefaultPosition )
622 {
623 int part1 = priv.x;
624 int part2 = priv.y;
625 return m_Word.Mid(part1, part2-part1);
626 }
627 //else: return the whole word below
628 }
629
630 return m_Word;
631 }
632
633 wxCursor wxHtmlWordCell::GetMouseCursor(wxHtmlWindowInterface *window) const
634 {
635 if ( !GetLink() )
636 {
637 return window->GetHTMLCursor(wxHtmlWindowInterface::HTMLCursor_Text);
638 }
639 else
640 {
641 return wxHtmlCell::GetMouseCursor(window);
642 }
643 }
644
645
646 //-----------------------------------------------------------------------------
647 // wxHtmlContainerCell
648 //-----------------------------------------------------------------------------
649
650 IMPLEMENT_ABSTRACT_CLASS(wxHtmlContainerCell, wxHtmlCell)
651
652 wxHtmlContainerCell::wxHtmlContainerCell(wxHtmlContainerCell *parent) : wxHtmlCell()
653 {
654 m_Cells = m_LastCell = NULL;
655 m_Parent = parent;
656 m_MaxTotalWidth = 0;
657 if (m_Parent) m_Parent->InsertCell(this);
658 m_AlignHor = wxHTML_ALIGN_LEFT;
659 m_AlignVer = wxHTML_ALIGN_BOTTOM;
660 m_IndentLeft = m_IndentRight = m_IndentTop = m_IndentBottom = 0;
661 m_WidthFloat = 100; m_WidthFloatUnits = wxHTML_UNITS_PERCENT;
662 m_UseBkColour = false;
663 m_UseBorder = false;
664 m_MinHeight = 0;
665 m_MinHeightAlign = wxHTML_ALIGN_TOP;
666 m_LastLayout = -1;
667 }
668
669 wxHtmlContainerCell::~wxHtmlContainerCell()
670 {
671 wxHtmlCell *cell = m_Cells;
672 while ( cell )
673 {
674 wxHtmlCell *cellNext = cell->GetNext();
675 delete cell;
676 cell = cellNext;
677 }
678 }
679
680
681
682 void wxHtmlContainerCell::SetIndent(int i, int what, int units)
683 {
684 int val = (units == wxHTML_UNITS_PIXELS) ? i : -i;
685 if (what & wxHTML_INDENT_LEFT) m_IndentLeft = val;
686 if (what & wxHTML_INDENT_RIGHT) m_IndentRight = val;
687 if (what & wxHTML_INDENT_TOP) m_IndentTop = val;
688 if (what & wxHTML_INDENT_BOTTOM) m_IndentBottom = val;
689 m_LastLayout = -1;
690 }
691
692
693
694 int wxHtmlContainerCell::GetIndent(int ind) const
695 {
696 if (ind & wxHTML_INDENT_LEFT) return m_IndentLeft;
697 else if (ind & wxHTML_INDENT_RIGHT) return m_IndentRight;
698 else if (ind & wxHTML_INDENT_TOP) return m_IndentTop;
699 else if (ind & wxHTML_INDENT_BOTTOM) return m_IndentBottom;
700 else return -1; /* BUG! Should not be called... */
701 }
702
703
704
705
706 int wxHtmlContainerCell::GetIndentUnits(int ind) const
707 {
708 bool p = false;
709 if (ind & wxHTML_INDENT_LEFT) p = m_IndentLeft < 0;
710 else if (ind & wxHTML_INDENT_RIGHT) p = m_IndentRight < 0;
711 else if (ind & wxHTML_INDENT_TOP) p = m_IndentTop < 0;
712 else if (ind & wxHTML_INDENT_BOTTOM) p = m_IndentBottom < 0;
713 if (p) return wxHTML_UNITS_PERCENT;
714 else return wxHTML_UNITS_PIXELS;
715 }
716
717
718 bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak,
719 wxArrayInt& known_pagebreaks) const
720 {
721 if (!m_CanLiveOnPagebreak)
722 return wxHtmlCell::AdjustPagebreak(pagebreak, known_pagebreaks);
723
724 wxHtmlCell *c = GetFirstChild();
725 bool rt = false;
726 int pbrk = *pagebreak - m_PosY;
727
728 while (c)
729 {
730 if (c->AdjustPagebreak(&pbrk, known_pagebreaks))
731 rt = true;
732 c = c->GetNext();
733 }
734 if (rt)
735 *pagebreak = pbrk + m_PosY;
736 return rt;
737 }
738
739
740 void wxHtmlContainerCell::Layout(int w)
741 {
742 wxHtmlCell::Layout(w);
743
744 if (m_LastLayout == w) return;
745
746 // VS: Any attempt to layout with negative or zero width leads to hell,
747 // but we can't ignore such attempts completely, since it sometimes
748 // happen (e.g. when trying how small a table can be). The best thing we
749 // can do is to set the width of child cells to zero
750 if (w < 1)
751 {
752 m_Width = 0;
753 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
754 cell->Layout(0);
755 // this does two things: it recursively calls this code on all
756 // child contrainers and resets children's position to (0,0)
757 return;
758 }
759
760 wxHtmlCell *nextCell;
761 long xpos = 0, ypos = m_IndentTop;
762 int xdelta = 0, ybasicpos = 0, ydiff;
763 int s_width, nextWordWidth, s_indent;
764 int ysizeup = 0, ysizedown = 0;
765 int MaxLineWidth = 0;
766 int curLineWidth = 0;
767 m_MaxTotalWidth = 0;
768
769
770 /*
771
772 WIDTH ADJUSTING :
773
774 */
775
776 if (m_WidthFloatUnits == wxHTML_UNITS_PERCENT)
777 {
778 if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100;
779 else m_Width = m_WidthFloat * w / 100;
780 }
781 else
782 {
783 if (m_WidthFloat < 0) m_Width = w + m_WidthFloat;
784 else m_Width = m_WidthFloat;
785 }
786
787 if (m_Cells)
788 {
789 int l = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
790 int r = (m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight;
791 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
792 cell->Layout(m_Width - (l + r));
793 }
794
795 /*
796
797 LAYOUTING :
798
799 */
800
801 // adjust indentation:
802 s_indent = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft;
803 s_width = m_Width - s_indent - ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
804
805 // my own layouting:
806 wxHtmlCell *cell = m_Cells,
807 *line = m_Cells;
808 while (cell != NULL)
809 {
810 switch (m_AlignVer)
811 {
812 case wxHTML_ALIGN_TOP : ybasicpos = 0; break;
813 case wxHTML_ALIGN_BOTTOM : ybasicpos = - cell->GetHeight(); break;
814 case wxHTML_ALIGN_CENTER : ybasicpos = - cell->GetHeight() / 2; break;
815 }
816 ydiff = cell->GetHeight() + ybasicpos;
817
818 if (cell->GetDescent() + ydiff > ysizedown) ysizedown = cell->GetDescent() + ydiff;
819 if (ybasicpos + cell->GetDescent() < -ysizeup) ysizeup = - (ybasicpos + cell->GetDescent());
820
821 // layout nonbreakable run of cells:
822 cell->SetPos(xpos, ybasicpos + cell->GetDescent());
823 xpos += cell->GetWidth();
824 if (!cell->IsTerminalCell())
825 {
826 // Container cell indicates new line
827 if (curLineWidth > m_MaxTotalWidth)
828 m_MaxTotalWidth = curLineWidth;
829
830 if (wxMax(cell->GetWidth(), cell->GetMaxTotalWidth()) > m_MaxTotalWidth)
831 m_MaxTotalWidth = cell->GetMaxTotalWidth();
832 curLineWidth = 0;
833 }
834 else
835 // Normal cell, add maximum cell width to line width
836 curLineWidth += cell->GetMaxTotalWidth();
837
838 cell = cell->GetNext();
839
840 // compute length of the next word that would be added:
841 nextWordWidth = 0;
842 if (cell)
843 {
844 nextCell = cell;
845 do
846 {
847 nextWordWidth += nextCell->GetWidth();
848 nextCell = nextCell->GetNext();
849 } while (nextCell && !nextCell->IsLinebreakAllowed());
850 }
851
852 // force new line if occurred:
853 if ((cell == NULL) ||
854 (xpos + nextWordWidth > s_width && cell->IsLinebreakAllowed()))
855 {
856 if (xpos > MaxLineWidth) MaxLineWidth = xpos;
857 if (ysizeup < 0) ysizeup = 0;
858 if (ysizedown < 0) ysizedown = 0;
859 switch (m_AlignHor) {
860 case wxHTML_ALIGN_LEFT :
861 case wxHTML_ALIGN_JUSTIFY :
862 xdelta = 0;
863 break;
864 case wxHTML_ALIGN_RIGHT :
865 xdelta = 0 + (s_width - xpos);
866 break;
867 case wxHTML_ALIGN_CENTER :
868 xdelta = 0 + (s_width - xpos) / 2;
869 break;
870 }
871 if (xdelta < 0) xdelta = 0;
872 xdelta += s_indent;
873
874 ypos += ysizeup;
875
876 if (m_AlignHor != wxHTML_ALIGN_JUSTIFY || cell == NULL)
877 {
878 while (line != cell)
879 {
880 line->SetPos(line->GetPosX() + xdelta,
881 ypos + line->GetPosY());
882 line = line->GetNext();
883 }
884 }
885 else // align == justify
886 {
887 // we have to distribute the extra horz space between the cells
888 // on this line
889
890 // an added complication is that some cells have fixed size and
891 // shouldn't get any increment (it so happens that these cells
892 // also don't allow line break on them which provides with an
893 // easy way to test for this) -- and neither should the cells
894 // adjacent to them as this could result in a visible space
895 // between two cells separated by, e.g. font change, cell which
896 // is wrong
897
898 int step = s_width - xpos;
899 if ( step > 0 )
900 {
901 // first count the cells which will get extra space
902 int total = -1;
903
904 const wxHtmlCell *c;
905 if ( line != cell )
906 {
907 for ( c = line; c != cell; c = c->GetNext() )
908 {
909 if ( c->IsLinebreakAllowed() )
910 {
911 total++;
912 }
913 }
914 }
915
916 // and now extra space to those cells which merit it
917 if ( total )
918 {
919 // first visible cell on line is not moved:
920 while (line !=cell && !line->IsLinebreakAllowed())
921 {
922 line->SetPos(line->GetPosX() + s_indent,
923 line->GetPosY() + ypos);
924 line = line->GetNext();
925 }
926
927 if (line != cell)
928 {
929 line->SetPos(line->GetPosX() + s_indent,
930 line->GetPosY() + ypos);
931
932 line = line->GetNext();
933 }
934
935 for ( int n = 0; line != cell; line = line->GetNext() )
936 {
937 if ( line->IsLinebreakAllowed() )
938 {
939 // offset the next cell relative to this one
940 // thus increasing our size
941 n++;
942 }
943
944 line->SetPos(line->GetPosX() + s_indent +
945 ((n * step) / total),
946 line->GetPosY() + ypos);
947 }
948 }
949 else
950 {
951 // this will cause the code to enter "else branch" below:
952 step = 0;
953 }
954 }
955 // else branch:
956 if ( step <= 0 ) // no extra space to distribute
957 {
958 // just set the indent properly
959 while (line != cell)
960 {
961 line->SetPos(line->GetPosX() + s_indent,
962 line->GetPosY() + ypos);
963 line = line->GetNext();
964 }
965 }
966 }
967
968 ypos += ysizedown;
969 xpos = 0;
970 ysizeup = ysizedown = 0;
971 line = cell;
972 }
973 }
974
975 // setup height & width, depending on container layout:
976 m_Height = ypos + (ysizedown + ysizeup) + m_IndentBottom;
977
978 if (m_Height < m_MinHeight)
979 {
980 if (m_MinHeightAlign != wxHTML_ALIGN_TOP)
981 {
982 int diff = m_MinHeight - m_Height;
983 if (m_MinHeightAlign == wxHTML_ALIGN_CENTER) diff /= 2;
984 cell = m_Cells;
985 while (cell)
986 {
987 cell->SetPos(cell->GetPosX(), cell->GetPosY() + diff);
988 cell = cell->GetNext();
989 }
990 }
991 m_Height = m_MinHeight;
992 }
993
994 if (curLineWidth > m_MaxTotalWidth)
995 m_MaxTotalWidth = curLineWidth;
996
997 m_MaxTotalWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
998 MaxLineWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight);
999 if (m_Width < MaxLineWidth) m_Width = MaxLineWidth;
1000
1001 m_LastLayout = w;
1002 }
1003
1004 void wxHtmlContainerCell::UpdateRenderingStatePre(wxHtmlRenderingInfo& info,
1005 wxHtmlCell *cell) const
1006 {
1007 wxHtmlSelection *s = info.GetSelection();
1008 if (!s) return;
1009 if (s->GetFromCell() == cell || s->GetToCell() == cell)
1010 {
1011 info.GetState().SetSelectionState(wxHTML_SEL_CHANGING);
1012 }
1013 }
1014
1015 void wxHtmlContainerCell::UpdateRenderingStatePost(wxHtmlRenderingInfo& info,
1016 wxHtmlCell *cell) const
1017 {
1018 wxHtmlSelection *s = info.GetSelection();
1019 if (!s) return;
1020 if (s->GetToCell() == cell)
1021 info.GetState().SetSelectionState(wxHTML_SEL_OUT);
1022 else if (s->GetFromCell() == cell)
1023 info.GetState().SetSelectionState(wxHTML_SEL_IN);
1024 }
1025
1026 #define mMin(a, b) (((a) < (b)) ? (a) : (b))
1027 #define mMax(a, b) (((a) < (b)) ? (b) : (a))
1028
1029 void wxHtmlContainerCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
1030 wxHtmlRenderingInfo& info)
1031 {
1032 #if 0 // useful for debugging
1033 dc.SetPen(*wxRED_PEN);
1034 dc.DrawRectangle(x+m_PosX,y+m_PosY,m_Width,m_Height);
1035 #endif
1036
1037 int xlocal = x + m_PosX;
1038 int ylocal = y + m_PosY;
1039
1040 if (m_UseBkColour)
1041 {
1042 wxBrush myb = wxBrush(m_BkColour, wxSOLID);
1043
1044 int real_y1 = mMax(ylocal, view_y1);
1045 int real_y2 = mMin(ylocal + m_Height - 1, view_y2);
1046
1047 dc.SetBrush(myb);
1048 dc.SetPen(*wxTRANSPARENT_PEN);
1049 dc.DrawRectangle(xlocal, real_y1, m_Width, real_y2 - real_y1 + 1);
1050 }
1051
1052 if (m_UseBorder)
1053 {
1054 wxPen mypen1(m_BorderColour1, 1, wxSOLID);
1055 wxPen mypen2(m_BorderColour2, 1, wxSOLID);
1056
1057 dc.SetPen(mypen1);
1058 dc.DrawLine(xlocal, ylocal, xlocal, ylocal + m_Height - 1);
1059 dc.DrawLine(xlocal, ylocal, xlocal + m_Width, ylocal);
1060 dc.SetPen(mypen2);
1061 dc.DrawLine(xlocal + m_Width - 1, ylocal, xlocal + m_Width - 1, ylocal + m_Height - 1);
1062 dc.DrawLine(xlocal, ylocal + m_Height - 1, xlocal + m_Width, ylocal + m_Height - 1);
1063 }
1064
1065 if (m_Cells)
1066 {
1067 // draw container's contents:
1068 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
1069 {
1070
1071 // optimize drawing: don't render off-screen content:
1072 if ((ylocal + cell->GetPosY() <= view_y2) &&
1073 (ylocal + cell->GetPosY() + cell->GetHeight() > view_y1))
1074 {
1075 // the cell is visible, draw it:
1076 UpdateRenderingStatePre(info, cell);
1077 cell->Draw(dc,
1078 xlocal, ylocal, view_y1, view_y2,
1079 info);
1080 UpdateRenderingStatePost(info, cell);
1081 }
1082 else
1083 {
1084 // the cell is off-screen, proceed with font+color+etc.
1085 // changes only:
1086 cell->DrawInvisible(dc, xlocal, ylocal, info);
1087 }
1088 }
1089 }
1090 }
1091
1092
1093
1094 void wxHtmlContainerCell::DrawInvisible(wxDC& dc, int x, int y,
1095 wxHtmlRenderingInfo& info)
1096 {
1097 if (m_Cells)
1098 {
1099 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
1100 {
1101 UpdateRenderingStatePre(info, cell);
1102 cell->DrawInvisible(dc, x + m_PosX, y + m_PosY, info);
1103 UpdateRenderingStatePost(info, cell);
1104 }
1105 }
1106 }
1107
1108
1109 wxColour wxHtmlContainerCell::GetBackgroundColour()
1110 {
1111 if (m_UseBkColour)
1112 return m_BkColour;
1113 else
1114 return wxNullColour;
1115 }
1116
1117
1118
1119 wxHtmlLinkInfo *wxHtmlContainerCell::GetLink(int x, int y) const
1120 {
1121 wxHtmlCell *cell = FindCellByPos(x, y);
1122
1123 // VZ: I don't know if we should pass absolute or relative coords to
1124 // wxHtmlCell::GetLink()? As the base class version just ignores them
1125 // anyhow, it hardly matters right now but should still be clarified
1126 return cell ? cell->GetLink(x, y) : NULL;
1127 }
1128
1129
1130
1131 void wxHtmlContainerCell::InsertCell(wxHtmlCell *f)
1132 {
1133 if (!m_Cells) m_Cells = m_LastCell = f;
1134 else
1135 {
1136 m_LastCell->SetNext(f);
1137 m_LastCell = f;
1138 if (m_LastCell) while (m_LastCell->GetNext()) m_LastCell = m_LastCell->GetNext();
1139 }
1140 f->SetParent(this);
1141 m_LastLayout = -1;
1142 }
1143
1144
1145
1146 void wxHtmlContainerCell::SetAlign(const wxHtmlTag& tag)
1147 {
1148 if (tag.HasParam(wxT("ALIGN")))
1149 {
1150 wxString alg = tag.GetParam(wxT("ALIGN"));
1151 alg.MakeUpper();
1152 if (alg == wxT("CENTER"))
1153 SetAlignHor(wxHTML_ALIGN_CENTER);
1154 else if (alg == wxT("LEFT"))
1155 SetAlignHor(wxHTML_ALIGN_LEFT);
1156 else if (alg == wxT("JUSTIFY"))
1157 SetAlignHor(wxHTML_ALIGN_JUSTIFY);
1158 else if (alg == wxT("RIGHT"))
1159 SetAlignHor(wxHTML_ALIGN_RIGHT);
1160 m_LastLayout = -1;
1161 }
1162 }
1163
1164
1165
1166 void wxHtmlContainerCell::SetWidthFloat(const wxHtmlTag& tag, double pixel_scale)
1167 {
1168 if (tag.HasParam(wxT("WIDTH")))
1169 {
1170 int wdi;
1171 wxString wd = tag.GetParam(wxT("WIDTH"));
1172
1173 if (wd[wd.length()-1] == wxT('%'))
1174 {
1175 wxSscanf(wd.c_str(), wxT("%i%%"), &wdi);
1176 SetWidthFloat(wdi, wxHTML_UNITS_PERCENT);
1177 }
1178 else
1179 {
1180 wxSscanf(wd.c_str(), wxT("%i"), &wdi);
1181 SetWidthFloat((int)(pixel_scale * (double)wdi), wxHTML_UNITS_PIXELS);
1182 }
1183 m_LastLayout = -1;
1184 }
1185 }
1186
1187
1188
1189 const wxHtmlCell* wxHtmlContainerCell::Find(int condition, const void* param) const
1190 {
1191 if (m_Cells)
1192 {
1193 for (wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext())
1194 {
1195 const wxHtmlCell *r = cell->Find(condition, param);
1196 if (r) return r;
1197 }
1198 }
1199 return NULL;
1200 }
1201
1202
1203 wxHtmlCell *wxHtmlContainerCell::FindCellByPos(wxCoord x, wxCoord y,
1204 unsigned flags) const
1205 {
1206 if ( flags & wxHTML_FIND_EXACT )
1207 {
1208 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
1209 {
1210 int cx = cell->GetPosX(),
1211 cy = cell->GetPosY();
1212
1213 if ( (cx <= x) && (cx + cell->GetWidth() > x) &&
1214 (cy <= y) && (cy + cell->GetHeight() > y) )
1215 {
1216 return cell->FindCellByPos(x - cx, y - cy, flags);
1217 }
1218 }
1219 }
1220 else if ( flags & wxHTML_FIND_NEAREST_AFTER )
1221 {
1222 wxHtmlCell *c;
1223 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
1224 {
1225 if ( cell->IsFormattingCell() )
1226 continue;
1227 int cellY = cell->GetPosY();
1228 if (!( y < cellY || (y < cellY + cell->GetHeight() &&
1229 x < cell->GetPosX() + cell->GetWidth()) ))
1230 continue;
1231
1232 c = cell->FindCellByPos(x - cell->GetPosX(), y - cellY, flags);
1233 if (c) return c;
1234 }
1235 }
1236 else if ( flags & wxHTML_FIND_NEAREST_BEFORE )
1237 {
1238 wxHtmlCell *c2, *c = NULL;
1239 for ( const wxHtmlCell *cell = m_Cells; cell; cell = cell->GetNext() )
1240 {
1241 if ( cell->IsFormattingCell() )
1242 continue;
1243 int cellY = cell->GetPosY();
1244 if (!( cellY + cell->GetHeight() <= y ||
1245 (y >= cellY && x >= cell->GetPosX()) ))
1246 break;
1247 c2 = cell->FindCellByPos(x - cell->GetPosX(), y - cellY, flags);
1248 if (c2)
1249 c = c2;
1250 }
1251 if (c) return c;
1252 }
1253
1254 return NULL;
1255 }
1256
1257
1258 bool wxHtmlContainerCell::ProcessMouseClick(wxHtmlWindowInterface *window,
1259 const wxPoint& pos,
1260 const wxMouseEvent& event)
1261 {
1262 #if WXWIN_COMPATIBILITY_2_6
1263 wxHtmlCellOnMouseClickCompatHelper compat(window, pos, event);
1264 return compat.CallOnMouseClick(this);
1265 }
1266
1267 void wxHtmlContainerCell::OnMouseClick(wxWindow*,
1268 int, int, const wxMouseEvent& event)
1269 {
1270 wxCHECK_RET( gs_helperOnMouseClick, _T("unexpected call to OnMouseClick") );
1271 wxHtmlWindowInterface *window = gs_helperOnMouseClick->window;
1272 const wxPoint& pos = gs_helperOnMouseClick->pos;
1273 #endif // WXWIN_COMPATIBILITY_2_6
1274
1275 bool retval = false;
1276 wxHtmlCell *cell = FindCellByPos(pos.x, pos.y);
1277 if ( cell )
1278 retval = cell->ProcessMouseClick(window, pos, event);
1279
1280 #if WXWIN_COMPATIBILITY_2_6
1281 gs_helperOnMouseClick->retval = retval;
1282 #else
1283 return retval;
1284 #endif // WXWIN_COMPATIBILITY_2_6
1285 }
1286
1287
1288 wxHtmlCell *wxHtmlContainerCell::GetFirstTerminal() const
1289 {
1290 if ( m_Cells )
1291 {
1292 wxHtmlCell *c2;
1293 for (wxHtmlCell *c = m_Cells; c; c = c->GetNext())
1294 {
1295 c2 = c->GetFirstTerminal();
1296 if ( c2 )
1297 return c2;
1298 }
1299 }
1300 return NULL;
1301 }
1302
1303 wxHtmlCell *wxHtmlContainerCell::GetLastTerminal() const
1304 {
1305 if ( m_Cells )
1306 {
1307 // most common case first:
1308 wxHtmlCell *c = m_LastCell->GetLastTerminal();
1309 if ( c )
1310 return c;
1311
1312 wxHtmlCell *ctmp;
1313 wxHtmlCell *c2 = NULL;
1314 for (c = m_Cells; c; c = c->GetNext())
1315 {
1316 ctmp = c->GetLastTerminal();
1317 if ( ctmp )
1318 c2 = ctmp;
1319 }
1320 return c2;
1321 }
1322 else
1323 return NULL;
1324 }
1325
1326
1327 static bool IsEmptyContainer(wxHtmlContainerCell *cell)
1328 {
1329 for ( wxHtmlCell *c = cell->GetFirstChild(); c; c = c->GetNext() )
1330 {
1331 if ( !c->IsTerminalCell() || !c->IsFormattingCell() )
1332 return false;
1333 }
1334 return true;
1335 }
1336
1337 void wxHtmlContainerCell::RemoveExtraSpacing(bool top, bool bottom)
1338 {
1339 if ( top )
1340 SetIndent(0, wxHTML_INDENT_TOP);
1341 if ( bottom )
1342 SetIndent(0, wxHTML_INDENT_BOTTOM);
1343
1344 if ( m_Cells )
1345 {
1346 wxHtmlCell *c;
1347 wxHtmlContainerCell *cont;
1348 if ( top )
1349 {
1350 for ( c = m_Cells; c; c = c->GetNext() )
1351 {
1352 if ( c->IsTerminalCell() )
1353 {
1354 if ( !c->IsFormattingCell() )
1355 break;
1356 }
1357 else
1358 {
1359 cont = (wxHtmlContainerCell*)c;
1360 if ( IsEmptyContainer(cont) )
1361 {
1362 cont->SetIndent(0, wxHTML_INDENT_VERTICAL);
1363 }
1364 else
1365 {
1366 cont->RemoveExtraSpacing(true, false);
1367 break;
1368 }
1369 }
1370 }
1371 }
1372
1373 if ( bottom )
1374 {
1375 wxArrayPtrVoid arr;
1376 for ( c = m_Cells; c; c = c->GetNext() )
1377 arr.Add((void*)c);
1378
1379 for ( int i = arr.GetCount() - 1; i >= 0; i--)
1380 {
1381 c = (wxHtmlCell*)arr[i];
1382 if ( c->IsTerminalCell() )
1383 {
1384 if ( !c->IsFormattingCell() )
1385 break;
1386 }
1387 else
1388 {
1389 cont = (wxHtmlContainerCell*)c;
1390 if ( IsEmptyContainer(cont) )
1391 {
1392 cont->SetIndent(0, wxHTML_INDENT_VERTICAL);
1393 }
1394 else
1395 {
1396 cont->RemoveExtraSpacing(false, true);
1397 break;
1398 }
1399 }
1400 }
1401 }
1402 }
1403 }
1404
1405
1406
1407
1408 // --------------------------------------------------------------------------
1409 // wxHtmlColourCell
1410 // --------------------------------------------------------------------------
1411
1412 IMPLEMENT_ABSTRACT_CLASS(wxHtmlColourCell, wxHtmlCell)
1413
1414 void wxHtmlColourCell::Draw(wxDC& dc,
1415 int x, int y,
1416 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
1417 wxHtmlRenderingInfo& info)
1418 {
1419 DrawInvisible(dc, x, y, info);
1420 }
1421
1422 void wxHtmlColourCell::DrawInvisible(wxDC& dc,
1423 int WXUNUSED(x), int WXUNUSED(y),
1424 wxHtmlRenderingInfo& info)
1425 {
1426 wxHtmlRenderingState& state = info.GetState();
1427 if (m_Flags & wxHTML_CLR_FOREGROUND)
1428 {
1429 state.SetFgColour(m_Colour);
1430 if (state.GetSelectionState() != wxHTML_SEL_IN)
1431 dc.SetTextForeground(m_Colour);
1432 else
1433 dc.SetTextForeground(
1434 info.GetStyle().GetSelectedTextColour(m_Colour));
1435 }
1436 if (m_Flags & wxHTML_CLR_BACKGROUND)
1437 {
1438 state.SetBgColour(m_Colour);
1439 if (state.GetSelectionState() != wxHTML_SEL_IN)
1440 {
1441 dc.SetTextBackground(m_Colour);
1442 dc.SetBackground(wxBrush(m_Colour, wxSOLID));
1443 }
1444 else
1445 {
1446 wxColour c = info.GetStyle().GetSelectedTextBgColour(m_Colour);
1447 dc.SetTextBackground(c);
1448 dc.SetBackground(wxBrush(c, wxSOLID));
1449 }
1450 }
1451 }
1452
1453
1454
1455
1456 // ---------------------------------------------------------------------------
1457 // wxHtmlFontCell
1458 // ---------------------------------------------------------------------------
1459
1460 IMPLEMENT_ABSTRACT_CLASS(wxHtmlFontCell, wxHtmlCell)
1461
1462 void wxHtmlFontCell::Draw(wxDC& dc,
1463 int WXUNUSED(x), int WXUNUSED(y),
1464 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
1465 wxHtmlRenderingInfo& WXUNUSED(info))
1466 {
1467 dc.SetFont(m_Font);
1468 }
1469
1470 void wxHtmlFontCell::DrawInvisible(wxDC& dc, int WXUNUSED(x), int WXUNUSED(y),
1471 wxHtmlRenderingInfo& WXUNUSED(info))
1472 {
1473 dc.SetFont(m_Font);
1474 }
1475
1476
1477
1478
1479
1480
1481
1482
1483 // ---------------------------------------------------------------------------
1484 // wxHtmlWidgetCell
1485 // ---------------------------------------------------------------------------
1486
1487 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWidgetCell, wxHtmlCell)
1488
1489 wxHtmlWidgetCell::wxHtmlWidgetCell(wxWindow *wnd, int w)
1490 {
1491 int sx, sy;
1492 m_Wnd = wnd;
1493 m_Wnd->GetSize(&sx, &sy);
1494 m_Width = sx, m_Height = sy;
1495 m_WidthFloat = w;
1496 }
1497
1498
1499 void wxHtmlWidgetCell::Draw(wxDC& WXUNUSED(dc),
1500 int WXUNUSED(x), int WXUNUSED(y),
1501 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
1502 wxHtmlRenderingInfo& WXUNUSED(info))
1503 {
1504 int absx = 0, absy = 0, stx, sty;
1505 wxHtmlCell *c = this;
1506
1507 while (c)
1508 {
1509 absx += c->GetPosX();
1510 absy += c->GetPosY();
1511 c = c->GetParent();
1512 }
1513
1514 wxScrolledWindow *scrolwin =
1515 wxDynamicCast(m_Wnd->GetParent(), wxScrolledWindow);
1516 wxCHECK_RET( scrolwin,
1517 _T("widget cells can only be placed in wxHtmlWindow") );
1518
1519 scrolwin->GetViewStart(&stx, &sty);
1520 m_Wnd->SetSize(absx - wxHTML_SCROLL_STEP * stx,
1521 absy - wxHTML_SCROLL_STEP * sty,
1522 m_Width, m_Height);
1523 }
1524
1525
1526
1527 void wxHtmlWidgetCell::DrawInvisible(wxDC& WXUNUSED(dc),
1528 int WXUNUSED(x), int WXUNUSED(y),
1529 wxHtmlRenderingInfo& WXUNUSED(info))
1530 {
1531 int absx = 0, absy = 0, stx, sty;
1532 wxHtmlCell *c = this;
1533
1534 while (c)
1535 {
1536 absx += c->GetPosX();
1537 absy += c->GetPosY();
1538 c = c->GetParent();
1539 }
1540
1541 ((wxScrolledWindow*)(m_Wnd->GetParent()))->GetViewStart(&stx, &sty);
1542 m_Wnd->SetSize(absx - wxHTML_SCROLL_STEP * stx, absy - wxHTML_SCROLL_STEP * sty, m_Width, m_Height);
1543 }
1544
1545
1546
1547 void wxHtmlWidgetCell::Layout(int w)
1548 {
1549 if (m_WidthFloat != 0)
1550 {
1551 m_Width = (w * m_WidthFloat) / 100;
1552 m_Wnd->SetSize(m_Width, m_Height);
1553 }
1554
1555 wxHtmlCell::Layout(w);
1556 }
1557
1558
1559
1560 // ----------------------------------------------------------------------------
1561 // wxHtmlTerminalCellsInterator
1562 // ----------------------------------------------------------------------------
1563
1564 const wxHtmlCell* wxHtmlTerminalCellsInterator::operator++()
1565 {
1566 if ( !m_pos )
1567 return NULL;
1568
1569 do
1570 {
1571 if ( m_pos == m_to )
1572 {
1573 m_pos = NULL;
1574 return NULL;
1575 }
1576
1577 if ( m_pos->GetNext() )
1578 m_pos = m_pos->GetNext();
1579 else
1580 {
1581 // we must go up the hierarchy until we reach container where this
1582 // is not the last child, and then go down to first terminal cell:
1583 while ( m_pos->GetNext() == NULL )
1584 {
1585 m_pos = m_pos->GetParent();
1586 if ( !m_pos )
1587 return NULL;
1588 }
1589 m_pos = m_pos->GetNext();
1590 }
1591 while ( m_pos->GetFirstChild() != NULL )
1592 m_pos = m_pos->GetFirstChild();
1593 } while ( !m_pos->IsTerminalCell() );
1594
1595 return m_pos;
1596 }
1597
1598 #endif