From e0c6027b5a0af9050eca56774967437a66241026 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 1 Jun 2003 13:35:26 +0000 Subject: [PATCH] added wxVListBox using wxVScrolledWindow and wxHtmlListBox using it git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20808 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/category.tex | 2 + docs/latex/wx/classes.tex | 2 + docs/latex/wx/htmllbox.tex | 82 +++++++++++ docs/latex/wx/vlbox.tex | 174 ++++++++++++++++++++++ include/wx/htmllbox.h | 94 ++++++++++++ include/wx/vlbox.h | 157 ++++++++++++++++++++ include/wx/vscroll.h | 16 ++- src/generic/htmllbox.cpp | 185 ++++++++++++++++++++++++ src/generic/vlbox.cpp | 288 +++++++++++++++++++++++++++++++++++++ src/generic/vscroll.cpp | 36 +++++ 10 files changed, 1034 insertions(+), 2 deletions(-) create mode 100644 docs/latex/wx/htmllbox.tex create mode 100644 docs/latex/wx/vlbox.tex create mode 100644 include/wx/htmllbox.h create mode 100644 include/wx/vlbox.h create mode 100644 src/generic/htmllbox.cpp create mode 100644 src/generic/vlbox.cpp diff --git a/docs/latex/wx/category.tex b/docs/latex/wx/category.tex index f41578b7c2..0959dd071b 100644 --- a/docs/latex/wx/category.tex +++ b/docs/latex/wx/category.tex @@ -91,6 +91,7 @@ that are not static can have \helpref{validators}{wxvalidator} associated with t \twocolitem{\helpref{wxComboBox}{wxcombobox}}{A choice with an editable area} \twocolitem{\helpref{wxGauge}{wxgauge}}{A control to represent a varying quantity, such as time remaining} \twocolitem{\helpref{wxGenericDirCtrl}{wxgenericdirctrl}}{A control for displaying a directory tree} +\twocolitem{\helpref{wxHtmlListBox}{wxhtmllistbox}}{A listbox showing HTML content} \twocolitem{\helpref{wxStaticBox}{wxstaticbox}}{A static, or group box for visually grouping related controls} \twocolitem{\helpref{wxListBox}{wxlistbox}}{A list of strings for single or multiple selection} \twocolitem{\helpref{wxListCtrl}{wxlistctrl}}{A control for displaying lists of strings and/or icons, plus a multicolumn report view} @@ -106,6 +107,7 @@ that are not static can have \helpref{validators}{wxvalidator} associated with t \twocolitem{\helpref{wxRadioBox}{wxradiobox}}{A group of radio buttons} \twocolitem{\helpref{wxRadioButton}{wxradiobutton}}{A round button to be used with others in a mutually exclusive way} \twocolitem{\helpref{wxSlider}{wxslider}}{A slider that can be dragged by the user} +\twocolitem{\helpref{wxVListBox}{wxvlistbox}}{A listbox supporting variable height rows} \end{twocollist} {\large {\bf Menus}} diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex index 4d374a4d41..d263aaa0a5 100644 --- a/docs/latex/wx/classes.tex +++ b/docs/latex/wx/classes.tex @@ -144,6 +144,7 @@ \input hthlpdat.tex \input hthlpfrm.tex \input htlnkinf.tex +\input htmllbox.tex \input htparser.tex \input htprint.tex \input httag.tex @@ -308,6 +309,7 @@ \input validatr.tex \input variant.tex \input view.tex +\input vlbox.tex \input vscroll.tex \input wave.tex \input window.tex diff --git a/docs/latex/wx/htmllbox.tex b/docs/latex/wx/htmllbox.tex new file mode 100644 index 0000000000..9e6875eb17 --- /dev/null +++ b/docs/latex/wx/htmllbox.tex @@ -0,0 +1,82 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Name: htmllbox.tex +%% Purpose: wxHtmlListBox documentation +%% Author: Vadim Zeitlin +%% Modified by: +%% Created: 01.06.03 +%% RCS-ID: $Id$ +%% Copyright: (c) 2003 Vadim Zeitlin +%% License: wxWindows license +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\section{\class{wxHtmlListBox}}\label{wxhtmllistbox} + +wxHtmlListBox is an implementation of \helpref{wxVListBox}{wxvlistbox} which +shows HTML content in the listbox rows. This is still an abstract base class +and you will need to derive your own class from it (see htlbox sample for the +example) but you will only need to override a single +\helpref{OnGetItem()}{wxhtmllistboxongetitem} function. + +\wxheading{Derived from} + +\helpref{wxVListBox}{wxvlistbox} + +\wxheading{Include files} + + + + +\latexignore{\rtfignore{\wxheading{Members}}} + + +\membersection{wxHtmlListBox::wxHtmlListBox}\label{wxhtmllistboxwxhtmllistbox} + +\func{}{wxHtmlListBox}{\param{wxWindow* }{parent}, \param{wxWindowID }{id = wxID\_ANY}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{size\_t }{countItems = 0}, \param{long }{style = 0}, \param{const wxString\& }{name = wxVListBoxNameStr}} + +Normal constructor which calls \helpref{Create()}{wxhtmllistboxcreate} +internally. + +\func{}{wxHtmlListBox}{\void} + +Default constructor, you must call \helpref{Create()}{wxhtmllistboxcreate} +later. + + +\membersection{wxHtmlListBox::\destruct{wxHtmlListBox}}\label{wxhtmllistboxdtor} + +\func{}{\destruct{wxHtmlListBox}}{\void} + +Destructor cleans up whatever resources we use. + + +\membersection{wxHtmlListBox::Create}\label{wxhtmllistboxcreate} + +\func{bool}{Create}{\param{wxWindow* }{parent}, \param{wxWindowID }{id = wxID\_ANY}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{size\_t }{countItems = 0}, \param{long }{style = 0}, \param{const wxString\& }{name = wxVListBoxNameStr}} + +Creates the control and optionally sets the initial number of items in it +(it may also be set or changed later with +\helpref{SetItemCount()}{wxvlistboxsetitemcount}). + +There are no special styles defined for wxHtmlListBox, in particular the +wxListBox styles can not be used here. + +Returns {\tt true} on success or {\tt false} if the control couldn't be created + + + +\membersection{wxHtmlListBox::OnGetItem}\label{wxhtmllistboxongetitem} + +\constfunc{wxString}{OnGetItem}{\param{size\_t }{n}} + +This method must be implemented in the derived class and should return +the body (i.e. without {\tt } nor {\tt } tags) of the HTML fragment +for the given item. + + +\membersection{wxHtmlListBox::OnGetItemMarkup}\label{wxhtmllistboxongetitemmarkup} + +\constfunc{wxString}{OnGetItemMarkup}{\param{size\_t }{n}} + +This function may be overridden to decorate HTML returned by +\helpref{OnGetItem()}{wxhtmllistboxongetitem}. + diff --git a/docs/latex/wx/vlbox.tex b/docs/latex/wx/vlbox.tex new file mode 100644 index 0000000000..90e63340f3 --- /dev/null +++ b/docs/latex/wx/vlbox.tex @@ -0,0 +1,174 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Name: vlbox.tex +%% Purpose: wxVListBox documentation +%% Author: Vadim Zeitlin +%% Modified by: +%% Created: 01.06.03 +%% RCS-ID: $Id$ +%% Copyright: (c) 2003 Vadim Zeitlin +%% License: wxWindows license +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\section{\class{wxVListBox}}\label{wxvlistbox} + +wxVListBox is a listbox-like control with the following two main differences +from a regular listbox: it can have an arbitrarily huge number of items because +it doesn't store them itself but uses \helpref{OnDrawItem()}{wxvlistboxondrawitem} +callback to draw them (so it is a {\Large V}irtual listbox) and its items can +have variable height as determined by +\helpref{OnMeasureItem()}{wxvlistboxonmeasureitem} (so it is also a listbox +with the lines of {\Large V}ariable height). + +Also, as a consequence of its virtual nature, it doesn't have any methods to +append or insert items in it as it isn't necessary to do it: you just have to +call \helpref{SetItemCount()}{wxvlistboxsetitemcount} to tell the control how +many items it should display. Of course, this also means that you will never +use this class directly because it has pure virtual functions, but will need to +derive your own class, such as \helpref{wxHtmlListBox}{wxhtmllistbox}, from it. + +However it emits the same events as \helpref{wxListBox}{wxlistbox} and the same +event macros may be used with it. + +\wxheading{Derived from} + +\helpref{wxVScrolledWindow}{wxvscrolledwindow} + +\wxheading{Include files} + + + +\latexignore{\rtfignore{\wxheading{Members}}} + + +\membersection{wxVListBox::wxVListBox}\label{wxvlistboxctor} + +\func{}{wxVListBox}{\param{wxWindow* }{parent}, \param{wxWindowID }{id = wxID\_ANY}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{size\_t }{countItems = 0}, \param{long }{style = 0}, \param{const wxString\& }{name = wxVListBoxNameStr}} + +Normal constructor which calls \helpref{Create()}{wxvlistboxcreate} internally. + +\func{}{wxVListBox}{\void} + +Default constructor, you must call \helpref{Create()}{wxvlistboxcreate} later. + + +\membersection{wxVListBox::Clear}\label{wxvlistboxclear} + +\func{void}{Clear}{\void} + +Deletes all items from the control. + + +\membersection{wxVListBox::Create}\label{wxvlistboxcreate} + +\func{bool}{Create}{\param{wxWindow* }{parent}, \param{wxWindowID }{id = wxID\_ANY}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{size\_t }{countItems = 0}, \param{long }{style = 0}, \param{const wxString\& }{name = wxVListBoxNameStr}} + +Creates the control and optionally sets the initial number of items in it +(it may also be set or changed later with +\helpref{SetItemCount()}{wxvlistboxsetitemcount}). + +There are no special styles defined for wxVListBox, in particular the wxListBox +styles can not be used here. + +Returns {\tt true} on success or {\tt false} if the control couldn't be created + + +\membersection{wxVListBox::GetItemCount}\label{wxvlistboxgetitemcount} + +\constfunc{size\_t}{GetItemCount}{\void} + +Get the number of items in the control. + +\wxheading{See also} + +\helpref{SetItemCount()}{wxvlistboxsetitemcount} + + +\membersection{wxVListBox::GetSelection}\label{wxvlistboxgetselection} + +\constfunc{int}{GetSelection}{\void} + +Get the currently selected item or $-1$ if there is no selection. + + +\membersection{wxVListBox::IsSelected}\label{wxvlistboxisselected} + +\constfunc{bool}{IsSelected}{\param{size\_t }{line}} + +Returns {\tt true} if this item is selected, {\tt false} otherwise. + + +\membersection{wxVListBox::OnDrawItem}\label{wxvlistboxondrawitem} + +\constfunc{void}{OnDrawItem}{\param{wxDC\& }{dc}, \param{const wxRect\& }{rect}, \param{size\_t }{n}} + +The derived class must implement this function to actually draw the item +with the given index on the provided DC. + +\wxheading{Parameters} + +\docparam{dc}{The device context to use for drawing} + +\docparam{rect}{The bounding rectangle for the item being drawn (DC clipping +region is set to this rectangle before calling this function)} + +\docparam{n}{The index of the item to be drawn} + + +\membersection{wxVListBox::OnDrawSeparator}\label{wxvlistboxondrawseparator} + +\constfunc{void}{OnDrawSeparator}{\param{wxDC\& }{dc}, \param{wxRect\& }{rect}, \param{size\_t }{n}} + +This method may be used to draw separators between the lines. The rectangle +passed to it may be modified, typically to deflate it a bit before passing to +\helpref{OnDrawItem()}{wxvlistboxondrawitem}. + +The base class version of this method doesn't do anything. + +\wxheading{Parameters} + +\docparam{dc}{The device context to use for drawing} + +\docparam{rect}{The bounding rectangle for the item} + +\docparam{n}{The index of the item} + + +\membersection{wxVListBox::OnMeasureItem}\label{wxvlistboxonmeasureitem} + +\constfunc{wxCoord}{OnMeasureItem}{\param{size\_t }{n}} + +The derived class must implement this method to return the height of the +specified item (in pixels). + + +\membersection{wxVListBox::SetItemCount}\label{wxvlistboxsetitemcount} + +\func{void}{SetItemCount}{\param{size\_t }{count}} + +Set the number of items to be shown in the control. + +This is just a synonym for +\helpref{wxVScrolledWindow::SetLineCount()}{wxvscrolledwindowsetlinecount}. + + +\membersection{wxVListBox::SetMargins}\label{wxvlistboxsetmargins} + +\func{void}{SetMargins}{\param{const wxPoint\& }{pt}} + +\func{void}{SetMargins}{\param{wxCoord }{x}, \param{wxCoord }{y}} + +Set the margins: horizontal margin is the distance between the window +border and the item contents while vertical margin is half of the +distance between items. + +By default both margins are $0$. + + +\membersection{wxVListBox::SetSelection}\label{wxvlistboxsetselection} + +\func{void}{SetSelection}{\param{int }{selection}} + +Set the selection to the specified item, if it is $-1$ the selection is +unset. The selected item will be automatically scrolled into view if it isn't +currently visible. + diff --git a/include/wx/htmllbox.h b/include/wx/htmllbox.h new file mode 100644 index 0000000000..c3764c399d --- /dev/null +++ b/include/wx/htmllbox.h @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/htmllbox.h +// Purpose: wxHtmlListBox is a listbox whose items are wxHtmlCells +// Author: Vadim Zeitlin +// Modified by: +// Created: 31.05.03 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_HTMLLBOX_H_ +#define _WX_HTMLLBOX_H_ + +#include "wx/vlbox.h" // base class + +class WXDLLEXPORT wxHtmlCell; +class WXDLLEXPORT wxHtmlWinParser; +class WXDLLEXPORT wxHtmlListBoxCache; + +// ---------------------------------------------------------------------------- +// wxHtmlListBox +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxHtmlListBox : public wxVListBox +{ +public: + // constructors and such + // --------------------- + + // default constructor, you must call Create() later + wxHtmlListBox() { Init(); } + + // normal constructor which calls Create() internally + wxHtmlListBox(wxWindow *parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + size_t countItems = 0, + long style = 0, + const wxString& name = wxVListBoxNameStr) + { + Init(); + + (void)Create(parent, id, pos, size, countItems, style, name); + } + + // really creates the control and sets the initial number of items in it + // (which may be changed later with SetItemCount()) + // + // there are no special styles defined for wxVListBox + // + // returns true on success or false if the control couldn't be created + bool Create(wxWindow *parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + size_t countItems = 0, + long style = 0, + const wxString& name = wxVListBoxNameStr); + + // destructor cleans up whatever resources we use + virtual ~wxHtmlListBox(); + +protected: + // this method must be implemented in the derived class and should return + // the body (i.e. without ) of the HTML for the given item + virtual wxString OnGetItem(size_t n) const = 0; + + // this function may be overridden to decorate HTML returned by OnGetItem() + virtual wxString OnGetItemMarkup(size_t n) const; + + + // we implement both of these functions in terms of OnGetItem(), they are + // not supposed to be overridden by our descendants + virtual void OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const; + virtual wxCoord OnMeasureItem(size_t n) const; + + + // common part of all ctors + void Init(); + + // ensure that the given item is cached + void CacheItem(size_t n) const; + +private: + wxHtmlListBoxCache *m_cache; + + // HTML parser we use + wxHtmlWinParser *m_htmlParser; +}; + +#endif // _WX_HTMLLBOX_H_ + diff --git a/include/wx/vlbox.h b/include/wx/vlbox.h new file mode 100644 index 0000000000..84fcfdfca9 --- /dev/null +++ b/include/wx/vlbox.h @@ -0,0 +1,157 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/vlbox.h +// Purpose: wxVListBox is a virtual listbox with lines of variable height +// Author: Vadim Zeitlin +// Modified by: +// Created: 31.05.03 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_VLBOX_H_ +#define _WX_VLBOX_H_ + +#include "wx/vscroll.h" // base class + +#define wxVListBoxNameStr _T("wxVListBox") + +// ---------------------------------------------------------------------------- +// wxVListBox +// ---------------------------------------------------------------------------- + +/* + This class has two main differences from a regular listbox: it can have an + arbitrarily huge number of items because it doesn't store them itself but + uses OnDrawItem() callback to draw them and its items can have variable + height as determined by OnMeasureItem(). + + It emits the same events as wxListBox and the same event macros may be used + with it. + */ +class WXDLLEXPORT wxVListBox : public wxVScrolledWindow +{ +public: + // constructors and such + // --------------------- + + // default constructor, you must call Create() later + wxVListBox() { Init(); } + + // normal constructor which calls Create() internally + wxVListBox(wxWindow *parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + size_t countItems = 0, + long style = 0, + const wxString& name = wxVListBoxNameStr) + { + Init(); + + (void)Create(parent, id, pos, size, countItems, style, name); + } + + // really creates the control and sets the initial number of items in it + // (which may be changed later with SetItemCount()) + // + // there are no special styles defined for wxVListBox + // + // returns true on success or false if the control couldn't be created + bool Create(wxWindow *parent, + wxWindowID id = wxID_ANY, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + size_t countItems = 0, + long style = 0, + const wxString& name = wxVListBoxNameStr); + + + // operations + // ---------- + + // set the number of items to be shown in the control + // + // this is just a synonym for wxVScrolledWindow::SetLineCount() + void SetItemCount(size_t count) { SetLineCount(count); } + + // delete all items from the control + void Clear() { SetItemCount(0); } + + // set the selection to the specified item, if it is -1 the selection is + // unset + void SetSelection(int selection) { DoSetSelection(selection, false); } + + // set the margins: horizontal margin is the distance between the window + // border and the item contents while vertical margin is half of the + // distance between items + // + // by default both margins are 0 + void SetMargins(const wxPoint& pt); + void SetMargins(wxCoord x, wxCoord y) { SetMargins(wxPoint(x, y)); } + + + // accessors + // --------- + + // get the number of items in the control + size_t GetItemCount() const { return GetLineCount(); } + + // get the currently selected item or -1 if there is no selection + int GetSelection() const { return m_selection; } + + // is this item selected? + bool IsSelected(size_t line) const { return (int)line == m_selection; } + + +protected: + // the derived class must implement this function to actually draw the item + // with the given index on the provided DC + virtual void OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const = 0; + + // the derived class must implement this method to return the height of the + // specified item + virtual wxCoord OnMeasureItem(size_t n) const = 0; + + // this method may be used to draw separators between the lines; note that + // the rectangle may be modified, typically to deflate it a bit before + // passing to OnDrawItem() + // + // the base class version doesn't do anything + virtual void OnDrawSeparator(wxDC& dc, wxRect& rect, size_t n) const; + + + // we implement OnGetLineHeight() in terms of OnMeasureItem() because this + // allows us to add borders to the items easily + // + // this function is not upposed to be overridden by the derived classes + virtual wxCoord OnGetLineHeight(size_t line) const; + + + // event handlers + void OnPaint(wxPaintEvent& event); + void OnKeyDown(wxKeyEvent& event); + void OnLeftDown(wxMouseEvent& event); + void OnLeftDClick(wxMouseEvent& event); + + + // common part of all ctors + void Init(); + + // SetSelection() with additional parameter telling it whether to send a + // notification event or not + void DoSetSelection(int selection, bool sendEvent = true); + +private: + // the current selection or -1 + int m_selection; + + // margins + wxPoint m_ptMargins; + + + DECLARE_EVENT_TABLE() +}; + +#endif // _WX_VLBOX_H_ + diff --git a/include/wx/vscroll.h b/include/wx/vscroll.h index 58b693f1e2..6d830f6417 100644 --- a/include/wx/vscroll.h +++ b/include/wx/vscroll.h @@ -90,6 +90,14 @@ public: virtual bool ScrollLines(int lines); virtual bool ScrollPages(int pages); + // redraw the specified line + void RefreshLine(size_t line); + + // return the item at the specified (in physical coordinates) position or + // wxNOT_FOUND if none, i.e. if it is below the last item + int HitTest(wxCoord x, wxCoord y) const; + int HitTest(const wxPoint& pt) const { return HitTest(pt.x, pt.y); } + // accessors // --------- @@ -104,8 +112,12 @@ public: // get the last currently visible line size_t GetLastVisibleLine() const { return m_lineFirst + m_nVisible - 1; } + // is this line currently visible? + bool IsVisible(size_t line) const + { return line >= m_lineFirst && line <= GetLastVisibleLine(); } + -//protected: +protected: // this function must be overridden in the derived class and it should // return the height of the given line in pixels virtual wxCoord OnGetLineHeight(size_t n) const = 0; @@ -125,7 +137,7 @@ public: // usual virtual void OnGetLinesHint(size_t lineMin, size_t lineMax) const { } -protected: + // the event handlers void OnSize(wxSizeEvent& event); void OnScroll(wxScrollWinEvent& event); diff --git a/src/generic/htmllbox.cpp b/src/generic/htmllbox.cpp new file mode 100644 index 0000000000..c38650ba37 --- /dev/null +++ b/src/generic/htmllbox.cpp @@ -0,0 +1,185 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: generic/htmllbox.cpp +// Purpose: implementation of wxHtmlListBox +// Author: Vadim Zeitlin +// Modified by: +// Created: 31.05.03 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#include "wx/htmllbox.h" + +#include "wx/html/htmlcell.h" +#include "wx/html/winpars.h" + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// this class is used by wxHtmlListBox to cache the parsed representation of +// the items to avoid doing it anew each time an item must be drawn +// +// TODO: extend the class to cache more than item +class wxHtmlListBoxCache +{ +public: + wxHtmlListBoxCache() { m_cell = NULL; } + ~wxHtmlListBoxCache() { delete m_cell; } + + // returns true if we already have this item cached + bool Has(size_t n) const { return m_cell && n == m_item; } + + // ensure that the item is cached + void Store(size_t n, wxHtmlCell *cell) + { + m_item = n; + + delete m_cell; + m_cell = cell; + } + + // return the cached cell for this index or NULL if none + wxHtmlCell *Get(size_t n) const + { + // we could be reading uninitialized m_item here but the code is still + // correct + return n == m_item ? m_cell : NULL; + } + +private: + // the parsed representation of the cached item or NULL + wxHtmlCell *m_cell; + + // the index of the currently cached item (only valid if m_cell != NULL) + size_t m_item; +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxHtmlListBox creation +// ---------------------------------------------------------------------------- + +void wxHtmlListBox::Init() +{ + m_htmlParser = NULL; + m_cache = new wxHtmlListBoxCache; +} + +bool wxHtmlListBox::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + size_t countItems, + long style, + const wxString& name) +{ + return wxVListBox::Create(parent, id, pos, size, countItems, style, name); +} + +wxHtmlListBox::~wxHtmlListBox() +{ + delete m_cache; + if ( m_htmlParser ) + { + delete m_htmlParser->GetDC(); + delete m_htmlParser; + } +} + +// ---------------------------------------------------------------------------- +// wxHtmlListBox items markup +// ---------------------------------------------------------------------------- + +wxString wxHtmlListBox::OnGetItemMarkup(size_t n) const +{ + // we don't even need to wrap the value returned by OnGetItem() inside + // "" and "" because wxHTML can parse it even + // without these tags + return OnGetItem(n); +} + +void wxHtmlListBox::CacheItem(size_t n) const +{ + if ( !m_cache->Has(n) ) + { + if ( !m_htmlParser ) + { + wxHtmlListBox *self = wxConstCast(this, wxHtmlListBox); + + self->m_htmlParser = new wxHtmlWinParser; + m_htmlParser->SetDC(new wxClientDC(self)); + } + + wxHtmlContainerCell *cell = (wxHtmlContainerCell *)m_htmlParser-> + Parse(OnGetItemMarkup(n)); + wxCHECK_RET( cell, _T("wxHtmlParser::Parse() returned NULL?") ); + + cell->Layout(GetClientSize().x); + + m_cache->Store(n, cell); + } +} + +// ---------------------------------------------------------------------------- +// wxHtmlListBox implementation of wxVListBox pure virtuals +// ---------------------------------------------------------------------------- + +void wxHtmlListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const +{ + CacheItem(n); + + wxHtmlCell *cell = m_cache->Get(n); + wxCHECK_RET( cell, _T("this cell should be cached!") ); + + // draw the selected cell in selected state + if ( IsSelected(n) ) + { + wxHtmlSelection htmlSel; + htmlSel.Set(wxPoint(0, 0), cell, wxPoint(INT_MAX, INT_MAX), cell); + wxHtmlRenderingState htmlRendState(&htmlSel); + htmlRendState.SetSelectionState(wxHTML_SEL_IN); + cell->Draw(dc, rect.x, rect.y, 0, INT_MAX, htmlRendState); + } + else + { + // note that we can't stop drawing exactly at the window boundary as then + // even the visible cells part could be not drawn, so always draw the + // entire cell + wxHtmlRenderingState htmlRendState(NULL); + cell->Draw(dc, rect.x, rect.y, 0, INT_MAX, htmlRendState); + } +} + +wxCoord wxHtmlListBox::OnMeasureItem(size_t n) const +{ + CacheItem(n); + + wxHtmlCell *cell = m_cache->Get(n); + wxCHECK_MSG( cell, 0, _T("this cell should be cached!") ); + + return cell->GetHeight() + cell->GetDescent(); +} + diff --git a/src/generic/vlbox.cpp b/src/generic/vlbox.cpp new file mode 100644 index 0000000000..7ebf949dac --- /dev/null +++ b/src/generic/vlbox.cpp @@ -0,0 +1,288 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: generic/vlbox.cpp +// Purpose: implementation of wxVListBox +// Author: Vadim Zeitlin +// Modified by: +// Created: 31.05.03 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/settings.h" +#endif //WX_PRECOMP + +#include "wx/vlbox.h" + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxVListBox, wxVScrolledWindow) + EVT_PAINT(wxVListBox::OnPaint) + + EVT_KEY_DOWN(wxVListBox::OnKeyDown) + EVT_LEFT_DOWN(wxVListBox::OnLeftDown) + EVT_LEFT_DCLICK(wxVListBox::OnLeftDClick) +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxVListBox creation +// ---------------------------------------------------------------------------- + +void wxVListBox::Init() +{ + m_selection = -1; +} + +bool wxVListBox::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + size_t countItems, + long style, + const wxString& name) +{ + if ( !wxVScrolledWindow::Create(parent, id, pos, size, style, name) ) + return false; + + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX)); + + SetItemCount(countItems); + + return true; +} + +// ---------------------------------------------------------------------------- +// selection handling +// ---------------------------------------------------------------------------- + +void wxVListBox::DoSetSelection(int selection, bool sendEvent) +{ + if ( selection == m_selection ) + { + // nothing to do + return; + } + + if ( m_selection != -1 ) + RefreshLine(m_selection); + + m_selection = selection; + + if ( m_selection != -1 ) + { + // if the line is not visible at all, we scroll it into view but we + // don't need to refresh it -- it will be redrawn anyhow + if ( !IsVisible(m_selection) ) + { + ScrollToLine(m_selection); + } + else // line is at least partly visible + { + // it is, indeed, only partly visible, so scroll it into view to + // make it entirely visible + if ( (size_t)m_selection == GetLastVisibleLine() ) + { + ScrollToLine(m_selection); + } + + // but in any case refresh it as even if it was only partly visible + // before we need to redraw it entirely as its background changed + RefreshLine(m_selection); + } + + // send a notification event if we were not called directly by user + if ( sendEvent ) + { + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, GetId()); + event.SetEventObject(this); + event.m_commandInt = selection; + + (void)GetEventHandler()->ProcessEvent(event); + } + } +} + +// ---------------------------------------------------------------------------- +// wxVListBox painting +// ---------------------------------------------------------------------------- + +void wxVListBox::SetMargins(const wxPoint& pt) +{ + if ( pt != m_ptMargins ) + { + m_ptMargins = pt; + + Refresh(); + } +} + +wxCoord wxVListBox::OnGetLineHeight(size_t line) const +{ + return OnMeasureItem(line) + 2*m_ptMargins.y; +} + +void wxVListBox::OnDrawSeparator(wxDC& WXUNUSED(dc), + wxRect& WXUNUSED(rect), + size_t WXUNUSED(n)) const +{ +} + +void wxVListBox::OnPaint(wxPaintEvent& event) +{ + wxPaintDC dc(this); + + // the update rectangle + wxRect rectUpdate = GetUpdateClientRect(); + + // the bounding rectangle of the current line + wxRect rectLine; + rectLine.width = GetClientSize().x; + + // iterate over all visible lines + const size_t lineMax = GetLastVisibleLine(); + for ( size_t line = GetFirstVisibleLine(); line <= lineMax; line++ ) + { + const wxCoord hLine = OnGetLineHeight(line); + + rectLine.height = hLine; + + // and draw the ones which intersect the update rect + if ( rectLine.Intersects(rectUpdate) ) + { + // don't allow drawing outside of the lines rectangle + wxDCClipper clip(dc, rectLine); + + if ( IsSelected(line) ) + { + wxBrush brush(wxSystemSettings:: + GetColour(wxSYS_COLOUR_HIGHLIGHT), + wxSOLID); + dc.SetBrush(brush); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(rectLine); + } + + wxRect rect = rectLine; + OnDrawSeparator(dc, rect, line); + + rect.Deflate(m_ptMargins.x, m_ptMargins.y); + OnDrawItem(dc, rect, line); + } + else // no intersection + { + if ( rectLine.GetTop() > rectUpdate.GetBottom() ) + { + // we are already below the update rect, no need to continue + // further + break; + } + //else: the next line may intersect the update rect + } + + rectLine.y += hLine; + } +} + +// ---------------------------------------------------------------------------- +// wxVListBox keyboard handling +// ---------------------------------------------------------------------------- + +void wxVListBox::OnKeyDown(wxKeyEvent& event) +{ + int selection = 0; // just to silent the stupid compiler warnings + switch ( event.GetKeyCode() ) + { + case WXK_HOME: + selection = 0; + break; + + case WXK_END: + selection = GetLineCount() - 1; + break; + + case WXK_DOWN: + if ( m_selection == (int)GetLineCount() - 1 ) + return; + + selection = m_selection + 1; + break; + + case WXK_UP: + if ( m_selection == -1 ) + selection = GetLineCount() - 1; + else if ( m_selection != 0 ) + selection = m_selection - 1; + else // m_selection == 0 + return; + break; + + case WXK_PAGEDOWN: + case WXK_NEXT: + PageDown(); + selection = GetFirstVisibleLine(); + break; + + case WXK_PAGEUP: + case WXK_PRIOR: + if ( m_selection == (int)GetFirstVisibleLine() ) + { + PageUp(); + } + + selection = GetFirstVisibleLine(); + break; + + default: + event.Skip(); + return; + } + + DoSetSelection(selection); +} + +// ---------------------------------------------------------------------------- +// wxVListBox mouse handling +// ---------------------------------------------------------------------------- + +void wxVListBox::OnLeftDown(wxMouseEvent& event) +{ + int item = HitTest(event.GetPosition()); + + DoSetSelection(item); +} + +void wxVListBox::OnLeftDClick(wxMouseEvent& event) +{ + int item = HitTest(event.GetPosition()); + if ( item != -1 ) + { + wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, GetId()); + event.SetEventObject(this); + event.m_commandInt = item; + + (void)GetEventHandler()->ProcessEvent(event); + } +} + diff --git a/src/generic/vscroll.cpp b/src/generic/vscroll.cpp index aa52fab013..e7cb8cfa06 100644 --- a/src/generic/vscroll.cpp +++ b/src/generic/vscroll.cpp @@ -170,9 +170,45 @@ void wxVScrolledWindow::SetLineCount(size_t count) // recalculate the scrollbars parameters + m_lineFirst = 1; // make sure it is != 0 ScrollToLine(0); } +void wxVScrolledWindow::RefreshLine(size_t line) +{ + // is this line visible? + if ( !IsVisible(line) ) + { + // no, it is useless to do anything + return; + } + + // calculate the rect occupied by this line on screen + wxRect rect; + rect.width = GetClientSize().x; + rect.height = OnGetLineHeight(line); + for ( size_t n = GetFirstVisibleLine(); n < line; n++ ) + { + rect.y += OnGetLineHeight(n); + } + + // do refresh it + RefreshRect(rect); +} + +int wxVScrolledWindow::HitTest(wxCoord WXUNUSED(x), wxCoord y) const +{ + const size_t lineMax = GetLastVisibleLine(); + for ( size_t line = GetFirstVisibleLine(); line <= lineMax; line++ ) + { + y -= OnGetLineHeight(line); + if ( y < 0 ) + return line; + } + + return wxNOT_FOUND; +} + // ---------------------------------------------------------------------------- // scrolling // ---------------------------------------------------------------------------- -- 2.45.2