]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/combobox.cpp
Fix discrepancy between different ways of measuring text extents under Mac.
[wxWidgets.git] / src / univ / combobox.cpp
index 53d2c180fc7685fff7ec97ad2d472069e96834a1..2a23793d7ed04b163ab0c7e4d4237b5f25c9d1fe 100644 (file)
@@ -1,6 +1,6 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        univ/combobox.cpp
-// Purpose:     wxComboControl and wxComboBox implementation
+// Name:        src/univ/combobox.cpp
+// Purpose:     wxComboBox implementation
 // Author:      Vadim Zeitlin
 // Modified by:
 // Created:     15.12.00
 // headers
 // ----------------------------------------------------------------------------
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-    #pragma implementation "univcombobox.h"
-#endif
-
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
 #endif
 
 #include "wx/tooltip.h"
-#include "wx/popupwin.h"
+#include "wx/combo.h"
 
 #include "wx/univ/renderer.h"
 #include "wx/univ/inphand.h"
 #include "wx/univ/theme.h"
 
-/*
-   The keyboard event flow:
-
-   1. they always come to the text ctrl
-   2. it forwards the ones it doesn't process to the wxComboControl
-   3. which passes them to the popup window if it is popped up
- */
-
-// constants
 // ----------------------------------------------------------------------------
-
-// the margin between the text control and the combo button
-static const wxCoord g_comboMargin = 2;
-
-// ----------------------------------------------------------------------------
-// wxComboButton is just a normal button except that it sends commands to the
-// combobox and not its parent
+// wxStdComboBoxInputHandler: allows the user to open/close the combo from kbd
 // ----------------------------------------------------------------------------
 
-class wxComboButton : public wxBitmapButton
+class WXDLLEXPORT wxStdComboBoxInputHandler : public wxStdInputHandler
 {
 public:
-    wxComboButton(wxComboControl *combo)
-        : wxBitmapButton(combo->GetParent(), -1, wxNullBitmap,
-                         wxDefaultPosition, wxDefaultSize,
-                         wxBORDER_NONE | wxBU_EXACTFIT)
-    {
-        m_combo = combo;
-
-        wxBitmap bmpNormal, bmpFocus, bmpPressed, bmpDisabled;
-
-        GetRenderer()->GetComboBitmaps(&bmpNormal,
-                                       &bmpFocus,
-                                       &bmpPressed,
-                                       &bmpDisabled);
-
-        SetBitmapLabel(bmpNormal);
-        SetBitmapFocus(bmpFocus.Ok() ? bmpFocus : bmpNormal);
-        SetBitmapSelected(bmpPressed.Ok() ? bmpPressed : bmpNormal);
-        SetBitmapDisabled(bmpDisabled.Ok() ? bmpDisabled : bmpNormal);
-
-        SetBestSize(wxDefaultSize);
-    }
-
-protected:
-    void OnButton(wxCommandEvent& WXUNUSED(event)) { m_combo->ShowPopup(); }
-
-    virtual wxSize DoGetBestClientSize() const
-    {
-        const wxBitmap& bmp = GetBitmapLabel();
+    wxStdComboBoxInputHandler(wxInputHandler *inphand);
 
-        return wxSize(bmp.GetWidth(), bmp.GetHeight());
-
-    }
-
-private:
-    wxComboControl *m_combo;
-
-    DECLARE_EVENT_TABLE()
+    virtual bool HandleKey(wxInputConsumer *consumer,
+                           const wxKeyEvent& event,
+                           bool pressed);
 };
 
 // ----------------------------------------------------------------------------
@@ -118,61 +67,32 @@ class wxComboListBox : public wxListBox, public wxComboPopup
 {
 public:
     // ctor and dtor
-    wxComboListBox(wxComboControl *combo, int style = 0);
+    wxComboListBox();
     virtual ~wxComboListBox();
 
     // implement wxComboPopup methods
-    virtual bool SetSelection(const wxString& value);
-    virtual void SetSelection(int n, bool select)
-        { wxListBox::SetSelection( n, select); };
-    virtual wxControl *GetControl() { return this; }
-    virtual void OnShow();
-    virtual wxCoord GetBestWidth() const;
-
-protected:
-    // we shouldn't return height too big from here
-    virtual wxSize DoGetBestClientSize() const;
+    virtual bool Create(wxWindow* parent);
+    virtual void SetStringValue(const wxString& s);
+    virtual wxString GetStringValue() const;
+    virtual wxWindow *GetControl() { return this; }
+    virtual void OnPopup();
+    virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight);
 
