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