From 95a4630380511f5e747b1465bf4834e5fac3d515 Mon Sep 17 00:00:00 2001
From: Robert Roebling <robert@roebling.de>
Date: Sat, 23 Sep 2006 09:14:49 +0000
Subject: [PATCH]   [ 1559479 ] wxImageComboBox     Actually wxBitmapComboBox.
 Also commited configure.     Not yet updated Makefiles.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41383 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 configure                       |  52 ++
 configure.in                    |   8 +
 docs/latex/wx/category.tex      |   1 +
 docs/latex/wx/classes.tex       |   1 +
 include/wx/bmpcbox.h            |  59 +++
 include/wx/generic/bmpcbox.h    | 177 +++++++
 include/wx/mac/setup0.h         |  10 +-
 include/wx/motif/setup0.h       |  10 +-
 include/wx/msw/setup0.h         |  10 +-
 include/wx/os2/setup0.h         |  10 +-
 include/wx/palmos/setup0.h      |  10 +-
 include/wx/setup_inc.h          |  10 +-
 include/wx/univ/setup0.h        |  10 +-
 include/wx/xrc/xh_all.h         |   1 +
 include/wx/xrc/xh_bmpcbox.h     |  34 ++
 samples/widgets/bmpcombobox.cpp | 876 ++++++++++++++++++++++++++++++++
 samples/widgets/widgets.bkl     |   1 +
 samples/xrc/rc/controls.xrc     |  25 +
 setup.h.in                      |   2 +
 setup.h_vms                     |   2 +
 src/generic/bmpcboxg.cpp        | 471 +++++++++++++++++
 src/xrc/xh_bmpcbox.cpp          | 102 ++++
 src/xrc/xmlrsall.cpp            |   3 +
 23 files changed, 1878 insertions(+), 7 deletions(-)
 create mode 100644 include/wx/bmpcbox.h
 create mode 100644 include/wx/generic/bmpcbox.h
 create mode 100644 include/wx/xrc/xh_bmpcbox.h
 create mode 100644 samples/widgets/bmpcombobox.cpp
 create mode 100644 src/generic/bmpcboxg.cpp
 create mode 100644 src/xrc/xh_bmpcbox.cpp

diff --git a/configure b/configure
index 94771eb0c4..0c626d1550 100755
--- a/configure
+++ b/configure
@@ -1041,6 +1041,7 @@ Optional Features:
   --enable-accel          use accelerators
   --enable-button         use wxButton class
   --enable-bmpbutton      use wxBitmapButton class
+  --enable-bmpcombobox    use wxBitmapComboBox class
   --enable-calendar       use wxCalendarCtrl class
   --enable-caret          use wxCaret class
   --enable-checkbox       use wxCheckBox class
@@ -2302,6 +2303,7 @@ if test $DEBUG_CONFIGURE = 1; then
   DEFAULT_wxUSE_ACCEL=no
   DEFAULT_wxUSE_BUTTON=no
   DEFAULT_wxUSE_BMPBUTTON=no
+  DEFAULT_wxUSE_BITMAPCOMBOBOX=no
   DEFAULT_wxUSE_CALCTRL=no
   DEFAULT_wxUSE_CARET=no
   DEFAULT_wxUSE_CHECKBOX=no
@@ -2514,6 +2516,7 @@ else
   DEFAULT_wxUSE_ACCEL=yes
   DEFAULT_wxUSE_BUTTON=yes
   DEFAULT_wxUSE_BMPBUTTON=yes
+  DEFAULT_wxUSE_BITMAPCOMBOBOX=yes
   DEFAULT_wxUSE_CALCTRL=yes
   DEFAULT_wxUSE_CARET=yes
   DEFAULT_wxUSE_CHECKBOX=yes
@@ -7927,6 +7930,47 @@ echo "${ECHO_T}no" >&6
           fi
 
 
+	  enablestring=
+          echo "$as_me:$LINENO: checking for --${enablestring:-enable}-bmpcombobox" >&5
+echo $ECHO_N "checking for --${enablestring:-enable}-bmpcombobox... $ECHO_C" >&6
+          no_cache=0
+          # Check whether --enable-bmpcombobox or --disable-bmpcombobox was given.
+if test "${enable_bmpcombobox+set}" = set; then
+  enableval="$enable_bmpcombobox"
+
+                          if test "$enableval" = yes; then
+                            ac_cv_use_bmpcombobox='wxUSE_BITMAPCOMBOBOX=yes'
+                          else
+                            ac_cv_use_bmpcombobox='wxUSE_BITMAPCOMBOBOX=no'
+                          fi
+
+else
+
+                          LINE=`grep "wxUSE_BITMAPCOMBOBOX" ${wx_arg_cache_file}`
+                          if test "x$LINE" != x ; then
+                            eval "DEFAULT_$LINE"
+                          else
+                            no_cache=1
+                          fi
+
+                          ac_cv_use_bmpcombobox='wxUSE_BITMAPCOMBOBOX='$DEFAULT_wxUSE_BITMAPCOMBOBOX
+
+fi;
+
+          eval "$ac_cv_use_bmpcombobox"
+          if test "$no_cache" != 1; then
+            echo $ac_cv_use_bmpcombobox >> ${wx_arg_cache_file}.tmp
+          fi
+
+          if test "$wxUSE_BITMAPCOMBOBOX" = yes; then
+            echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+          else
+            echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+          fi
+
+
 	  enablestring=
           echo "$as_me:$LINENO: checking for --${enablestring:-enable}-calendar" >&5
 echo $ECHO_N "checking for --${enablestring:-enable}-calendar... $ECHO_C" >&6
@@ -45532,6 +45576,14 @@ _ACEOF
   USES_CONTROLS=1
 fi
 
+if test "$wxUSE_BITMAPCOMBOBOX" = "yes"; then
+  cat >>confdefs.h <<\_ACEOF
+#define wxUSE_BITMAPCOMBOBOX 1
+_ACEOF
+
+  USES_CONTROLS=1
+fi
+
 if test "$wxUSE_DATAVIEWCTRL" = "yes"; then
   cat >>confdefs.h <<\_ACEOF
 #define wxUSE_DATAVIEWCTRL 1
diff --git a/configure.in b/configure.in
index 76a9ae25c7..8af20daa02 100644
--- a/configure.in
+++ b/configure.in
@@ -510,6 +510,7 @@ if test $DEBUG_CONFIGURE = 1; then
   DEFAULT_wxUSE_ACCEL=no
   DEFAULT_wxUSE_BUTTON=no
   DEFAULT_wxUSE_BMPBUTTON=no
+  DEFAULT_wxUSE_BITMAPCOMBOBOX=no
   DEFAULT_wxUSE_CALCTRL=no
   DEFAULT_wxUSE_CARET=no
   DEFAULT_wxUSE_CHECKBOX=no
@@ -722,6 +723,7 @@ else
   DEFAULT_wxUSE_ACCEL=yes
   DEFAULT_wxUSE_BUTTON=yes
   DEFAULT_wxUSE_BMPBUTTON=yes
+  DEFAULT_wxUSE_BITMAPCOMBOBOX=yes
   DEFAULT_wxUSE_CALCTRL=yes
   DEFAULT_wxUSE_CARET=yes
   DEFAULT_wxUSE_CHECKBOX=yes
@@ -1141,6 +1143,7 @@ fi
 WX_ARG_ENABLE(accel,       [  --enable-accel          use accelerators], wxUSE_ACCEL)
 WX_ARG_ENABLE(button,      [  --enable-button         use wxButton class], wxUSE_BUTTON)
 WX_ARG_ENABLE(bmpbutton,   [  --enable-bmpbutton      use wxBitmapButton class], wxUSE_BMPBUTTON)
+WX_ARG_ENABLE(bmpcombobox, [  --enable-bmpcombobox    use wxBitmapComboBox class], wxUSE_BITMAPCOMBOBOX)
 WX_ARG_ENABLE(calendar,    [  --enable-calendar       use wxCalendarCtrl class], wxUSE_CALCTRL)
 WX_ARG_ENABLE(caret,       [  --enable-caret          use wxCaret class], wxUSE_CARET)
 WX_ARG_ENABLE(checkbox,    [  --enable-checkbox       use wxCheckBox class], wxUSE_CHECKBOX)
@@ -6539,6 +6542,11 @@ if test "$wxUSE_HYPERLINKCTRL" = "yes"; then
   USES_CONTROLS=1
 fi
 
+if test "$wxUSE_BITMAPCOMBOBOX" = "yes"; then
+  AC_DEFINE(wxUSE_BITMAPCOMBOBOX)
+  USES_CONTROLS=1
+fi
+
 if test "$wxUSE_DATAVIEWCTRL" = "yes"; then
   AC_DEFINE(wxUSE_DATAVIEWCTRL)
   USES_CONTROLS=1
diff --git a/docs/latex/wx/category.tex b/docs/latex/wx/category.tex
index c8110b3cdc..e44f9ab644 100644
--- a/docs/latex/wx/category.tex
+++ b/docs/latex/wx/category.tex
@@ -88,6 +88,7 @@ that are not static can have \helpref{validators}{wxvalidator} associated with t
 \twocolitem{\helpref{wxControl}{wxcontrol}}{The base class for controls}
 \twocolitem{\helpref{wxButton}{wxbutton}}{Push button control, displaying text}
 \twocolitem{\helpref{wxBitmapButton}{wxbitmapbutton}}{Push button control, displaying a bitmap}
+\twocolitem{\helpref{wxBitmapComboBox}{wxbitmapcombobox}}{A combobox with bitmaps next to text items}
 \twocolitem{\helpref{wxToggleButton}{wxtogglebutton}}{A button which stays pressed when clicked by user.}
 \twocolitem{\helpref{wxCalendarCtrl}{wxcalendarctrl}}{Control showing an entire calendar month}
 \twocolitem{\helpref{wxCheckBox}{wxcheckbox}}{Checkbox control}
diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex
index 21cf4dc08a..2a8a97886e 100644
--- a/docs/latex/wx/classes.tex
+++ b/docs/latex/wx/classes.tex
@@ -18,6 +18,7 @@
 \input artprov.tex
 \input autoobj.tex
 \input bitmap.tex