-    // filter mouse move events happening outside the list box
-    void OnMouseMove(wxMouseEvent& event);
-
-    // set m_clicked value from here
-    void OnLeftUp(wxMouseEvent& event);
-
-    // called whenever the user selects or activates a listbox item
-    void OnSelect(wxCommandEvent& event);
+    // fix virtual function hiding
+    virtual void SetSelection(int n) { DoSetSelection(n, true); }
+    void SetSelection(int n, bool select) { DoSetSelection(n, select); }
 
     // used to process wxUniv actions
     bool PerformAction(const wxControlAction& action,
                        long numArg,
                        const wxString& strArg);
 
-private:
-    // has the mouse been released on this control?
-    bool m_clicked;
-
-    DECLARE_EVENT_TABLE()
-};
-
-// ----------------------------------------------------------------------------
-// wxComboTextCtrl is a simple text ctrl which forwards
-// wxEVT_COMMAND_TEXT_UPDATED events and all key events to the combobox
-// ----------------------------------------------------------------------------
-
-class wxComboTextCtrl : public wxTextCtrl
-{
-public:
-    wxComboTextCtrl(wxComboControl *combo,
-                    const wxString& value,
-                    long style,
-                    const wxValidator& validator);
-
 protected:
-    void OnKey(wxKeyEvent& event);
-    void OnText(wxCommandEvent& event);
+    // set m_clicked value from here
+    void OnLeftUp(wxMouseEvent& event);
 
 private:
-    wxComboControl *m_combo;
+    friend class wxComboBox; // it accesses our DoGetItemClientData()
 
     DECLARE_EVENT_TABLE()
 };
@@ -181,425 +101,61 @@ private:
 // event tables and such
 // ----------------------------------------------------------------------------
 
-BEGIN_EVENT_TABLE(wxComboButton, wxButton)
-    EVT_BUTTON(-1, wxComboButton::OnButton)
-END_EVENT_TABLE()
-
 BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
-    EVT_LISTBOX(-1, wxComboListBox::OnSelect)
-    EVT_LISTBOX_DCLICK(-1, wxComboListBox::OnSelect)
-    EVT_MOTION(wxComboListBox::OnMouseMove)
     EVT_LEFT_UP(wxComboListBox::OnLeftUp)
 END_EVENT_TABLE()
 
-BEGIN_EVENT_TABLE(wxComboControl, wxControl)
-    EVT_KEY_DOWN(wxComboControl::OnKey)
-    EVT_KEY_UP(wxComboControl::OnKey)
-END_EVENT_TABLE()
-
-BEGIN_EVENT_TABLE(wxComboTextCtrl, wxTextCtrl)
-    EVT_KEY_DOWN(wxComboTextCtrl::OnKey)
-    EVT_KEY_UP(wxComboTextCtrl::OnKey)
-    EVT_TEXT(-1, wxComboTextCtrl::OnText)
-END_EVENT_TABLE()
-
-IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
+IMPLEMENT_DYNAMIC_CLASS2(wxComboBox, wxControl, wxComboCtrl)
 
 // ============================================================================
 // implementation
 // ============================================================================
 
 // ----------------------------------------------------------------------------
