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