+\input bitmapcombobox.tex
 \input bbutton.tex
 \input bmpdatob.tex
 \input bmphand.tex
diff --git a/include/wx/bmpcbox.h b/include/wx/bmpcbox.h
new file mode 100644
index 0000000000..1cd4ea9371
--- /dev/null
+++ b/include/wx/bmpcbox.h
@@ -0,0 +1,59 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        wx/bmpcbox.h
+// Purpose:     wxBitmapComboBox base header
+// Author:      Jaakko Salli
+// Modified by:
+// Created:     Aug-31-2006
+// Copyright:   (c) Jaakko Salli
+// RCS-ID:      $Id:
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_BMPCBOX_H_BASE_
+#define _WX_BMPCBOX_H_BASE_
+
+
+#include "wx/defs.h"
+
+#if wxUSE_BITMAPCOMBOBOX
+
+#include "wx/bitmap.h"
+
+
+extern WXDLLIMPEXP_DATA_ADV(const wxChar) wxBitmapComboBoxNameStr[];
+
+
+class WXDLLIMPEXP_ADV wxBitmapComboBoxBase
+{
+public:
+
+    // ctors and such
+    wxBitmapComboBoxBase() { }
+
+    virtual ~wxBitmapComboBoxBase() { }
+
+    // Returns the image of the item with the given index.
+    virtual wxBitmap GetItemBitmap(unsigned int n) const = 0;
+
+    // Sets the image for the given item.
+    virtual void SetItemBitmap(unsigned int n, const wxBitmap& bitmap) = 0;
+
+    // Returns size of the image used in list
+    virtual wxSize GetBitmapSize() const = 0;
+
+protected:
+
+private:
+};
+
+
+#if defined(__WXUNIVERSAL__)
+    #include "wx/generic/bmpcbox.h"
+#else
+    #include "wx/generic/bmpcbox.h"
+#endif
+
+#endif // wxUSE_BITMAPCOMBOBOX
+
+#endif
+    // _WX_BMPCBOX_H_BASE_
diff --git a/include/wx/generic/bmpcbox.h b/include/wx/generic/bmpcbox.h
new file mode 100644
index 0000000000..263cfbe02c
--- /dev/null
+++ b/include/wx/generic/bmpcbox.h
@@ -0,0 +1,177 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        wx/generic/bmpcbox.h
+// Purpose:     wxBitmapComboBox
+// Author:      Jaakko Salli
+// Modified by:
+// Created:     Aug-30-2006
+// RCS-ID:      $Id:
+// Copyright:   (c) Jaakko Salli
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_GENERIC_BMPCBOX_H_
+#define _WX_GENERIC_BMPCBOX_H_
+
+
+#define wxGENERIC_BITMAPCOMBOBOX     1
+
+#if !wxUSE_ODCOMBOBOX
+    #error "Generic wxBitmapComboBox depends on wxOwnerDrawnComboBox"
+#endif
+
+#include "wx/odcombo.h"
+
+
+// ----------------------------------------------------------------------------
+// wxBitmapComboBox: a wxComboBox that allows images to be shown
+// in front of string items.
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_ADV wxBitmapComboBox : public wxOwnerDrawnComboBox,
+                                         public wxBitmapComboBoxBase
+{
+public:
+
+    // ctors and such
+    wxBitmapComboBox() : wxOwnerDrawnComboBox(), wxBitmapComboBoxBase()
+    {
+        Init();
+    }
+
+    wxBitmapComboBox(wxWindow *parent,
+                     wxWindowID id = wxID_ANY,
+                     const wxString& value = wxEmptyString,
+                     const wxPoint& pos = wxDefaultPosition,
+                     const wxSize& size = wxDefaultSize,
+                     int n = 0,
+                     const wxString choices[] = NULL,
+                     long style = 0,
+                     const wxValidator& validator = wxDefaultValidator,
+                     const wxString& name = wxBitmapComboBoxNameStr)
+        : wxOwnerDrawnComboBox(),
+          wxBitmapComboBoxBase()
+    {
+        Init();
+
+        (void)Create(parent, id, value, pos, size, n,
+                     choices, style, validator, name);
+    }
+
+    wxBitmapComboBox(wxWindow *parent,
+                     wxWindowID id,
+                     const wxString& value,
+                     const wxPoint& pos,
+                     const wxSize& size,
+                     const wxArrayString& choices,
+                     long style,
+                     const wxValidator& validator = wxDefaultValidator,
+                     const wxString& name = wxBitmapComboBoxNameStr);
+
+    bool Create(wxWindow *parent,
+                wxWindowID id,
+                const wxString& value,
+                const wxPoint& pos,
+                const wxSize& size,
+                int n,
+                const wxString choices[],
+                long style = 0,
+                const wxValidator& validator = wxDefaultValidator,
+                const wxString& name = wxBitmapComboBoxNameStr);
+
+    bool Create(wxWindow *parent,
+                wxWindowID id,
+                const wxString& value,
+                const wxPoint& pos,
+                const wxSize& size,
+                const wxArrayString& choices,
+                long style = 0,
+                const wxValidator& validator = wxDefaultValidator,
+                const wxString& name = wxBitmapComboBoxNameStr);
+
+    virtual ~wxBitmapComboBox();
+
+    // Adds item with image to the end of the combo box.
+    int Append(const wxString& item, const wxBitmap& bitmap = wxNullBitmap)
+        { return DoAppendWithImage(item, bitmap); }
+
+    int Append(const wxString& item, const wxBitmap& bitmap, void *clientData)
+        { int n = DoAppendWithImage(item, bitmap); SetClientData(n, clientData); return n; }
+    int Append(const wxString& item, const wxBitmap& bitmap, wxClientData *clientData)
+        { int n = DoAppendWithImage(item, bitmap); SetClientObject(n, clientData); return n; }
+
+    // Returns size of image used in list.
+    virtual wxSize GetBitmapSize() const
+    {
+        return m_usedImgSize;
+    }
+
+    // Returns the image of the item with the given index.
+    virtual wxBitmap GetItemBitmap(unsigned int n) const;
+
+    // Inserts item with image into the list before pos. Not valid for wxCB_SORT or wxCB_SORT
+    // styles, use Append instead.
+    int Insert(const wxString& item, const wxBitmap& bitmap, unsigned int pos)
+        { return DoInsertWithImage(item, bitmap, pos); }
+
+    int Insert(const wxString& item, const wxBitmap& bitmap,
+               unsigned int pos, void *clientData);
+    int Insert(const wxString& item, const wxBitmap& bitmap,
+               unsigned int pos, wxClientData *clientData);
+
+    // Sets the image for the given item.
+    virtual void SetItemBitmap(unsigned int n, const wxBitmap& bitmap);
+
+    virtual void Clear();
+    virtual void Delete(unsigned int n);
+
+protected:
+
+    virtual void OnDrawBackground(wxDC& dc, const wxRect& rect, int item, int flags) const;
+    virtual void OnDrawItem(wxDC& dc, const wxRect& rect, int item, int flags) const;
+    virtual wxCoord OnMeasureItem(size_t item) const;
+    virtual wxCoord OnMeasureItemWidth(size_t item) const;
+
+    virtual int DoAppendWithImage(const wxString& item, const wxBitmap& bitmap);
+    virtual int DoInsertWithImage(const wxString& item, const wxBitmap& bitmap,
+                                  unsigned int pos);
+
+    virtual int DoAppend(const wxString& item);
+    virtual int DoInsert(const wxString& item, unsigned int pos);
+
+    virtual bool SetFont(const wxFont& font);
+
+    virtual wxSize DoGetBestSize() const;
+
+    // Event handlers
+    void OnResize(wxSizeEvent& event);
+
+    // Recalculates amount of empty space needed in front of
+    // text in control itself.
+    void DetermineIndent();
+
+    bool OnAddBitmap(const wxBitmap& bitmap);
+
+    // Adds image to position - called in Append/Insert before
+    // string is added.
+    bool DoInsertBitmap(const wxBitmap& image, unsigned int pos);
+
+
+    wxArrayPtrVoid      m_bitmaps;  // Images associated with items
+    wxSize              m_usedImgSize;  // Size of bitmaps
+
+private:
+    int                 m_imgAreaWidth;  // Width and height of area next to text field
+    int                 m_fontHeight;
+    bool                m_inResize;
+
+    void Init();
+    void PostCreate();
+
+    DECLARE_EVENT_TABLE()
+
+    DECLARE_DYNAMIC_CLASS(wxBitmapComboBox)
+};
+
+
+#endif
+    // _WX_GENERIC_BMPCBOX_H_
diff --git a/include/wx/mac/setup0.h b/include/wx/mac/setup0.h
index 6553e78eef..5ddefa3abe 100644
--- a/include/wx/mac/setup0.h
+++ b/include/wx/mac/setup0.h
@@ -715,9 +715,17 @@
 //
 // Default is 1.
 //
-// Recommended setting: 1 but can be safely set to 0
+// Recommended setting: 1 but can be safely set to 0, except where it is
+//                      needed as a base class for generic wxBitmapComboBox.
 #define wxUSE_ODCOMBOBOX 1
 
+// wxBitmapComboBox is a combobox that can have images in front of text items.
+//
+// Default is 1.
+//
+// Recommended setting: 1 but can be safely set to 0
+#define wxUSE_BITMAPCOMBOBOX 1
+
 // ----------------------------------------------------------------------------
 // Miscellaneous GUI stuff
 // ----------------------------------------------------------------------------
diff --git a/include/wx/motif/setup0.h b/include/wx/motif/setup0.h
index 38dfe662a1..579d0b46fb 100644
--- a/include/wx/motif/setup0.h
+++ b/include/wx/motif/setup0.h
@@ -714,9 +714,17 @@
 //
 // Default is 1.
 //
-// Recommended setting: 1 but can be safely set to 0
+// Recommended setting: 1 but can be safely set to 0, except where it is
+//                      needed as a base class for generic wxBitmapComboBox.
 #define wxUSE_ODCOMBOBOX 1
 
+// wxBitmapComboBox is a combobox that can have images in front of text items.
+//
+// Default is 1.
+//
+// Recommended setting: 1 but can be safely set to 0
+#define wxUSE_BITMAPCOMBOBOX 1
+
 // ----------------------------------------------------------------------------
 // Miscellaneous GUI stuff
 // ----------------------------------------------------------------------------
diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h
index dd619890f1..210b8632b1 100644
--- a/include/wx/msw/setup0.h
+++ b/include/wx/msw/setup0.h
@@ -714,9 +714,17 @@
 //
 // Default is 1.
 //
-// Recommended setting: 1 but can be safely set to 0
+// Recommended setting: 1 but can be safely set to 0, except where it is
+//                      needed as a base class for generic wxBitmapComboBox.
 #define wxUSE_ODCOMBOBOX 1
 
+// wxBitmapComboBox is a combobox that can have images in front of text items.
+//
+// Default is 1.
+//
+// Recommended setting: 1 but can be safely set to 0
+#define wxUSE_BITMAPCOMBOBOX 1
+
 // ----------------------------------------------------------------------------
 // Miscellaneous GUI stuff
 // ----------------------------------------------------------------------------
diff --git a/include/wx/os2/setup0.h b/include/wx/os2/setup0.h
index e5bf0dcb99..ac641478d9 100644
--- a/include/wx/os2/setup0.h
+++ b/include/wx/os2/setup0.h
@@ -714,9 +714,17 @@
 //
 // Default is 1.
 //
-// Recommended setting: 1 but can be safely set to 0
+// Recommended setting: 1 but can be safely set to 0, except where it is
+//                      needed as a base class for generic wxBitmapComboBox.
 #define wxUSE_ODCOMBOBOX 1
 
+// wxBitmapComboBox is a combobox that can have images in front of text items.
+//
+// Default is 1.
+//
+// Recommended setting: 1 but can be safely set to 0
+#define wxUSE_BITMAPCOMBOBOX 1
+
 // ----------------------------------------------------------------------------
 // Miscellaneous GUI stuff
 // ----------------------------------------------------------------------------
diff --git a/include/wx/palmos/setup0.h b/include/wx/palmos/setup0.h
index cae1b9934a..819ae6e975 100644
--- a/include/wx/palmos/setup0.h
+++ b/include/wx/palmos/setup0.h
@@ -714,9 +714,17 @@
 //
 // Default is 1.
 //
-// Recommended setting: 1 but can be safely set to 0
+// Recommended setting: 1 but can be safely set to 0, except where it is
+//                      needed as a base class for generic wxBitmapComboBox.
 #define wxUSE_ODCOMBOBOX 1
 
+// wxBitmapComboBox is a combobox that can have images in front of text items.
+//
+// Default is 1.
+//
+// Recommended setting: 1 but can be safely set to 0
+#define wxUSE_BITMAPCOMBOBOX 1
+
 // ----------------------------------------------------------------------------
 // Miscellaneous GUI stuff
 // ----------------------------------------------------------------------------
diff --git a/include/wx/setup_inc.h b/include/wx/setup_inc.h
index 924ff071f2..c66943f8ae 100644
--- a/include/wx/setup_inc.h
+++ b/include/wx/setup_inc.h
@@ -710,9 +710,17 @@
 //
 // Default is 1.
 //
-// Recommended setting: 1 but can be safely set to 0
+// Recommended setting: 1 but can be safely set to 0, except where it is
+//                      needed as a base class for generic wxBitmapComboBox.
 #define wxUSE_ODCOMBOBOX 1
 
+// wxBitmapComboBox is a combobox that can have images in front of text items.
+//
+// Default is 1.
+//
+// Recommended setting: 1 but can be safely set to 0
+#define wxUSE_BITMAPCOMBOBOX 1
+
 // ----------------------------------------------------------------------------
 // Miscellaneous GUI stuff
 // ----------------------------------------------------------------------------
diff --git a/include/wx/univ/setup0.h b/include/wx/univ/setup0.h
index c49eda2228..6694c86291 100644
--- a/include/wx/univ/setup0.h
+++ b/include/wx/univ/setup0.h
@@ -727,9 +727,17 @@
 //
 // Default is 1.
 //
-// Recommended setting: 1 but can be safely set to 0
+// Recommended setting: 1 but can be safely set to 0, except where it is
+//                      needed as a base class for generic wxBitmapComboBox.
 #define wxUSE_ODCOMBOBOX 1
 
+// wxBitmapComboBox a combobox that can have images in front of text items.
+//
+// Default is 1.
+//
+// Recommended setting: 1 but can be safely set to 0
+#define wxUSE_BITMAPCOMBOBOX 1
+
 // ----------------------------------------------------------------------------
 // Miscellaneous GUI stuff
 // ----------------------------------------------------------------------------
diff --git a/include/wx/xrc/xh_all.h b/include/wx/xrc/xh_all.h
index c7ef079507..4e4922ef20 100644
--- a/include/wx/xrc/xh_all.h
+++ b/include/wx/xrc/xh_all.h
@@ -63,5 +63,6 @@
 #include "wx/xrc/xh_fontpicker.h"
 #include "wx/xrc/xh_dirpicker.h"
 #include "wx/xrc/xh_hyperlink.h"
+#include "wx/xrc/xh_bmpcbox.h"
 
 #endif // _WX_XH_ALL_H_