-// wxComboControl creation
-// ----------------------------------------------------------------------------
-
-wxComboControl::wxComboControl()
-{
-    Init();
-}
-
-wxComboControl::wxComboControl(wxWindow *parent,
-                               wxWindowID id,
-                               const wxString& value,
-                               const wxPoint& pos,
-                               const wxSize& size,
-                               long style,
-                               const wxValidator& validator,
-                               const wxString& name)
-{
-    Init();
-
-    (void)Create(parent, id, value, pos, size, style, validator, name);
-}
-
-void wxComboControl::Init()
-{
-    m_popup = (wxComboPopup *)NULL;
-    m_winPopup = (wxPopupComboWindow *)NULL;
-    m_isPopupShown = FALSE;
-    m_btn = NULL;
-    m_text = NULL;
-}
-
-bool wxComboControl::Create(wxWindow *parent,
-                            wxWindowID id,
-                            const wxString& value,
-                            const wxPoint& pos,
-                            const wxSize& size,
-                            long style,
-                            const wxValidator& validator,
-                            const wxString& name)
-{
-    // first create our own window, i.e. the one which will contain all
-    // subcontrols
-    style &= ~wxBORDER_NONE;
-    style |= wxBORDER_SUNKEN;
-    if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
-        return FALSE;
-
-    // create the text control and the button as our siblings (*not* children),
-    // don't care about size/position here - they will be set in DoMoveWindow()
-    m_btn = new wxComboButton(this);
-    m_text = new wxComboTextCtrl(this,
-                                 value,
-                                 style & wxCB_READONLY ? wxTE_READONLY : 0,
-                                 validator);
-
-    // for compatibility with the other ports, the height specified is the
-    // combined height of the combobox itself and the popup
-    if ( size.y == -1 )
-    {
-        // ok, use default height for popup too
-        m_heightPopup = -1;
-    }
-    else
-    {
-        m_heightPopup = size.y - DoGetBestSize().y;
-    }
-
-    SetBestSize(size);
-    Move(pos);
-
-    // create the popup window immediately here to allow creating the controls
-    // with parent == GetPopupWindow() from the derived class ctor
-    m_winPopup = new wxPopupComboWindow(this);
-
-    // have to disable this window to avoid interfering it with message
-    // processing to the text and the button... but pretend it is enabled to
-    // make IsEnabled() return TRUE
-    wxControl::Enable(FALSE); // don't use non virtual Disable() here!
-    m_isEnabled = TRUE;
-
-    CreateInputHandler(wxINP_HANDLER_COMBOBOX);
-
-    return TRUE;
-}
-
-wxComboControl::~wxComboControl()
-{
-    // as the button and the text control are the parent's children and not
-    // ours, we have to delete them manually - they are not deleted
-    // automatically by wxWindows when we're deleted
-    delete m_btn;
-    delete m_text;
-
-    delete m_winPopup;
-}
-
-// ----------------------------------------------------------------------------
-// geometry stuff
-// ----------------------------------------------------------------------------
-
-void wxComboControl::DoSetSize(int x, int y,
-                               int width, int WXUNUSED(height),
-                               int sizeFlags)
-{
-    // combo height is always fixed
-    wxControl::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags);
-}
-
-wxSize wxComboControl::DoGetBestClientSize() const
-{
-    wxSize sizeBtn = m_btn->GetBestSize(),
-           sizeText = m_text->GetBestSize();
-    wxCoord widthPopup = 0;
-
-    if (m_popup)
-    {
-        widthPopup = m_popup->GetBestWidth();
-    }
-
-    return wxSize(wxMax(sizeText.x + g_comboMargin + sizeBtn.x, widthPopup), 
-                  wxMax(sizeBtn.y, sizeText.y));
-}
-
-void wxComboControl::DoMoveWindow(int x, int y, int width, int height)
-{
-    wxControl::DoMoveWindow(x, y, width, height);
-
-    // position the subcontrols inside the client area
-    wxRect rectBorders = GetRenderer()->GetBorderDimensions(GetBorder());
-    x += rectBorders.x;
-    y += rectBorders.y;
-    width -= rectBorders.x + rectBorders.width;
-    height -= rectBorders.y + rectBorders.height;
-
-    wxSize sizeBtn = m_btn->GetBestSize();
-
-    wxCoord wText = width - sizeBtn.x;
-    wxPoint p = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
-    m_text->SetSize(x - p.x, y - p.y, wText, height);
-    m_btn->SetSize(x - p.x + wText, y - p.y, sizeBtn.x, height);
-}
-
-// ----------------------------------------------------------------------------
-// operations
-// ----------------------------------------------------------------------------
-
-bool wxComboControl::Enable(bool enable)
-{
-    if ( !wxControl::Enable(enable) )
-        return FALSE;
-
-    m_btn->Enable(enable);
-    m_text->Enable(enable);
-
-    return TRUE;
-}
-
-bool wxComboControl::Show(bool show)
-{
-    if ( !wxControl::Show(show) )
-        return FALSE;
-
-    if (m_btn)
-        m_btn->Show(show);
-
-    if (m_text)
-        m_text->Show(show);
-
-    return TRUE;
-}
-
-#if wxUSE_TOOLTIPS
-void wxComboControl::DoSetToolTip(wxToolTip *tooltip)
-{
-    wxControl::DoSetToolTip(tooltip);    
-
-    // Set tool tip for button and text box
-    if (m_text && m_btn)
-    {
-        if (tooltip)
-        {
-            const wxString &tip = tooltip->GetTip();
-            m_text->SetToolTip(tip);
-            m_btn->SetToolTip(tip);
-        }
-        else
-        {
-            m_text->SetToolTip(NULL);
-            m_btn->SetToolTip(NULL);
-        }
-    }
-}
-#endif // wxUSE_TOOLTIPS
-
-// ----------------------------------------------------------------------------
-// popup window handling
+// wxComboListBox
 // ----------------------------------------------------------------------------
 
