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