diff --git a/include/wx/xrc/xh_bmpcbox.h b/include/wx/xrc/xh_bmpcbox.h
new file mode 100644
index 0000000000..4772ac5937
--- /dev/null
+++ b/include/wx/xrc/xh_bmpcbox.h
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        wx/xrc/xh_bmpcbox.h
+// Purpose:     XML resource handler for wxBitmapComboBox
+// Author:      Jaakko Salli
+// Created:     Sep-10-2006
+// RCS-ID:      $Id:
+// Copyright:   (c) 2006 Jaakko Salli
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_XH_BMPCBOX_H_
+#define _WX_XH_BMPCBOX_H_
+
+#include "wx/xrc/xmlres.h"
+
+#if wxUSE_BITMAPCOMBOBOX
+
+class WXDLLIMPEXP_ADV wxBitmapComboBox;
+
+class WXDLLIMPEXP_XRC wxBitmapComboBoxXmlHandler : public wxXmlResourceHandler
+{
+    DECLARE_DYNAMIC_CLASS(wxBitmapComboBoxXmlHandler)
+public:
+    wxBitmapComboBoxXmlHandler();
+    virtual wxObject *DoCreateResource();
+    virtual bool CanHandle(wxXmlNode *node);
+private:
+    wxBitmapComboBox*    m_combobox;
+    bool                m_isInside;
+};
+
+#endif
+
+#endif // _WX_XH_BMPCBOX_H_
diff --git a/samples/widgets/bmpcombobox.cpp b/samples/widgets/bmpcombobox.cpp
new file mode 100644
index 0000000000..ca61907a5c
--- /dev/null
+++ b/samples/widgets/bmpcombobox.cpp
@@ -0,0 +1,876 @@
+/////////////////////////////////////////////////////////////////////////////
+// Program:     wxWidgets Widgets Sample
+// Name:        bmpcombobox.cpp
+// Purpose:     Part of the widgets sample showing wxBitmapComboBox
+// Author:      Jaakko Salli
+// Created:     Sep-01-2006
+// Id:          $Id:
+// Copyright:   (c) 2006 Jaakko Salli
+// License:     wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+// for compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_BITMAPCOMBOBOX
+
+// for all others, include the necessary headers
+#ifndef WX_PRECOMP
+    #include "wx/log.h"
+
+    #include "wx/bitmap.h"
+    #include "wx/button.h"
+    #include "wx/checkbox.h"
+    #include "wx/combobox.h"
+    #include "wx/radiobox.h"
+    #include "wx/statbox.h"
+    #include "wx/textctrl.h"
+    #include "wx/filedlg.h"
+#endif
+
+#include "wx/stattext.h"
+#include "wx/dc.h"
+#include "wx/dcmemory.h"
+#include "wx/sizer.h"
+#include "wx/icon.h"
+#include "wx/dir.h"
+#include "wx/filename.h"
+#include "wx/image.h"
+#include "wx/imaglist.h"
+#include "wx/bmpcbox.h"
+
+
+#include "widgets.h"
+
+#include "icons/odcombobox.xpm"
+
+// Images loaded from file are reduced this width and height, if larger
+#define IMG_SIZE_TRUNC  150
+
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// control ids
+enum
+{
+    BitmapComboBoxPage_Reset = wxID_HIGHEST,
+    BitmapComboBoxPage_Insert,
+    BitmapComboBoxPage_InsertText,
+    BitmapComboBoxPage_ChangeHeight,
+    BitmapComboBoxPage_LoadFromFile,
+    BitmapComboBoxPage_SetFromFile,
+    BitmapComboBoxPage_AddWidgetIcons,
+    BitmapComboBoxPage_AddSeveralWithImages,
+    BitmapComboBoxPage_AddSeveral,
+    BitmapComboBoxPage_AddMany,
+    BitmapComboBoxPage_Clear,
+    BitmapComboBoxPage_Change,
+    BitmapComboBoxPage_Delete,
+    BitmapComboBoxPage_DeleteText,
+    BitmapComboBoxPage_DeleteSel,
+    BitmapComboBoxPage_Combo
+};
+
+
+// ----------------------------------------------------------------------------
+// BitmapComboBoxWidgetsPage
+// ----------------------------------------------------------------------------
+
+class BitmapComboBoxWidgetsPage : public WidgetsPage
+{
+public:
+    BitmapComboBoxWidgetsPage(WidgetsBookCtrl *book, wxImageList *imaglist);
+
+    virtual wxControl *GetWidget() const { return m_combobox; }
+    virtual void RecreateWidget() { CreateCombo(); }
+
+    // lazy creation of the content
+    virtual void CreateContent();
+
+protected:
+    // event handlers
+    void OnButtonReset(wxCommandEvent& event);
+    void OnButtonChange(wxCommandEvent& event);
+    void OnButtonDelete(wxCommandEvent& event);
+    void OnButtonDeleteSel(wxCommandEvent& event);
+    void OnButtonClear(wxCommandEvent& event);
+    void OnButtonInsert(wxCommandEvent &event);
+    void OnTextChangeHeight(wxCommandEvent& event);
+    void OnButtonLoadFromFile(wxCommandEvent& event);
+    void OnButtonSetFromFile(wxCommandEvent& event);
+    void OnButtonAddSeveral(wxCommandEvent& event);
+    void OnButtonAddSeveralWithImages(wxCommandEvent& event);
+    void OnButtonAddWidgetIcons(wxCommandEvent& event);
+    void OnButtonAddMany(wxCommandEvent& event);
+
+    void OnComboBox(wxCommandEvent& event);
+    void OnComboText(wxCommandEvent& event);
+
+    void OnCheckOrRadioBox(wxCommandEvent& event);
+
+    void OnTextPopupWidth(wxCommandEvent& event);
+    void OnTextPopupHeight(wxCommandEvent& event);
+    void OnTextButtonAll(wxCommandEvent& event);
+
+    void OnUpdateUIInsert(wxUpdateUIEvent& event);
+    void OnUpdateUIAddSeveral(wxUpdateUIEvent& event);
+    void OnUpdateUIAddSeveralWithImages(wxUpdateUIEvent& event);
+    void OnUpdateUIClearButton(wxUpdateUIEvent& event);
+    void OnUpdateUIDeleteButton(wxUpdateUIEvent& event);
+    void OnUpdateUIDeleteSelButton(wxUpdateUIEvent& event);
+    void OnUpdateUIResetButton(wxUpdateUIEvent& event);
+
+    // reset the bmpcombobox parameters
+    void Reset();
+
+    // (re)create the bmpcombobox
+    void CreateCombo();
+
+    // helpers for creating bitmaps
+    wxBitmap CreateBitmap(const wxColour& colour);
+    wxBitmap CreateRandomBitmap(wxString* pStr);
+    wxBitmap LoadBitmap(const wxString& filepath);
+    wxBitmap QueryBitmap(wxString* pStr);
+
+    void LoadWidgetImages( wxArrayString* strings, wxImageList* images );
+
+    wxSizer *CreateSizerWithSmallTextAndLabel(const wxString& label,
+                                              wxWindowID id,
+                                              wxTextCtrl **ppText);
+
+    // the controls
+    // ------------
+
+    // the checkboxes for styles
+    wxCheckBox *m_chkSort,
+               *m_chkReadonly,
+               *m_chkScaleimages;
+
+    // the combobox itself and the sizer it is in
+    wxBitmapComboBox *m_combobox;
+    wxSizer *m_sizerCombo;
+
+    // the text entries for "Add/change string" and "Delete" buttons
+    wxTextCtrl *m_textInsert,
+               *m_textChangeHeight,
+               *m_textChange,
+               *m_textDelete;
+
+private:
+    DECLARE_EVENT_TABLE()
+    DECLARE_WIDGETS_PAGE(BitmapComboBoxWidgetsPage)
+};
+
+// ----------------------------------------------------------------------------
+// event tables
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(BitmapComboBoxWidgetsPage, WidgetsPage)
+    EVT_BUTTON(BitmapComboBoxPage_Reset, BitmapComboBoxWidgetsPage::OnButtonReset)
+    EVT_BUTTON(BitmapComboBoxPage_Change, BitmapComboBoxWidgetsPage::OnButtonChange)
+    EVT_BUTTON(BitmapComboBoxPage_Delete, BitmapComboBoxWidgetsPage::OnButtonDelete)
+    EVT_BUTTON(BitmapComboBoxPage_DeleteSel, BitmapComboBoxWidgetsPage::OnButtonDeleteSel)
+    EVT_BUTTON(BitmapComboBoxPage_Clear, BitmapComboBoxWidgetsPage::OnButtonClear)
+    EVT_BUTTON(BitmapComboBoxPage_Insert, BitmapComboBoxWidgetsPage::OnButtonInsert)
+    EVT_BUTTON(BitmapComboBoxPage_AddSeveral, BitmapComboBoxWidgetsPage::OnButtonAddSeveral)
+    EVT_BUTTON(BitmapComboBoxPage_AddSeveralWithImages, BitmapComboBoxWidgetsPage::OnButtonAddSeveralWithImages)
+    EVT_BUTTON(BitmapComboBoxPage_AddWidgetIcons, BitmapComboBoxWidgetsPage::OnButtonAddWidgetIcons)
+    EVT_BUTTON(BitmapComboBoxPage_AddMany, BitmapComboBoxWidgetsPage::OnButtonAddMany)
+    EVT_BUTTON(BitmapComboBoxPage_LoadFromFile, BitmapComboBoxWidgetsPage::OnButtonLoadFromFile)
+    EVT_BUTTON(BitmapComboBoxPage_SetFromFile, BitmapComboBoxWidgetsPage::OnButtonSetFromFile)
+
+    EVT_TEXT_ENTER(BitmapComboBoxPage_InsertText, BitmapComboBoxWidgetsPage::OnButtonInsert)
+    EVT_TEXT(BitmapComboBoxPage_ChangeHeight, BitmapComboBoxWidgetsPage::OnTextChangeHeight)
+    EVT_TEXT_ENTER(BitmapComboBoxPage_DeleteText, BitmapComboBoxWidgetsPage::OnButtonDelete)
+
+    EVT_UPDATE_UI(BitmapComboBoxPage_Reset, BitmapComboBoxWidgetsPage::OnUpdateUIResetButton)
+    EVT_UPDATE_UI(BitmapComboBoxPage_Insert, BitmapComboBoxWidgetsPage::OnUpdateUIInsert)
+    EVT_UPDATE_UI(BitmapComboBoxPage_LoadFromFile, BitmapComboBoxWidgetsPage::OnUpdateUIInsert)
+    EVT_UPDATE_UI(BitmapComboBoxPage_AddSeveral, BitmapComboBoxWidgetsPage::OnUpdateUIAddSeveral)
+    EVT_UPDATE_UI(BitmapComboBoxPage_AddSeveralWithImages, BitmapComboBoxWidgetsPage::OnUpdateUIAddSeveralWithImages)
+    EVT_UPDATE_UI(BitmapComboBoxPage_Clear, BitmapComboBoxWidgetsPage::OnUpdateUIClearButton)
+    EVT_UPDATE_UI(BitmapComboBoxPage_DeleteText, BitmapComboBoxWidgetsPage::OnUpdateUIClearButton)
+    EVT_UPDATE_UI(BitmapComboBoxPage_Delete, BitmapComboBoxWidgetsPage::OnUpdateUIDeleteButton)
+    EVT_UPDATE_UI(BitmapComboBoxPage_Change, BitmapComboBoxWidgetsPage::OnUpdateUIDeleteSelButton)
+    EVT_UPDATE_UI(BitmapComboBoxPage_DeleteSel, BitmapComboBoxWidgetsPage::OnUpdateUIDeleteSelButton)
+
+    EVT_COMBOBOX(BitmapComboBoxPage_Combo, BitmapComboBoxWidgetsPage::OnComboBox)
+    EVT_TEXT(BitmapComboBoxPage_Combo, BitmapComboBoxWidgetsPage::OnComboText)
+    EVT_TEXT_ENTER(BitmapComboBoxPage_Combo, BitmapComboBoxWidgetsPage::OnComboText)
+
+    EVT_CHECKBOX(wxID_ANY, BitmapComboBoxWidgetsPage::OnCheckOrRadioBox)
+    EVT_RADIOBOX(wxID_ANY, BitmapComboBoxWidgetsPage::OnCheckOrRadioBox)
+END_EVENT_TABLE()
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+
+
+IMPLEMENT_WIDGETS_PAGE(BitmapComboBoxWidgetsPage, _T("BitmapCombobox"),
+                       GENERIC_CTRLS | WITH_ITEMS_CTRLS | COMBO_CTRLS
+                       );
+
+
+BitmapComboBoxWidgetsPage::BitmapComboBoxWidgetsPage(WidgetsBookCtrl *book,
+                                             wxImageList *imaglist)
+                  : WidgetsPage(book, imaglist, odcombobox_xpm)
+{
+    // init everything
+    m_chkSort =
+    m_chkReadonly =
+    m_chkScaleimages = (wxCheckBox *)NULL;
+
+    m_combobox = (wxBitmapComboBox *)NULL;
+    m_sizerCombo = (wxSizer *)NULL;
+}
+
+// create a sizer containing a label and a small text ctrl
+wxSizer *BitmapComboBoxWidgetsPage::CreateSizerWithSmallTextAndLabel(const wxString& label,
+                                                                    wxWindowID id,
+                                                                    wxTextCtrl **ppText)
+{
+    wxControl* control = new wxStaticText(this, wxID_ANY, label);
+    wxSizer *sizerRow = new wxBoxSizer(wxHORIZONTAL);
+    wxTextCtrl *text = new wxTextCtrl(this, id, wxEmptyString,
+        wxDefaultPosition, wxSize(50,-1), wxTE_PROCESS_ENTER);
+
+    sizerRow->Add(control, 0, wxRIGHT | wxALIGN_CENTRE_VERTICAL, 5);
+    sizerRow->Add(text, 1, wxFIXED_MINSIZE | wxLEFT | wxALIGN_CENTRE_VERTICAL, 5);
+
+    if ( ppText )
+        *ppText = text;
+
+    return sizerRow;
+}
+
+void BitmapComboBoxWidgetsPage::CreateContent()
+{
+    /*
+       What we create here is a frame having 3 panes: style pane is the
+       leftmost one, in the middle the pane with buttons allowing to perform
+       miscellaneous combobox operations and the pane containing the combobox
+       itself to the right
+    */
+    //wxTextCtrl *text;
+    wxSizer *sizerRow;
+
+    wxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);
+
+    wxSizer *sizerLeft = new wxBoxSizer(wxVERTICAL);
+
+    // left pane - style box
+    wxStaticBox *box = new wxStaticBox(this, wxID_ANY, _T("&Set style"));
+
+    wxSizer *sizerStyle = new wxStaticBoxSizer(box, wxVERTICAL);
+
+    m_chkSort = CreateCheckBoxAndAddToSizer(sizerStyle, _T("&Sort items"));
+    m_chkReadonly = CreateCheckBoxAndAddToSizer(sizerStyle, _T("&Read only"));
+
+    wxButton *btn = new wxButton(this, BitmapComboBoxPage_Reset, _T("&Reset"));
+    sizerStyle->Add(btn, 0, wxALIGN_CENTRE_HORIZONTAL | wxALL, 3);
+
+    sizerLeft->Add(sizerStyle, 0, wxGROW | wxALIGN_CENTRE_HORIZONTAL);
+
+    // left pane - other options box
+    box = new wxStaticBox(this, wxID_ANY, _T("Demo options"));
+
+    wxSizer *sizerOptions = new wxStaticBoxSizer(box, wxVERTICAL);
+
+    m_chkScaleimages = CreateCheckBoxAndAddToSizer(sizerOptions, _T("&Scale loaded images to fit"));
+
+    sizerRow = CreateSizerWithSmallTextAndLabel(_T("Control &height:"),
+                                                BitmapComboBoxPage_ChangeHeight,
+                                                &m_textChangeHeight);
+    m_textChangeHeight->SetSize(20, -1);
+    sizerOptions->Add(sizerRow, 0, wxALL | wxFIXED_MINSIZE /*| wxGROW*/, 5);
+
+    sizerLeft->Add(sizerOptions, 0, wxGROW | wxALIGN_CENTRE_HORIZONTAL | wxTOP, 2);
+
+    // middle pane
+    wxStaticBox *box2 = new wxStaticBox(this, wxID_ANY,
+        _T("&Change wxBitmapComboBox contents"));
+    wxSizer *sizerMiddle = new wxStaticBoxSizer(box2, wxVERTICAL);
+
+#if wxUSE_IMAGE
+    btn = new wxButton(this, BitmapComboBoxPage_AddWidgetIcons, _T("Add &widget icons"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, BitmapComboBoxPage_LoadFromFile, _T("Insert image from &file"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, BitmapComboBoxPage_SetFromFile, _T("&Set image from file"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+#endif
+
+    btn = new wxButton(this, BitmapComboBoxPage_AddSeveralWithImages, _T("A&ppend a few strings with images"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, BitmapComboBoxPage_AddSeveral, _T("Append a &few strings"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, BitmapComboBoxPage_AddMany, _T("Append &many strings"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    sizerRow = CreateSizerWithTextAndButton(BitmapComboBoxPage_Delete,
+                                            _T("&Delete this item"),
+                                            BitmapComboBoxPage_DeleteText,
+                                            &m_textDelete);
+    sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, BitmapComboBoxPage_DeleteSel, _T("Delete &selection"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+    btn = new wxButton(this, BitmapComboBoxPage_Clear, _T("&Clear"));
+    sizerMiddle->Add(btn, 0, wxALL | wxGROW, 5);
+
+#if wxUSE_IMAGE
+    wxInitAllImageHandlers();
+#endif
+
+    // right pane
+    wxSizer *sizerRight = new wxBoxSizer(wxVERTICAL);
+    m_combobox = new wxBitmapComboBox();
+    m_combobox->Create(this, BitmapComboBoxPage_Combo, wxEmptyString,
+                       wxDefaultPosition, wxDefaultSize,
+                       0, NULL,
+                       wxCB_READONLY);
+
+#if defined(wxGENERIC_BITMAPCOMBOBOX)
+    // This will sure make the list look nicer when larger images are used.
+    m_combobox->SetPopupMaxHeight(600);
+#endif
+
+    sizerRight->Add(m_combobox, 0, wxGROW | wxALL, 5);
+    sizerRight->SetMinSize(150, 0);
+    m_sizerCombo = sizerRight; // save it to modify it later
+
+    // the 3 panes panes compose the window
+    sizerTop->Add(sizerLeft, 0, wxGROW | (wxALL & ~wxLEFT), 10);
+    sizerTop->Add(sizerMiddle, 5, wxGROW | wxALL, 10);
+    sizerTop->Add(sizerRight, 4, wxGROW | (wxALL & ~wxRIGHT), 10);
+
+    // final initializations
+    Reset();
+
+    SetSizer(sizerTop);
+
+    sizerTop->Fit(this);
+}
+
+// ----------------------------------------------------------------------------
+// operations
+// ----------------------------------------------------------------------------
+
+void BitmapComboBoxWidgetsPage::Reset()
+{
+    m_chkSort->SetValue(false);
+    m_chkReadonly->SetValue(true);
+    m_chkScaleimages->SetValue(true);
+}
+
+void BitmapComboBoxWidgetsPage::CreateCombo()
+{
+    int flags = ms_defaultFlags;
+
+    if ( m_chkSort->GetValue() )
+        flags |= wxCB_SORT;
+    if ( m_chkReadonly->GetValue() )
+        flags |= wxCB_READONLY;
+
+    wxArrayString items;
+    wxArrayPtrVoid bitmaps;
+    if ( m_combobox )
+    {
+        unsigned int count = m_combobox->GetCount();
+        for ( unsigned int n = 0; n < count; n++ )
+        {
+            items.Add(m_combobox->GetString(n));
+            bitmaps.Add(new wxBitmap(m_combobox->GetItemBitmap(n)));
+        }
+
+        m_sizerCombo->Detach( m_combobox );
+        delete m_combobox;
+    }
+
+    m_combobox = new wxBitmapComboBox();
+    m_combobox->Create(this, BitmapComboBoxPage_Combo, wxEmptyString,
+                       wxDefaultPosition, wxDefaultSize,
+                       0, NULL,
+                       flags);
+
+#if defined(wxGENERIC_BITMAPCOMBOBOX)
+    // This will sure make the list look nicer when larger images are used.
+    m_combobox->SetPopupMaxHeight(600);
+#endif
+
+    unsigned int count = items.GetCount();
+    for ( unsigned int n = 0; n < count; n++ )
+    {
+        wxBitmap* bmp = (wxBitmap*) bitmaps[n];
+        m_combobox->Append(items[n], *bmp);
+        delete bmp;
+    }
+
+    m_sizerCombo->Add(m_combobox, 0, wxGROW | wxALL, 5);
+    m_sizerCombo->Layout();
+
+    // Allow changing height inorder to demonstrate flexible
+    // size of image "thumbnail" painted in the control itself.
+    long h = 0;
+    m_textChangeHeight->GetValue().ToLong(&h);
+    if ( h >= 5 )
+        m_combobox->SetSize(-1, h);
+}
+
+// ----------------------------------------------------------------------------
+// event handlers
+// ----------------------------------------------------------------------------
+
+void BitmapComboBoxWidgetsPage::OnButtonReset(wxCommandEvent& WXUNUSED(event))
+{
+    Reset();
+
+    CreateCombo();
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonChange(wxCommandEvent& WXUNUSED(event))
+{
+    int sel = m_combobox->GetSelection();
+    if ( sel != wxNOT_FOUND )
+    {
+#ifndef __WXGTK__
+        m_combobox->SetString(sel, m_textChange->GetValue());
+#else
+        wxLogMessage(_T("Not implemented in wxGTK"));
+#endif
+    }
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonDelete(wxCommandEvent& WXUNUSED(event))
+{
+    unsigned long n;
+    if ( !m_textDelete->GetValue().ToULong(&n) ||
+            (n >= m_combobox->GetCount()) )
+    {
+        return;
+    }
+
+    m_combobox->Delete(n);
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonDeleteSel(wxCommandEvent& WXUNUSED(event))
+{
+    int sel = m_combobox->GetSelection();
+    if ( sel != wxNOT_FOUND )
+    {
+        m_combobox->Delete(sel);
+    }
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonClear(wxCommandEvent& WXUNUSED(event))
+{
+    m_combobox->Clear();
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonInsert(wxCommandEvent& WXUNUSED(event))
+{
+    static unsigned int s_item = 0;
+
+    wxString s = m_textInsert->GetValue();
+    if ( !m_textInsert->IsModified() )
+    {
+        // update the default string
+        m_textInsert->SetValue(wxString::Format(_T("test item %u"), ++s_item));
+    }
+
+    if (m_combobox->GetSelection() >= 0)
+        m_combobox->Insert(s, wxNullBitmap, m_combobox->GetSelection());
+}
+
+void BitmapComboBoxWidgetsPage::OnTextChangeHeight(wxCommandEvent& WXUNUSED(event))
+{
+    long h = 0;
+    m_textChangeHeight->GetValue().ToLong(&h);
+    if ( h < 5 )
+        return;
+    m_combobox->SetSize(-1, h);
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonLoadFromFile(wxCommandEvent& WXUNUSED(event))
+{
+    wxString s;
+    m_combobox->Insert(s, QueryBitmap(&s), m_combobox->GetSelection());
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonSetFromFile(wxCommandEvent& WXUNUSED(event))
+{
+    m_combobox->SetItemBitmap(m_combobox->GetSelection(), QueryBitmap(NULL));
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonAddMany(wxCommandEvent& WXUNUSED(event))
+{
+    // "many" means 1000 here
+    for ( unsigned int n = 0; n < 1000; n++ )
+    {
+        m_combobox->Append(wxString::Format(_T("item #%u"), n));
+    }
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonAddSeveral(wxCommandEvent& WXUNUSED(event))
+{
+    m_combobox->Append(_T("First"));
+    m_combobox->Append(_T("another one"));
+    m_combobox->Append(_T("and the last (very very very very very very very very very very long) one"));
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonAddSeveralWithImages(wxCommandEvent& WXUNUSED(event))
+{
+    int i;
+
+    for ( i=0; i<4; i++ )
+    {
+        wxString s;
+        wxBitmap bmp = CreateRandomBitmap(&s);
+        m_combobox->Append(s, bmp);
+    }
+}
+
+void BitmapComboBoxWidgetsPage::LoadWidgetImages( wxArrayString* strings, wxImageList* images )
+{
+    wxFileName fn;
+    fn.AssignCwd();
+    fn.AppendDir(wxT("icons"));
+    
+    wxSetCursor(*wxHOURGLASS_CURSOR);
+
+    if ( !wxDir::Exists(fn.GetFullPath()) ||
+         !wxDir::GetAllFiles(fn.GetFullPath(),strings,wxT("*.xpm")) )
+    {
+        fn.RemoveLastDir();
+        fn.RemoveLastDir();
+        fn.AppendDir(wxT("icons"));
+        if ( !wxDir::Exists(fn.GetFullPath()) ||
+             !wxDir::GetAllFiles(fn.GetFullPath(),strings,wxT("*.xpm")) )
+        {
+            // Try ../../../samples/widgets/icons
+            fn.AssignCwd();
+            fn.RemoveLastDir();
+            fn.RemoveLastDir();
+            fn.RemoveLastDir();
+            fn.AppendDir(wxT("samples"));
+            fn.AppendDir(wxT("widgets"));
+            fn.AppendDir(wxT("icons"));
+            if ( !wxDir::Exists(fn.GetFullPath()) ||
+                 !wxDir::GetAllFiles(fn.GetFullPath(),strings,wxT("*.xpm")) )
+            {
+                wxLogWarning(wxT("Could not load widget icons."));
+                wxSetCursor(*wxSTANDARD_CURSOR);
+                return;
+            }
+        }
+    }
+
+    unsigned int i;
+
+    // Get size of existing images in list
+    wxSize foundSize = m_combobox->GetBitmapSize();
+
+    for ( i=0; i<strings->size(); i++ )
+    {
+        fn.SetFullName((*strings)[i]);
+        wxString name =fn.GetName();
+
+        // Handle few exceptions
+        if ( name == wxT("bmpbtn") )
+        {
+            strings->RemoveAt(i);
+            i--;
+        }
+        else
+        {
+#if wxUSE_IMAGE
+            wxASSERT(fn.FileExists());
+            wxImage image(fn.GetFullPath());
+            wxASSERT(image.Ok());
+            if ( m_chkScaleimages->GetValue() && foundSize.x > 0 )
+                image.Rescale(foundSize.x, foundSize.y);
+            wxBitmap bmp(image);
+            wxASSERT( bmp.Ok() );
+#else
+            wxBitmap bmp(wxNullBitmap);
+#endif
+            images->Add(bmp);
+            (*strings)[i] = name;
+        }
+    }
+
+    wxSetCursor(*wxSTANDARD_CURSOR);
+}
+
+void BitmapComboBoxWidgetsPage::OnButtonAddWidgetIcons(wxCommandEvent& WXUNUSED(event))
+{
+    wxArrayString strings;
+
+    int sz = 32;
+    //if ( m_chkScaleimages->GetValue() )
+    //    sz = 16;
+
+    wxImageList images(sz, sz);
+
+    LoadWidgetImages(&strings, &images);
+
+    unsigned int i;
+
+    for ( i=0; i<strings.size(); i++ )
+    {
+        m_combobox->Append(strings[i], images.GetBitmap(i));
+    }
+}
+
+void BitmapComboBoxWidgetsPage::OnUpdateUIResetButton(wxUpdateUIEvent& event)
+{
+    if (m_combobox)
+        event.Enable( m_chkSort->GetValue() || m_chkReadonly->GetValue() );
+}
+
+void BitmapComboBoxWidgetsPage::OnUpdateUIInsert(wxUpdateUIEvent& event)
+{
+    if (m_combobox)
+    {
+        bool enable = !(m_combobox->GetWindowStyle() & wxCB_SORT);
+
+        event.Enable(enable);
+    }
+}
+
+void BitmapComboBoxWidgetsPage::OnUpdateUIDeleteButton(wxUpdateUIEvent& event)
+{
+    if (m_combobox)
+    {
+      unsigned long n;
+      event.Enable(m_textDelete->GetValue().ToULong(&n) &&
+        (n < (unsigned)m_combobox->GetCount()));
+    }
+}
+
+void BitmapComboBoxWidgetsPage::OnUpdateUIDeleteSelButton(wxUpdateUIEvent& event)
+{
+    if (m_combobox)
+        event.Enable(m_combobox->GetSelection() != wxNOT_FOUND);
+}
+
+void BitmapComboBoxWidgetsPage::OnUpdateUIClearButton(wxUpdateUIEvent& event)
+{
+    if (m_combobox)
+        event.Enable(m_combobox->GetCount() != 0);
+}
+
+void BitmapComboBoxWidgetsPage::OnUpdateUIAddSeveral(wxUpdateUIEvent& event)
+{
+    if (m_combobox)
+        event.Enable(!(m_combobox->GetWindowStyle() & wxCB_SORT));
+}
+
+void BitmapComboBoxWidgetsPage::OnUpdateUIAddSeveralWithImages(wxUpdateUIEvent& event)
+{
+    if (m_combobox)
+        event.Enable(!(m_combobox->GetWindowStyle() & wxCB_SORT));
+}
+
+void BitmapComboBoxWidgetsPage::OnComboText(wxCommandEvent& event)
+{
+    if (!m_combobox)
+        return;
+
+    wxString s = event.GetString();
+
+    wxASSERT_MSG( s == m_combobox->GetValue(),
+                  _T("event and combobox values should be the same") );
+
+    if (event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER)
+        wxLogMessage(_T("BitmapCombobox enter pressed (now '%s')"), s.c_str());
+    else
+        wxLogMessage(_T("BitmapCombobox text changed (now '%s')"), s.c_str());
+}
+
+void BitmapComboBoxWidgetsPage::OnComboBox(wxCommandEvent& event)
+{
+    long sel = event.GetInt();
+    m_textDelete->SetValue(wxString::Format(_T("%ld"), sel));
+
+    wxLogMessage(_T("BitmapCombobox item %ld selected"), sel);
+
+    wxLogMessage(_T("BitmapCombobox GetValue(): %s"), m_combobox->GetValue().c_str() );
+}
+
+void BitmapComboBoxWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& WXUNUSED(event))
+{
+    CreateCombo();
+}
+
+#if wxUSE_IMAGE
+wxBitmap BitmapComboBoxWidgetsPage::LoadBitmap(const wxString& filepath)
+{
+    // Get size of existing images in list
+    wxSize foundSize = m_combobox->GetBitmapSize();
+
+    wxImage image(filepath);
+    if ( image.Ok() )
+    {
+        // Rescale very large images
+        int ow = image.GetWidth();
+        int oh = image.GetHeight();
+
+        if ( foundSize.x > 0 &&
+             (ow != foundSize.x || oh != foundSize.y) )
+        {
+            int w = ow;
+            if ( w > foundSize.x )
+                w = foundSize.x;
+            int h = oh;
+            if ( h > foundSize.y )
+                h = foundSize.y;
+
+            image.Rescale(w, h);
+        }
+
+        return wxBitmap(image);
+    }
+
+    return wxNullBitmap;
+}
+#else
+wxBitmap BitmapComboBoxWidgetsPage::LoadBitmap(const wxString& WXUNUSED(filepath))
+{
+    return wxNullBitmap;
+}
+#endif
+
+wxBitmap BitmapComboBoxWidgetsPage::QueryBitmap(wxString* pStr)
+{
+    wxString filepath = wxFileSelector(wxT("Choose image file"),
+                                       wxT(""),
+                                       wxT(""),
+                                       wxT(""),
+                                       wxT("*.*"),
+                                       wxOPEN | wxFILE_MUST_EXIST,
+                                       this);
+
+    wxBitmap bitmap;
+
+    ::wxSetCursor( *wxHOURGLASS_CURSOR );
+
+    if ( filepath.length() )
+    {
+        if ( pStr )
+        {
+            *pStr = wxFileName(filepath).GetName();
+        }
+
+        bitmap = LoadBitmap(filepath);
+    }
+
+    ::wxSetCursor( *wxSTANDARD_CURSOR );
+
+    return bitmap;
+}
+
+wxBitmap BitmapComboBoxWidgetsPage::CreateBitmap(const wxColour& colour)
+{
+    int ch = m_combobox->GetBitmapSize().y;
+    int h0 = ch - 5;
+
+    long w = ch;
+    long h = ch;
+
+    if ( w <= 0 )
+        w = h0 - 1;
+    if ( h <= 0 )
+        h = h0;
+    if ( h > ch )
+        h = ch;
+
+    wxMemoryDC dc;
+    wxBitmap bmp(w,h);
+    dc.SelectObject(bmp);
+
+    // Draw transparent background
+    wxColour magic(255,0,255);
+    wxBrush magicBrush(magic);
+    dc.SetBrush(magicBrush);
+    dc.SetPen(*wxTRANSPARENT_PEN);
+    dc.DrawRectangle(0,0,bmp.GetWidth(),bmp.GetHeight());
+
+    // Draw image content
+    dc.SetBrush(wxBrush(colour));
+    dc.DrawCircle(h/2,h/2+1,(h/2));
+
+    dc.SelectObject(wxNullBitmap);
+
+    // Finalize transparency with a mask
+    wxMask *mask = new wxMask(bmp, magic);
+    bmp.SetMask(mask);
+
+    return bmp;
+}
+
+wxBitmap BitmapComboBoxWidgetsPage::CreateRandomBitmap( wxString* pStr )
+{
+    int i = rand() % 6;
+    const wxChar* str = wxT("");
+    wxBitmap bmp;
+
+    if ( i == 0 )
+    {
+        str = wxT("Red Circle");
+        bmp = CreateBitmap( *wxRED );
+    }
+    else if ( i == 1 )
+    {
+        str = wxT("Green Circle");
+        bmp = CreateBitmap( *wxGREEN );
+    }
+    else if ( i == 2 )
+    {
+        str = wxT("Blue Circle");
+        bmp = CreateBitmap( *wxBLUE );
+    }
+    else if ( i == 3 )
+    {
+        str = wxT("Black Circle");
+        bmp = CreateBitmap( *wxBLACK );
+    }
+    else if ( i == 4 )
+    {
+        str = wxT("Cyan Circle");
+        bmp = CreateBitmap( *wxCYAN );
+    }
+    else if ( i == 5 )
+    {
+        str = wxT("Light Grey Circle");
+        bmp = CreateBitmap( *wxLIGHT_GREY );
+    }
+
+    if ( pStr )
+        *pStr = str;
+
+    return bmp;
+}
+
+#endif //wxUSE_BITMAPCOMBOBOX
diff --git a/samples/widgets/widgets.bkl b/samples/widgets/widgets.bkl
index 6a539c09c2..28dd7f8812 100644
--- a/samples/widgets/widgets.bkl
+++ b/samples/widgets/widgets.bkl
@@ -5,6 +5,7 @@
 
     <exe id="widgets" template="wx_sample" template_append="wx_append">
         <sources>
+            bmpcombobox.cpp
             button.cpp
             checkbox.cpp
             combobox.cpp
diff --git a/samples/xrc/rc/controls.xrc b/samples/xrc/rc/controls.xrc
index 2a92ca1362..f1b5a3f559 100644
--- a/samples/xrc/rc/controls.xrc
+++ b/samples/xrc/rc/controls.xrc
@@ -406,6 +406,31 @@
                                     </content>
                                 </object>
                             </object>
+                            <object class="sizeritem">
+                                <flag>wxALIGN_TOP|wxALIGN_CENTRE_HORIZONTAL|wxALL</flag>
+                                <border>5</border>
+                                <object class="wxBitmapComboBox">
+                                    <size>200,-1</size>
+                                    <style>wxCB_READONLY</style>
+                                    <selection>2</selection>
+                                    <object class="ownerdrawnitem">
+										<text>This is a</text>
+										<bitmap>basicdlg.xpm</bitmap>
+									 </object>
+                                    <object class="ownerdrawnitem">
+										<text>read-only</text>
+										<bitmap>derivdlg.xpm</bitmap>
+									 </object>
+                                    <object class="ownerdrawnitem">
+										<text>wxBitmapComboBox</text>
+										<bitmap>uncenter.xpm</bitmap>
+									 </object>
+                                    <object class="ownerdrawnitem">
+										<text>control</text>
+										<bitmap>custclas.xpm</bitmap>
+									</object>
+                                </object>
+                            </object>
                         </object>
                     </object>
                 </object>
diff --git a/setup.h.in b/setup.h.in
index 0b5a17c593..dc70720199 100644
--- a/setup.h.in
+++ b/setup.h.in
@@ -356,6 +356,8 @@
 
 #define wxUSE_ODCOMBOBOX 0
 
+#define wxUSE_BITMAPCOMBOBOX 0
+
 
 #define wxUSE_ACCEL 0
 
diff --git a/setup.h_vms b/setup.h_vms
index 249cf1a812..c93c220075 100644
--- a/setup.h_vms
+++ b/setup.h_vms
@@ -378,6 +378,8 @@ typedef pid_t GPid;
 
 #define wxUSE_ODCOMBOBOX 1
 
+#define wxUSE_BITMAPCOMBOBOX 1
+
 #define wxUSE_ACCEL 1
 
 #define wxUSE_HOTKEY 1
diff --git a/src/generic/bmpcboxg.cpp b/src/generic/bmpcboxg.cpp
new file mode 100644
index 0000000000..88d9cd7218
--- /dev/null
+++ b/src/generic/bmpcboxg.cpp
@@ -0,0 +1,471 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        src/generic/bmpcboxg.cpp
+// Purpose:     wxBitmapComboBox
+// Author:      Jaakko Salli
+// Modified by:
+// Created:     Aug-31-2006
+// RCS-ID:      $Id:
+// Copyright:   (c) 2005 Jaakko Salli
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_BITMAPCOMBOBOX
+
+#include "wx/bmpcbox.h"
+
+#if defined(wxGENERIC_BITMAPCOMBOBOX)
+
+#ifndef WX_PRECOMP
+    #include "wx/log.h"
+#endif
+
+#include "wx/odcombo.h"
+#include "wx/settings.h"
+
+#if wxUSE_IMAGE
+    #include "wx/image.h"
+#endif
+
+
+const wxChar wxBitmapComboBoxNameStr[] = wxT("bitmapComboBox");
+
+
+// These macros allow wxArrayPtrVoid to be used in more convenient manner
+#define GetBitmapPtr(n)     ((wxBitmap*)m_bitmaps[n])
+
+
+#define IMAGE_SPACING_RIGHT         4  // Space left of image
+
+#define IMAGE_SPACING_LEFT          4  // Space right of image, left of text
+
+#define IMAGE_SPACING_VERTICAL      2  // Space top and bottom of image
+
+#define IMAGE_SPACING_CTRL_VERTICAL 7  // Spacing used in control size calculation
+
+#define EXTRA_FONT_HEIGHT           0  // Add to increase min. height of list items
+
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+
+BEGIN_EVENT_TABLE(wxBitmapComboBox, wxOwnerDrawnComboBox)
+    EVT_SIZE(wxBitmapComboBox::OnResize)
+END_EVENT_TABLE()
+
+
+IMPLEMENT_DYNAMIC_CLASS(wxBitmapComboBox, wxOwnerDrawnComboBox)
+
+void wxBitmapComboBox::Init()
+{
+    m_fontHeight = 0;
+    m_imgAreaWidth = 0;
+    m_inResize = false;
+}
+
+wxBitmapComboBox::wxBitmapComboBox(wxWindow *parent,
+                                  wxWindowID id,
+                                  const wxString& value,
+                                  const wxPoint& pos,
+                                  const wxSize& size,
+                                  const wxArrayString& choices,
+                                  long style,
+                                  const wxValidator& validator,
+                                  const wxString& name)
+    : wxOwnerDrawnComboBox(),
+      wxBitmapComboBoxBase()
+{
+    Init();
+
+    Create(parent,id,value,pos,size,choices,style,validator,name);
+}
+
+bool wxBitmapComboBox::Create(wxWindow *parent,
+                              wxWindowID id,
+                              const wxString& value,
+                              const wxPoint& pos,
+                              const wxSize& size,
+                              const wxArrayString& choices,
+                              long style,
+                              const wxValidator& validator,
+                              const wxString& name)
+{
+    if ( !wxOwnerDrawnComboBox::Create(parent, id, value,
+                                       pos, size,
+                                       choices, style,
+                                       validator, name) )
+    {
+        return false;
+    }
+
+    PostCreate();
+
+    return true;
+}
+
+bool wxBitmapComboBox::Create(wxWindow *parent,
+                              wxWindowID id,
+                              const wxString& value,
+                              const wxPoint& pos,
+                              const wxSize& size,
+                              int n,
+                              const wxString choices[],
+                              long style,
+                              const wxValidator& validator,
+                              const wxString& name)
+{
+    if ( !wxOwnerDrawnComboBox::Create(parent, id, value,
+                                       pos, size, n,
+                                       choices, style,
+                                       validator, name) )
+    {
+        return false;
+    }
+
+    PostCreate();
+
+    return true;
+}
+
+void wxBitmapComboBox::PostCreate()
+{
+    m_fontHeight = GetCharHeight() + EXTRA_FONT_HEIGHT;
+}
+
+wxBitmapComboBox::~wxBitmapComboBox()
+{
+    Clear();
+}
+
+// ----------------------------------------------------------------------------
+// Item manipulation
+// ----------------------------------------------------------------------------
+
+void wxBitmapComboBox::SetItemBitmap(unsigned int n, const wxBitmap& bitmap)
+{
+    wxCHECK_RET( n < m_bitmaps.size(), wxT("invalid item index") );
+    OnAddBitmap(bitmap);
+    *GetBitmapPtr(n) = bitmap;
+
+    if ( (int)n == GetSelection() )
+        Refresh();
+}
+
+wxBitmap wxBitmapComboBox::GetItemBitmap(unsigned int n) const
+{
+    wxCHECK_MSG( n < m_bitmaps.size(), wxNullBitmap, wxT("invalid item index") );
+    return *GetBitmapPtr(n);
+}
+
+int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap,
+                             unsigned int pos, void *clientData)
+{
+    int n = DoInsertWithImage(item, bitmap, pos);
+    if ( n != wxNOT_FOUND )
+        SetClientData(n, clientData);
+
+    return n;
+}
+
+int wxBitmapComboBox::Insert(const wxString& item, const wxBitmap& bitmap,
+                             unsigned int pos, wxClientData *clientData)
+{
+    int n = DoInsertWithImage(item, bitmap, pos);
+    if ( n != wxNOT_FOUND )
+        SetClientObject(n, clientData);
+
+    return n;
+}
+
+bool wxBitmapComboBox::OnAddBitmap(const wxBitmap& bitmap)
+{
+    if ( bitmap.Ok() )
+    {
+        int width = bitmap.GetWidth();
+        int height = bitmap.GetHeight();
+
+        if ( m_usedImgSize.x <= 0 )
+        {
+            //
+            // If size not yet determined, get it from this image.
+            m_usedImgSize.x = width;
+            m_usedImgSize.y = height;
+
+            InvalidateBestSize();
+            wxSize newSz = GetBestSize();
+            wxSize sz = GetSize();
+            if ( newSz.y > sz.y )
+                SetSize(sz.x, newSz.y);
+            else
+                DetermineIndent();
+        }
+
+        wxCHECK_MSG(width == m_usedImgSize.x && height == m_usedImgSize.y,
+                    false,
+                    wxT("you can only add images of same size"));
+    }
+
+    return true;
+}
+
+bool wxBitmapComboBox::DoInsertBitmap(const wxBitmap& bitmap, unsigned int pos)
+{
+    if ( !OnAddBitmap(bitmap) )
+        return false;
+
+    // NB: We must try to set the image before DoInsert or
+    //     DoAppend because OnMeasureItem might be called
+    //     before it returns.
+    m_bitmaps.Insert( new wxBitmap(bitmap), pos);
+
+    return true;
+}
+
+int wxBitmapComboBox::DoAppendWithImage(const wxString& item, const wxBitmap& image)
+{
+    unsigned int pos = m_bitmaps.size();
+
+    if ( !DoInsertBitmap(image, pos) )
+        return wxNOT_FOUND;
+
+    int index = wxOwnerDrawnComboBox::DoAppend(item);
+
+    if ( index < 0 )
+        index = m_bitmaps.size();
+
+    // Need to re-check the index incase DoAppend sorted
+    if ( (unsigned int) index != pos )
+    {
+        wxBitmap* bmp = GetBitmapPtr(pos);
+        m_bitmaps.RemoveAt(pos);
+        m_bitmaps.Insert(bmp, index);
+    }
+
+    return index;
+}
+
+int wxBitmapComboBox::DoInsertWithImage(const wxString& item,
+                                        const wxBitmap& image,
+                                        unsigned int pos)
+{
+    if ( !DoInsertBitmap(image, pos) )
+        return wxNOT_FOUND;
+
+    return wxOwnerDrawnComboBox::DoInsert(item, pos);
+}
+
+int wxBitmapComboBox::DoAppend(const wxString& item)
+{
+    return DoAppendWithImage(item, wxNullBitmap);
+}
+
+int wxBitmapComboBox::DoInsert(const wxString& item, unsigned int pos)
+{
+    return DoInsertWithImage(item, wxNullBitmap, pos);
+}
+
+void wxBitmapComboBox::Clear()
+{
+    wxOwnerDrawnComboBox::Clear();
+
+    unsigned int i;
+
+    for ( i=0; i<m_bitmaps.size(); i++ )
+        delete GetBitmapPtr(i);
+
+    m_bitmaps.Empty();
+
+    m_usedImgSize.x = 0;
+    m_usedImgSize.y = 0;
+
+    DetermineIndent();
+}
+
+void wxBitmapComboBox::Delete(unsigned int n)
+{
+    wxOwnerDrawnComboBox::Delete(n);
+    delete GetBitmapPtr(n);
+    m_bitmaps.RemoveAt(n);
+}
+
+// ----------------------------------------------------------------------------
+// wxBitmapComboBox event handlers and such
+// ----------------------------------------------------------------------------
+
+void wxBitmapComboBox::DetermineIndent()
+{
+    //
+    // Recalculate amount of empty space needed in front of
+    // text in control itself.
+    int indent = m_imgAreaWidth = 0;
+
+    if ( m_usedImgSize.x > 0 )
+    {
+        indent = m_usedImgSize.y + IMAGE_SPACING_LEFT + IMAGE_SPACING_RIGHT;
+        m_imgAreaWidth = indent;
+
+        indent -= 3;
+    }
+
+    SetCustomPaintWidth(indent);
+}
+
+void wxBitmapComboBox::OnResize(wxSizeEvent& event)
+{
+    // Prevent infinite looping
+    if ( !m_inResize )
+    {
+        m_inResize = true;
+        DetermineIndent();
+        m_inResize = false;
+    }
+
+    event.Skip();
+}
+
+wxSize wxBitmapComboBox::DoGetBestSize() const
+{
+    wxSize sz = wxOwnerDrawnComboBox::DoGetBestSize();
+
+    // Scale control to match height of highest image.
+    int h2 = m_usedImgSize.y + IMAGE_SPACING_CTRL_VERTICAL;
+
+    if ( h2 > sz.y )
+        sz.y = h2;
+
+    CacheBestSize(sz);
+    return sz;
+}
+
+// ----------------------------------------------------------------------------
+// wxBitmapComboBox miscellaneous
+// ----------------------------------------------------------------------------
+
+bool wxBitmapComboBox::SetFont(const wxFont& font)
+{
+    bool res = wxOwnerDrawnComboBox::SetFont(font);
+    m_fontHeight = GetCharHeight() + EXTRA_FONT_HEIGHT;
+    return res;
+}
+
+// ----------------------------------------------------------------------------
+// wxBitmapComboBox item drawing and measuring
+// ----------------------------------------------------------------------------
+
+void wxBitmapComboBox::OnDrawBackground(wxDC& dc,
+                                        const wxRect& rect,
+                                        int item,
+                                        int flags) const
+{
+    if ( GetCustomPaintWidth() == 0 ||
+         !(flags & wxODCB_PAINTING_SELECTED) ||
+         item < 0 )
+    {
+        wxOwnerDrawnComboBox::OnDrawBackground(dc, rect, item, flags);
+        return;
+    }
+
+    //
+    // Just paint simple selection background under where is text
+    // (ie. emulate what MSW image choice does).
+    //
+
+    int xPos = 0;  // Starting x of selection rectangle
+    const int vSizeDec = 1;  // Vertical size reduction of selection rectangle edges
+
+    xPos = GetCustomPaintWidth() + 2;
+
+    wxCoord x, y;
+    GetTextExtent(GetString(item), &x, &y, 0, 0);
+
+    dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
+
+    wxColour selCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
+    dc.SetPen(selCol);
+    dc.SetBrush(selCol);
+    dc.DrawRectangle(rect.x+xPos,
+                     rect.y+vSizeDec,
+                     x + 4,
+                     rect.height-(vSizeDec*2));
+}
+
+void wxBitmapComboBox::OnDrawItem(wxDC& dc,
+                                 const wxRect& rect,
+                                 int item,
+                                 int flags) const
+{
+    wxString text;
+    int imgAreaWidth = m_imgAreaWidth;
+    bool drawText;
+
+    if ( imgAreaWidth == 0 )
+    {
+        wxOwnerDrawnComboBox::OnDrawItem(dc, rect, item, flags);
+        return;
+    }
+
+    if ( flags & wxODCB_PAINTING_CONTROL )
+    {
+        text = GetValue();
+        if ( HasFlag(wxCB_READONLY) )
+            drawText = true;
+        else
+            drawText = false;
+    }
+    else
+    {
+        text = GetString(item);
+        drawText = true;
+    }
+
+    const wxBitmap& bmp = *GetBitmapPtr(item);
+    if ( bmp.Ok() )
+    {
+        wxCoord w = bmp.GetWidth();
+        wxCoord h = bmp.GetHeight();
+
+        // Draw the image centered
+        dc.DrawBitmap(bmp,
+                      rect.x + (m_usedImgSize.x-w)/2 + IMAGE_SPACING_LEFT,
+                      rect.y + (rect.height-h)/2,
+                      true);
+    }
+
+    if ( drawText )
+        dc.DrawText(GetString(item),
+                    rect.x + imgAreaWidth + 1,
+                    rect.y + (rect.height-dc.GetCharHeight())/2);
+}
+
+wxCoord wxBitmapComboBox::OnMeasureItem(size_t WXUNUSED(item)) const
+{
+    int imgHeightArea = m_usedImgSize.y + 2;
+    return imgHeightArea > m_fontHeight ? imgHeightArea : m_fontHeight;
+}
+
+wxCoord wxBitmapComboBox::OnMeasureItemWidth(size_t item) const
+{
+    wxCoord x, y;
+    GetTextExtent(GetString(item), &x, &y, 0, 0);
+    x += m_imgAreaWidth;
+    return x;
+}
+
+#endif // defined(wxGENERIC_BITMAPCOMBOBOX)
+
+#endif // wxUSE_BITMAPCOMBOBOX
diff --git a/src/xrc/xh_bmpcbox.cpp b/src/xrc/xh_bmpcbox.cpp
new file mode 100644
index 0000000000..9c6e5ff894
--- /dev/null
+++ b/src/xrc/xh_bmpcbox.cpp
@@ -0,0 +1,102 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        src/xrc/xh_bmpcbox.cpp
+// Purpose:     XRC resource for wxBitmapComboBox
+// Author:      Jaakko Salli
+// Created:     Sep-10-2006
+// RCS-ID:      $Id:
+// Copyright:   (c) 2006 Jaakko Salli
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_XRC && wxUSE_BITMAPCOMBOBOX
+
+#include "wx/xrc/xh_bmpcbox.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/intl.h"
+#endif
+
+#include "wx/bmpcbox.h"
+
+IMPLEMENT_DYNAMIC_CLASS(wxBitmapComboBoxXmlHandler, wxXmlResourceHandler)
+
+wxBitmapComboBoxXmlHandler::wxBitmapComboBoxXmlHandler()
+                     :wxXmlResourceHandler()
+                     ,m_combobox(NULL)
+                     ,m_isInside(false)
+{
+    XRC_ADD_STYLE(wxCB_SORT);
+    XRC_ADD_STYLE(wxCB_READONLY);
+    AddWindowStyles();
+}
+
+wxObject *wxBitmapComboBoxXmlHandler::DoCreateResource()
+{
+    if (m_class == wxT("ownerdrawnitem"))
+    {
+        wxCHECK_MSG(m_combobox, NULL, wxT("Incorrect syntax of XRC resource: ownerdrawnitem not within a bitmapcombobox!"));
+
+        m_combobox->Append(GetText(wxT("text")), GetBitmap(wxT("bitmap"), wxART_MISSING_IMAGE));
+
+        return m_combobox;
+    }
+    else /*if( m_class == wxT("wxBitmapComboBox"))*/
+    {
+        // find the selection
+        long selection = GetLong( wxT("selection"), -1 );
+
+        XRC_MAKE_INSTANCE(control, wxBitmapComboBox)
+
+        control->Create(m_parentAsWindow,
+                        GetID(),
+                        GetText(wxT("value")),
+                        GetPosition(), GetSize(),
+                        0,
+                        NULL,
+                        GetStyle(),
+                        wxDefaultValidator,
+                        GetName());
+
+        m_isInside = true;
+        m_combobox = control;
+
+        wxXmlNode *children_node = GetParamNode(wxT("object"));
+
+        wxXmlNode *n = children_node;
+
+        while (n)
+        {
+            if ((n->GetType() == wxXML_ELEMENT_NODE) &&
+                (n->GetName() == wxT("object")))
+            {
+                CreateResFromNode(n, control, NULL);
+            }
+            n = n->GetNext();
+        }
+
+        m_isInside = false;
+        m_combobox = NULL;
+
+        if (selection != -1)
+            control->SetSelection(selection);
+
+        SetupWindow(control);
+
+        return control;
+    }
+}
+
+bool wxBitmapComboBoxXmlHandler::CanHandle(wxXmlNode *node)
+{
+    return ((!m_isInside && IsOfClass(node, wxT("wxBitmapComboBox"))) ||
+            (m_isInside && IsOfClass(node, wxT("ownerdrawnitem"))));
+}
+
+#endif // wxUSE_XRC && wxUSE_BITMAPCOMBOBOX
diff --git a/src/xrc/xmlrsall.cpp b/src/xrc/xmlrsall.cpp
index bc6254ec92..73df95c094 100644
--- a/src/xrc/xmlrsall.cpp
+++ b/src/xrc/xmlrsall.cpp
@@ -80,6 +80,9 @@ void wxXmlResource::InitAllHandlers()
 #if wxUSE_ODCOMBOBOX
     AddHandler(new wxOwnerDrawnComboBoxXmlHandler);
 #endif
+#if wxUSE_BITMAPCOMBOBOX
+    AddHandler(new wxBitmapComboBoxXmlHandler);
+#endif
 #if wxUSE_NOTEBOOK
     AddHandler(new wxNotebookXmlHandler);
 #endif
-- 
2.50.0