-void wxComboControl::SetPopupControl(wxComboPopup *popup)
-{
-    m_popup = popup;
-}
-
-void wxComboControl::ShowPopup()
+wxComboListBox::wxComboListBox() : wxListBox(), wxComboPopup()
 {
-    wxCHECK_RET( m_popup, _T("no popup to show in wxComboControl") );
-    wxCHECK_RET( !IsPopupShown(), _T("popup window already shown") );
-
-    wxControl *control = m_popup->GetControl();
-
-    // size and position the popup window correctly
-    m_winPopup->SetSize(GetSize().x,
-                        m_heightPopup == -1 ? control->GetBestSize().y
-                                            : m_heightPopup);
-    wxSize sizePopup = m_winPopup->GetClientSize();
-    control->SetSize(0, 0, sizePopup.x, sizePopup.y);
-
-    // some controls don't accept the size we give then: e.g. a listbox may
-    // require more space to show its last row
-    wxSize sizeReal = control->GetSize();
-    if ( sizeReal != sizePopup )
-    {
-        m_winPopup->SetClientSize(sizeReal);
-    }
-
-    m_winPopup->PositionNearCombo();
-
-    // show it
-    m_popup->OnShow();
-    m_winPopup->Popup(m_text);
-    m_text->SelectAll();
-    m_popup->SetSelection(m_text->GetValue());
-
-    m_isPopupShown = TRUE;
 }
 
-void wxComboControl::HidePopup()
+bool wxComboListBox::Create(wxWindow* parent)
 {
-    wxCHECK_RET( m_popup, _T("no popup to hide in wxComboControl") );
-    wxCHECK_RET( IsPopupShown(), _T("popup window not shown") );
-
-    m_winPopup->Dismiss();
-
-    m_isPopupShown = FALSE;
-}
-
-void wxComboControl::OnSelect(const wxString& value)
-{
-    m_text->SetValue(value);
-    m_text->SelectAll();
-
-    OnDismiss();
-}
-
-void wxComboControl::OnDismiss()
-{
-    HidePopup();
-    m_text->SetFocus();
-}
-
-// ----------------------------------------------------------------------------
-// wxComboTextCtrl
-// ----------------------------------------------------------------------------
-
-wxComboTextCtrl::wxComboTextCtrl(wxComboControl *combo,
-                                 const wxString& value,
-                                 long style,
-                                 const wxValidator& validator)
-               : wxTextCtrl(combo->GetParent(), -1, value,
+    if ( !wxListBox::Create(parent, wxID_ANY,
                             wxDefaultPosition, wxDefaultSize,
-                            wxBORDER_NONE | style,
-                            validator)
-{
-    m_combo = combo;
-}
-
-void wxComboTextCtrl::OnText(wxCommandEvent& event)
-{
-    if ( m_combo->IsPopupShown() )
-    {
-        m_combo->GetPopupControl()->SetSelection(GetValue());
-    }
-
-    // we need to make a copy of the event to have the correct originating
-    // object and id
-    wxCommandEvent event2 = event;
-    event2.SetEventObject(m_combo);
-    event2.SetId(m_combo->GetId());
-
-    // there is a small incompatibility with wxMSW here: the combobox gets the
-    // event before the text control in our case which corresponds to SMW
-    // CBN_EDITUPDATE notification and not CBN_EDITCHANGE one wxMSW currently
-    // uses
-    //
-    // if this is really a problem, we can play games with the event handlers
-    // to circumvent this
-    (void)m_combo->ProcessEvent(event2);
-
-    event.Skip();
-}
-
-// pass the keys we don't process to the combo first
-void wxComboTextCtrl::OnKey(wxKeyEvent& event)
-{
-    switch ( event.GetKeyCode() )
-    {
-        case WXK_RETURN:
-            // the popup control gets it first but only if it is shown
-            if ( !m_combo->IsPopupShown() )
-                break;
-            //else: fall through
-
-        case WXK_UP:
-        case WXK_DOWN:
-        case WXK_ESCAPE:
-        case WXK_PAGEDOWN:
-        case WXK_PAGEUP:
-        case WXK_PRIOR:
-        case WXK_NEXT:
-            (void)m_combo->ProcessEvent(event);
-            return;
-    }
-
-    event.Skip();
-}
+                            0, NULL,
+                            wxBORDER_SIMPLE |
+                            ( m_combo->GetWindowStyle() & wxCB_SORT ? wxLB_SORT : 0 ) ) )
+        return false;
 
