From 9ebb7cade2df5aeb8531950d2a79cd57a336bcec Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 22 Oct 2006 22:09:16 +0000
Subject: [PATCH] added wxSimpleHtmlListBox (patch 1576109 by Francesco)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42257 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 build/bakefiles/files.bkl    |   2 +
 docs/changes.txt             |   1 +
 docs/latex/wx/category.tex   |   3 +-
 docs/latex/wx/htmllbox.tex   | 173 ++++++++++++++++++++++++++++++++++-
 docs/latex/wx/vlbox.tex      |   4 +
 include/wx/ctrlsub.h         |   8 +-
 include/wx/htmllbox.h        | 142 +++++++++++++++++++++++++++-
 include/wx/xrc/xh_all.h      |   1 +
 include/wx/xrc/xh_htmllbox.h |  34 +++++++
 samples/htlbox/htlbox.cpp    | 113 +++++++++++++++++++----
 samples/xrc/rc/controls.xrc  |  28 ++++++
 src/generic/htmllbox.cpp     | 130 ++++++++++++++++++++++++++
 src/xrc/xh_htmllbox.cpp      |  86 +++++++++++++++++
 src/xrc/xmlrsall.cpp         |   1 +
 14 files changed, 696 insertions(+), 30 deletions(-)
 create mode 100644 include/wx/xrc/xh_htmllbox.h
 create mode 100644 src/xrc/xh_htmllbox.cpp

diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl
index 5ac20c086e..4522b5c657 100644
--- a/build/bakefiles/files.bkl
+++ b/build/bakefiles/files.bkl
@@ -2956,6 +2956,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     src/xrc/xh_radbx.cpp
     src/xrc/xh_scrol.cpp
     src/xrc/xh_scwin.cpp
+    src/xrc/xh_htmllbox.cpp
     src/xrc/xh_sizer.cpp
     src/xrc/xh_slidr.cpp
     src/xrc/xh_spin.cpp
@@ -3012,6 +3013,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     wx/xrc/xh_radbx.h
     wx/xrc/xh_scrol.h
     wx/xrc/xh_scwin.h
+    wx/xrc/xh_htmllbox.h
     wx/xrc/xh_sizer.h
     wx/xrc/xh_slidr.h
     wx/xrc/xh_spin.h
diff --git a/docs/changes.txt b/docs/changes.txt
index 5afdfed18b..7d21c120d3 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -71,6 +71,7 @@ All (GUI):
 - Reverted wxBuffered[Paint]DC to pre 2.7.1 state, added
   wxAutoBufferedPaintDC and wxAutoBufferedPaintDCFactory.
 - Renamed wxProgressDialog::UpdatePulse() to just Pulse()
+- Added wxSimpleHtmlListBox (Francesco Montorsi)
 
 Unix Ports:
 
diff --git a/docs/latex/wx/category.tex b/docs/latex/wx/category.tex
index 06d8021a8a..52b546326c 100644
--- a/docs/latex/wx/category.tex
+++ b/docs/latex/wx/category.tex
@@ -102,7 +102,8 @@ that are not static can have \helpref{validators}{wxvalidator} associated with t
 \twocolitem{\helpref{wxDataViewCtrl}{wxdataviewctrl}}{A control to tabular or tree like data}
 \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{wxHtmlListBox}{wxhtmllistbox}}{An abstract class for creating listboxes showing HTML content}
+\twocolitem{\helpref{wxSimpleHtmlListBox}{wxsimplehtmllistbox}}{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}
diff --git a/docs/latex/wx/htmllbox.tex b/docs/latex/wx/htmllbox.tex
index 2cdd92b8c0..d7cc8f62cd 100644
--- a/docs/latex/wx/htmllbox.tex
+++ b/docs/latex/wx/htmllbox.tex
@@ -1,6 +1,6 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Name:        htmllbox.tex
-%% Purpose:     wxHtmlListBox documentation
+%% Purpose:     wxHtmlListBox and wxSimpleHtmlListBox documentation
 %% Author:      Vadim Zeitlin
 %% Modified by:
 %% Created:     01.06.03
@@ -30,13 +30,17 @@ example) but you will only need to override a single
 
 <wx/htmllbox.h>
 
+\wxheading{See also}
+
+\helpref{wxSimpleHtmlListBox}{wxsimplehtmllistbox}
+
 
 \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{long }{style = 0}, \param{const wxString\& }{name = wxVListBoxNameStr}}
+\func{}{wxHtmlListBox}{\param{wxWindow* }{parent}, \param{wxWindowID }{id = wxID\_ANY}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{long }{style = 0}, \param{const wxString\& }{name = wxHtmlListBoxNameStr}}
 
 Normal constructor which calls \helpref{Create()}{wxhtmllistboxcreate}
 internally.
@@ -56,14 +60,14 @@ 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{long }{style = 0}, \param{const wxString\& }{name = wxVListBoxNameStr}}
+\func{bool}{Create}{\param{wxWindow* }{parent}, \param{wxWindowID }{id = wxID\_ANY}, \param{const wxPoint\& }{pos = wxDefaultPosition}, \param{const wxSize\& }{size = wxDefaultSize}, \param{long }{style = 0}, \param{const wxString\& }{name = wxHtmlListBoxNameStr}}
 
 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.
+wxListBox styles (with the exception of {\tt wxLB_MULTIPLE}) can not be used here.
 
 Returns {\tt true} on success or {\tt false} if the control couldn't be created
 
@@ -124,6 +128,12 @@ This method must be implemented in the derived class and should return
 the body (i.e. without {\tt <html>} nor {\tt <body>} tags) of the HTML fragment
 for the given item.
 
