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