]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/combo/combo.cpp
Use template class instead of template function in wxVectorSort().
[wxWidgets.git] / samples / combo / combo.cpp
index 0b734e139ee59def6084cf63380a84b859113cf4..288fbc27e739fc2cd21eaab4021a468d9def1d9b 100644 (file)
@@ -78,13 +78,23 @@ public:
     void OnQuit(wxCommandEvent& event);
     void OnAbout(wxCommandEvent& event);
 
+    void OnShowComparison( wxCommandEvent& event );
+
     // log wxComboCtrl events
     void OnComboBoxUpdate( wxCommandEvent& event );
 
+    void OnIdle( wxIdleEvent& event );
+
+
+    wxCheckBox*     m_cbUseAnim;
+
 protected:
     wxTextCtrl*     m_logWin;
     wxLog*          m_logOld;
 
+    // Common list of items for all dialogs.
+    wxArrayString   m_arrItems;
+
 private:
     // any class wishing to process wxWidgets events must use this macro
     DECLARE_EVENT_TABLE()
@@ -97,6 +107,8 @@ private:
 // IDs for the controls and the menu commands
 enum
 {
+    ComboControl_Compare = wxID_HIGHEST,
+
     // menu items
     ComboControl_Quit = wxID_EXIT,
 
@@ -117,8 +129,11 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_TEXT(wxID_ANY,MyFrame::OnComboBoxUpdate)
     EVT_COMBOBOX(wxID_ANY,MyFrame::OnComboBoxUpdate)
 
-    EVT_MENU(ComboControl_Quit,  MyFrame::OnQuit)
-    EVT_MENU(ComboControl_About, MyFrame::OnAbout)
+    EVT_MENU(ComboControl_Compare,  MyFrame::OnShowComparison)
+    EVT_MENU(ComboControl_Quit,     MyFrame::OnQuit)
+    EVT_MENU(ComboControl_About,    MyFrame::OnAbout)
+
+    EVT_IDLE(MyFrame::OnIdle)
 END_EVENT_TABLE()
 
 // Create a new application object: this macro will allow wxWidgets to create
@@ -139,8 +154,11 @@ IMPLEMENT_APP(MyApp)
 // 'Main program' equivalent: the program execution "starts" here
 bool MyApp::OnInit()
 {
+    if ( !wxApp::OnInit() )
+        return false;
+
     // create the main application window
-    MyFrame *frame = new MyFrame(_T("wxComboCtrl Sample"));
+    MyFrame *frame = new MyFrame(wxT("wxComboCtrl and wxOwnerDrawnComboBox Sample"));
 
     // and show it (the frames, unlike simple controls, are not shown when
     // created initially)
@@ -153,6 +171,106 @@ bool MyApp::OnInit()
 }
 
 
+// ----------------------------------------------------------------------------
+// wxOwnerDrawnComboBox with custom paint list items
+// ----------------------------------------------------------------------------
+
+class wxPenStyleComboBox : public wxOwnerDrawnComboBox
+{
+public:
+    virtual void OnDrawItem( wxDC& dc,
+                             const wxRect& rect,
+                             int item,
+                             int flags ) const
+    {
+        if ( item == wxNOT_FOUND )
+            return;
+
+        wxRect r(rect);
+        r.Deflate(3);
+        r.height -= 2;
+
+        int penStyle = wxSOLID;
+        if ( item == 1 )
+            penStyle = wxTRANSPARENT;
+        else if ( item == 2 )
+            penStyle = wxDOT;
+        else if ( item == 3 )
+            penStyle = wxLONG_DASH;
+        else if ( item == 4 )
+            penStyle = wxSHORT_DASH;
+        else if ( item == 5 )
+            penStyle = wxDOT_DASH;
+        else if ( item == 6 )
+            penStyle = wxBDIAGONAL_HATCH;
+        else if ( item == 7 )
+            penStyle = wxCROSSDIAG_HATCH;
+        else if ( item == 8 )
+            penStyle = wxFDIAGONAL_HATCH;
+        else if ( item == 9 )
+            penStyle = wxCROSS_HATCH;
+        else if ( item == 10 )
+            penStyle = wxHORIZONTAL_HATCH;
+        else if ( item == 11 )
+            penStyle = wxVERTICAL_HATCH;
+
+        wxPen pen( dc.GetTextForeground(), 3, penStyle );
+
+        // Get text colour as pen colour
+        dc.SetPen( pen );
+
+        if ( !(flags & wxODCB_PAINTING_CONTROL) )
+        {
+            dc.DrawText(GetString( item ),
+                        r.x + 3,
+                        (r.y + 0) + ( (r.height/2) - dc.GetCharHeight() )/2
+                       );
+
+            dc.DrawLine( r.x+5, r.y+((r.height/4)*3), r.x+r.width - 5, r.y+((r.height/4)*3) );
+        }
+        else
+        {
+            dc.DrawLine( r.x+5, r.y+r.height/2, r.x+r.width - 5, r.y+r.height/2 );
+        }
+    }
+
+    virtual void OnDrawBackground( wxDC& dc, const wxRect& rect,
+                                   int item, int flags ) const
+    {
+
+        // If item is selected or even, or we are painting the
+        // combo control itself, use the default rendering.
+        if ( (flags & (wxODCB_PAINTING_CONTROL|wxODCB_PAINTING_SELECTED)) ||
+             (item & 1) == 0 )
+        {
+            wxOwnerDrawnComboBox::OnDrawBackground(dc,rect,item,flags);
+            return;
+        }
+
+        // Otherwise, draw every other background with different colour.
+        wxColour bgCol(240,240,250);
+        dc.SetBrush(wxBrush(bgCol));
+        dc.SetPen(wxPen(bgCol));
+        dc.DrawRectangle(rect);
+    }
+
+    virtual wxCoord OnMeasureItem( size_t item ) const
+    {
+        // Simply demonstrate the ability to have variable-height items
+        if ( item & 1 )
+            return 36;
+        else
+            return 24;
+    }
+
+    virtual wxCoord OnMeasureItemWidth( size_t WXUNUSED(item) ) const
+    {
+        return -1; // default - will be measured from text width
+    }
+
+};
+
+
 // ----------------------------------------------------------------------------
 // wxListView Custom popup interface
 // ----------------------------------------------------------------------------
@@ -163,14 +281,6 @@ class ListViewComboPopup : public wxListView, public wxComboPopup
 {
 public:
 
-/*
-    ListViewComboPopup(wxComboCtrlBase* combo)
-        : wxListView(), wxComboPopup(combo)
-    {
-        m_value = -1;
-        m_itemHere = -1; // hot item in list
-    }
-*/
     virtual void Init()
     {
         m_value = -1;
@@ -265,13 +375,6 @@ class TreeCtrlComboPopup : public wxTreeCtrl, public wxComboPopup
 {
 public:
 
-/*
-    TreeCtrlComboPopup(wxComboCtrlBase* combo)
-        : wxTreeCtrl(), wxComboPopup(combo)
-    {
-    }
-*/
-
     virtual void Init()
     {
     }
@@ -280,9 +383,7 @@ public:
     {
         return wxTreeCtrl::Create(parent,1,
                                   wxPoint(0,0),wxDefaultSize,
-                                  wxTR_HIDE_ROOT|wxTR_HAS_BUTTONS|
-                                  wxTR_SINGLE|wxTR_LINES_AT_ROOT|
-                                  wxSIMPLE_BORDER);
+                                  wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT | wxSIMPLE_BORDER );
     }
 
     virtual void OnShow()
@@ -394,145 +495,129 @@ BEGIN_EVENT_TABLE(TreeCtrlComboPopup, wxTreeCtrl)
 END_EVENT_TABLE()
 
 // ----------------------------------------------------------------------------
-// wxOwnerDrawnComboBox with custom paint list items
+// wxComboCtrl with custom popup animation. We use EVT_TIMER, which is quite
+// safe, but requires much more can than doing it in a single function (ie.
+// AnimateShow) and using combination of wxSleep and wxSafeYield.
 // ----------------------------------------------------------------------------
-/*
-class wxPenStyleComboBox : public wxOwnerDrawnComboBox
+
+#if wxUSE_TIMER
+
+#define CUSTOM_COMBOBOX_ANIMATION_DURATION  200  // In milliseconds
+
+#include "wx/timer.h"
+
+class wxComboCtrlWithCustomPopupAnim : public wxComboCtrl
 {
 public:
-    virtual bool OnDrawListItem( wxDC& dc, const wxRect& rect, int item, int flags )
+
+    virtual bool AnimateShow( const wxRect& rect, int flags )
     {
-        wxRect r(rect);
-        r.Deflate(3);
-        r.height -= 2;
+        MyFrame* myFrame = (MyFrame*) ::wxGetTopLevelParent(this);
 
-        int pen_style = wxSOLID;
-        if ( item == 1 )
-            pen_style = wxTRANSPARENT;
-        else if ( item == 2 )
-            pen_style = wxDOT;
-        else if ( item == 3 )
-            pen_style = wxLONG_DASH;
-        else if ( item == 4 )
-            pen_style = wxSHORT_DASH;
-        else if ( item == 5 )
-            pen_style = wxDOT_DASH;
-        else if ( item == 6 )
-            pen_style = wxBDIAGONAL_HATCH;
-        else if ( item == 7 )
-            pen_style = wxCROSSDIAG_HATCH;
-        else if ( item == 8 )
-            pen_style = wxFDIAGONAL_HATCH;
-        else if ( item == 9 )
-            pen_style = wxCROSS_HATCH;
-        else if ( item == 10 )
-            pen_style = wxHORIZONTAL_HATCH;
-        else if ( item == 11 )
-            pen_style = wxVERTICAL_HATCH;
+        if ( !myFrame->m_cbUseAnim->GetValue() )
+            return true;
 
-        wxPen pen( dc.GetTextForeground(), 3, pen_style );
+        m_animStart = ::wxGetLocalTimeMillis();
+        m_animRect = rect;
+        m_animFlags = flags;
 
-        // Get text colour as pen colour
-        dc.SetPen ( pen );
+        wxScreenDC dc;
 
-        if ( !(flags & wxCP_PAINTING_CONTROL) )
-        {
-            dc.DrawText(GetString( item ),
-                        r.x + 3,
-                        (r.y + 0) + ( (r.height/2) - dc.GetCharHeight() )/2
-                       );
+        wxBitmap bitmap( rect.width, rect.height, -1 );
+        wxMemoryDC memdc( bitmap );
+        memdc.Blit( 0, 0, rect.width, rect.height, &dc, rect.x, rect.y );
+        memdc.SelectObject(wxNullBitmap); 
+        m_animBackBitmap = bitmap;
 
-            dc.DrawLine( r.x+5, r.y+((r.height/4)*3), r.x+r.width - 5, r.y+((r.height/4)*3) );
-        }
-        else
-        {
-            dc.DrawLine( r.x+5, r.y+r.height/2, r.x+r.width - 5, r.y+r.height/2 );
-        }
+        m_animTimer.SetOwner( this, wxID_ANY );
+        m_animTimer.Start( 10, wxTIMER_CONTINUOUS );
 
-        return true;
+        DoOnTimer();
+        return false;
     }
 
-    virtual wxCoord OnMeasureListItem( int WXUNUSED(item) )
+private:
+    void OnTimerEvent( wxTimerEvent& WXUNUSED(event) )
     {
-        return 24;
+        DoOnTimer();
     }
 
-    virtual wxCoord OnMeasureListItemWidth( int WXUNUSED(item) )
+    void DoOnTimer()
     {
-        return -1; // default - will be measured from text width
-    }
+        bool stopTimer = false;
 
-};
-*/
+        wxWindow* popup = GetPopupControl()->GetControl();
+        wxScreenDC dc;
+        const wxRect& rect = m_animRect;
 
-class wxPenStylePopup : public wxVListBoxComboPopup
-{
-public:
-    virtual void OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
-    {
-        if ( item == wxNOT_FOUND )
-            return;
+        // Popup was hidden before it was fully shown?
+        if ( IsPopupWindowState(Hidden) )
+        {
+            stopTimer = true;
+        }
+        else
+        {
+            wxLongLong t = ::wxGetLocalTimeMillis();
 
-        wxRect r(rect);
-        r.Deflate(3);
-        r.height -= 2;
+            int pos = (int) (t-m_animStart).GetLo();
+            if ( pos < CUSTOM_COMBOBOX_ANIMATION_DURATION )
+            {
+                //
+                // Actual animation happens here
+                //
+                int width = rect.width;
+                int height = rect.height;
 
-        int pen_style = wxSOLID;
-        if ( item == 1 )
-            pen_style = wxTRANSPARENT;
-        else if ( item == 2 )
-            pen_style = wxDOT;
-        else if ( item == 3 )
-            pen_style = wxLONG_DASH;
-        else if ( item == 4 )
-            pen_style = wxSHORT_DASH;
-        else if ( item == 5 )
-            pen_style = wxDOT_DASH;
-        else if ( item == 6 )
-            pen_style = wxBDIAGONAL_HATCH;
-        else if ( item == 7 )
-            pen_style = wxCROSSDIAG_HATCH;
-        else if ( item == 8 )
-            pen_style = wxFDIAGONAL_HATCH;
-        else if ( item == 9 )
-            pen_style = wxCROSS_HATCH;
-        else if ( item == 10 )
-            pen_style = wxHORIZONTAL_HATCH;
-        else if ( item == 11 )
-            pen_style = wxVERTICAL_HATCH;
+                int center_x = rect.x + (width/2);
+                int center_y = rect.y + (height/2);
 
-        wxPen pen( dc.GetTextForeground(), 3, pen_style );
+                double d_height = (double) height;
 
-        // Get text colour as pen colour
-        dc.SetPen ( pen );
+                dc.SetPen( *wxBLACK_PEN );
+                dc.SetBrush( *wxTRANSPARENT_BRUSH );
 
-        if ( !(flags & wxCP_PAINTING_CONTROL) )
-        {
-            dc.DrawText(GetString( item ),
-                        r.x + 3,
-                        (r.y + 0) + ( (r.height/2) - dc.GetCharHeight() )/2
-                       );
+                int w = (((pos*256)/CUSTOM_COMBOBOX_ANIMATION_DURATION)*width)/256;
 
-            dc.DrawLine( r.x+5, r.y+((r.height/4)*3), r.x+r.width - 5, r.y+((r.height/4)*3) );
+                double ratio = ((double)w / (double)width);
+                int h = (int)(d_height * ratio);
+                dc.DrawBitmap( m_animBackBitmap, rect.x, rect.y );
+                dc.DrawRectangle( center_x - w/2, center_y - h/2, w, h );
+            }
+            else
+            {
+                stopTimer = true;
+            }
         }
-        else
+
+        if ( stopTimer )
         {
-            dc.DrawLine( r.x+5, r.y+r.height/2, r.x+r.width - 5, r.y+r.height/2 );
+            dc.DrawBitmap( m_animBackBitmap, rect.x, rect.y );
+            popup->Move( 0, 0 );
+            m_animTimer.Stop();
+            DoShowPopup( m_animRect, m_animFlags );
         }
     }
 
-    virtual wxCoord OnMeasureItem( size_t WXUNUSED(item) ) const
-    {
-        return 24;
-    }
-
-    virtual wxCoord OnMeasureItemWidth( size_t WXUNUSED(item) ) const
-    {
-        return -1; // default - will be measured from text width
-    }
+    // Popup animation related
+    wxLongLong  m_animStart;
+    wxTimer     m_animTimer;
+    wxRect      m_animRect;
+    wxBitmap    m_animBackBitmap;
+    int         m_animFlags;
 
+    DECLARE_EVENT_TABLE()
 };
 
+BEGIN_EVENT_TABLE(wxComboCtrlWithCustomPopupAnim, wxComboCtrl)
+    EVT_TIMER(wxID_ANY, wxComboCtrlWithCustomPopupAnim::OnTimerEvent)
+END_EVENT_TABLE()
+
+#else
+
+#define wxComboCtrlWithCustomPopupAnim wxComboCtrl
+
+#endif
+
 // ----------------------------------------------------------------------------
 // wxComboCtrl with entirely custom button action (opens file dialog)
 // ----------------------------------------------------------------------------
@@ -597,7 +682,7 @@ public:
                          wxEmptyString,
                          GetValue(),
                          wxT("All files (*.*)|*.*"),
-                         wxOPEN);
+                         wxFD_OPEN);
 
         if ( dlg.ShowModal() == wxID_OK )
         {
@@ -605,6 +690,11 @@ public:
         }
     }
 
+    // Implement empty DoSetPopupControl to prevent assertion failure.
+    virtual void DoSetPopupControl(wxComboPopup* WXUNUSED(popup))
+    {
+    }
+
 private:
     void Init()
     {
@@ -624,7 +714,6 @@ MyFrame::MyFrame(const wxString& title)
     wxBoxSizer* topRowSizer;
     wxBoxSizer* colSizer;
     wxBoxSizer* rowSizer;
-    wxStaticBoxSizer* groupSizer;
 
     // set the frame icon
     SetIcon(wxICON(sample));
@@ -635,14 +724,17 @@ MyFrame::MyFrame(const wxString& title)
 
     // the "About" item should be in the help menu
     wxMenu *helpMenu = new wxMenu;
-    helpMenu->Append(ComboControl_About, _T("&About...\tF1"), _T("Show about dialog"));
+    helpMenu->Append(ComboControl_About, wxT("&About...\tF1"), wxT("Show about dialog"));
 
-    fileMenu->Append(ComboControl_Quit, _T("E&xit\tAlt-X"), _T("Quit this program"));
+    fileMenu->Append(ComboControl_Compare, wxT("&Compare against wxComboBox..."),
+        wxT("Show some wxOwnerDrawnComboBoxes side-by-side with native wxComboBoxes."));
+    fileMenu->AppendSeparator();
+    fileMenu->Append(ComboControl_Quit, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
 
     // now append the freshly created menu to the menu bar...
     wxMenuBar *menuBar = new wxMenuBar();
-    menuBar->Append(fileMenu, _T("&File"));
-    menuBar->Append(helpMenu, _T("&Help"));
+    menuBar->Append(fileMenu, wxT("&File"));
+    menuBar->Append(helpMenu, wxT("&Help"));
 
     // ... and attach this menu bar to the frame
     SetMenuBar(menuBar);
@@ -651,12 +743,13 @@ MyFrame::MyFrame(const wxString& title)
     wxPanel* panel = new wxPanel(this);
 
     // Prepare log window right away since it shows EVT_TEXTs
-    m_logWin = new wxTextCtrl( panel, 105, wxEmptyString, wxDefaultPosition,
-                               wxSize(-1,125), wxTE_MULTILINE|wxFULL_REPAINT_ON_RESIZE );
-    m_logWin->SetEditable(false);
-    wxLogTextCtrl* logger = new wxLogTextCtrl( m_logWin );
-    m_logOld = logger->SetActiveTarget( logger );
-    logger->SetTimestamp( NULL );
+    m_logWin = new wxTextCtrl(panel, 105, wxEmptyString,
+                              wxDefaultPosition,
+                              wxSize(-1, 125),
+                              wxTE_MULTILINE);
+    wxLogTextCtrl* logger = new wxLogTextCtrl(m_logWin);
+    m_logOld = logger->SetActiveTarget(logger);
+    logger->DisableTimestamp();
 
 
     topSizer = new wxBoxSizer( wxVERTICAL );
@@ -666,176 +759,85 @@ MyFrame::MyFrame(const wxString& title)
     colSizer = new wxBoxSizer( wxVERTICAL );
 
 
-    // Make sure GetFeatures is implemented
-    int features = wxComboCtrl::GetFeatures();
-    wxLogDebug(wxT("wxComboCtrl features: 0x%X (all features: 0x%X)"),
-               features,wxComboCtrlFeatures::All);
-
-
-    wxComboBox* cb;
     wxComboCtrl* cc;
-    wxGenericComboControl* gcc;
+    wxGenericComboCtrl* gcc;
     wxOwnerDrawnComboBox* odc;
 
     // Create common strings array
-    wxArrayString arrItems;
-    arrItems.Add( wxT("Solid") );
-    arrItems.Add( wxT("Transparent") );
-    arrItems.Add( wxT("Dot") );
-    arrItems.Add( wxT("Long Dash") );
-    arrItems.Add( wxT("Short Dash") );
-    arrItems.Add( wxT("Dot Dash") );
-    arrItems.Add( wxT("Backward Diagonal Hatch") );
-    arrItems.Add( wxT("Cross-diagonal Hatch") );
-    arrItems.Add( wxT("Forward Diagonal Hatch") );
-    arrItems.Add( wxT("Cross Hatch") );
-    arrItems.Add( wxT("Horizontal Hatch") );
-    arrItems.Add( wxT("Vertical Hatch") );
-
-    int border = 4;
-
-    //
-    // Show some wxOwnerDrawComboBoxes for comparison
-    //
-    rowSizer = new wxBoxSizer(wxHORIZONTAL);
-
-    groupSizer = new wxStaticBoxSizer(new wxStaticBox(panel,wxID_ANY,wxT(" wxOwnerDrawnComboBox ")),
-                                      wxVERTICAL);
-
-    groupSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Writable, sorted:")), 0,
-                     wxALIGN_CENTER_VERTICAL|wxRIGHT|wxEXPAND, border );
-
-    odc = new wxOwnerDrawnComboBox(panel,wxID_ANY,wxEmptyString,
-                                   wxDefaultPosition, wxDefaultSize,
-                                   arrItems,
-                                   wxCB_SORT // wxNO_BORDER|wxCB_READONLY
-                                  );
-
-    odc->Append(wxT("H - Appended Item")); // test sorting in append
-
-    odc->SetValue(wxT("Dot Dash"));
-
-    groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
-
-    //
-    // Readonly ODComboBox
-    groupSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Read-only:")), 0,
-                     wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
-
-    odc = new wxOwnerDrawnComboBox(panel,wxID_ANY,wxEmptyString,
-                                   wxDefaultPosition, wxDefaultSize,
-                                   arrItems,
-                                   wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
-                                  );
-
-    odc->SetValue(wxT("Dot Dash"));
-    odc->SetText(wxT("Dot Dash (Testing SetText)"));
-
-    groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
-
-    //
-    // Disabled ODComboBox
-    groupSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Disabled:")), 0,
-                   wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
-
-    odc = new wxOwnerDrawnComboBox(panel,wxID_ANY,wxEmptyString,
-                                     wxDefaultPosition, wxDefaultSize,
-                                     arrItems,
-                                     wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
-                                     );
-
-    odc->SetValue(wxT("Dot Dash"));
-    odc->Enable(false);
-
-    groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
-
-    rowSizer->Add( groupSizer, 1, wxEXPAND|wxALL, border );
+    m_arrItems.Add( wxT("Solid") );
+    m_arrItems.Add( wxT("Transparent") );
+    m_arrItems.Add( wxT("Dot") );
+    m_arrItems.Add( wxT("Long Dash") );
+    m_arrItems.Add( wxT("Short Dash") );
+    m_arrItems.Add( wxT("Dot Dash") );
+    m_arrItems.Add( wxT("Backward Diagonal Hatch") );
+    m_arrItems.Add( wxT("Cross-diagonal Hatch") );
+    m_arrItems.Add( wxT("Forward Diagonal Hatch") );
+    m_arrItems.Add( wxT("Cross Hatch") );
+    m_arrItems.Add( wxT("Horizontal Hatch") );
+    m_arrItems.Add( wxT("Vertical Hatch") );
 
 
-    groupSizer = new wxStaticBoxSizer(new wxStaticBox(panel,wxID_ANY,wxT(" wxComboBox ")),
-                                      wxVERTICAL);
-
     //
-    // wxComboBox
+    // Create pen selector ODComboBox with owner-drawn items
     //
-    groupSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Writable, sorted:")), 0,
-                     wxALIGN_CENTER_VERTICAL|wxRIGHT|wxEXPAND, border );
-
-    cb = new wxComboBox(panel,wxID_ANY,wxEmptyString,
-                        wxDefaultPosition, wxDefaultSize,
-                        arrItems,
-                        wxCB_SORT // wxNO_BORDER|wxCB_READONLY
-                       );
-
-    cb->Append(wxT("H - Appended Item")); // test sorting in append
-
-    cb->SetValue(wxT("Dot Dash"));
-
-    groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
-
-    //
-    // Readonly wxComboBox
-    groupSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Read-only:")), 0,
-                     wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
-
-    cb = new wxComboBox(panel,wxID_ANY,wxEmptyString,
-                        wxDefaultPosition, wxDefaultSize,
-                        arrItems,
-                        wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
-                       );
-
-    cb->SetValue(wxT("Dot Dash"));
-
-    groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
+    rowSizer->Add( new wxStaticText(panel,wxID_ANY,
+                   wxT("OwnerDrawnComboBox with owner-drawn items:")), 1,
+                   wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
+    colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
 
-    //
-    // Disabled wxComboBox
-    groupSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Disabled:")), 0,
-                   wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
 
-    cb = new wxComboBox(panel,wxID_ANY,wxEmptyString,
-                        wxDefaultPosition, wxDefaultSize,
-                        arrItems,
-                        wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
-                       );
 
-    cb->SetValue(wxT("Dot Dash"));
-    cb->Enable(false);
+    // When defining derivative class for callbacks, we need
+    // to use two-stage creation (or redefine the common wx
+    // constructor).
+    odc = new wxPenStyleComboBox();
+    odc->Create(panel,wxID_ANY,wxEmptyString,
+                wxDefaultPosition, wxDefaultSize,
+                m_arrItems,
+                wxCB_READONLY //wxNO_BORDER | wxCB_READONLY
+               );
 
-    groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
 
-    rowSizer->Add( groupSizer, 1, wxEXPAND|wxALL, border );
+    odc->SetSelection(0);
 
+    rowSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxALL, 4 );
+    rowSizer->AddStretchSpacer(1);
+    colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
 
-    colSizer->Add( rowSizer, 1, wxEXPAND|wxALL, border );
 
 
     //
-    // Pen selector ODComboBox with application painted items
+    // Same but with changed button position
     //
-    rowSizer = new wxBoxSizer ( wxHORIZONTAL );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
     rowSizer->Add( new wxStaticText(panel,wxID_ANY,
-                   wxT("OwnerDrawnComboBox with Custom Paint Items and Button Placing:")), 1,
+                   wxT("OwnerDrawnComboBox with owner-drawn items and button on the left:")), 1,
                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
 
-    rowSizer = new wxBoxSizer ( wxHORIZONTAL );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
+
 
     // When defining derivative class for callbacks, we need
     // to use two-stage creation (or redefine the common wx
     // constructor).
-    odc = new wxOwnerDrawnComboBox(panel,wxID_ANY,wxEmptyString,
-                                   wxDefaultPosition, wxDefaultSize,
-                                   arrItems,
-                                   wxCB_READONLY //wxNO_BORDER | wxCB_READONLY
-                                  );
+    odc = new wxPenStyleComboBox();
+    odc->Create(panel,wxID_ANY,wxEmptyString,
+                wxDefaultPosition, wxDefaultSize,
+                m_arrItems,
+                wxCB_READONLY //wxNO_BORDER | wxCB_READONLY
+               );
 
-    odc->SetPopupControl( new wxPenStylePopup() );
 
-    //m_odc->SetCustomPaintWidth( 60 );
     odc->SetSelection(0);
-    odc->SetButtonPosition(-2, // width adjustment
-                           -6, // height adjustment
+
+    // Use button size that is slightly smaller than the default.
+    wxSize butSize = odc->GetButtonSize();
+    odc->SetButtonPosition(butSize.x - 2, // button width
+                           butSize.y - 6, // button height
                            wxLEFT, // side
                            2 // horizontal spacing
                           );
@@ -849,40 +851,28 @@ MyFrame::MyFrame(const wxString& title)
     // List View wxComboCtrl
     //
 
-    rowSizer = new wxBoxSizer ( wxHORIZONTAL );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
     rowSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("List View wxComboCtrl:")), 1,
                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
-    rowSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Tree Ctrl wxGenericComboControl:")), 1,
+    rowSizer->Add( new wxStaticText(panel,wxID_ANY,wxT("Tree Ctrl wxComboControl:")), 1,
                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
 
-    rowSizer = new wxBoxSizer ( wxHORIZONTAL );
-    cc = new wxComboCtrl(panel,2,wxEmptyString,
-                            wxDefaultPosition, wxDefaultSize);
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
+    cc = new wxComboCtrlWithCustomPopupAnim();
+    cc->Create(panel, wxID_ANY, wxEmptyString);
+
+    // Make sure we use popup that allows focusing the listview.
+    cc->UseAltPopupWindow();
 
     cc->SetPopupMinWidth(300);
 
     ListViewComboPopup* iface = new ListViewComboPopup();
     cc->SetPopupControl(iface);
 
-    iface->AddSelection( wxT("Cabbage") );
-    iface->AddSelection( wxT("Potato") );
-    iface->AddSelection( wxT("Onion") );
-    iface->AddSelection( wxT("Carrot") );
-    iface->AddSelection( wxT("Cauliflower") );
-    iface->AddSelection( wxT("Bean") );
-    iface->AddSelection( wxT("Raddish") );
-    iface->AddSelection( wxT("Banana") );
-    iface->AddSelection( wxT("Apple") );
-    iface->AddSelection( wxT("Orange") );
-    iface->AddSelection( wxT("Kiwi") );
-    iface->AddSelection( wxT("Strawberry") );
-    iface->AddSelection( wxT("Cucumber") );
-    iface->AddSelection( wxT("Blackberry") );
-    iface->AddSelection( wxT("Melon") );
-    iface->AddSelection( wxT("Cherry") );
-    iface->AddSelection( wxT("Pea") );
-    iface->AddSelection( wxT("Pear") );
+    int i;
+    for ( i=0; i<100; i++ )
+        iface->AddSelection( wxString::Format(wxT("Item %02i"),i));
 
     rowSizer->Add( cc, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
 
@@ -891,9 +881,12 @@ MyFrame::MyFrame(const wxString& title)
     // Tree Ctrl wxComboCtrl
     //
 
-    // Note that we test that wxGenericComboControl works
-    gcc = new wxGenericComboControl(panel,wxID_ANY,wxEmptyString,
-                                    wxDefaultPosition, wxDefaultSize);
+    // Note that we test that wxGenericComboCtrl works
+    gcc = new wxGenericComboCtrl(panel,wxID_ANY,wxEmptyString,
+                                 wxDefaultPosition, wxDefaultSize);
+
+    // Make sure we use popup that allows focusing the treectrl.
+    gcc->UseAltPopupWindow();
 
     // Set popup interface right away, otherwise some of the calls
     // below may fail
@@ -905,24 +898,22 @@ MyFrame::MyFrame(const wxString& title)
 
     wxTreeItemId groupId;
 
-    groupId = tcPopup->AppendItem(rootId,wxT("Controls"));
-    tcPopup->AppendItem(groupId,wxT("wxButton"));
-    tcPopup->AppendItem(groupId,wxT("wxCheckBox"));
-    tcPopup->AppendItem(groupId,wxT("wxListCtrl"));
-    tcPopup->AppendItem(groupId,wxT("wxStaticBox"));
-    tcPopup->AppendItem(groupId,wxT("wxStaticText"));
-    tcPopup->AppendItem(groupId,wxT("wxTextCtrl"));
-    tcPopup->AppendItem(groupId,wxT("wxTreeCtrl"));
-    groupId = tcPopup->AppendItem(rootId,wxT("Dialogs"));
-    tcPopup->AppendItem(groupId,wxT("wxDirDialog"));
-    tcPopup->AppendItem(groupId,wxT("wxFileDialog"));
-    tcPopup->AppendItem(groupId,wxT("wxWizard"));
-
-    gcc->SetValue(wxT("wxStaticBox"));
+    for ( i=0; i<4; i++ )
+    {
+        groupId = tcPopup->AppendItem(rootId,
+            wxString::Format(wxT("Branch %02i"),i));
+
+        int n;
+        for ( n=0; n<25; n++ )
+            tcPopup->AppendItem(groupId,
+                wxString::Format(wxT("Subitem %02i"),(i*25)+n));
+    }
+
+    gcc->SetValue(wxT("Subitem 05"));
 
     // Move button to left - it makes more sense for a tree ctrl
-    gcc->SetButtonPosition(0, // width adjustment
-                           0, // height adjustment
+    gcc->SetButtonPosition(-1, // button width
+                           -1, // button height
                            wxLEFT, // side
                            0 // horizontal spacing
                           );
@@ -938,25 +929,25 @@ MyFrame::MyFrame(const wxString& title)
     // Custom Dropbutton Bitmaps
     // (second one uses blank button background)
     //
-    rowSizer = new wxBoxSizer ( wxHORIZONTAL );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
     rowSizer->Add( new wxStaticText(panel,wxID_ANY,
                    wxT("OwnerDrawnComboBox with simple dropbutton graphics:")), 1,
                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
 
     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
 
-    rowSizer = new wxBoxSizer ( wxHORIZONTAL );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
 
     odc = new wxOwnerDrawnComboBox(panel,wxID_ANY,wxEmptyString,
                                    wxDefaultPosition, wxDefaultSize,
-                                   arrItems,
+                                   m_arrItems,
                                    (long)0 // wxCB_SORT // wxNO_BORDER | wxCB_READONLY
                                   );
 
     wxOwnerDrawnComboBox* odc2;
     odc2 = new wxOwnerDrawnComboBox(panel,wxID_ANY,wxEmptyString,
                                     wxDefaultPosition, wxDefaultSize,
-                                    arrItems,
+                                    m_arrItems,
                                     (long)0 // wxCB_SORT // wxNO_BORDER | wxCB_READONLY
                                    );
 
@@ -965,7 +956,7 @@ MyFrame::MyFrame(const wxString& title)
     wxImage imgPressed(wxT("dropbutp.png"));
     wxImage imgHover(wxT("dropbuth.png"));
 
-    if ( imgNormal.Ok() && imgPressed.Ok() && imgHover.Ok() )
+    if ( imgNormal.IsOk() && imgPressed.IsOk() && imgHover.IsOk() )
     {
         wxBitmap bmpNormal(imgNormal);
         wxBitmap bmpPressed(imgPressed);
@@ -991,7 +982,7 @@ MyFrame::MyFrame(const wxString& title)
     //
     // wxComboCtrl with totally custom button action (open file dialog)
     //
-    rowSizer = new wxBoxSizer ( wxHORIZONTAL );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
     rowSizer->Add( new wxStaticText(panel,wxID_ANY,
                         wxT("wxComboCtrl with custom button action:")), 1,
                    wxALIGN_CENTER_VERTICAL|wxRIGHT, 4 );
@@ -999,7 +990,7 @@ MyFrame::MyFrame(const wxString& title)
 
     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
 
-    rowSizer = new wxBoxSizer ( wxHORIZONTAL );
+    rowSizer = new wxBoxSizer( wxHORIZONTAL );
     wxFileSelectorCombo* fsc;
 
     fsc = new wxFileSelectorCombo(panel,wxID_ANY,wxEmptyString,
@@ -1011,35 +1002,200 @@ MyFrame::MyFrame(const wxString& title)
     colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, 5 );
 
 
+    // Make sure GetFeatures is implemented
+    wxComboCtrl::GetFeatures();
+
+
     topRowSizer->Add( colSizer, 1, wxALL, 2 );
 
-    topRowSizer->Add( m_logWin, 1, wxEXPAND|wxALL, 5 );
+    colSizer = new wxBoxSizer( wxVERTICAL );
+
+    wxStaticBoxSizer* sbSizer = new wxStaticBoxSizer( new wxStaticBox(panel,
+                                                                      wxID_ANY,
+                                                                      wxT("Options")),
+                                                      wxVERTICAL );
+
+    m_cbUseAnim = new wxCheckBox(panel, wxID_ANY, wxT("Custom popup animation for ListView wxComboCtrl"));
+    m_cbUseAnim->SetValue(true);
+    sbSizer->Add( m_cbUseAnim, 0, wxALL, 3 );
+
+    colSizer->Add( sbSizer, 0, wxEXPAND|wxALL, 3 );
+    colSizer->AddSpacer(8);
+    colSizer->Add( new wxStaticText(panel, wxID_ANY, wxT("Log Messages:")), 0, wxTOP|wxLEFT, 3 );
+    colSizer->Add( m_logWin, 1, wxEXPAND|wxALL, 3 );
+
+    topRowSizer->Add( colSizer, 1, wxEXPAND|wxALL, 2 );
     topSizer->Add( topRowSizer, 1, wxEXPAND );
 
     panel->SetSizer( topSizer );
     topSizer->SetSizeHints( panel );
 
-    SetSize(740,480);
+    SetSize(740,400);
     Centre();
 }
 
-MyFrame::~MyFrame()
-{
-    delete wxLog::SetActiveTarget(m_logOld);
-}
-
 // event handlers
 
 void MyFrame::OnComboBoxUpdate( wxCommandEvent& event )
 {
     // Don't show messages for the log output window (it'll crash)
-    if ( event.GetId() == 105 )
+    if ( !event.GetEventObject()->IsKindOf(CLASSINFO(wxComboCtrl)) )
         return;
 
     if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
+    {
         wxLogDebug(wxT("EVT_COMBOBOX(id=%i,selection=%i)"),event.GetId(),event.GetSelection());
+    }
     else if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED )
+    {
         wxLogDebug(wxT("EVT_TEXT(id=%i,string=\"%s\")"),event.GetId(),event.GetString().c_str());
+    }
+}
+
+void MyFrame::OnShowComparison( wxCommandEvent& WXUNUSED(event) )
+{
+    //
+    // Show some wxOwnerDrawComboBoxes for comparison
+    //
+
+    wxBoxSizer* colSizer;
+    wxBoxSizer* rowSizer;
+    wxStaticBoxSizer* groupSizer;
+
+    wxComboBox* cb;
+    wxOwnerDrawnComboBox* odc;
+
+    const int border = 4;
+
+    wxDialog* dlg = new wxDialog(this,wxID_ANY,
+                                 wxT("Compare against wxComboBox"),
+                                 wxDefaultPosition,wxDefaultSize,
+                                 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
+
+    colSizer = new wxBoxSizer( wxVERTICAL );
+
+    rowSizer = new wxBoxSizer(wxHORIZONTAL);
+
+    groupSizer = new wxStaticBoxSizer(new wxStaticBox(dlg,wxID_ANY,wxT(" wxOwnerDrawnComboBox ")),
+                                      wxVERTICAL);
+
+    groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Writable, sorted:")), 0,
+                     wxALIGN_CENTER_VERTICAL|wxRIGHT|wxEXPAND, border );
+
+    odc = new wxOwnerDrawnComboBox(dlg,wxID_ANY,wxEmptyString,
+                                   wxDefaultPosition, wxDefaultSize,
+                                   m_arrItems,
+                                   wxCB_SORT // wxNO_BORDER|wxCB_READONLY
+                                  );
+
+    odc->Append(wxT("H - Appended Item")); // test sorting in append
+
+    odc->SetValue(wxT("Dot Dash"));
+
+    groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
+
+    //
+    // Readonly ODComboBox
+    groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Read-only:")), 0,
+                     wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
+
+    odc = new wxOwnerDrawnComboBox(dlg,wxID_ANY,wxEmptyString,
+                                   wxDefaultPosition, wxDefaultSize,
+                                   m_arrItems,
+                                   wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
+                                  );
+
+    odc->SetValue(wxT("Dot Dash"));
+    odc->SetText(wxT("Dot Dash (Testing SetText)"));
+
+    groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
+
+    //
+    // Disabled ODComboBox
+    groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Disabled:")), 0,
+                   wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
+
+    odc = new wxOwnerDrawnComboBox(dlg,wxID_ANY,wxEmptyString,
+                                     wxDefaultPosition, wxDefaultSize,
+                                     m_arrItems,
+                                     wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
+                                     );
+
+    odc->SetValue(wxT("Dot Dash"));
+    odc->Enable(false);
+
+    groupSizer->Add( odc, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
+
+    rowSizer->Add( groupSizer, 1, wxEXPAND|wxALL, border );
+
+
+    groupSizer = new wxStaticBoxSizer(new wxStaticBox(dlg,wxID_ANY,wxT(" wxComboBox ")),
+                                      wxVERTICAL);
+
+    //
+    // wxComboBox
+    //
+    groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Writable, sorted:")), 0,
+                     wxALIGN_CENTER_VERTICAL|wxRIGHT|wxEXPAND, border );
+
+    cb = new wxComboBox(dlg,wxID_ANY,wxEmptyString,
+                        wxDefaultPosition, wxDefaultSize,
+                        m_arrItems,
+                        wxCB_SORT // wxNO_BORDER|wxCB_READONLY
+                       );
+
+    cb->Append(wxT("H - Appended Item")); // test sorting in append
+
+    cb->SetValue(wxT("Dot Dash"));
+
+    groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
+
+    //
+    // Readonly wxComboBox
+    groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Read-only:")), 0,
+                     wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
+
+    cb = new wxComboBox(dlg,wxID_ANY,wxEmptyString,
+                        wxDefaultPosition, wxDefaultSize,
+                        m_arrItems,
+                        wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
+                       );
+
+    cb->SetValue(wxT("Dot Dash"));
+
+    groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
+
+    //
+    // Disabled wxComboBox
+    groupSizer->Add( new wxStaticText(dlg,wxID_ANY,wxT("Disabled:")), 0,
+                   wxALIGN_CENTER_VERTICAL|wxRIGHT, border );
+
+    cb = new wxComboBox(dlg,wxID_ANY,wxEmptyString,
+                        wxDefaultPosition, wxDefaultSize,
+                        m_arrItems,
+                        wxCB_SORT|wxCB_READONLY // wxNO_BORDER|wxCB_READONLY
+                       );
+
+    cb->SetValue(wxT("Dot Dash"));
+    cb->Enable(false);
+
+    groupSizer->Add( cb, 1, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxALL, border );
+
+    rowSizer->Add( groupSizer, 1, wxEXPAND|wxALL, border );
+
+    colSizer->Add( rowSizer, 0, wxEXPAND|wxALL, border );
+
+    dlg->SetSizer( colSizer );
+    colSizer->SetSizeHints( dlg );
+
+    dlg->SetSize(60,240);
+    dlg->Centre();
+    dlg->ShowModal();
+}
+
+MyFrame::~MyFrame()
+{
+    delete wxLog::SetActiveTarget(m_logOld);
 }
 
 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
@@ -1051,14 +1207,38 @@ void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
 {
     wxMessageBox(wxString::Format(
-                    _T("Welcome to %s!\n")
-                    _T("\n")
-                    _T("This is the wxWidgets wxComboCtrl sample\n")
-                    _T("running under %s."),
+                    wxT("Welcome to %s!\n")
+                    wxT("\n")
+                    wxT("This is the wxWidgets wxComboCtrl and wxOwnerDrawnComboBox sample\n")
+                    wxT("running under %s."),
                     wxVERSION_STRING,
                     wxGetOsDescription().c_str()
                  ),
-                 _T("About wxComboCtrl sample"),
+                 wxT("About wxComboCtrl sample"),
                  wxOK | wxICON_INFORMATION,
                  this);
 }
+
+void MyFrame::OnIdle(wxIdleEvent& event)
+{
+    // This code is useful for debugging focus problems
+    // (which are plentiful when dealing with popup windows).
+#if 0
+    static wxWindow* lastFocus = (wxWindow*) NULL;
+
+    wxWindow* curFocus = ::wxWindow::FindFocus();
+
+    if ( curFocus != lastFocus )
+    {
+        const wxChar* className = wxT("<none>");
+        if ( curFocus )
+            className = curFocus->GetClassInfo()->GetClassName();
+        lastFocus = curFocus;
+        wxLogDebug( wxT("FOCUSED: %s %X"),
+            className,
+            (unsigned int)curFocus);
+    }
+#endif
+
+    event.Skip();
+}