+Note that this function should always return a text fragment for the \arg{n} item
+which renders with the same height both when it is selected and when it's not:
+i.e. if you call, inside your OnGetItem() implementation, {\tt IsSelected(n)} to
+make the items appear differently when they are selected, then you should make sure
+that the returned HTML fragment will render with the same height or else you'll
+see some artifacts when the user selects an item.
 
 \membersection{wxHtmlListBox::OnGetItemMarkup}\label{wxhtmllistboxongetitemmarkup}
 
@@ -148,3 +158,158 @@ Called when the user clicks on hypertext link. Does nothing by default.
 
 See also \helpref{wxHtmlLinkInfo}{wxhtmllinkinfo}.
 
+
+
+
+
+
+
+%
+% wxSimpleHtmlListBox
+%
+
+
+\section{\class{wxSimpleHtmlListBox}}\label{wxsimplehtmllistbox}
+
+wxSimpleHtmlListBox is an implementation of \helpref{wxHtmlListBox}{wxhtmllistbox} which
+shows HTML content in the listbox rows.
+
+Unlike \helpref{wxHtmlListBox}{wxhtmllistbox}, this is not an abstract class and thus it
+has the advantage that you can use it without deriving your own class from it.
+However, it also has the disadvantage that this is not a virtual control and thus it's not
+well-suited for those cases where you need to show a huge number of items: every time you
+add/insert a string, it will be stored internally and thus will take memory.
+
+The interface exposed by wxSimpleHtmlListBox fully implements the
+\helpref{wxControlWithItems}{wxcontrolwithitems} interface, thus you should refer to
+\helpref{wxControlWithItems}{wxcontrolwithitems}'s documentation for the API reference
+for adding/removing/retrieving items in the listbox.
+Also note that the \helpref{wxVListBox::SetItemCount}{wxvlistboxsetitemcount} function is
+{\tt protected} in wxSimpleHtmlListBox's context so that you cannot call it directly,
+wxSimpleHtmlListBox will do it for you.
+
+Note: in case you need to append a lot of items to the control at once, make sure to use the
+\helpref{Append(const wxArrayString \&)}{wxcontrolwithitemsappend} function.
+
+Thus the only difference between a \helpref{wxListBox}{wxlistbox} and a wxSimpleHtmlListBox
+is that the latter stores strings which can contain HTML fragments (see the list of
+\helpref{tags supported by wxHTML}{htmltagssupported}).
+
+Note that the HTML strings you fetch to wxSimpleHtmlListBox should not contain the {\tt <html>} 
+or {\tt <body>} tags.
+
+
+\wxheading{Derived from}
+
+\helpref{wxHtmlListBox}{wxhtmllistbox}, \helpref{wxControlWithItems}{wxcontrolwithitems}\\
+\helpref{wxVListBox}{wxvlistbox}\\
+\helpref{wxVScrolledWindow}{wxvscrolledwindow}\\
+\helpref{wxPanel}{wxpanel}\\
+\helpref{wxWindow}{wxwindow}\\
+\helpref{wxEvtHandler}{wxevthandler}\\
+\helpref{wxObject}{wxobject}
+
+\wxheading{Include files}
+
+<wx/htmllbox.h>
+
+\wxheading{Window styles}
+
+\twocolwidtha{5cm}%
+\begin{twocollist}\itemsep=0pt
+\twocolitem{\windowstyle{wxHLB\_DEFAULT\_STYLE}}{The default style: wxSUNKEN_BORDER}
+\twocolitem{\windowstyle{wxHLB\_MULTIPLE}}{Multiple-selection list: the user can toggle multiple
+items on and off.}
+\end{twocollist}
+
+See also \helpref{window styles overview}{windowstyles}.
+
+\wxheading{Event handling}
+
+A wxSimpleHtmlListBox emits the same events used by \helpref{wxListBox}{wxlistbox}:
+
+\twocolwidtha{7cm}
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf EVT\_LISTBOX(id, func)}}{Process a wxEVT\_COMMAND\_LISTBOX\_SELECTED event,
+when an item on the list is selected.}
+\twocolitem{{\bf EVT\_LISTBOX\_DCLICK(id, func)}}{Process a wxEVT\_COMMAND\_LISTBOX\_DOUBLECLICKED event,
+when the listbox is double-clicked.}
+\end{twocollist}
+
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+
+\membersection{wxSimpleHtmlListBox::wxSimpleHtmlListBox}\label{wxsimplehtmllistboxctor}
+
+\func{}{wxHtmlListBox}{\param{wxWindow*}{ parent}, \param{wxWindowID}{ id},\rtfsp
+\param{const wxPoint\&}{ pos = wxDefaultPosition}, \param{const wxSize\&}{ size = wxDefaultSize},\rtfsp
+\param{int}{ n = 0}, \param{const wxString }{choices[] = NULL},\rtfsp
+\param{long}{ style = wxHLB\_DEFAULT\_STYLE}, \param{const wxValidator\& }{validator = wxDefaultValidator},\rtfsp
+\param{const wxString\& }{name = ``simpleHtmlListBox"}}
+
+\func{}{wxHtmlListBox}{\param{wxWindow*}{ parent}, \param{wxWindowID}{ id},\rtfsp
+\param{const wxPoint\&}{ pos}, \param{const wxSize\&}{ size},\rtfsp
+\param{const wxArrayString\& }{choices},\rtfsp
+\param{long}{ style = wxHLB\_DEFAULT\_STYLE}, \param{const wxValidator\& }{validator = wxDefaultValidator},\rtfsp
+\param{const wxString\& }{name = ``simpleHtmlListBox"}}
+
+Constructor, creating and showing the HTML list box.
+
+\wxheading{Parameters}
+
+\docparam{parent}{Parent window. Must not be NULL.}
+
+\docparam{id}{Window identifier. A value of -1 indicates a default value.}
+
+\docparam{pos}{Window position.}
+
+\docparam{size}{Window size. If the default size (-1, -1) is specified then the window is sized
+appropriately.}
+
+\docparam{n}{Number of strings with which to initialise the control.}
+
+\docparam{choices}{An array of strings with which to initialise the control.}
+
+\docparam{style}{Window style. See {\tt wxHLB\_*} flags.}
+
+\docparam{validator}{Window validator.}
+
+\docparam{name}{Window name.}
+
+\wxheading{See also}
+
+\helpref{wxSimpleHtmlListBox::Create}{wxsimplehtmllistboxcreate}
+
+
+
+\func{}{wxSimpleHtmlListBox}{\void}
+
+Default constructor, you must call \helpref{Create()}{wxsimplehtmllistboxcreate}
+later.
+
+
+\membersection{wxSimpleHtmlListBox::\destruct{wxSimpleHtmlListBox}}\label{wxsimplehtmllistboxdtor}
+
+\func{}{\destruct{wxSimpleHtmlListBox}}{\void}
+
+Frees the array of stored items and relative client data.
+
+
+\membersection{wxSimpleHtmlListBox::Create}\label{wxsimplehtmllistboxcreate}
+
+\func{bool}{Create}{\param{wxWindow*}{ parent}, \param{wxWindowID}{ id},\rtfsp
+\param{const wxPoint\&}{ pos = wxDefaultPosition}, \param{const wxSize\&}{ size = wxDefaultSize},\rtfsp
+\param{int}{ n}, \param{const wxString }{choices[] = NULL},\rtfsp
+\param{long}{ style = wxHLB\_DEFAULT\_STYLE}, \param{const wxValidator\& }{validator = wxDefaultValidator},\rtfsp
+\param{const wxString\& }{name = ``simpleHtmlListBox"}}
+
+\func{bool}{Create}{\param{wxWindow*}{ parent}, \param{wxWindowID}{ id},\rtfsp
+\param{const wxPoint\&}{ pos}, \param{const wxSize\&}{ size},\rtfsp
+\param{const wxArrayString\& }{choices},\rtfsp
+\param{long}{ style = wxHLB\_DEFAULT\_STYLE}, \param{const wxValidator\& }{validator = wxDefaultValidator},\rtfsp
+\param{const wxString\& }{name = ``simpleHtmlListBox"}}
+
+Creates the HTML listbox for two-step construction. 
+See \helpref{wxSimpleHtmlListBox::wxSimpleHtmlListBox}{wxsimplehtmllistboxctor} for further details.
+
diff --git a/docs/latex/wx/vlbox.tex b/docs/latex/wx/vlbox.tex
index 1723177aa5..00e4c8f295 100644
--- a/docs/latex/wx/vlbox.tex
+++ b/docs/latex/wx/vlbox.tex
@@ -41,6 +41,10 @@ event macros may be used with it.
 
 <wx/vlbox.h>
 
+\wxheading{See also}
+
+\helpref{wxSimpleHtmlListBox}{wxsimplehtmllistbox}, \helpref{wxHtmlListBox}{wxhtmllistbox}
+
 \latexignore{\rtfignore{\wxheading{Members}}}
 
 
diff --git a/include/wx/ctrlsub.h b/include/wx/ctrlsub.h
index e6ad7e9f71..308fb6a03a 100644
--- a/include/wx/ctrlsub.h
+++ b/include/wx/ctrlsub.h
@@ -155,13 +155,13 @@ protected:
 // two versions
 #define wxCONTROL_ITEMCONTAINER_CLIENTDATAOBJECT_RECAST                    \
     void SetClientData(void *data)                                         \
-        { wxControl::SetClientData(data); }                                \
+        { wxEvtHandler::SetClientData(data); }                             \
     void *GetClientData() const                                            \
-        { return wxControl::GetClientData(); }                             \
+        { return wxEvtHandler::GetClientData(); }                          \
     void SetClientObject(wxClientData *data)                               \
-        { wxControl::SetClientObject(data); }                              \
+        { wxEvtHandler::SetClientObject(data); }                           \
     wxClientData *GetClientObject() const                                  \
-        { return wxControl::GetClientObject(); }                           \
+        { return wxEvtHandler::GetClientObject(); }                        \
     void SetClientData(unsigned int n, void* clientData)                   \
         { wxItemContainer::SetClientData(n, clientData); }                 \
     void* GetClientData(unsigned int n) const                              \
diff --git a/include/wx/htmllbox.h b/include/wx/htmllbox.h
index 8a2a379e35..9e5a4b44b7 100644
--- a/include/wx/htmllbox.h
+++ b/include/wx/htmllbox.h
@@ -14,6 +14,7 @@
 
 #include "wx/vlbox.h"               // base class
 #include "wx/html/htmlwin.h"
+#include "wx/ctrlsub.h"
 
 #if wxUSE_FILESYSTEM
     #include "wx/filesys.h"
@@ -24,6 +25,9 @@ class WXDLLIMPEXP_HTML wxHtmlWinParser;
 class WXDLLIMPEXP_HTML wxHtmlListBoxCache;
 class WXDLLIMPEXP_HTML wxHtmlListBoxStyle;
 
+extern WXDLLEXPORT_DATA(const wxChar) wxHtmlListBoxNameStr[];
+extern WXDLLEXPORT_DATA(const wxChar) wxSimpleHtmlListBoxNameStr[];
+
 // ----------------------------------------------------------------------------
 // wxHtmlListBox
 // ----------------------------------------------------------------------------
@@ -46,7 +50,7 @@ public:
                   const wxPoint& pos = wxDefaultPosition,
                   const wxSize& size = wxDefaultSize,
                   long style = 0,
-                  const wxString& name = wxVListBoxNameStr);
+                  const wxString& name = wxHtmlListBoxNameStr);
 
     // really creates the control and sets the initial number of items in it
     // (which may be changed later with SetItemCount())
@@ -59,7 +63,7 @@ public:
                 const wxPoint& pos = wxDefaultPosition,
                 const wxSize& size = wxDefaultSize,
                 long style = 0,
-                const wxString& name = wxVListBoxNameStr);
+                const wxString& name = wxHtmlListBoxNameStr);
 
     // destructor cleans up whatever resources we use
     virtual ~wxHtmlListBox();
@@ -111,7 +115,7 @@ protected:
     // This method may be overriden to handle clicking on a link in
     // the listbox. By default, clicking links is ignored.
     virtual void OnLinkClicked(size_t WXUNUSED(n),
-                               const wxHtmlLinkInfo& WXUNUSED(link)) {}
+                               const wxHtmlLinkInfo& WXUNUSED(link)) { }
 
     // event handlers
     void OnSize(wxSizeEvent& event);
@@ -183,5 +187,137 @@ private:
     DECLARE_NO_COPY_CLASS(wxHtmlListBox)
 };
 
+
+// ----------------------------------------------------------------------------
+// wxSimpleHtmlListBox
+// ----------------------------------------------------------------------------
+
+#define wxHLB_DEFAULT_STYLE     wxBORDER_SUNKEN
+#define wxHLB_MULTIPLE          wxLB_MULTIPLE
+
+class WXDLLIMPEXP_HTML wxSimpleHtmlListBox : public wxHtmlListBox,
+                                             public wxItemContainer
+{
+public:
+    // wxListbox-compatible constructors
+    // ---------------------------------
+
+    wxSimpleHtmlListBox() { }
+
+    wxSimpleHtmlListBox(wxWindow *parent,
+                        wxWindowID id,
+                        const wxPoint& pos = wxDefaultPosition,
+                        const wxSize& size = wxDefaultSize,
+                        int n = 0, const wxString choices[] = NULL,
+                        long style = wxHLB_DEFAULT_STYLE,
+                        const wxValidator& validator = wxDefaultValidator,
+                        const wxString& name = wxSimpleHtmlListBoxNameStr)
+    {
+        Create(parent, id, pos, size, n, choices, style, validator, name);
+    }
+
+    wxSimpleHtmlListBox(wxWindow *parent,
+                        wxWindowID id,
+                        const wxPoint& pos,
+                        const wxSize& size,
+                        const wxArrayString& choices,
+                        long style = wxHLB_DEFAULT_STYLE,
+                        const wxValidator& validator = wxDefaultValidator,
+                        const wxString& name = wxSimpleHtmlListBoxNameStr)
+    {
+        Create(parent, id, pos, size, choices, style, validator, name);
+    }
+
+    bool Create(wxWindow *parent, wxWindowID id,
+                const wxPoint& pos = wxDefaultPosition,
+                const wxSize& size = wxDefaultSize,
+                int n = 0, const wxString choices[] = NULL,
+                long style = wxHLB_DEFAULT_STYLE,
+                const wxValidator& validator = wxDefaultValidator,
+                const wxString& name = wxSimpleHtmlListBoxNameStr);
+    bool Create(wxWindow *parent, wxWindowID id,
+                const wxPoint& pos,
+                const wxSize& size,
+                const wxArrayString& choices,
+                long style = wxHLB_DEFAULT_STYLE,
+                const wxValidator& validator = wxDefaultValidator,
+                const wxString& name = wxSimpleHtmlListBoxNameStr);
+                
+    virtual ~wxSimpleHtmlListBox();
+
+    // these must be overloaded otherwise the compiler will complain
+    // about  wxItemContainerImmutable::[G|S]etSelection being pure virtuals...
+    void SetSelection(int n)
+        { return wxVListBox::SetSelection(n); }
+    int GetSelection() const
+        { return wxVListBox::GetSelection(); }
+
+    // see ctrlsub.h for more info about this:
+    wxCONTROL_ITEMCONTAINER_CLIENTDATAOBJECT_RECAST
+
+
+    // accessing strings
+    // -----------------
+
+    virtual unsigned int GetCount() const
+        { return m_items.GetCount(); }
+
+    virtual wxString GetString(unsigned int n) const;
+
+    // override default unoptimized wxItemContainer::GetStrings() function
+    wxArrayString GetStrings() const
+        { return m_items; }
+
+    virtual void SetString(unsigned int n, const wxString& s);
+
+    virtual void Clear();
+    virtual void Delete(unsigned int n);
+
+    // override default unoptimized wxItemContainer::Append() function
+    void Append(const wxArrayString& strings);
+
+    // since we override one Append() overload, we need to overload all others too
+    int Append(const wxString& item)
+        { return wxItemContainer::Append(item); }
+    int Append(const wxString& item, void *clientData)
+        { return wxItemContainer::Append(item, clientData); }
+    int Append(const wxString& item, wxClientData *clientData)
+        { return wxItemContainer::Append(item, clientData); }
+
+
+protected:
+
+    virtual int DoAppend(const wxString& item);
+    virtual int DoInsert(const wxString& item, unsigned int pos);
+
+    virtual void DoSetItemClientData(unsigned int n, void *clientData)
+        { m_clientData[n] = clientData; }
+
+    virtual void *DoGetItemClientData(unsigned int n) const
+        { return m_clientData[n]; }
+    virtual void DoSetItemClientObject(unsigned int n, wxClientData *clientData)
+        { m_clientData[n] = (void *)clientData; }
+    virtual wxClientData *DoGetItemClientObject(unsigned int n) const
+        { return (wxClientData *)m_clientData[n]; }
+
+    // calls wxHtmlListBox::SetItemCount() and RefreshAll()
+    void UpdateCount();
+
+    // overload these functions just to change their visibility: users of
+    // wxSimpleHtmlListBox shouldn't be allowed to call them directly!
+    virtual void SetItemCount(size_t count)
+        { return wxHtmlListBox::SetItemCount(count); }
+    virtual void SetLineCount(size_t count)
+        { return wxHtmlListBox::SetLineCount(count); }
+
+    virtual wxString OnGetItem(size_t n) const
+        { return m_items[n]; }
+
+    wxArrayString m_items;
+    wxArrayPtrVoid m_clientData;
+
+    DECLARE_NO_COPY_CLASS(wxSimpleHtmlListBox)
+};
+
 #endif // _WX_HTMLLBOX_H_
 
diff --git a/include/wx/xrc/xh_all.h b/include/wx/xrc/xh_all.h
index d3364fc18e..bf900cf07f 100644
--- a/include/wx/xrc/xh_all.h
+++ b/include/wx/xrc/xh_all.h
@@ -53,6 +53,7 @@
 #include "wx/xrc/xh_gdctl.h"
 #include "wx/xrc/xh_frame.h"
 #include "wx/xrc/xh_scwin.h"
+#include "wx/xrc/xh_htmllbox.h"
 #include "wx/xrc/xh_split.h"
 #include "wx/xrc/xh_wizrd.h"
 #include "wx/xrc/xh_statbar.h"
diff --git a/include/wx/xrc/xh_htmllbox.h b/include/wx/xrc/xh_htmllbox.h
new file mode 100644
index 0000000000..1550697920
--- /dev/null
+++ b/include/wx/xrc/xh_htmllbox.h
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        wx/xrc/xh_htmllbox.h
+// Purpose:     XML resource handler for wxSimpleHtmlListBox
+// Author:      Francesco Montorsi
+// Created:     2006/10/21
+// RCS-ID:      $Id$
+// Copyright:   (c) 2006 Francesco Montorsi
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_XH_SIMPLEHTMLLISTBOX_H_
+#define _WX_XH_SIMPLEHTMLLISTBOX_H_
+
+#include "wx/xrc/xmlres.h"
+
+#if wxUSE_XRC && wxUSE_HTML
+
+class WXDLLIMPEXP_XRC wxSimpleHtmlListBoxXmlHandler : public wxXmlResourceHandler
+{
+public:
+    wxSimpleHtmlListBoxXmlHandler();
+    virtual wxObject *DoCreateResource();
+    virtual bool CanHandle(wxXmlNode *node);
+
+private:
+    bool m_insideBox;
+    wxArrayString strList;
+
+    DECLARE_DYNAMIC_CLASS(wxSimpleHtmlListBoxXmlHandler)
+};
+
+#endif // wxUSE_XRC && wxUSE_HTML
+
+#endif // _WX_XH_SIMPLEHTMLLISTBOX_H_
diff --git a/samples/htlbox/htlbox.cpp b/samples/htlbox/htlbox.cpp
index f0b76886b1..a53accf347 100644
--- a/samples/htlbox/htlbox.cpp
+++ b/samples/htlbox/htlbox.cpp
@@ -63,6 +63,7 @@
 class MyHtmlListBox : public wxHtmlListBox
 {
 public:
+    MyHtmlListBox() { }
     MyHtmlListBox(wxWindow *parent, bool multi = false);
 
     void SetChangeSelFg(bool change) { m_change = change; }
@@ -97,8 +98,10 @@ protected:
 #endif
 
     DECLARE_NO_COPY_CLASS(MyHtmlListBox)
+    DECLARE_DYNAMIC_CLASS(MyHtmlListBox)
 };
 
+
 class MyFrame : public wxFrame
 {
 public:
@@ -106,6 +109,7 @@ public:
     virtual ~MyFrame();
 
     // event handlers
+    void OnSimpleOrCustomBox(wxCommandEvent& event);
     void OnQuit(wxCommandEvent& event);
     void OnAbout(wxCommandEvent& event);
 
@@ -127,9 +131,16 @@ public:
     {
         wxLogMessage(_T("Listbox item %d double clicked."), event.GetInt());
     }
+    
+    wxSimpleHtmlListBox *GetSimpleBox() 
+        { return wxDynamicCast(m_hlbox, wxSimpleHtmlListBox); }
+    MyHtmlListBox *GetMyBox()
+        { return wxDynamicCast(m_hlbox, MyHtmlListBox); }
+
+    void CreateBox();
 
 private:
-    MyHtmlListBox *m_hlbox;
+    wxHtmlListBox *m_hlbox;
 
     // any class wishing to process wxWidgets events must use this macro
     DECLARE_EVENT_TABLE()
@@ -149,7 +160,9 @@ public:
 enum
 {
     // menu items
-    HtmlLbox_Quit = 1,
+    HtmlLbox_CustomBox = 1,
+    HtmlLbox_SimpleBox,
+    HtmlLbox_Quit,
 
     HtmlLbox_SetMargins,
     HtmlLbox_DrawSeparator,
@@ -172,6 +185,8 @@ enum
 // ----------------------------------------------------------------------------
 
 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+    EVT_MENU(HtmlLbox_CustomBox,  MyFrame::OnSimpleOrCustomBox)
+    EVT_MENU(HtmlLbox_SimpleBox,  MyFrame::OnSimpleOrCustomBox)
     EVT_MENU(HtmlLbox_Quit,  MyFrame::OnQuit)
 
     EVT_MENU(HtmlLbox_SetMargins, MyFrame::OnSetMargins)
@@ -206,7 +221,7 @@ IMPLEMENT_APP(MyApp)
 // frame constructor
 MyFrame::MyFrame()
        : wxFrame(NULL, wxID_ANY, _T("HtmlLbox wxWidgets Sample"),
-                 wxDefaultPosition, wxSize(400, 500))
+                 wxDefaultPosition, wxSize(500, 500))
 {
     // set the frame icon
     SetIcon(wxIcon(sample_xpm));
@@ -214,6 +229,11 @@ MyFrame::MyFrame()
 #if wxUSE_MENUS
     // create a menu bar
     wxMenu *menuFile = new wxMenu;
+    menuFile->AppendRadioItem(HtmlLbox_CustomBox, _T("Use custom box"), 
+                              _T("Use a wxHtmlListBox virtual class control"));
+    menuFile->AppendRadioItem(HtmlLbox_SimpleBox, _T("Use simple box"), 
+                              _T("Use a wxSimpleHtmlListBox control"));
+    menuFile->AppendSeparator();
     menuFile->Append(HtmlLbox_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
 
     // create our specific menu
@@ -259,9 +279,9 @@ MyFrame::MyFrame()
     CreateStatusBar(2);
     SetStatusText(_T("Welcome to wxWidgets!"));
 #endif // wxUSE_STATUSBAR
-
+    
     // create the child controls
-    m_hlbox = new MyHtmlListBox(this);
+    CreateBox();
     wxTextCtrl *text = new wxTextCtrl(this, wxID_ANY, _T(""),
                                       wxDefaultPosition, wxDefaultSize,
                                       wxTE_MULTILINE);
@@ -269,8 +289,8 @@ MyFrame::MyFrame()
 
     // and lay them out
     wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
-    sizer->Add(m_hlbox, 1, wxGROW);
-    sizer->Add(text, 1, wxGROW);
+    sizer->Add(m_hlbox, 2, wxGROW);
+    sizer->Add(text, 3, wxGROW);
 
     SetSizer(sizer);
 }
@@ -280,10 +300,61 @@ MyFrame::~MyFrame()
     delete wxLog::SetActiveTarget(NULL);
 }
 
+void MyFrame::CreateBox()
+{
+    bool multi = GetMenuBar()->IsChecked(HtmlLbox_ToggleMulti);
+
+    if ( GetMenuBar()->IsChecked(HtmlLbox_CustomBox) )
+    {
+        m_hlbox = new MyHtmlListBox(this, multi);
+    }
+    else // simple listbox
+    {
+        m_hlbox = new wxSimpleHtmlListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
+                                          0, NULL, multi ? wxLB_MULTIPLE : 0);
+        
+        // unlike wxHtmlListBox which is abstract, wxSimpleHtmlListBox is a
+        // concrete control and doesn't support virtual mode, this we need
+        // to add all of its items from the beginning
+        wxArrayString arr;
+        for (size_t n = 0; n < 1000; n++ )
+        {
+            wxColour clr((unsigned char)(abs((int)n - 192) % 256),
+                         (unsigned char)(abs((int)n - 256) % 256),
+                         (unsigned char)(abs((int)n - 128) % 256));
+            int level = n % 6 + 1;
+
+            wxString label = wxString::Format(_T("<h%d><font color=%s>")
+                    _T("Item</font> <b>%lu</b>")
+                    _T("</h%d>"),
+                    level,
+                    clr.GetAsString(wxC2S_HTML_SYNTAX).c_str(),
+                    (unsigned long)n, level);
+            arr.Add(label);
+        }
+
+        GetSimpleBox()->Append(arr);
+    }
+}
+
+
 // ----------------------------------------------------------------------------
 // menu event handlers
 // ----------------------------------------------------------------------------
 
+void MyFrame::OnSimpleOrCustomBox(wxCommandEvent& WXUNUSED(event))
+{
+    wxWindow *old = m_hlbox;
+ 
+    // we need to recreate the listbox
+    CreateBox();
+    GetSizer()->Replace(old, m_hlbox);
+    delete old;
+    
+    GetSizer()->Layout();
+    Refresh();
+}
+
 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 {
     // true is to force the frame to close
@@ -318,17 +389,16 @@ void MyFrame::OnSetMargins(wxCommandEvent& WXUNUSED(event))
     }
 }
 
-void MyFrame::OnToggleMulti(wxCommandEvent& event)
+void MyFrame::OnToggleMulti(wxCommandEvent& WXUNUSED(event))
 {
+    wxWindow *old = m_hlbox;
+ 
     // we need to recreate the listbox
-    wxSizer *sizer = GetSizer();
-    sizer->Detach(m_hlbox);
-    delete m_hlbox;
-
-    m_hlbox = new MyHtmlListBox(this, event.IsChecked());
-    sizer->Prepend(m_hlbox, 1, wxGROW);
+    CreateBox();
+    GetSizer()->Replace(old, m_hlbox);
+    delete old;
 
-    sizer->Layout();
+    GetSizer()->Layout();
 }
 
 void MyFrame::OnSelectAll(wxCommandEvent& WXUNUSED(event))
@@ -343,7 +413,8 @@ void MyFrame::OnUpdateUISelectAll(wxUpdateUIEvent& event)
 
 void MyFrame::OnUpdateItem(wxCommandEvent& WXUNUSED(event))
 {
-    m_hlbox->UpdateFirstItem();
+    if (GetMyBox())
+        GetMyBox()->UpdateFirstItem();
 }
 
 void MyFrame::OnSetBgCol(wxCommandEvent& WXUNUSED(event))
@@ -376,8 +447,11 @@ void MyFrame::OnSetSelBgCol(wxCommandEvent& WXUNUSED(event))
 
 void MyFrame::OnSetSelFgCol(wxCommandEvent& event)
 {
-    m_hlbox->SetChangeSelFg(!event.IsChecked());
-    m_hlbox->Refresh();
+    if (GetMyBox())
+    {
+        GetMyBox()->SetChangeSelFg(!event.IsChecked());
+        GetMyBox()->Refresh();
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -422,6 +496,8 @@ void MyFrame::OnLboxSelect(wxCommandEvent& event)
 // MyHtmlListBox
 // ============================================================================
 
+IMPLEMENT_DYNAMIC_CLASS(MyHtmlListBox, wxHtmlListBox)
+
 MyHtmlListBox::MyHtmlListBox(wxWindow *parent, bool multi)
              : wxHtmlListBox(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                              multi ? wxLB_MULTIPLE : 0)
@@ -517,3 +593,4 @@ void MyHtmlListBox::OnLinkClicked(size_t WXUNUSED(n),
 
     RefreshLine(1);
 }
+
diff --git a/samples/xrc/rc/controls.xrc b/samples/xrc/rc/controls.xrc
index 71c4e565d6..8ddde48b50 100644
--- a/samples/xrc/rc/controls.xrc
+++ b/samples/xrc/rc/controls.xrc
@@ -558,6 +558,34 @@
                         </object>
                     </object>
                 </object>
+                <object class="notebookpage">
+                    <label>wxSimpleHtmlListBox</label>
+                    <object class="wxPanel" name="simplehtmllistbox">
+                        <object class="wxFlexGridSizer">
+                            <cols>1</cols>
+                            <rows>0</rows>
+                            <vgap>0</vgap>
+                            <hgap>0</hgap>
+                            <growablecols>0</growablecols>
+                            <growablerows>0</growablerows>
+                            <object class="sizeritem">
+                                <flag>wxALIGN_CENTER|wxALL</flag>
+                                <border>5</border>
+                                <object class="wxSimpleHtmlListBox" name="controls_simplehtmllistbox">
+                                    <size>250,160</size>
+                                    <style>wxHLB_MULTIPLE|wxHLB_DEFAULT_STYLE</style>
+                                    <content>
+                                        <item>&lt;b&gt;Bold&lt;/b&gt; Milk</item>
+                                        <item>&lt;i&gt;Rainbow &lt;font color="red"&gt;P&lt;/font&gt;&lt;font color="blue"&gt;i&lt;/font&gt;&lt;font color="yellow"&gt;z&lt;/font&gt;&lt;font color="green"&gt;z&lt;/font&gt;&lt;font color="purple"&gt;a&lt;/font&gt;&lt;/i&gt;</item>
+                                        <item>&lt;tt&gt;Plain bread&lt;/tt&gt;</item>
+                                        <item>&lt;font color="orange" size="+1"&gt;Orange juice&lt;/font&gt;</item>
+                                        <item>Paper towels</item>
+                                    </content>
+                                </object>
+                            </object>
+                        </object>
+                    </object>
+                </object>
                 <object class="notebookpage">
                     <label>wxListCtrl</label>
                     <object class="wxPanel" name="listctrl">
diff --git a/src/generic/htmllbox.cpp b/src/generic/htmllbox.cpp
index b104f3c2f5..7e4f8d73e4 100644
--- a/src/generic/htmllbox.cpp
+++ b/src/generic/htmllbox.cpp
@@ -46,6 +46,9 @@ FORCE_WXHTML_MODULES()
 // small border always added to the cells:
 static const wxCoord CELL_BORDER = 2;
 
+const wxChar wxHtmlListBoxNameStr[] = wxT("htmlListBox");
+const wxChar wxSimpleHtmlListBoxNameStr[] = wxT("simpleHtmlListBox");
+
 // ============================================================================
 // private classes
 // ============================================================================
@@ -541,4 +544,131 @@ void wxHtmlListBox::OnLeftDown(wxMouseEvent& event)
     }
 }
 
+
+// ----------------------------------------------------------------------------
+// wxSimpleHtmlListBox
+// ----------------------------------------------------------------------------
+
+bool wxSimpleHtmlListBox::Create(wxWindow *parent, wxWindowID id,
+                                 const wxPoint& pos,
+                                 const wxSize& size,
+                                 int n, const wxString choices[],
+                                 long style,
+                                 const wxValidator& validator,
+                                 const wxString& name)
+{
+    if (!wxHtmlListBox::Create(parent, id, pos, size, style, name))
+        return false;
+
+    SetValidator(validator);
+    for (int i=0; i<n; i++)
+        Append(choices[i]);
+
+    return true;
+}
+
+bool wxSimpleHtmlListBox::Create(wxWindow *parent, wxWindowID id,
+                                    const wxPoint& pos,
+                                    const wxSize& size,
+                                    const wxArrayString& choices,
+                                    long style,
+                                    const wxValidator& validator,
+                                    const wxString& name)
+{
+    if (!wxHtmlListBox::Create(parent, id, pos, size, style, name))
+        return false;
+
+    SetValidator(validator);
+    Append(choices);
+
+    return true;
+}
+
+wxSimpleHtmlListBox::~wxSimpleHtmlListBox()
+{
+    wxASSERT(m_items.GetCount() == m_clientData.GetCount());
+    if (HasClientObjectData())
+    {
+        // clear the array of client data objects
+        for (size_t i=0; i<m_items.GetCount(); i++)
+            delete DoGetItemClientObject(i);
+    }
+
+    m_items.Clear();
+    m_clientData.Clear();
+}
+
+void wxSimpleHtmlListBox::Clear()
+{
+    m_items.Clear();
+    m_clientData.Clear();
+    UpdateCount();
+}
+
+void wxSimpleHtmlListBox::Delete(unsigned int n)
+{
+    m_items.RemoveAt(n);
+    m_clientData.RemoveAt(n);
+    UpdateCount();
+}
+
+void wxSimpleHtmlListBox::Append(const wxArrayString& strings)
+{
+    // we know how many items are going to be added - avoid too many reallocs
+    // m_items.Alloc(strings.GetCount());
+    // FIXME: Alloc() will clear all the old contents.
+    //        Suggested fix = make Grow() public and make WX_APPEND_ARRAY take
+    //        care of calling it automatically
+
+    // append all given items at once
+    WX_APPEND_ARRAY(m_items, strings);
+    m_clientData.Add(NULL, strings.GetCount());
+    UpdateCount();
+}
+
+int wxSimpleHtmlListBox::DoAppend(const wxString& item)
+{
+    m_items.Add(item);
+    m_clientData.Add(NULL);
+    UpdateCount();
+    return GetCount()-1;
+}
+
+int wxSimpleHtmlListBox::DoInsert(const wxString& item, unsigned int pos)
+{
+    m_items.Insert(item, pos);
+    m_clientData.Insert(NULL, pos);
+    UpdateCount();
+    return pos;
+}
+
+void wxSimpleHtmlListBox::SetString(unsigned int n, const wxString& s)
+{
+    wxCHECK_RET( IsValid(n),
+                 wxT("invalid index in wxSimpleHtmlListBox::SetString") );
+
+    m_items[n]=s; 
+    RefreshLine(n);
+}
+
+wxString wxSimpleHtmlListBox::GetString(unsigned int n) const
+{
+    wxCHECK_MSG( IsValid(n), wxEmptyString,
+                 wxT("invalid index in wxSimpleHtmlListBox::GetString") );
+
+    return m_items[n];
+}
+
+void wxSimpleHtmlListBox::UpdateCount()
+{
+    wxASSERT(m_items.GetCount() == m_clientData.GetCount());
+    wxHtmlListBox::SetItemCount(m_items.GetCount());
+
+    // very small optimization: if you need to add lot of items to
+    // a wxSimpleHtmlListBox be sure to use the
+    // wxSimpleHtmlListBox::Append(const wxArrayString&) method instead!
+    if (!this->IsFrozen())
+        RefreshAll();
+}
+
 #endif // wxUSE_HTML
diff --git a/src/xrc/xh_htmllbox.cpp b/src/xrc/xh_htmllbox.cpp
new file mode 100644
index 0000000000..f351b04cae
--- /dev/null
+++ b/src/xrc/xh_htmllbox.cpp
@@ -0,0 +1,86 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        xh_simplehtmllbox.cpp
+// Purpose:     XML resource handler for wxSimpleHtmlListBox
+// Author:      Francesco Montorsi
+// Created:     2006/10/21
+// RCS-ID:      $Id$
+// Copyright:   (c) 2006 Francesco Montorsi
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_XRC && wxUSE_HTML
+
+#include "wx/xrc/xh_htmllbox.h"
+
+#include "wx/htmllbox.h"
+#include "wx/filesys.h"
+
+IMPLEMENT_DYNAMIC_CLASS(wxSimpleHtmlListBoxXmlHandler, wxXmlResourceHandler)
+
+wxSimpleHtmlListBoxXmlHandler::wxSimpleHtmlListBoxXmlHandler()
+: wxXmlResourceHandler(), m_insideBox(false)
+{
+    XRC_ADD_STYLE(wxHLB_DEFAULT_STYLE);
+    XRC_ADD_STYLE(wxHLB_MULTIPLE);
+    AddWindowStyles();
+}
+
+wxObject *wxSimpleHtmlListBoxXmlHandler::DoCreateResource()
+{
+    if ( m_class == wxT("wxSimpleHtmlListBox"))
+    {
+        // find the selection
+        long selection = GetLong(wxT("selection"), -1);
+
+        // need to build the list of strings from children
+        m_insideBox = true;
+        CreateChildrenPrivately(NULL, GetParamNode(wxT("content")));
+        m_insideBox = false;
+
+        XRC_MAKE_INSTANCE(control, wxSimpleHtmlListBox)
+
+        control->Create(m_parentAsWindow,
+                        GetID(),
+                        GetPosition(), GetSize(),
+                        strList,
+                        GetStyle(_T("style"), wxHLB_DEFAULT_STYLE),
+                        wxDefaultValidator,
+                        GetName());
+
+        if (selection != -1)
+            control->SetSelection(selection);
+
+        SetupWindow(control);
+        strList.Clear();    // dump the strings
+
+        return control;
+    }
+    else
+    {
+        // on the inside now.
+        // handle <item>Label</item>
+
+        // add to the list
+        wxString str = GetNodeContent(m_node);
+        if (m_resource->GetFlags() & wxXRC_USE_LOCALE)
+            str = wxGetTranslation(str, m_resource->GetDomain());
+        strList.Add(str);
+
+        return NULL;
+    }
+}
+
+bool wxSimpleHtmlListBoxXmlHandler::CanHandle(wxXmlNode *node)
+{
+    return (IsOfClass(node, wxT("wxSimpleHtmlListBox")) ||
+           (m_insideBox && node->GetName() == wxT("item")));
+}
+
+#endif // wxUSE_XRC && wxUSE_HTML
diff --git a/src/xrc/xmlrsall.cpp b/src/xrc/xmlrsall.cpp
index 45dfefdd9b..8c5757e1aa 100644
--- a/src/xrc/xmlrsall.cpp
+++ b/src/xrc/xmlrsall.cpp
@@ -92,6 +92,7 @@ void wxXmlResource::InitAllHandlers()
 #endif
 #if wxUSE_HTML
     AddHandler(new wxHtmlWindowXmlHandler);
+    AddHandler(new wxSimpleHtmlListBoxXmlHandler);
 #endif
 #if wxUSE_HYPERLINKCTRL
     AddHandler( new wxHyperlinkCtrlXmlHandler);
-- 
2.50.0