-// ----------------------------------------------------------------------------
-// wxComboListBox
-// ----------------------------------------------------------------------------
-
-wxComboListBox::wxComboListBox(wxComboControl *combo, int style)
-              : wxListBox(combo->GetPopupWindow(), -1,
-                          wxDefaultPosition, wxDefaultSize,
-                          0, NULL,
-                          wxBORDER_SIMPLE | wxLB_INT_HEIGHT | style),
-                wxComboPopup(combo)
-{
     // we don't react to the mouse events outside the window at all
     StopAutoScrolling();
+
+    return true;
 }
 
 wxComboListBox::~wxComboListBox()
 {
 }
 
-bool wxComboListBox::SetSelection(const wxString& value)
+wxString wxComboListBox::GetStringValue() const
 {
-    // FindItem() would just find the current item for an empty string (it
-    // always matches), but we want to show the first one in such case
-    if ( value.empty() )
-    {
-        if ( GetCount() )
-        {
-            wxListBox::SetSelection(0);
-        }
-        //else: empty listbox - nothing to do
-    }
-    else if ( !FindItem(value) )
-    {
-        // no match att all
-        return FALSE;
-    }
-
-    return TRUE;
+    return wxListBox::GetStringSelection();
 }
 
-void wxComboListBox::OnSelect(wxCommandEvent& event)
+void wxComboListBox::SetStringValue(const wxString& value)
 {
-    if ( m_clicked )
+    if ( !value.empty() )
     {
-        // first update the combo and close the listbox
-        m_combo->OnSelect(event.GetString());
-
-        // next let the user code have the event
-
-        // all fields are already filled by the listbox, just change the event
-        // type and send it to the combo
-        wxCommandEvent event2 = event;
-        event2.SetEventType(wxEVT_COMMAND_COMBOBOX_SELECTED);
-        event2.SetEventObject(m_combo);
-        event2.SetId(m_combo->GetId());
-        m_combo->ProcessEvent(event2);
+        if (FindString(value) != wxNOT_FOUND)
+            wxListBox::SetStringSelection(value);
     }
-    //else: ignore the events resultign from just moving the mouse initially
+    else
+        wxListBox::SetSelection(-1);
 }
 
