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 const wxChar wxHtmlListBoxNameStr
[] = wxT("htmlListBox");
50 const wxChar wxSimpleHtmlListBoxNameStr
[] = wxT("simpleHtmlListBox");
52 // ============================================================================
54 // ============================================================================
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 // this class is used by wxHtmlListBox to cache the parsed representation of
61 // the items to avoid doing it anew each time an item must be drawn
62 class wxHtmlListBoxCache
65 // invalidate a single item, used by Clear() and InvalidateRange()
66 void InvalidateItem(size_t n
)
68 m_items
[n
] = (size_t)-1;
76 for ( size_t n
= 0; n
< SIZE
; n
++ )
78 m_items
[n
] = (size_t)-1;
87 for ( size_t n
= 0; n
< SIZE
; n
++ )
93 // completely invalidate the cache
96 for ( size_t n
= 0; n
< SIZE
; n
++ )
102 // return the cached cell for this index or NULL if none
103 wxHtmlCell
*Get(size_t item
) const
105 for ( size_t n
= 0; n
< SIZE
; n
++ )
107 if ( m_items
[n
] == item
)
114 // returns true if we already have this item cached
115 bool Has(size_t item
) const { return Get(item
) != NULL
; }
117 // ensure that the item is cached
118 void Store(size_t item
, wxHtmlCell
*cell
)
120 delete m_cells
[m_next
];
121 m_cells
[m_next
] = cell
;
122 m_items
[m_next
] = item
;
124 // advance to the next item wrapping around if there are no more
125 if ( ++m_next
== SIZE
)
129 // forget the cached value of the item(s) between the given ones (inclusive)
130 void InvalidateRange(size_t from
, size_t to
)
132 for ( size_t n
= 0; n
< SIZE
; n
++ )
134 if ( m_items
[n
] >= from
&& m_items
[n
] <= to
)
142 // the max number of the items we cache
145 // the index of the LRU (oldest) cell
148 // the parsed representation of the cached item or NULL
149 wxHtmlCell
*m_cells
[SIZE
];
151 // the index of the currently cached item (only valid if m_cells != NULL)
152 size_t m_items
[SIZE
];
155 // ----------------------------------------------------------------------------
156 // wxHtmlListBoxStyle
157 // ----------------------------------------------------------------------------
159 // just forward wxDefaultHtmlRenderingStyle callbacks to the main class so that
160 // they could be overridden by the user code
161 class wxHtmlListBoxStyle
: public wxDefaultHtmlRenderingStyle
164 wxHtmlListBoxStyle(const wxHtmlListBox
& hlbox
) : m_hlbox(hlbox
) { }
166 virtual wxColour
GetSelectedTextColour(const wxColour
& colFg
)
168 return m_hlbox
.GetSelectedTextColour(colFg
);
171 virtual wxColour
GetSelectedTextBgColour(const wxColour
& colBg
)
173 return m_hlbox
.GetSelectedTextBgColour(colBg
);
177 const wxHtmlListBox
& m_hlbox
;
179 DECLARE_NO_COPY_CLASS(wxHtmlListBoxStyle
)
182 // ----------------------------------------------------------------------------
184 // ----------------------------------------------------------------------------
186 BEGIN_EVENT_TABLE(wxHtmlListBox
, wxVListBox
)
187 EVT_SIZE(wxHtmlListBox::OnSize
)
188 EVT_MOTION(wxHtmlListBox::OnMouseMove
)
189 EVT_LEFT_DOWN(wxHtmlListBox::OnLeftDown
)
192 // ============================================================================
194 // ============================================================================
196 IMPLEMENT_ABSTRACT_CLASS(wxHtmlListBox
, wxVListBox
)
199 // ----------------------------------------------------------------------------
200 // wxHtmlListBox creation
201 // ----------------------------------------------------------------------------
203 wxHtmlListBox::wxHtmlListBox()
204 : wxHtmlWindowMouseHelper(this)
209 // normal constructor which calls Create() internally
210 wxHtmlListBox::wxHtmlListBox(wxWindow
*parent
,
215 const wxString
& name
)
216 : wxHtmlWindowMouseHelper(this)
220 (void)Create(parent
, id
, pos
, size
, style
, name
);
223 void wxHtmlListBox::Init()
226 m_htmlRendStyle
= new wxHtmlListBoxStyle(*this);
227 m_cache
= new wxHtmlListBoxCache
;
230 bool wxHtmlListBox::Create(wxWindow
*parent
,
235 const wxString
& name
)
237 return wxVListBox::Create(parent
, id
, pos
, size
, style
, name
);
240 wxHtmlListBox::~wxHtmlListBox()
246 delete m_htmlParser
->GetDC();
250 delete m_htmlRendStyle
;
253 // ----------------------------------------------------------------------------
254 // wxHtmlListBox appearance
255 // ----------------------------------------------------------------------------
257 wxColour
wxHtmlListBox::GetSelectedTextColour(const wxColour
& colFg
) const
259 return m_htmlRendStyle
->
260 wxDefaultHtmlRenderingStyle::GetSelectedTextColour(colFg
);
264 wxHtmlListBox::GetSelectedTextBgColour(const wxColour
& WXUNUSED(colBg
)) const
266 return GetSelectionBackground();
269 // ----------------------------------------------------------------------------
270 // wxHtmlListBox items markup
271 // ----------------------------------------------------------------------------
273 wxString
wxHtmlListBox::OnGetItemMarkup(size_t n
) const
275 // we don't even need to wrap the value returned by OnGetItem() inside
276 // "<html><body>" and "</body></html>" because wxHTML can parse it even
277 // without these tags
281 // ----------------------------------------------------------------------------
282 // wxHtmlListBox cache handling
283 // ----------------------------------------------------------------------------
285 void wxHtmlListBox::CacheItem(size_t n
) const
287 if ( !m_cache
->Has(n
) )
291 wxHtmlListBox
*self
= wxConstCast(this, wxHtmlListBox
);
293 self
->m_htmlParser
= new wxHtmlWinParser(self
);
294 m_htmlParser
->SetDC(new wxClientDC(self
));
295 m_htmlParser
->SetFS(&self
->m_filesystem
);
298 m_htmlParser
->SetInputEncoding(GetFont().GetEncoding());
300 // use system's default GUI font by default:
301 m_htmlParser
->SetStandardFonts();
304 wxHtmlContainerCell
*cell
= (wxHtmlContainerCell
*)m_htmlParser
->
305 Parse(OnGetItemMarkup(n
));
306 wxCHECK_RET( cell
, _T("wxHtmlParser::Parse() returned NULL?") );
308 // set the cell's ID to item's index so that CellCoordsToPhysical()
309 // can quickly find the item:
310 cell
->SetId(wxString::Format(_T("%lu"), (unsigned long)n
));
312 cell
->Layout(GetClientSize().x
- 2*GetMargins().x
);
314 m_cache
->Store(n
, cell
);
318 void wxHtmlListBox::OnSize(wxSizeEvent
& event
)
320 // we need to relayout all the cached cells
326 void wxHtmlListBox::RefreshRow(size_t line
)
328 m_cache
->InvalidateRange(line
, line
);
330 wxVListBox::RefreshRow(line
);
333 void wxHtmlListBox::RefreshRows(size_t from
, size_t to
)
335 m_cache
->InvalidateRange(from
, to
);
337 wxVListBox::RefreshRows(from
, to
);
340 void wxHtmlListBox::RefreshAll()
344 wxVListBox::RefreshAll();
347 void wxHtmlListBox::SetItemCount(size_t count
)
349 // the items are going to change, forget the old ones
352 wxVListBox::SetItemCount(count
);
355 // ----------------------------------------------------------------------------
356 // wxHtmlListBox implementation of wxVListBox pure virtuals
357 // ----------------------------------------------------------------------------
359 void wxHtmlListBox::OnDrawItem(wxDC
& dc
, const wxRect
& rect
, size_t n
) const
363 wxHtmlCell
*cell
= m_cache
->Get(n
);
364 wxCHECK_RET( cell
, _T("this cell should be cached!") );
366 wxHtmlRenderingInfo htmlRendInfo
;
368 // note that we can't stop drawing exactly at the window boundary as then
369 // even the visible cells part could be not drawn, so always draw the
372 rect
.x
+ CELL_BORDER
, rect
.y
+ CELL_BORDER
,
373 0, INT_MAX
, htmlRendInfo
);
376 wxCoord
wxHtmlListBox::OnMeasureItem(size_t n
) const
380 wxHtmlCell
*cell
= m_cache
->Get(n
);
381 wxCHECK_MSG( cell
, 0, _T("this cell should be cached!") );
383 return cell
->GetHeight() + cell
->GetDescent() + 4;
386 // ----------------------------------------------------------------------------
387 // wxHtmlListBox implementation of wxHtmlListBoxWinInterface
388 // ----------------------------------------------------------------------------
390 void wxHtmlListBox::SetHTMLWindowTitle(const wxString
& WXUNUSED(title
))
395 void wxHtmlListBox::OnHTMLLinkClicked(const wxHtmlLinkInfo
& link
)
397 OnLinkClicked(GetItemForCell(link
.GetHtmlCell()), link
);
400 void wxHtmlListBox::OnLinkClicked(size_t WXUNUSED(n
),
401 const wxHtmlLinkInfo
& link
)
403 wxHtmlLinkEvent
event(GetId(), link
);
404 GetEventHandler()->ProcessEvent(event
);
408 wxHtmlListBox::OnHTMLOpeningURL(wxHtmlURLType
WXUNUSED(type
),
409 const wxString
& WXUNUSED(url
),
410 wxString
*WXUNUSED(redirect
)) const
415 wxPoint
wxHtmlListBox::HTMLCoordsToWindow(wxHtmlCell
*cell
,
416 const wxPoint
& pos
) const
418 return CellCoordsToPhysical(pos
, cell
);
421 wxWindow
* wxHtmlListBox::GetHTMLWindow() { return this; }
423 wxColour
wxHtmlListBox::GetHTMLBackgroundColour() const
425 return GetBackgroundColour();
428 void wxHtmlListBox::SetHTMLBackgroundColour(const wxColour
& WXUNUSED(clr
))
433 void wxHtmlListBox::SetHTMLBackgroundImage(const wxBitmap
& WXUNUSED(bmpBg
))
438 void wxHtmlListBox::SetHTMLStatusText(const wxString
& WXUNUSED(text
))
443 wxCursor
wxHtmlListBox::GetHTMLCursor(HTMLCursor type
) const
445 // we don't want to show text selection cursor in listboxes
446 if (type
== HTMLCursor_Text
)
447 return wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor_Default
);
449 // in all other cases, use the same cursor as wxHtmlWindow:
450 return wxHtmlWindow::GetDefaultHTMLCursor(type
);
453 // ----------------------------------------------------------------------------
454 // wxHtmlListBox handling of HTML links
455 // ----------------------------------------------------------------------------
457 wxPoint
wxHtmlListBox::GetRootCellCoords(size_t n
) const
459 wxPoint
pos(CELL_BORDER
, CELL_BORDER
);
461 pos
.y
+= GetRowsHeight(GetVisibleBegin(), n
);
465 bool wxHtmlListBox::PhysicalCoordsToCell(wxPoint
& pos
, wxHtmlCell
*& cell
) const
467 int n
= HitTest(pos
);
468 if ( n
== wxNOT_FOUND
)
471 // convert mouse coordinates to coords relative to item's wxHtmlCell:
472 pos
-= GetRootCellCoords(n
);
475 cell
= m_cache
->Get(n
);
480 size_t wxHtmlListBox::GetItemForCell(const wxHtmlCell
*cell
) const
482 wxCHECK_MSG( cell
, 0, _T("no cell") );
484 cell
= cell
->GetRootCell();
486 wxCHECK_MSG( cell
, 0, _T("no root cell") );
488 // the cell's ID contains item index, see CacheItem():
490 if ( !cell
->GetId().ToULong(&n
) )
492 wxFAIL_MSG( _T("unexpected root cell's ID") );
500 wxHtmlListBox::CellCoordsToPhysical(const wxPoint
& pos
, wxHtmlCell
*cell
) const
502 return pos
+ GetRootCellCoords(GetItemForCell(cell
));
505 void wxHtmlListBox::OnInternalIdle()
507 wxVListBox::OnInternalIdle();
509 if ( wxHtmlWindowMouseHelper::DidMouseMove() )
511 wxPoint pos
= ScreenToClient(wxGetMousePosition());
514 if ( !PhysicalCoordsToCell(pos
, cell
) )
517 wxHtmlWindowMouseHelper::HandleIdle(cell
, pos
);
521 void wxHtmlListBox::OnMouseMove(wxMouseEvent
& event
)
523 wxHtmlWindowMouseHelper::HandleMouseMoved();
527 void wxHtmlListBox::OnLeftDown(wxMouseEvent
& event
)
529 wxPoint pos
= event
.GetPosition();
532 if ( !PhysicalCoordsToCell(pos
, cell
) )
538 if ( !wxHtmlWindowMouseHelper::HandleMouseClick(cell
, pos
, event
) )
540 // no link was clicked, so let the listbox code handle the click (e.g.
541 // by selecting another item in the list):
547 // ----------------------------------------------------------------------------
548 // wxSimpleHtmlListBox
549 // ----------------------------------------------------------------------------
551 bool wxSimpleHtmlListBox::Create(wxWindow
*parent
, wxWindowID id
,
554 int n
, const wxString choices
[],
556 const wxValidator
& validator
,
557 const wxString
& name
)
559 if (!wxHtmlListBox::Create(parent
, id
, pos
, size
, style
, name
))
563 SetValidator(validator
);
565 for (int i
=0; i
<n
; i
++)
571 bool wxSimpleHtmlListBox::Create(wxWindow
*parent
, wxWindowID id
,
574 const wxArrayString
& choices
,
576 const wxValidator
& validator
,
577 const wxString
& name
)
579 if (!wxHtmlListBox::Create(parent
, id
, pos
, size
, style
, name
))
583 SetValidator(validator
);
590 wxSimpleHtmlListBox::~wxSimpleHtmlListBox()
592 wxASSERT(m_items
.GetCount() == m_HTMLclientData
.GetCount());
593 if (HasClientObjectData())
595 // clear the array of client data objects
596 for (size_t i
=0; i
<m_items
.GetCount(); i
++)
597 delete DoGetItemClientObject(i
);
601 m_HTMLclientData
.Clear();
604 void wxSimpleHtmlListBox::Clear()
607 m_HTMLclientData
.Clear();
611 void wxSimpleHtmlListBox::Delete(unsigned int n
)
614 m_HTMLclientData
.RemoveAt(n
);
618 void wxSimpleHtmlListBox::Append(const wxArrayString
& strings
)
620 // append all given items at once
621 WX_APPEND_ARRAY(m_items
, strings
);
622 m_HTMLclientData
.Add(NULL
, strings
.GetCount());
626 int wxSimpleHtmlListBox::DoAppend(const wxString
& item
)
629 m_HTMLclientData
.Add(NULL
);
634 int wxSimpleHtmlListBox::DoInsert(const wxString
& item
, unsigned int pos
)
636 m_items
.Insert(item
, pos
);
637 m_HTMLclientData
.Insert(NULL
, pos
);
642 void wxSimpleHtmlListBox::SetString(unsigned int n
, const wxString
& s
)
644 wxCHECK_RET( IsValid(n
),
645 wxT("invalid index in wxSimpleHtmlListBox::SetString") );
651 wxString
wxSimpleHtmlListBox::GetString(unsigned int n
) const
653 wxCHECK_MSG( IsValid(n
), wxEmptyString
,
654 wxT("invalid index in wxSimpleHtmlListBox::GetString") );
659 void wxSimpleHtmlListBox::UpdateCount()
661 wxASSERT(m_items
.GetCount() == m_HTMLclientData
.GetCount());
662 wxHtmlListBox::SetItemCount(m_items
.GetCount());
664 // very small optimization: if you need to add lot of items to
665 // a wxSimpleHtmlListBox be sure to use the
666 // wxSimpleHtmlListBox::Append(const wxArrayString&) method instead!
667 if (!this->IsFrozen())