| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: htmlcell.cpp |
| 3 | // Purpose: wxHtmlCell - basic element of HTML output |
| 4 | // Author: Vaclav Slavik |
| 5 | // Copyright: (c) 1999 Vaclav Slavik |
| 6 | // Licence: wxWindows Licence |
| 7 | ///////////////////////////////////////////////////////////////////////////// |
| 8 | |
| 9 | |
| 10 | #ifdef __GNUG__ |
| 11 | #pragma implementation |
| 12 | #endif |
| 13 | |
| 14 | #include <wx/wxprec.h> |
| 15 | |
| 16 | #include "wx/defs.h" |
| 17 | #if wxUSE_HTML |
| 18 | |
| 19 | #ifdef __BORDLANDC__ |
| 20 | #pragma hdrstop |
| 21 | #endif |
| 22 | |
| 23 | #ifndef WXPRECOMP |
| 24 | #include <wx/wx.h> |
| 25 | #endif |
| 26 | |
| 27 | #include <wx/html/htmlcell.h> |
| 28 | #include <wx/html/htmlwin.h> |
| 29 | #include <stdlib.h> |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | //----------------------------------------------------------------------------- |
| 35 | // wxHtmlCell |
| 36 | //----------------------------------------------------------------------------- |
| 37 | |
| 38 | |
| 39 | void wxHtmlCell::OnMouseClick(wxWindow *parent, int x, int y, bool left, bool middle, bool right) |
| 40 | { |
| 41 | if (GetLink() != wxEmptyString) |
| 42 | ((wxHtmlWindow*)parent) -> OnLinkClicked(GetLink()); |
| 43 | // note : this overcasting is legal because parent is *always* wxHtmlWindow |
| 44 | } |
| 45 | |
| 46 | |
| 47 | |
| 48 | //----------------------------------------------------------------------------- |
| 49 | // wxHtmlWordCell |
| 50 | //----------------------------------------------------------------------------- |
| 51 | |
| 52 | wxHtmlWordCell::wxHtmlWordCell(const wxString& word, wxDC& dc) : wxHtmlCell() |
| 53 | { |
| 54 | m_Word = word; |
| 55 | m_Word.Replace(" ", " ", TRUE); |
| 56 | m_Word.Replace(""", "\"", TRUE); |
| 57 | m_Word.Replace("<", "<", TRUE); |
| 58 | m_Word.Replace(">", ">", TRUE); |
| 59 | m_Word.Replace("&", "&", TRUE); |
| 60 | dc.GetTextExtent(m_Word, &m_Width, &m_Height, &m_Descent); |
| 61 | } |
| 62 | |
| 63 | |
| 64 | |
| 65 | void wxHtmlWordCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) |
| 66 | { |
| 67 | dc.DrawText(m_Word, x + m_PosX, y + m_PosY); |
| 68 | wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); |
| 69 | } |
| 70 | |
| 71 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | |
| 76 | |
| 77 | //----------------------------------------------------------------------------- |
| 78 | // wxHtmlContainerCell |
| 79 | //----------------------------------------------------------------------------- |
| 80 | |
| 81 | |
| 82 | wxHtmlContainerCell::wxHtmlContainerCell(wxHtmlContainerCell *parent) : wxHtmlCell() |
| 83 | { |
| 84 | m_Cells = m_LastCell = NULL; |
| 85 | m_Parent = parent; |
| 86 | if (m_Parent) m_Parent -> InsertCell(this); |
| 87 | m_AlignHor = HTML_ALIGN_LEFT; |
| 88 | m_AlignVer = HTML_ALIGN_BOTTOM; |
| 89 | m_IndentLeft = m_IndentRight = m_IndentTop = m_IndentBottom = 0; |
| 90 | m_WidthFloat = 100; m_WidthFloatUnits = HTML_UNITS_PERCENT; |
| 91 | m_UseBkColour = FALSE; |
| 92 | m_UseBorder = FALSE; |
| 93 | m_MinHeight = m_MaxLineWidth = 0; |
| 94 | m_MinHeightAlign = HTML_ALIGN_TOP; |
| 95 | } |
| 96 | |
| 97 | |
| 98 | |
| 99 | void wxHtmlContainerCell::SetIndent(int i, int what, int units) |
| 100 | { |
| 101 | int val = (units == HTML_UNITS_PIXELS) ? i : -i; |
| 102 | if (what & HTML_INDENT_LEFT) m_IndentLeft = val; |
| 103 | if (what & HTML_INDENT_RIGHT) m_IndentRight = val; |
| 104 | if (what & HTML_INDENT_TOP) m_IndentTop = val; |
| 105 | if (what & HTML_INDENT_BOTTOM) m_IndentBottom = val; |
| 106 | } |
| 107 | |
| 108 | |
| 109 | |
| 110 | int wxHtmlContainerCell::GetIndent(int ind) const |
| 111 | { |
| 112 | if (ind & HTML_INDENT_LEFT) return m_IndentLeft; |
| 113 | else if (ind & HTML_INDENT_RIGHT) return m_IndentRight; |
| 114 | else if (ind & HTML_INDENT_TOP) return m_IndentTop; |
| 115 | else if (ind & HTML_INDENT_BOTTOM) return m_IndentBottom; |
| 116 | else return -1; /* BUG! Should not be called... */ |
| 117 | } |
| 118 | |
| 119 | |
| 120 | |
| 121 | |
| 122 | int wxHtmlContainerCell::GetIndentUnits(int ind) const |
| 123 | { |
| 124 | bool p = FALSE; |
| 125 | if (ind & HTML_INDENT_LEFT) p = m_IndentLeft < 0; |
| 126 | else if (ind & HTML_INDENT_RIGHT) p = m_IndentRight < 0; |
| 127 | else if (ind & HTML_INDENT_TOP) p = m_IndentTop < 0; |
| 128 | else if (ind & HTML_INDENT_BOTTOM) p = m_IndentBottom < 0; |
| 129 | if (p) return HTML_UNITS_PERCENT; |
| 130 | else return HTML_UNITS_PIXELS; |
| 131 | } |
| 132 | |
| 133 | |
| 134 | |
| 135 | void wxHtmlContainerCell::Layout(int w) |
| 136 | { |
| 137 | wxHtmlCell *cell = m_Cells, *line = m_Cells; |
| 138 | long xpos = 0, ypos = m_IndentTop; |
| 139 | int xdelta = 0, ybasicpos = 0, ydiff; |
| 140 | int s_width, s_indent; |
| 141 | int ysizeup = 0, ysizedown = 0; |
| 142 | |
| 143 | /* |
| 144 | |
| 145 | WIDTH ADJUSTING : |
| 146 | |
| 147 | */ |
| 148 | |
| 149 | if (m_WidthFloatUnits == HTML_UNITS_PERCENT) { |
| 150 | if (m_WidthFloat < 0) m_Width = (100 + m_WidthFloat) * w / 100; |
| 151 | else m_Width = m_WidthFloat * w / 100; |
| 152 | } |
| 153 | else { |
| 154 | if (m_WidthFloat < 0) m_Width = w + m_WidthFloat; |
| 155 | else m_Width = m_WidthFloat; |
| 156 | } |
| 157 | |
| 158 | if (m_Cells) { |
| 159 | int l = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft; |
| 160 | int r = (m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight; |
| 161 | m_Cells -> Layout(m_Width - (l + r)); |
| 162 | } |
| 163 | |
| 164 | /* |
| 165 | |
| 166 | LAYOUTING : |
| 167 | |
| 168 | */ |
| 169 | |
| 170 | // adjust indentation: |
| 171 | s_indent = (m_IndentLeft < 0) ? (-m_IndentLeft * m_Width / 100) : m_IndentLeft; |
| 172 | s_width = m_Width - s_indent - ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight); |
| 173 | |
| 174 | m_MaxLineWidth = 0; |
| 175 | |
| 176 | // my own layouting: |
| 177 | while (cell != NULL) { |
| 178 | switch (m_AlignVer) { |
| 179 | case HTML_ALIGN_TOP : ybasicpos = 0; break; |
| 180 | case HTML_ALIGN_BOTTOM : ybasicpos = - cell -> GetHeight(); break; |
| 181 | case HTML_ALIGN_CENTER : ybasicpos = - cell -> GetHeight() / 2; break; |
| 182 | } |
| 183 | ydiff = cell -> GetHeight() + ybasicpos; |
| 184 | |
| 185 | if (cell -> GetDescent() + ydiff > ysizedown) ysizedown = cell -> GetDescent() + ydiff; |
| 186 | if (ybasicpos + cell -> GetDescent() < -ysizeup) ysizeup = - (ybasicpos + cell -> GetDescent()); |
| 187 | |
| 188 | cell -> SetPos(xpos, ybasicpos + cell -> GetDescent()); |
| 189 | xpos += cell -> GetWidth(); |
| 190 | cell = cell -> GetNext(); |
| 191 | |
| 192 | // force new line if occured: |
| 193 | if ((cell == NULL) || (xpos + cell -> GetWidth() > s_width)) { |
| 194 | if (xpos > m_MaxLineWidth) m_MaxLineWidth = xpos; |
| 195 | if (ysizeup < 0) ysizeup = 0; |
| 196 | if (ysizedown < 0) ysizedown = 0; |
| 197 | switch (m_AlignHor) { |
| 198 | case HTML_ALIGN_LEFT : xdelta = 0; break; |
| 199 | case HTML_ALIGN_RIGHT : xdelta = 0 + (s_width - xpos); break; |
| 200 | case HTML_ALIGN_CENTER : xdelta = 0 + (s_width - xpos) / 2; break; |
| 201 | } |
| 202 | if (xdelta < 0) xdelta = 0; |
| 203 | xdelta += s_indent; |
| 204 | |
| 205 | ypos += ysizeup; |
| 206 | while (line != cell) { |
| 207 | line -> SetPos(line -> GetPosX() + xdelta, ypos + line -> GetPosY()); |
| 208 | line = line -> GetNext(); |
| 209 | } |
| 210 | |
| 211 | ypos += ysizedown; |
| 212 | xpos = 0; |
| 213 | ysizeup = ysizedown = 0; |
| 214 | line = cell; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | // setup height & width, depending on container layout: |
| 219 | m_Height = ypos + (ysizedown + ysizeup) + m_IndentBottom; |
| 220 | |
| 221 | if (m_Height < m_MinHeight) { |
| 222 | if (m_MinHeightAlign != HTML_ALIGN_TOP) { |
| 223 | int diff = m_MinHeight - m_Height; |
| 224 | if (m_MinHeightAlign == HTML_ALIGN_CENTER) diff /= 2; |
| 225 | cell = m_Cells; |
| 226 | while (cell) { |
| 227 | cell -> SetPos(cell -> GetPosX(), cell -> GetPosY() + diff); |
| 228 | cell = cell -> GetNext(); |
| 229 | } |
| 230 | } |
| 231 | m_Height = m_MinHeight; |
| 232 | } |
| 233 | |
| 234 | m_MaxLineWidth += s_indent + ((m_IndentRight < 0) ? (-m_IndentRight * m_Width / 100) : m_IndentRight); |
| 235 | if (m_Width < m_MaxLineWidth) m_Width = m_MaxLineWidth; |
| 236 | |
| 237 | wxHtmlCell::Layout(w); |
| 238 | } |
| 239 | |
| 240 | |
| 241 | #define mMin(a, b) (((a) < (b)) ? (a) : (b)) |
| 242 | #define mMax(a, b) (((a) < (b)) ? (b) : (a)) |
| 243 | |
| 244 | void wxHtmlContainerCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) |
| 245 | { |
| 246 | // container visible, draw it: |
| 247 | if ((y + m_PosY < view_y2) && (y + m_PosY + m_Height > view_y1)) { |
| 248 | |
| 249 | if (m_UseBkColour) { |
| 250 | wxBrush myb = wxBrush(m_BkColour, wxSOLID); |
| 251 | |
| 252 | int real_y1 = mMax(y + m_PosY, view_y1); |
| 253 | int real_y2 = mMin(y + m_PosY + m_Height - 1, view_y2); |
| 254 | |
| 255 | dc.SetBrush(myb); |
| 256 | dc.SetPen(*wxTRANSPARENT_PEN); |
| 257 | dc.DrawRectangle(x + m_PosX, real_y1, m_Width, real_y2 - real_y1 + 1); |
| 258 | } |
| 259 | |
| 260 | if (m_UseBorder) { |
| 261 | wxPen mypen1(m_BorderColour1, 1, wxSOLID); |
| 262 | wxPen mypen2(m_BorderColour2, 1, wxSOLID); |
| 263 | |
| 264 | dc.SetPen(mypen1); |
| 265 | dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX, y + m_PosY + m_Height - 1); |
| 266 | dc.DrawLine(x + m_PosX, y + m_PosY, x + m_PosX + m_Width - 1, y + m_PosY); |
| 267 | dc.SetPen(mypen2); |
| 268 | dc.DrawLine(x + m_PosX + m_Width - 1, y + m_PosY, x + m_PosX + m_Width - 1, y + m_PosY + m_Height - 1); |
| 269 | dc.DrawLine(x + m_PosX, y + m_PosY + m_Height - 1, x + m_PosX + m_Width - 1, y + m_PosY + m_Height - 1); |
| 270 | } |
| 271 | |
| 272 | if (m_Cells) m_Cells -> Draw(dc, x + m_PosX, y + m_PosY, view_y1, view_y2); |
| 273 | } |
| 274 | // container invisible, just proceed font+color changing: |
| 275 | else { |
| 276 | if (m_Cells) m_Cells -> DrawInvisible(dc, x + m_PosX, y + m_PosY); |
| 277 | } |
| 278 | |
| 279 | wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); |
| 280 | } |
| 281 | |
| 282 | |
| 283 | |
| 284 | void wxHtmlContainerCell::DrawInvisible(wxDC& dc, int x, int y) |
| 285 | { |
| 286 | if (m_Cells) m_Cells -> DrawInvisible(dc, x + m_PosX, y + m_PosY); |
| 287 | wxHtmlCell::DrawInvisible(dc, x, y); |
| 288 | } |
| 289 | |
| 290 | |
| 291 | |
| 292 | wxString wxHtmlContainerCell::GetLink(int x, int y) const |
| 293 | { |
| 294 | wxHtmlCell *c = m_Cells; |
| 295 | int cx, cy, cw, ch; |
| 296 | |
| 297 | while (c) { |
| 298 | cx = c -> GetPosX(), cy = c -> GetPosY(); |
| 299 | cw = c -> GetWidth(), ch = c -> GetHeight(); |
| 300 | if ((x >= cx) && (x < cx + cw) && (y >= cy) && (y < cy + ch)) |
| 301 | return c -> GetLink(x - cx, y - cy); |
| 302 | c = c -> GetNext(); |
| 303 | } |
| 304 | return wxEmptyString; |
| 305 | } |
| 306 | |
| 307 | |
| 308 | |
| 309 | void wxHtmlContainerCell::InsertCell(wxHtmlCell *f) |
| 310 | { |
| 311 | if (!m_Cells) m_Cells = m_LastCell = f; |
| 312 | else { |
| 313 | m_LastCell -> SetNext(f); |
| 314 | m_LastCell = f; |
| 315 | if (m_LastCell) while (m_LastCell -> GetNext()) m_LastCell = m_LastCell -> GetNext(); |
| 316 | } |
| 317 | f -> SetParent(this); |
| 318 | } |
| 319 | |
| 320 | |
| 321 | |
| 322 | void wxHtmlContainerCell::SetAlign(const wxHtmlTag& tag) |
| 323 | { |
| 324 | if (tag.HasParam("ALIGN")) { |
| 325 | wxString alg = tag.GetParam("ALIGN"); |
| 326 | alg.MakeUpper(); |
| 327 | if (alg == "CENTER") |
| 328 | SetAlignHor(HTML_ALIGN_CENTER); |
| 329 | else if (alg == "LEFT") |
| 330 | SetAlignHor(HTML_ALIGN_LEFT); |
| 331 | else if (alg == "RIGHT") |
| 332 | SetAlignHor(HTML_ALIGN_RIGHT); |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | |
| 337 | |
| 338 | void wxHtmlContainerCell::SetWidthFloat(const wxHtmlTag& tag) |
| 339 | { |
| 340 | if (tag.HasParam("WIDTH")) { |
| 341 | int wdi; |
| 342 | wxString wd = tag.GetParam("WIDTH"); |
| 343 | |
| 344 | if (wd[wd.Length()-1] == '%') { |
| 345 | sscanf(wd.c_str(), "%i%%", &wdi); |
| 346 | SetWidthFloat(wdi, HTML_UNITS_PERCENT); |
| 347 | } |
| 348 | else { |
| 349 | sscanf(wd.c_str(), "%i", &wdi); |
| 350 | SetWidthFloat(wdi, HTML_UNITS_PIXELS); |
| 351 | } |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | |
| 356 | |
| 357 | const wxHtmlCell* wxHtmlContainerCell::Find(int condition, const void* param) const |
| 358 | { |
| 359 | const wxHtmlCell *r = NULL; |
| 360 | |
| 361 | if (m_Cells) { |
| 362 | r = m_Cells -> Find(condition, param); |
| 363 | if (r) return r; |
| 364 | } |
| 365 | |
| 366 | return wxHtmlCell::Find(condition, param); |
| 367 | } |
| 368 | |
| 369 | |
| 370 | |
| 371 | void wxHtmlContainerCell::OnMouseClick(wxWindow *parent, int x, int y, bool left, bool middle, bool right) |
| 372 | { |
| 373 | if (m_Cells) { |
| 374 | wxHtmlCell *c = m_Cells; |
| 375 | while (c) { |
| 376 | if ( (c -> GetPosX() <= x) && |
| 377 | (c -> GetPosY() <= y) && |
| 378 | (c -> GetPosX() + c -> GetWidth() > x) && |
| 379 | (c -> GetPosY() + c -> GetHeight() > y)) { |
| 380 | c -> OnMouseClick(parent, x - c -> GetPosX(), y - c -> GetPosY(), left, middle, right); |
| 381 | break; |
| 382 | } |
| 383 | c = c -> GetNext(); |
| 384 | } |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | |
| 389 | |
| 390 | |
| 391 | |
| 392 | //-------------------------------------------------------------------------------- |
| 393 | // wxHtmlColourCell |
| 394 | //-------------------------------------------------------------------------------- |
| 395 | |
| 396 | void wxHtmlColourCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) |
| 397 | { |
| 398 | if (m_Flags & HTML_CLR_FOREGROUND) |
| 399 | dc.SetTextForeground(m_Colour); |
| 400 | if (m_Flags & HTML_CLR_BACKGROUND) { |
| 401 | dc.SetBackground(wxBrush(m_Colour, wxSOLID)); |
| 402 | dc.SetTextBackground(m_Colour); |
| 403 | } |
| 404 | wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); |
| 405 | } |
| 406 | |
| 407 | void wxHtmlColourCell::DrawInvisible(wxDC& dc, int x, int y) |
| 408 | { |
| 409 | if (m_Flags & HTML_CLR_FOREGROUND) |
| 410 | dc.SetTextForeground(m_Colour); |
| 411 | if (m_Flags & HTML_CLR_BACKGROUND) { |
| 412 | dc.SetBackground(wxBrush(m_Colour, wxSOLID)); |
| 413 | dc.SetTextBackground(m_Colour); |
| 414 | } |
| 415 | wxHtmlCell::DrawInvisible(dc, x, y); |
| 416 | } |
| 417 | |
| 418 | |
| 419 | |
| 420 | |
| 421 | //-------------------------------------------------------------------------------- |
| 422 | // wxHtmlFontCell |
| 423 | //-------------------------------------------------------------------------------- |
| 424 | |
| 425 | void wxHtmlFontCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) |
| 426 | { |
| 427 | dc.SetFont(*m_Font); |
| 428 | wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); |
| 429 | } |
| 430 | |
| 431 | void wxHtmlFontCell::DrawInvisible(wxDC& dc, int x, int y) |
| 432 | { |
| 433 | dc.SetFont(*m_Font); |
| 434 | wxHtmlCell::DrawInvisible(dc, x, y); |
| 435 | } |
| 436 | |
| 437 | |
| 438 | |
| 439 | |
| 440 | |
| 441 | |
| 442 | |
| 443 | |
| 444 | //-------------------------------------------------------------------------------- |
| 445 | // wxHtmlWidgetCell |
| 446 | //-------------------------------------------------------------------------------- |
| 447 | |
| 448 | wxHtmlWidgetCell::wxHtmlWidgetCell(wxWindow *wnd, int w) |
| 449 | { |
| 450 | int sx, sy; |
| 451 | m_Wnd = wnd; |
| 452 | m_Wnd -> GetSize(&sx, &sy); |
| 453 | m_Width = sx, m_Height = sy; |
| 454 | m_WidthFloat = w; |
| 455 | } |
| 456 | |
| 457 | |
| 458 | void wxHtmlWidgetCell::Draw(wxDC& dc, int x, int y, int view_y1, int view_y2) |
| 459 | { |
| 460 | int absx = 0, absy = 0, stx, sty; |
| 461 | wxHtmlCell *c = this; |
| 462 | |
| 463 | while (c) { |
| 464 | absx += c -> GetPosX(); |
| 465 | absy += c -> GetPosY(); |
| 466 | c = c -> GetParent(); |
| 467 | } |
| 468 | |
| 469 | ((wxScrolledWindow*)(m_Wnd -> GetParent())) -> ViewStart(&stx, &sty); |
| 470 | |
| 471 | m_Wnd -> SetSize(absx - HTML_SCROLL_STEP * stx, absy - HTML_SCROLL_STEP * sty, m_Width, m_Height); |
| 472 | // m_Wnd -> Refresh(); |
| 473 | |
| 474 | wxHtmlCell::Draw(dc, x, y, view_y1, view_y2); |
| 475 | } |
| 476 | |
| 477 | |
| 478 | |
| 479 | void wxHtmlWidgetCell::DrawInvisible(wxDC& dc, int x, int y) |
| 480 | { |
| 481 | int absx = 0, absy = 0, stx, sty; |
| 482 | wxHtmlCell *c = this; |
| 483 | |
| 484 | while (c) { |
| 485 | absx += c -> GetPosX(); |
| 486 | absy += c -> GetPosY(); |
| 487 | c = c -> GetParent(); |
| 488 | } |
| 489 | ((wxScrolledWindow*)(m_Wnd -> GetParent())) -> ViewStart(&stx, &sty); |
| 490 | |
| 491 | m_Wnd -> SetSize(absx - HTML_SCROLL_STEP * stx, absy - HTML_SCROLL_STEP * sty, m_Width, m_Height); |
| 492 | wxHtmlCell::DrawInvisible(dc, x, y); |
| 493 | } |
| 494 | |
| 495 | |
| 496 | |
| 497 | void wxHtmlWidgetCell::Layout(int w) |
| 498 | { |
| 499 | if (m_WidthFloat != 0) { |
| 500 | m_Width = (w * m_WidthFloat) / 100; |
| 501 | m_Wnd -> SetSize(m_Width, m_Height); |
| 502 | } |
| 503 | |
| 504 | wxHtmlCell::Layout(w); |
| 505 | } |
| 506 | |
| 507 | #endif |