1
///////////////////////////////////////////////////////////////////////////////
2
// Name: wx/htmllbox.cpp
3
// Purpose: wxHtmlListBox is a listbox whose items are wxHtmlCells
4
// Author: Vadim Zeitlin
5
// Modified by: Charlie Fenton
7
// RCS-ID: $Id: htmllbox.h 49804 2007-11-10 01:09:42Z VZ $
8
// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwidgets.org>
9
// Licence: wxWindows licence
10
///////////////////////////////////////////////////////////////////////////////
12
// Modified for BOINC from wx/htmllbox.cpp
15
// ============================================================================
17
// ============================================================================
19
// ----------------------------------------------------------------------------
21
// ----------------------------------------------------------------------------
24
#include "BOINCHtmlLBox.h"
26
// ----------------------------------------------------------------------------
28
// ----------------------------------------------------------------------------
30
const wxChar BOINCHtmlListBoxNameStr[] = wxT("BOINCHtmlListBox");
32
// ============================================================================
34
// ============================================================================
36
// ----------------------------------------------------------------------------
37
// CBOINCHtmlListBoxCache
38
// ----------------------------------------------------------------------------
40
// this class is used by CBOINCHtmlListBox to cache the parsed representation of
41
// the items to avoid doing it anew each time an item must be drawn
42
class CBOINCHtmlListBoxCache
45
// invalidate a single item, used by Clear() and InvalidateRange()
46
void InvalidateItem(size_t n)
48
m_items[n] = (size_t)-1;
54
CBOINCHtmlListBoxCache()
56
for ( size_t n = 0; n < SIZE; n++ )
58
m_items[n] = (size_t)-1;
65
~CBOINCHtmlListBoxCache()
67
for ( size_t n = 0; n < SIZE; n++ )
73
// completely invalidate the cache
76
for ( size_t n = 0; n < SIZE; n++ )
82
// return the cached cell for this index or NULL if none
83
wxHtmlCell *Get(size_t item) const
85
for ( size_t n = 0; n < SIZE; n++ )
87
if ( m_items[n] == item )
94
// returns true if we already have this item cached
95
bool Has(size_t item) const { return Get(item) != NULL; }
97
// ensure that the item is cached
98
void Store(size_t item, wxHtmlCell *cell)
100
delete m_cells[m_next];
101
m_cells[m_next] = cell;
102
m_items[m_next] = item;
104
// advance to the next item wrapping around if there are no more
105
if ( ++m_next == SIZE )
109
// forget the cached value of the item(s) between the given ones (inclusive)
110
void InvalidateRange(size_t from, size_t to)
112
for ( size_t n = 0; n < SIZE; n++ )
114
if ( m_items[n] >= from && m_items[n] <= to )
122
// the max number of the items we cache
125
// the index of the LRU (oldest) cell
128
// the parsed representation of the cached item or NULL
129
wxHtmlCell *m_cells[SIZE];
131
// the index of the currently cached item (only valid if m_cells != NULL)
132
size_t m_items[SIZE];
135
// ----------------------------------------------------------------------------
136
// CBOINCHtmlListBoxStyle
137
// ----------------------------------------------------------------------------
139
// just forward wxDefaultHtmlRenderingStyle callbacks to the main class so that
140
// they could be overridden by the user code
141
class CBOINCHtmlListBoxStyle : public wxDefaultHtmlRenderingStyle
144
CBOINCHtmlListBoxStyle(const CBOINCHtmlListBox& hlbox) : m_hlbox(hlbox) { }
146
virtual wxColour GetSelectedTextColour(const wxColour& colFg)
148
return m_hlbox.GetSelectedTextColour(colFg);
151
virtual wxColour GetSelectedTextBgColour(const wxColour& colBg)
153
return m_hlbox.GetSelectedTextBgColour(colBg);
157
const CBOINCHtmlListBox& m_hlbox;
159
DECLARE_NO_COPY_CLASS(CBOINCHtmlListBoxStyle)
162
// ----------------------------------------------------------------------------
164
// ----------------------------------------------------------------------------
166
BEGIN_EVENT_TABLE(CBOINCHtmlListBox, CBOINCVListBox)
167
EVT_SIZE(CBOINCHtmlListBox::OnSize)
168
EVT_MOTION(CBOINCHtmlListBox::OnMouseMove)
169
EVT_LEFT_DOWN(CBOINCHtmlListBox::OnLeftDown)
172
// ============================================================================
174
// ============================================================================
176
IMPLEMENT_ABSTRACT_CLASS(CBOINCHtmlListBox, CBOINCVListBox)
179
// ----------------------------------------------------------------------------
180
// CBOINCHtmlListBox creation
181
// ----------------------------------------------------------------------------
183
CBOINCHtmlListBox::CBOINCHtmlListBox()
184
: wxHtmlWindowMouseHelper(this)
189
// normal constructor which calls Create() internally
190
CBOINCHtmlListBox::CBOINCHtmlListBox(wxWindow *parent,
195
const wxString& name)
196
: wxHtmlWindowMouseHelper(this)
200
(void)Create(parent, id, pos, size, style, name);
203
void CBOINCHtmlListBox::Init()
206
m_htmlRendStyle = new CBOINCHtmlListBoxStyle(*this);
207
m_cache = new CBOINCHtmlListBoxCache;
210
bool CBOINCHtmlListBox::Create(wxWindow *parent,
215
const wxString& name)
217
return CBOINCVListBox::Create(parent, id, pos, size, style, name);
220
CBOINCHtmlListBox::~CBOINCHtmlListBox()
226
delete m_htmlParser->GetDC();
230
delete m_htmlRendStyle;
233
// ----------------------------------------------------------------------------
234
// CBOINCHtmlListBox appearance
235
// ----------------------------------------------------------------------------
237
wxColour CBOINCHtmlListBox::GetSelectedTextColour(const wxColour& colFg) const
239
return m_htmlRendStyle->
240
wxDefaultHtmlRenderingStyle::GetSelectedTextColour(colFg);
244
CBOINCHtmlListBox::GetSelectedTextBgColour(const wxColour& WXUNUSED(colBg)) const
246
return GetSelectionBackground();
249
// ----------------------------------------------------------------------------
250
// CBOINCHtmlListBox items markup
251
// ----------------------------------------------------------------------------
253
wxString CBOINCHtmlListBox::OnGetItemMarkup(size_t n) const
255
// we don't even need to wrap the value returned by OnGetItem() inside
256
// "<html><body>" and "</body></html>" because wxHTML can parse it even
257
// without these tags
261
// ----------------------------------------------------------------------------
262
// CBOINCHtmlListBox cache handling
263
// ----------------------------------------------------------------------------
265
void CBOINCHtmlListBox::CacheItem(size_t n) const
267
if ( !m_cache->Has(n) )
271
CBOINCHtmlListBox *self = wxConstCast(this, CBOINCHtmlListBox);
273
self->m_htmlParser = new wxHtmlWinParser(self);
274
m_htmlParser->SetDC(new wxClientDC(self));
275
m_htmlParser->SetFS(&self->m_filesystem);
278
m_htmlParser->SetInputEncoding(GetFont().GetEncoding());
280
// use system's default GUI font by default:
281
m_htmlParser->SetStandardFonts();
284
wxHtmlContainerCell *cell = (wxHtmlContainerCell *)m_htmlParser->
285
Parse(OnGetItemMarkup(n));
286
wxCHECK_RET( cell, _T("wxHtmlParser::Parse() returned NULL?") );
288
// set the cell's ID to item's index so that CellCoordsToPhysical()
289
// can quickly find the item:
290
cell->SetId(wxString::Format(_T("%lu"), (unsigned long)n));
292
cell->Layout(GetClientSize().x - (2 * GetMargins().x));
294
m_cache->Store(n, cell);
298
void CBOINCHtmlListBox::OnSize(wxSizeEvent& event)
300
// we need to relayout all the cached cells
306
void CBOINCHtmlListBox::RefreshItem(size_t item)
310
m_cache->InvalidateRange(item, item);
312
GetItemRect(item, rect);
316
void CBOINCHtmlListBox::RefreshItems(size_t from, size_t to)
320
m_cache->InvalidateRange(from, to);
322
for (size_t i = from; i <= to; ++i) {
323
GetItemRect(i, rect);
328
void CBOINCHtmlListBox::SetItemCount(size_t count)
330
// the items are going to change, forget the old ones
333
CBOINCVListBox::SetItemCount(count);
336
// ----------------------------------------------------------------------------
337
// CBOINCHtmlListBox implementation of CBOINCVListBox pure virtuals
338
// ----------------------------------------------------------------------------
340
void CBOINCHtmlListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
344
wxHtmlCell *cell = m_cache->Get(n);
345
wxCHECK_RET( cell, _T("this cell should be cached!") );
347
wxHtmlRenderingInfo htmlRendInfo;
349
// draw the selected cell in selected state
352
wxHtmlSelection htmlSel;
353
htmlSel.Set(wxPoint(0,0), cell, wxPoint(INT_MAX, INT_MAX), cell);
354
htmlRendInfo.SetSelection(&htmlSel);
355
if ( m_htmlRendStyle )
356
htmlRendInfo.SetStyle(m_htmlRendStyle);
357
htmlRendInfo.GetState().SetSelectionState(wxHTML_SEL_IN);
360
// note that we can't stop drawing exactly at the window boundary as then
361
// even the visible cells part could be not drawn, so always draw the
364
rect.x + CELL_BORDER, rect.y + CELL_BORDER,
365
0, INT_MAX, htmlRendInfo);
368
wxCoord CBOINCHtmlListBox::OnMeasureItem(size_t n) const
372
wxHtmlCell *cell = m_cache->Get(n);
373
wxCHECK_MSG( cell, 0, _T("this cell should be cached!") );
375
return cell->GetHeight() + cell->GetDescent() + (2 * CELL_BORDER);
378
wxCoord CBOINCHtmlListBox::GetMaxItemWidth() const
380
wxCoord w, maxWidth = 0;
381
size_t n = GetItemCount();
382
for (size_t i = 0; i < n; ++i) {
384
wxHtmlCell *cell = m_cache->Get(i);
385
w = cell->GetWidth();
386
if (w > maxWidth) maxWidth = w;
391
// ----------------------------------------------------------------------------
392
// CBOINCHtmlListBox implementation of wxHtmlListBoxWinInterface
393
// ----------------------------------------------------------------------------
395
void CBOINCHtmlListBox::SetHTMLWindowTitle(const wxString& WXUNUSED(title))
400
void CBOINCHtmlListBox::OnHTMLLinkClicked(const wxHtmlLinkInfo& link)
402
OnLinkClicked(GetItemForCell(link.GetHtmlCell()), link);
405
void CBOINCHtmlListBox::OnLinkClicked(size_t WXUNUSED(n),
406
const wxHtmlLinkInfo& link)
408
wxHtmlLinkEvent event(GetId(), link);
409
GetEventHandler()->ProcessEvent(event);
413
CBOINCHtmlListBox::OnHTMLOpeningURL(wxHtmlURLType WXUNUSED(type),
414
const wxString& WXUNUSED(url),
415
wxString *WXUNUSED(redirect)) const
420
wxPoint CBOINCHtmlListBox::HTMLCoordsToWindow(wxHtmlCell *cell,
421
const wxPoint& pos) const
423
return CellCoordsToPhysical(pos, cell);
426
wxWindow* CBOINCHtmlListBox::GetHTMLWindow() { return this; }
428
wxColour CBOINCHtmlListBox::GetHTMLBackgroundColour() const
430
return GetBackgroundColour();
433
void CBOINCHtmlListBox::SetHTMLBackgroundColour(const wxColour& WXUNUSED(clr))
438
void CBOINCHtmlListBox::SetHTMLBackgroundImage(const wxBitmap& WXUNUSED(bmpBg))
443
void CBOINCHtmlListBox::SetHTMLStatusText(const wxString& WXUNUSED(text))
448
wxCursor CBOINCHtmlListBox::GetHTMLCursor(HTMLCursor type) const
450
// we don't want to show text selection cursor in listboxes
451
if (type == HTMLCursor_Text)
452
return wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor_Default);
454
// in all other cases, use the same cursor as wxHtmlWindow:
455
return wxHtmlWindow::GetDefaultHTMLCursor(type);
458
// ----------------------------------------------------------------------------
459
// CBOINCHtmlListBox utilities
460
// ----------------------------------------------------------------------------
462
int CBOINCHtmlListBox::HitTest(const wxPoint& pos)
464
if ( CBOINCVListBox::HitTest(pos) == wxNOT_FOUND )
468
size_t n = GetItemCount();
471
GetViewStart(&x, &y);
472
wxPoint p(-x*PIXELS_PER_HORIZONTAL_SCROLL_UNIT, -y*PIXELS_PER_VERTICAL_SCROLL_UNIT);
473
p.y -= GetMargins().y + CELL_BORDER;
474
p.x += GetMargins().x - CELL_BORDER;
478
for (size_t i = 0; i < n; ++i) {
480
wxHtmlCell *aCell = m_cache->Get(i);
481
r.height = OnGetItemHeight(i);
482
r.width = aCell->GetWidth();
483
if (r.Contains(pos)) {
484
// convert mouse coordinates to coords relative to item's wxHtmlCell:
487
r.y += r.height; // + (2 * GetMargins().y);
492
void CBOINCHtmlListBox::GetItemRect(size_t item, wxRect& rect)
494
wxPoint pos = GetRootCellCoords(item);
495
pos.x += GetMargins().x - CELL_BORDER;
496
pos.y -= GetMargins().y + CELL_BORDER;
497
rect.SetTopLeft(pos);
499
wxHtmlCell *cell = m_cache->Get(item);
500
rect.height = OnGetItemHeight(item);
501
rect.width = cell->GetWidth();
504
bool CBOINCHtmlListBox::IsVisible(size_t item)
508
GetItemRect(item, rect);
510
return (rect.Intersects(GetRect()));
513
// ----------------------------------------------------------------------------
514
// CBOINCHtmlListBox handling of HTML links
515
// ----------------------------------------------------------------------------
517
wxPoint CBOINCHtmlListBox::GetRootCellCoords(size_t n) const
520
// wxPoint pos(GetMargins().x - CELL_BORDER, -GetMargins().y - CELL_BORDER);
523
for (size_t i = 0; i < n; ++i) {
524
pos.y += OnGetItemHeight(i);
526
GetViewStart(&x, &y);
527
pos.x -= x*PIXELS_PER_HORIZONTAL_SCROLL_UNIT;
528
pos.y -= y*PIXELS_PER_VERTICAL_SCROLL_UNIT;
532
bool CBOINCHtmlListBox::PhysicalCoordsToCell(wxPoint& pos, wxHtmlCell*& cell) const
534
if ( CBOINCVListBox::HitTest(pos) == wxNOT_FOUND )
538
size_t n = GetItemCount();
540
wxPoint p(CELL_BORDER, CELL_BORDER);
544
GetViewStart(&x, &y);
545
p.x -= x*PIXELS_PER_HORIZONTAL_SCROLL_UNIT;
546
p.y -= y*PIXELS_PER_VERTICAL_SCROLL_UNIT;
549
for (size_t i = 0; i < n; ++i) {
551
wxHtmlCell *aCell = m_cache->Get(i);
552
r.height = aCell->GetHeight() + aCell->GetDescent() + (2 * CELL_BORDER);
553
r.width = aCell->GetWidth();
554
if (r.Contains(pos)) {
556
// convert mouse coordinates to coords relative to item's wxHtmlCell:
557
pos -= r.GetTopLeft();
560
r.y += r.height + (2 * GetMargins().y);
566
size_t CBOINCHtmlListBox::GetItemForCell(const wxHtmlCell *cell) const
568
wxCHECK_MSG( cell, 0, _T("no cell") );
570
cell = cell->GetRootCell();
572
wxCHECK_MSG( cell, 0, _T("no root cell") );
574
// the cell's ID contains item index, see CacheItem():
576
if ( !cell->GetId().ToULong(&n) )
578
wxFAIL_MSG( _T("unexpected root cell's ID") );
586
CBOINCHtmlListBox::CellCoordsToPhysical(const wxPoint& pos, wxHtmlCell *cell) const
588
return pos + GetRootCellCoords(GetItemForCell(cell));
591
void CBOINCHtmlListBox::OnInternalIdle()
593
CBOINCVListBox::OnInternalIdle();
595
if ( wxHtmlWindowMouseHelper::DidMouseMove() )
597
wxPoint pos = ScreenToClient(wxGetMousePosition());
600
if ( !PhysicalCoordsToCell(pos, cell) )
603
wxHtmlWindowMouseHelper::HandleIdle(cell, pos);
607
void CBOINCHtmlListBox::OnMouseMove(wxMouseEvent& event)
609
wxHtmlWindowMouseHelper::HandleMouseMoved();
613
void CBOINCHtmlListBox::OnLeftDown(wxMouseEvent& event)
615
wxPoint pos = event.GetPosition();
618
if ( !PhysicalCoordsToCell(pos, cell) )
624
if ( !wxHtmlWindowMouseHelper::HandleMouseClick(cell, pos, event) )
626
// no link was clicked, so let the listbox code handle the click (e.g.
627
// by selecting another item in the list):