1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: generic/htmllbox.cpp
3 // Purpose: implementation of wxHtmlListBox
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
28 #include "wx/dcclient.h"
33 #include "wx/htmllbox.h"
35 #include "wx/html/htmlcell.h"
36 #include "wx/html/winpars.h"
38 // this hack forces the linker to always link in m_* files
39 #include "wx/html/forcelnk.h"
40 FORCE_WXHTML_MODULES()
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 // small border always added to the cells:
47 static const wxCoord CELL_BORDER
= 2;
49 // ============================================================================
51 // ============================================================================
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 // this class is used by wxHtmlListBox to cache the parsed representation of
58 // the items to avoid doing it anew each time an item must be drawn
59 class wxHtmlListBoxCache
62 // invalidate a single item, used by Clear() and InvalidateRange()
63 void InvalidateItem(size_t n
)
65 m_items
[n
] = (size_t)-1;
73 for ( size_t n
= 0; n
< SIZE
; n
++ )
75 m_items
[n
] = (size_t)-1;
84 for ( size_t n
= 0; n
< SIZE
; n
++ )
90 // completely invalidate the cache
93 for ( size_t n
= 0; n
< SIZE
; n
++ )
99 // return the cached cell for this index or NULL if none
100 wxHtmlCell
*Get(size_t item
) const
102 for ( size_t n
= 0; n
< SIZE
; n
++ )
104 if ( m_items
[n
] == item
)
111 // returns true if we already have this item cached
112 bool Has(size_t item
) const { return Get(item
) != NULL
; }
114 // ensure that the item is cached
115 void Store(size_t item
, wxHtmlCell
*cell
)
117 delete m_cells
[m_next
];
118 m_cells
[m_next
] = cell
;
119 m_items
[m_next
] = item
;
121 // advance to the next item wrapping around if there are no more
122 if ( ++m_next
== SIZE
)
126 // forget the cached value of the item(s) between the given ones (inclusive)
127 void InvalidateRange(size_t from
, size_t to
)
129 for ( size_t n
= 0; n
< SIZE
; n
++ )
131 if ( m_items
[n
] >= from
&& m_items
[n
] <= to
)
139 // the max number of the items we cache
142 // the index of the LRU (oldest) cell
145 // the parsed representation of the cached item or NULL
146 wxHtmlCell
*m_cells
[SIZE
];
148 // the index of the currently cached item (only valid if m_cells != NULL)
149 size_t m_items
[SIZE
];
152 // ----------------------------------------------------------------------------
153 // wxHtmlListBoxStyle
154 // ----------------------------------------------------------------------------
156 // just forward wxDefaultHtmlRenderingStyle callbacks to the main class so that
157 // they could be overridden by the user code
158 class wxHtmlListBoxStyle
: public wxDefaultHtmlRenderingStyle
161 wxHtmlListBoxStyle(const wxHtmlListBox
& hlbox
) : m_hlbox(hlbox
) { }
163 virtual wxColour
GetSelectedTextColour(const wxColour
& colFg
)
165 return m_hlbox
.GetSelectedTextColour(colFg
);
168 virtual wxColour
GetSelectedTextBgColour(const wxColour
& colBg
)
170 return m_hlbox
.GetSelectedTextBgColour(colBg
);
174 const wxHtmlListBox
& m_hlbox
;
176 DECLARE_NO_COPY_CLASS(wxHtmlListBoxStyle
)
179 // ----------------------------------------------------------------------------
181 // ----------------------------------------------------------------------------
183 BEGIN_EVENT_TABLE(wxHtmlListBox
, wxVListBox
)
184 EVT_SIZE(wxHtmlListBox::OnSize
)
185 EVT_MOTION(wxHtmlListBox::OnMouseMove
)
186 EVT_LEFT_DOWN(wxHtmlListBox::OnLeftDown
)
189 // ============================================================================
191 // ============================================================================
193 IMPLEMENT_ABSTRACT_CLASS(wxHtmlListBox
, wxVListBox
)
196 // ----------------------------------------------------------------------------
197 // wxHtmlListBox creation
198 // ----------------------------------------------------------------------------
200 wxHtmlListBox::wxHtmlListBox()
201 : wxHtmlWindowMouseHelper(this)
206 // normal constructor which calls Create() internally
207 wxHtmlListBox::wxHtmlListBox(wxWindow
*parent
,
212 const wxString
& name
)
213 : wxHtmlWindowMouseHelper(this)
217 (void)Create(parent
, id
, pos
, size
, style
, name
);
220 void wxHtmlListBox::Init()
223 m_htmlRendStyle
= new wxHtmlListBoxStyle(*this);
224 m_cache
= new wxHtmlListBoxCache
;
227 bool wxHtmlListBox::Create(wxWindow
*parent
,
232 const wxString
& name
)
234 return wxVListBox::Create(parent
, id
, pos
, size
, style
, name
);
237 wxHtmlListBox::~wxHtmlListBox()
243 delete m_htmlParser
->GetDC();
247 delete m_htmlRendStyle
;
250 // ----------------------------------------------------------------------------
251 // wxHtmlListBox appearance
252 // ----------------------------------------------------------------------------
254 wxColour
wxHtmlListBox::GetSelectedTextColour(const wxColour
& colFg
) const
256 return m_htmlRendStyle
->
257 wxDefaultHtmlRenderingStyle::GetSelectedTextColour(colFg
);
261 wxHtmlListBox::GetSelectedTextBgColour(const wxColour
& WXUNUSED(colBg
)) const
263 return GetSelectionBackground();
266 // ----------------------------------------------------------------------------
267 // wxHtmlListBox items markup
268 // ----------------------------------------------------------------------------
270 wxString
wxHtmlListBox::OnGetItemMarkup(size_t n
) const
272 // we don't even need to wrap the value returned by OnGetItem() inside
273 // "<html><body>" and "</body></html>" because wxHTML can parse it even
274 // without these tags
278 // ----------------------------------------------------------------------------
279 // wxHtmlListBox cache handling
280 // ----------------------------------------------------------------------------
282 void wxHtmlListBox::CacheItem(size_t n
) const
284 if ( !m_cache
->Has(n
) )
288 wxHtmlListBox
*self
= wxConstCast(this, wxHtmlListBox
);
290 self
->m_htmlParser
= new wxHtmlWinParser(self
);
291 m_htmlParser
->SetDC(new wxClientDC(self
));
292 m_htmlParser
->SetFS(&self
->m_filesystem
);
294 // use system's default GUI font by default:
295 m_htmlParser
->SetStandardFonts();
298 wxHtmlContainerCell
*cell
= (wxHtmlContainerCell
*)m_htmlParser
->
299 Parse(OnGetItemMarkup(n
));
300 wxCHECK_RET( cell
, _T("wxHtmlParser::Parse() returned NULL?") );
302 // set the cell's ID to item's index so that CellCoordsToPhysical()
303 // can quickly find the item:
304 cell
->SetId(wxString::Format(_T("%lu"), (unsigned long)n
));
306 cell
->Layout(GetClientSize().x
- 2*GetMargins().x
);
308 m_cache
->Store(n
, cell
);
312 void wxHtmlListBox::OnSize(wxSizeEvent
& event
)
314 // we need to relayout all the cached cells
320 void wxHtmlListBox::RefreshLine(size_t line
)
322 m_cache
->InvalidateRange(line
, line
);
324 wxVListBox::RefreshLine(line
);
327 void wxHtmlListBox::RefreshLines(size_t from
, size_t to
)
329 m_cache
->InvalidateRange(from
, to
);
331 wxVListBox::RefreshLines(from
, to
);
334 void wxHtmlListBox::RefreshAll()
338 wxVListBox::RefreshAll();
341 void wxHtmlListBox::SetItemCount(size_t count
)
343 // the items are going to change, forget the old ones
346 wxVListBox::SetItemCount(count
);
349 // ----------------------------------------------------------------------------
350 // wxHtmlListBox implementation of wxVListBox pure virtuals
351 // ----------------------------------------------------------------------------
353 void wxHtmlListBox::OnDrawItem(wxDC
& dc
, const wxRect
& rect
, size_t n
) const
357 wxHtmlCell
*cell
= m_cache
->Get(n
);
358 wxCHECK_RET( cell
, _T("this cell should be cached!") );
360 wxHtmlRenderingInfo htmlRendInfo
;
362 // draw the selected cell in selected state
365 wxHtmlSelection htmlSel
;
366 htmlSel
.Set(wxPoint(0,0), cell
, wxPoint(INT_MAX
, INT_MAX
), cell
);
367 htmlRendInfo
.SetSelection(&htmlSel
);
368 if ( m_htmlRendStyle
)
369 htmlRendInfo
.SetStyle(m_htmlRendStyle
);
370 htmlRendInfo
.GetState().SetSelectionState(wxHTML_SEL_IN
);
373 // note that we can't stop drawing exactly at the window boundary as then
374 // even the visible cells part could be not drawn, so always draw the
377 rect
.x
+ CELL_BORDER
, rect
.y
+ CELL_BORDER
,
378 0, INT_MAX
, htmlRendInfo
);
381 wxCoord
wxHtmlListBox::OnMeasureItem(size_t n
) const
385 wxHtmlCell
*cell
= m_cache
->Get(n
);
386 wxCHECK_MSG( cell
, 0, _T("this cell should be cached!") );
388 return cell
->GetHeight() + cell
->GetDescent() + 4;
391 // ----------------------------------------------------------------------------
392 // wxHtmlListBox implementation of wxHtmlListBoxWinInterface
393 // ----------------------------------------------------------------------------
395 void wxHtmlListBox::SetHTMLWindowTitle(const wxString
& WXUNUSED(title
))
400 void wxHtmlListBox::OnHTMLLinkClicked(const wxHtmlLinkInfo
& link
)
402 OnLinkClicked(GetItemForCell(link
.GetHtmlCell()), link
);
406 wxHtmlListBox::OnHTMLOpeningURL(wxHtmlURLType
WXUNUSED(type
),
407 const wxString
& WXUNUSED(url
),
408 wxString
*WXUNUSED(redirect
)) const
413 wxPoint
wxHtmlListBox::HTMLCoordsToWindow(wxHtmlCell
*cell
,
414 const wxPoint
& pos
) const
416 return CellCoordsToPhysical(pos
, cell
);
419 wxWindow
* wxHtmlListBox::GetHTMLWindow() { return this; }
421 wxColour
wxHtmlListBox::GetHTMLBackgroundColour() const
423 return GetBackgroundColour();
426 void wxHtmlListBox::SetHTMLBackgroundColour(const wxColour
& WXUNUSED(clr
))
431 void wxHtmlListBox::SetHTMLBackgroundImage(const wxBitmap
& WXUNUSED(bmpBg
))
436 void wxHtmlListBox::SetHTMLStatusText(const wxString
& WXUNUSED(text
))
441 wxCursor
wxHtmlListBox::GetHTMLCursor(HTMLCursor type
) const
443 // we don't want to show text selection cursor in listboxes
444 if (type
== HTMLCursor_Text
)
445 return wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor_Default
);
447 // in all other cases, use the same cursor as wxHtmlWindow:
448 return wxHtmlWindow::GetDefaultHTMLCursor(type
);
451 // ----------------------------------------------------------------------------
452 // wxHtmlListBox handling of HTML links
453 // ----------------------------------------------------------------------------
455 wxPoint
wxHtmlListBox::GetRootCellCoords(size_t n
) const
457 wxPoint
pos(CELL_BORDER
, CELL_BORDER
);
459 pos
.y
+= GetLinesHeight(GetFirstVisibleLine(), n
);
463 bool wxHtmlListBox::PhysicalCoordsToCell(wxPoint
& pos
, wxHtmlCell
*& cell
) const
465 int n
= HitTest(pos
);
466 if ( n
== wxNOT_FOUND
)
469 // convert mouse coordinates to coords relative to item's wxHtmlCell:
470 pos
-= GetRootCellCoords(n
);
473 cell
= m_cache
->Get(n
);
478 size_t wxHtmlListBox::GetItemForCell(const wxHtmlCell
*cell
) const
480 wxCHECK_MSG( cell
, 0, _T("no cell") );
482 cell
= cell
->GetRootCell();
484 wxCHECK_MSG( cell
, 0, _T("no root cell") );
486 // the cell's ID contains item index, see CacheItem():
488 if ( !cell
->GetId().ToULong(&n
) )
490 wxFAIL_MSG( _T("unexpected root cell's ID") );
498 wxHtmlListBox::CellCoordsToPhysical(const wxPoint
& pos
, wxHtmlCell
*cell
) const
500 return pos
+ GetRootCellCoords(GetItemForCell(cell
));
503 void wxHtmlListBox::OnInternalIdle()
505 wxVListBox::OnInternalIdle();
507 if ( wxHtmlWindowMouseHelper::DidMouseMove() )
509 wxPoint pos
= ScreenToClient(wxGetMousePosition());
512 if ( !PhysicalCoordsToCell(pos
, cell
) )
515 wxHtmlWindowMouseHelper::HandleIdle(cell
, pos
);
519 void wxHtmlListBox::OnMouseMove(wxMouseEvent
& event
)
521 wxHtmlWindowMouseHelper::HandleMouseMoved();
525 void wxHtmlListBox::OnLeftDown(wxMouseEvent
& event
)
527 wxPoint pos
= event
.GetPosition();
530 if ( !PhysicalCoordsToCell(pos
, cell
) )
536 if ( !wxHtmlWindowMouseHelper::HandleMouseClick(cell
, pos
, event
) )
538 // no link was clicked, so let the listbox code handle the click (e.g.
539 // by selecting another item in the list):