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