-void wxComboListBox::OnShow()
+void wxComboListBox::OnPopup()
 {
-    // nobody clicked us yet
-    m_clicked = FALSE;
 }
 
 bool wxComboListBox::PerformAction(const wxControlAction& action,
@@ -611,8 +167,8 @@ bool wxComboListBox::PerformAction(const wxControlAction& action,
     {
         // we don't let the listbox handle this as instead of just using the
         // single key presses, as usual, we use the text ctrl value as prefix
-        // and this is done by wxComboControl itself
-        return TRUE;
+        // and this is done by wxComboCtrl itself
+        return true;
     }
 
     return wxListBox::PerformAction(action, numArg, strArg);
@@ -621,59 +177,35 @@ bool wxComboListBox::PerformAction(const wxControlAction& action,
 void wxComboListBox::OnLeftUp(wxMouseEvent& event)
 {
     // we should dismiss the combo now
-    m_clicked = TRUE;
-
-    event.Skip();
-}
+    // first update the combo and close the listbox
+    Dismiss();
+    m_combo->SetValue(wxListBox::GetStringSelection());
 
-void wxComboListBox::OnMouseMove(wxMouseEvent& event)
-{
-    // while a wxComboListBox is shown, it always has capture, so if it doesn't
-    // we're about to go away anyhow (normally this shouldn't happen at all,
-    // but I don't put assert here as it just might do on other platforms and
-    // it doesn't break anythign anyhow)
-    if ( this == wxWindow::GetCapture() )
-    {
-        if ( HitTest(event.GetPosition()) == wxHT_WINDOW_INSIDE )
-        {
-            event.Skip();
-        }
-        //else: popup shouldn't react to the mouse motions outside it, it only
-        //      captures the mouse to be able to detect when it must be
-        //      dismissed, so don't call Skip()
-    }
-}
+    // next let the user code have the event
+    wxCommandEvent evt(wxEVT_COMMAND_COMBOBOX_SELECTED,m_combo->GetId());
+    evt.SetInt(wxListBox::GetSelection());
+    evt.SetEventObject(m_combo);
+    m_combo->ProcessWindowEvent(evt);
 
-wxCoord wxComboListBox::GetBestWidth() const
-{
-    wxSize size = wxListBox::GetBestSize();
-    return size.x;
+    event.Skip();
 }
 
-wxSize wxComboListBox::DoGetBestClientSize() const
+wxSize wxComboListBox::GetAdjustedSize(int minWidth,
+                                       int WXUNUSED(prefHeight),
+                                       int maxHeight)
 {
-    // don't return size too big or we risk to not fit on the screen
-    wxSize size = wxListBox::DoGetBestClientSize();
-    wxCoord hChar = GetCharHeight();
-
-    int nLines = size.y / hChar;
-
-    // 10 is the same limit as used by wxMSW
-    if ( nLines > 10 )
-    {
-        size.y = 10*hChar;
-    }
-
-    return size;
+    wxSize bestSize = wxListBox::GetBestSize();
+    return wxSize(wxMax(bestSize.x,minWidth),
+                  wxMin(bestSize.y,maxHeight));
 }
 
 // ----------------------------------------------------------------------------
 // wxComboBox
 // ----------------------------------------------------------------------------
 
-wxComboBox::wxComboBox()
+void wxComboBox::Init()
 {
-    Init();
+    m_lbox = NULL;
 }
 
 wxComboBox::wxComboBox(wxWindow *parent,
@@ -681,21 +213,30 @@ wxComboBox::wxComboBox(wxWindow *parent,
                        const wxString& value,
                        const wxPoint& pos,
                        const wxSize& size,
-                       int n,
-                       const wxString *choices,
+                       const wxArrayString& choices,
                        long style,
                        const wxValidator& validator,
                        const wxString& name)
 {
     Init();
 
-    (void)Create(parent, id, value, pos, size, n, choices,
-                 style, validator, name);
+    Create(parent, id, value, pos, size, choices, style, validator, name);
 }
 
-void wxComboBox::Init()
+bool wxComboBox::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)
 {
-    m_lbox = (wxListBox *)NULL;
+    wxCArrayString chs(choices);
+
+    return Create(parent, id, value, pos, size, chs.GetCount(),
+                  chs.GetStrings(), style, validator, name);
 }
 
 bool wxComboBox::Create(wxWindow *parent,
@@ -704,25 +245,24 @@ bool wxComboBox::Create(wxWindow *parent,
                         const wxPoint& pos,
                         const wxSize& size,
                         int n,
-                        const wxString *choices,
+                        const wxString choices[],
                         long style,
                         const wxValidator& validator,
                         const wxString& name)
 {
-    if ( !wxComboControl::Create(parent, id, value, pos, size, style,
+    if ( !wxComboCtrl::Create(parent, id, value, pos, size, style,
                                  validator, name) )
     {
-        return FALSE;
+        return false;
     }
 
-    wxComboListBox *combolbox =
-        new wxComboListBox(this, style & wxCB_SORT ? wxLB_SORT : 0);
+    wxComboListBox *combolbox = new wxComboListBox();
+    SetPopupControl(combolbox);
+
     m_lbox = combolbox;
     m_lbox->Set(n, choices);
 
-    SetPopupControl(combolbox);
-
-    return TRUE;
+    return true;
 }
 
 wxComboBox::~wxComboBox()
@@ -733,121 +273,140 @@ wxComboBox::~wxComboBox()
 // wxComboBox methods forwarded to wxTextCtrl
 // ----------------------------------------------------------------------------
 
-wxString wxComboBox::GetValue() const
+wxString wxComboBox::DoGetValue() const
 {
-    return GetText()->GetValue();
+    return wxComboCtrl::GetValue();
 }
 
 void wxComboBox::SetValue(const wxString& value)
 {
-    GetText()->SetValue(value);
+    wxComboCtrl::SetValue(value);
+}
+
+void wxComboBox::WriteText(const wxString& value)
+{
+    if ( GetTextCtrl() ) GetTextCtrl()->WriteText(value);
 }
 
 void wxComboBox::Copy()
 {
-    GetText()->Copy();
+    if ( GetTextCtrl() ) GetTextCtrl()->Copy();
 }
 
 void wxComboBox::Cut()
 {
-    GetText()->Cut();
+    if ( GetTextCtrl() ) GetTextCtrl()->Cut();
 }
 
 void wxComboBox::Paste()
 {
-    GetText()->Paste();
+    if ( GetTextCtrl() ) GetTextCtrl()->Paste();
 }
 
 void wxComboBox::SetInsertionPoint(long pos)
 {
-    GetText()->SetInsertionPoint(pos);
+    if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPoint(pos);
 }
 
 void wxComboBox::SetInsertionPointEnd()
 {
-    GetText()->SetInsertionPointEnd();
+    if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPointEnd();
 }
 
 long wxComboBox::GetInsertionPoint() const
 {
-    return GetText()->GetInsertionPoint();
+    if ( GetTextCtrl() )
+        return GetTextCtrl()->GetInsertionPoint();
+    return -1;
 }
 
-long wxComboBox::GetLastPosition() const
+wxTextPos wxComboBox::GetLastPosition() const
 {
-    return GetText()->GetLastPosition();
+    if ( GetTextCtrl() )
+        return GetTextCtrl()->GetLastPosition();
+    return -1;
 }
 
 void wxComboBox::Replace(long from, long to, const wxString& value)
 {
-    GetText()->Replace(from, to, value);
+    if ( GetTextCtrl() ) GetTextCtrl()->Replace(from, to, value);
 }
 
 void wxComboBox::Remove(long from, long to)
 {
-    GetText()->Remove(from, to);
+    if ( GetTextCtrl() ) GetTextCtrl()->Remove(from, to);
 }
 
 void wxComboBox::SetSelection(long from, long to)
 {
-    GetText()->SetSelection(from, to);
+    if ( GetTextCtrl() ) GetTextCtrl()->SetSelection(from, to);
+}
+
+void wxComboBox::GetSelection(long *from, long *to) const
+{
+    if ( GetTextCtrl() ) GetTextCtrl()->GetSelection(from, to);
 }
 
 void wxComboBox::SetEditable(bool editable)
 {
-    GetText()->SetEditable(editable);
+    if ( GetTextCtrl() ) GetTextCtrl()->SetEditable(editable);
 }
 
 // ----------------------------------------------------------------------------
 // wxComboBox methods forwarded to wxListBox
 // ----------------------------------------------------------------------------
 
-void wxComboBox::Clear()
+void wxComboBox::DoClear()
 {
     GetLBox()->Clear();
-    GetText()->SetValue(wxEmptyString);
+    if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
 }
 
-void wxComboBox::Delete(int n)
+void wxComboBox::DoDeleteOneItem(unsigned int n)
 {
-    wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Delete") );
+    wxCHECK_RET( IsValid(n), wxT("invalid index in wxComboBox::Delete") );
 
-    if (GetSelection() == n)
-        GetText()->SetValue(wxEmptyString);
+    if (GetSelection() == (int)n)
+        if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
 
     GetLBox()->Delete(n);
 }
 
-int wxComboBox::GetCount() const
+unsigned int wxComboBox::GetCount() const
 {
     return GetLBox()->GetCount();
 }
 
-wxString wxComboBox::GetString(int n) const
+wxString wxComboBox::GetString(unsigned int n) const
 {
-    wxCHECK_MSG( (n >= 0) && (n < GetCount()), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
+    wxCHECK_MSG( IsValid(n), wxEmptyString, wxT("invalid index in wxComboBox::GetString") );
 
     return GetLBox()->GetString(n);
 }
 
-void wxComboBox::SetString(int n, const wxString& s)
+void wxComboBox::SetString(unsigned int n, const wxString& s)
 {
-    wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::SetString") );
+    wxCHECK_RET( IsValid(n), wxT("invalid index in wxComboBox::SetString") );
 
     GetLBox()->SetString(n, s);
 }
 
-int wxComboBox::FindString(const wxString& s) const
+int wxComboBox::FindString(const wxString& s, bool bCase) const
 {
-    return GetLBox()->FindString(s);
+    return GetLBox()->FindString(s, bCase);
 }
 
-void wxComboBox::Select(int n)
+void wxComboBox::SetSelection(int n)
 {
-    wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Select") );
+    wxCHECK_RET( (n == wxNOT_FOUND || IsValid(n)), wxT("invalid index in wxComboBox::Select") );
 
     GetLBox()->SetSelection(n);
-    GetText()->SetValue(GetLBox()->GetString(n));
+
+    wxString str;
+    if ( n != wxNOT_FOUND )
+        str = GetLBox()->GetString(n);
+
+    SetText(str);
 }
 
 int wxComboBox::GetSelection() const
@@ -855,101 +414,109 @@ int wxComboBox::GetSelection() const
 #if 1 // FIXME:: What is the correct behavior?
     // if the current value isn't one of the listbox strings, return -1
     return GetLBox()->GetSelection();
-#else    
-    // Why oh why is this done this way? 
-    // It is not because the value displayed in the text can be found 
+#else
+    // Why oh why is this done this way?
+    // It is not because the value displayed in the text can be found
     // in the list that it is the item that is selected!
-    return FindString(GetText()->GetValue());
+    return FindString(if ( GetTextCtrl() ) GetTextCtrl()->GetValue());
 #endif
 }
 
-int wxComboBox::DoAppend(const wxString& item)
+wxString wxComboBox::GetStringSelection() const
 {
-    return GetLBox()->Append(item);
+    return GetLBox()->GetStringSelection();
 }
 
-int wxComboBox::DoInsert(const wxString& item, int pos)
+wxClientDataType wxComboBox::GetClientDataType() const
 {
-    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
-    wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
+    return GetLBox()->GetClientDataType();
+}
 
-    if (pos == GetCount())
-        return DoAppend(item);
+void wxComboBox::SetClientDataType(wxClientDataType clientDataItemsType)
+{
+    GetLBox()->SetClientDataType(clientDataItemsType);
+}
 
-    GetLBox()->Insert(item, pos);
-    return pos;
+int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
+                              unsigned int pos,
+                              void **clientData, wxClientDataType type)
+{
+    return GetLBox()->DoInsertItems(items, pos, clientData, type);
 }
 
-void wxComboBox::DoSetItemClientData(int n, void* clientData)
+void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
 {
-    GetLBox()->SetClientData(n, clientData);
+    GetLBox()->DoSetItemClientData(n, clientData);
 }
 
-void *wxComboBox::DoGetItemClientData(int n) const
+void *wxComboBox::DoGetItemClientData(unsigned int n) const
 {
-    return GetLBox()->GetClientData(n);
+    return GetLBox()->DoGetItemClientData(n);
 }
 
-void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData)
+bool wxComboBox::IsEditable() const
 {
-    GetLBox()->SetClientObject(n, clientData);
+    return GetTextCtrl() != NULL && (!HasFlag(wxCB_READONLY) || GetTextCtrl()->IsEditable() );
 }
 
-wxClientData* wxComboBox::DoGetItemClientObject(int n) const
+void wxComboBox::Undo()
 {
-    return GetLBox()->GetClientObject(n);
+    if (IsEditable())
+        if ( GetTextCtrl() ) GetTextCtrl()->Undo();
 }
 
-// ----------------------------------------------------------------------------
-// input handling
-// ----------------------------------------------------------------------------
+void wxComboBox::Redo()
+{
+    if (IsEditable())
+        if ( GetTextCtrl() ) GetTextCtrl()->Redo();
+}
 
-void wxComboControl::OnKey(wxKeyEvent& event)
+void wxComboBox::SelectAll()
 {
-    if ( m_isPopupShown )
-    {
-        // pass it to the popped up control
-        (void)m_popup->GetControl()->ProcessEvent(event);
-    }
-    else // no popup
-    {
-        event.Skip();
-    }
+    if ( GetTextCtrl() ) GetTextCtrl()->SelectAll();
 }
 
-bool wxComboControl::PerformAction(const wxControlAction& action,
-                                   long numArg,
-                                   const wxString& strArg)
+bool wxComboBox::CanCopy() const
 {
-    bool processed = FALSE;
-    if ( action == wxACTION_COMBOBOX_POPUP )
-    {
-        if ( !m_isPopupShown )
-        {
-            ShowPopup();
+    if (GetTextCtrl() != NULL)
+        return GetTextCtrl()->CanCopy();
+    else
+        return false;
+}
 
-            processed = TRUE;
-        }
-    }
-    else if ( action == wxACTION_COMBOBOX_DISMISS )
-    {
-        if ( m_isPopupShown )
-        {
-            HidePopup();
+bool wxComboBox::CanCut() const
+{
+    if (GetTextCtrl() != NULL)
+        return GetTextCtrl()->CanCut();
+    else
+        return false;
+}
 
-            processed = TRUE;
-        }
-    }
+bool wxComboBox::CanPaste() const
+{
+    if (IsEditable())
+        return GetTextCtrl()->CanPaste();
+    else
+        return false;
+}
 
-    if ( !processed )
-    {
-        // pass along
-        return wxControl::PerformAction(action, numArg, strArg);
-    }
+bool wxComboBox::CanUndo() const
+{
+    if (IsEditable())
+        return GetTextCtrl()->CanUndo();
+    else
+        return false;
+}
 
-    return TRUE;
+bool wxComboBox::CanRedo() const
+{
+    if (IsEditable())
+        return GetTextCtrl()->CanRedo();
+    else
+        return false;
 }
 
+
 // ----------------------------------------------------------------------------
 // wxStdComboBoxInputHandler
 // ----------------------------------------------------------------------------
@@ -977,15 +544,23 @@ bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
                 break;
         }
 
-        if ( !!action )
+        if ( !action.IsEmpty() )
         {
             consumer->PerformAction(action);
 
-            return TRUE;
+            return true;
         }
     }
 
     return wxStdInputHandler::HandleKey(consumer, event, pressed);
 }
 
+/* static */
+wxInputHandler *wxComboBox::GetStdInputHandler(wxInputHandler *handlerDef)
+{
+    static wxStdComboBoxInputHandler s_handler(handlerDef);
+
+    return &s_handler;
+}
+
 #endif // wxUSE_COMBOBOX