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