]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/combobox.cpp
assert if opening more than one find/replace dialog under the same parent -- this...
[wxWidgets.git] / src / univ / combobox.cpp
index 216ea60c58c38e1ea2d7ee5b631c8e1ee27534cd..ba970585eda85e72e7d86ba37579e72d2e82248f 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        univ/combobox.cpp
+// Name:        src/univ/combobox.cpp
 // Purpose:     wxComboControl and wxComboBox implementation
 // Author:      Vadim Zeitlin
 // Modified by:
@@ -9,16 +9,6 @@
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-/*
-    TODO:
-
-   +1. typing in the text should select the string in listbox
-   +2. scrollbars in listbox are unusable
-   +3. the initially selected item is not selected
-   ?4. kbd interface (what does GTK do?)
-    5. there is still autoscrolling without scrollbars - but is it bad?
- */
-
 // ============================================================================
 // declarations
 // ============================================================================
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __GNUG__
-    #pragma implementation "univcombobox.h"
-#endif
-
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
@@ -51,6 +37,7 @@
     #include "wx/validate.h"
 #endif
 
+#include "wx/tooltip.h"
 #include "wx/popupwin.h"
 
 #include "wx/univ/renderer.h"
    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
@@ -74,7 +67,7 @@ class wxComboButton : public wxBitmapButton
 {
 public:
     wxComboButton(wxComboControl *combo)
-        : wxBitmapButton(combo->GetParent(), -1, wxNullBitmap,
+        : wxBitmapButton(combo->GetParent(), wxID_ANY, wxNullBitmap,
                          wxDefaultPosition, wxDefaultSize,
                          wxBORDER_NONE | wxBU_EXACTFIT)
     {
@@ -96,7 +89,7 @@ public:
     }
 
 protected:
-    void OnButton(wxCommandEvent& event) { m_combo->ShowPopup(); }
+    void OnButton(wxCommandEvent& WXUNUSED(event)) { m_combo->ShowPopup(); }
 
     virtual wxSize DoGetBestClientSize() const
     {
@@ -125,9 +118,14 @@ public:
     virtual ~wxComboListBox();
 
     // implement wxComboPopup methods
-    virtual bool SetSelection(const wxString& value);
+    virtual bool SetSelection(const wxString& s);
     virtual wxControl *GetControl() { return this; }
     virtual void OnShow();
+    virtual wxCoord GetBestWidth() const;
+
+    // fix virtual function hiding
+    virtual void SetSelection(int n) { DoSetSelection(n, true); }
+    void SetSelection(int n, bool select) { DoSetSelection(n, select); }
 
 protected:
     // we shouldn't return height too big from here
@@ -182,12 +180,12 @@ private:
 // ----------------------------------------------------------------------------
 
 BEGIN_EVENT_TABLE(wxComboButton, wxButton)
-    EVT_BUTTON(-1, wxComboButton::OnButton)
+    EVT_BUTTON(wxID_ANY, wxComboButton::OnButton)
 END_EVENT_TABLE()
 
 BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
-    EVT_LISTBOX(-1, wxComboListBox::OnSelect)
-    EVT_LISTBOX_DCLICK(-1, wxComboListBox::OnSelect)
+    EVT_LISTBOX(wxID_ANY, wxComboListBox::OnSelect)
+    EVT_LISTBOX_DCLICK(wxID_ANY, wxComboListBox::OnSelect)
     EVT_MOTION(wxComboListBox::OnMouseMove)
     EVT_LEFT_UP(wxComboListBox::OnLeftUp)
 END_EVENT_TABLE()
@@ -200,10 +198,10 @@ END_EVENT_TABLE()
 BEGIN_EVENT_TABLE(wxComboTextCtrl, wxTextCtrl)
     EVT_KEY_DOWN(wxComboTextCtrl::OnKey)
     EVT_KEY_UP(wxComboTextCtrl::OnKey)
-    EVT_TEXT(-1, wxComboTextCtrl::OnText)
+    EVT_TEXT(wxID_ANY, wxComboTextCtrl::OnText)
 END_EVENT_TABLE()
 
-IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl);
+IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
 
 // ============================================================================
 // implementation
@@ -217,7 +215,7 @@ void wxComboControl::Init()
 {
     m_popup = (wxComboPopup *)NULL;
     m_winPopup = (wxPopupComboWindow *)NULL;
-    m_isPopupShown = FALSE;
+    m_isPopupShown = false;
     m_btn = NULL;
     m_text = NULL;
 }
@@ -236,7 +234,7 @@ bool wxComboControl::Create(wxWindow *parent,
     style &= ~wxBORDER_NONE;
     style |= wxBORDER_SUNKEN;
     if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
-        return FALSE;
+        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()
@@ -248,10 +246,10 @@ bool wxComboControl::Create(wxWindow *parent,
 
     // for compatibility with the other ports, the height specified is the
     // combined height of the combobox itself and the popup
-    if ( size.y == -1 )
+    if ( size.y == wxDefaultCoord )
     {
         // ok, use default height for popup too
-        m_heightPopup = -1;
+        m_heightPopup = wxDefaultCoord;
     }
     else
     {
@@ -267,20 +265,20 @@ bool wxComboControl::Create(wxWindow *parent,
 
     // 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;
+    // make IsEnabled() return true
+    wxControl::Enable(false); // don't use non virtual Disable() here!
+    m_isEnabled = true;
 
     CreateInputHandler(wxINP_HANDLER_COMBOBOX);
 
-    return TRUE;
+    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
+    // automatically by wxWidgets when we're deleted
     delete m_btn;
     delete m_text;
 
@@ -292,7 +290,7 @@ wxComboControl::~wxComboControl()
 // ----------------------------------------------------------------------------
 
 void wxComboControl::DoSetSize(int x, int y,
-                               int width, int height,
+                               int width, int WXUNUSED(height),
                                int sizeFlags)
 {
     // combo height is always fixed
@@ -303,8 +301,15 @@ 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(sizeBtn.x + sizeText.x, wxMax(sizeBtn.y, sizeText.y));
+    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)
@@ -333,18 +338,18 @@ void wxComboControl::DoMoveWindow(int x, int y, int width, int height)
 bool wxComboControl::Enable(bool enable)
 {
     if ( !wxControl::Enable(enable) )
-        return FALSE;
+        return false;
 
     m_btn->Enable(enable);
     m_text->Enable(enable);
 
-    return TRUE;
+    return true;
 }
 
 bool wxComboControl::Show(bool show)
 {
     if ( !wxControl::Show(show) )
-        return FALSE;
+        return false;
 
     if (m_btn)
         m_btn->Show(show);
@@ -352,9 +357,32 @@ bool wxComboControl::Show(bool show)
     if (m_text)
         m_text->Show(show);
 
-    return TRUE;
+    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
 // ----------------------------------------------------------------------------
@@ -373,7 +401,7 @@ void wxComboControl::ShowPopup()
 
     // size and position the popup window correctly
     m_winPopup->SetSize(GetSize().x,
-                        m_heightPopup == -1 ? control->GetBestSize().y
+                        m_heightPopup == wxDefaultCoord ? control->GetBestSize().y
                                             : m_heightPopup);
     wxSize sizePopup = m_winPopup->GetClientSize();
     control->SetSize(0, 0, sizePopup.x, sizePopup.y);
@@ -394,7 +422,7 @@ void wxComboControl::ShowPopup()
     m_text->SelectAll();
     m_popup->SetSelection(m_text->GetValue());
 
-    m_isPopupShown = TRUE;
+    m_isPopupShown = true;
 }
 
 void wxComboControl::HidePopup()
@@ -404,7 +432,7 @@ void wxComboControl::HidePopup()
 
     m_winPopup->Dismiss();
 
-    m_isPopupShown = FALSE;
+    m_isPopupShown = false;
 }
 
 void wxComboControl::OnSelect(const wxString& value)
@@ -429,7 +457,7 @@ wxComboTextCtrl::wxComboTextCtrl(wxComboControl *combo,
                                  const wxString& value,
                                  long style,
                                  const wxValidator& validator)
-               : wxTextCtrl(combo->GetParent(), -1, value,
+               : wxTextCtrl(combo->GetParent(), wxID_ANY, value,
                             wxDefaultPosition, wxDefaultSize,
                             wxBORDER_NONE | style,
                             validator)
@@ -492,7 +520,7 @@ void wxComboTextCtrl::OnKey(wxKeyEvent& event)
 // ----------------------------------------------------------------------------
 
 wxComboListBox::wxComboListBox(wxComboControl *combo, int style)
-              : wxListBox(combo->GetPopupWindow(), -1,
+              : wxListBox(combo->GetPopupWindow(), wxID_ANY,
                           wxDefaultPosition, wxDefaultSize,
                           0, NULL,
                           wxBORDER_SIMPLE | wxLB_INT_HEIGHT | style),
@@ -521,10 +549,10 @@ bool wxComboListBox::SetSelection(const wxString& value)
     else if ( !FindItem(value) )
     {
         // no match att all
-        return FALSE;
+        return false;
     }
 
-    return TRUE;
+    return true;
 }
 
 void wxComboListBox::OnSelect(wxCommandEvent& event)
@@ -544,13 +572,13 @@ void wxComboListBox::OnSelect(wxCommandEvent& event)
         event2.SetId(m_combo->GetId());
         m_combo->ProcessEvent(event2);
     }
-    //else: ignore the events resultign from just moving the mouse initially
+    //else: ignore the events resulting from just moving the mouse initially
 }
 
 void wxComboListBox::OnShow()
 {
     // nobody clicked us yet
-    m_clicked = FALSE;
+    m_clicked = false;
 }
 
 bool wxComboListBox::PerformAction(const wxControlAction& action,
@@ -563,7 +591,7 @@ 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;
+        return true;
     }
 
     return wxListBox::PerformAction(action, numArg, strArg);
@@ -572,7 +600,7 @@ bool wxComboListBox::PerformAction(const wxControlAction& action,
 void wxComboListBox::OnLeftUp(wxMouseEvent& event)
 {
     // we should dismiss the combo now
-    m_clicked = TRUE;
+    m_clicked = true;
 
     event.Skip();
 }
@@ -582,7 +610,7 @@ 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)
+    // it doesn't break anything anyhow)
     if ( this == wxWindow::GetCapture() )
     {
         if ( HitTest(event.GetPosition()) == wxHT_WINDOW_INSIDE )
@@ -595,6 +623,12 @@ void wxComboListBox::OnMouseMove(wxMouseEvent& event)
     }
 }
 
+wxCoord wxComboListBox::GetBestWidth() const
+{
+    wxSize size = wxListBox::GetBestSize();
+    return size.x;
+}
+
 wxSize wxComboListBox::DoGetBestClientSize() const
 {
     // don't return size too big or we risk to not fit on the screen
@@ -621,13 +655,44 @@ void wxComboBox::Init()
     m_lbox = (wxListBox *)NULL;
 }
 
+wxComboBox::wxComboBox(wxWindow *parent,
+                       wxWindowID id,
+                       const wxString& value,
+                       const wxPoint& pos,
+                       const wxSize& size,
+                       const wxArrayString& choices,
+                       long style,
+                       const wxValidator& validator,
+                       const wxString& name)
+{
+    Init();
+
+    Create(parent, id, value, pos, size, choices, style, validator, name);
+}
+
+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)
+{
+    wxCArrayString chs(choices);
+
+    return Create(parent, id, value, pos, size, chs.GetCount(),
+                  chs.GetStrings(), style, validator, name);
+}
+
 bool wxComboBox::Create(wxWindow *parent,
                         wxWindowID id,
                         const wxString& value,
                         const wxPoint& pos,
                         const wxSize& size,
                         int n,
-                        const wxString *choices,
+                        const wxString choices[],
                         long style,
                         const wxValidator& validator,
                         const wxString& name)
@@ -635,7 +700,7 @@ bool wxComboBox::Create(wxWindow *parent,
     if ( !wxComboControl::Create(parent, id, value, pos, size, style,
                                  validator, name) )
     {
-        return FALSE;
+        return false;
     }
 
     wxComboListBox *combolbox =
@@ -645,7 +710,7 @@ bool wxComboBox::Create(wxWindow *parent,
 
     SetPopupControl(combolbox);
 
-    return TRUE;
+    return true;
 }
 
 wxComboBox::~wxComboBox()
@@ -696,7 +761,7 @@ long wxComboBox::GetInsertionPoint() const
     return GetText()->GetInsertionPoint();
 }
 
-long wxComboBox::GetLastPosition() const
+wxTextPos wxComboBox::GetLastPosition() const
 {
     return GetText()->GetLastPosition();
 }
@@ -728,10 +793,16 @@ void wxComboBox::SetEditable(bool editable)
 void wxComboBox::Clear()
 {
     GetLBox()->Clear();
+    GetText()->SetValue(wxEmptyString);
 }
 
 void wxComboBox::Delete(int n)
 {
+    wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Delete") );
+
+    if (GetSelection() == n)
+        GetText()->SetValue(wxEmptyString);
+
     GetLBox()->Delete(n);
 }
 
@@ -742,22 +813,26 @@ int wxComboBox::GetCount() const
 
 wxString wxComboBox::GetString(int n) const
 {
+    wxCHECK_MSG( (n >= 0) && (n < GetCount()), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
+
     return GetLBox()->GetString(n);
 }
 
 void wxComboBox::SetString(int n, const wxString& s)
 {
+    wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("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 combobox index") );
+    wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Select") );
 
     GetLBox()->SetSelection(n);
     GetText()->SetValue(GetLBox()->GetString(n));
@@ -765,8 +840,15 @@ void wxComboBox::Select(int n)
 
 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
+    // in the list that it is the item that is selected!
     return FindString(GetText()->GetValue());
+#endif
 }
 
 int wxComboBox::DoAppend(const wxString& item)
@@ -774,6 +856,18 @@ int wxComboBox::DoAppend(const wxString& item)
     return GetLBox()->Append(item);
 }
 
+int wxComboBox::DoInsert(const wxString& item, int pos)
+{
+    wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
+    wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
+
+    if (pos == GetCount())
+        return DoAppend(item);
+
+    GetLBox()->Insert(item, pos);
+    return pos;
+}
+
 void wxComboBox::DoSetItemClientData(int n, void* clientData)
 {
     GetLBox()->SetClientData(n, clientData);
@@ -794,6 +888,69 @@ wxClientData* wxComboBox::DoGetItemClientObject(int n) const
     return GetLBox()->GetClientObject(n);
 }
 
+bool wxComboBox::IsEditable() const
+{
+    return GetText() != NULL && (!HasFlag(wxCB_READONLY) || GetText()->IsEditable());
+}
+
+void wxComboBox::Undo()
+{
+    if (IsEditable())
+        GetText()->Undo();
+}
+
+void wxComboBox::Redo()
+{
+    if (IsEditable())
+        GetText()->Redo();
+}
+
+void wxComboBox::SelectAll()
+{
+    GetText()->SelectAll();
+}
+
+bool wxComboBox::CanCopy() const
+{
+    if (GetText() != NULL)
+        return GetText()->CanCopy();
+    else
+        return false;
+}
+
+bool wxComboBox::CanCut() const
+{
+    if (GetText() != NULL)
+        return GetText()->CanCut();
+    else
+        return false;
+}
+
+bool wxComboBox::CanPaste() const
+{
+    if (IsEditable())
+        return GetText()->CanPaste();
+    else
+        return false;
+}
+
+bool wxComboBox::CanUndo() const
+{
+    if (IsEditable())
+        return GetText()->CanUndo();
+    else
+        return false;
+}
+
+bool wxComboBox::CanRedo() const
+{
+    if (IsEditable())
+        return GetText()->CanRedo();
+    else
+        return false;
+}
+
+
 // ----------------------------------------------------------------------------
 // input handling
 // ----------------------------------------------------------------------------
@@ -815,14 +972,14 @@ bool wxComboControl::PerformAction(const wxControlAction& action,
                                    long numArg,
                                    const wxString& strArg)
 {
-    bool processed = FALSE;
+    bool processed = false;
     if ( action == wxACTION_COMBOBOX_POPUP )
     {
         if ( !m_isPopupShown )
         {
             ShowPopup();
 
-            processed = TRUE;
+            processed = true;
         }
     }
     else if ( action == wxACTION_COMBOBOX_DISMISS )
@@ -831,7 +988,7 @@ bool wxComboControl::PerformAction(const wxControlAction& action,
         {
             HidePopup();
 
-            processed = TRUE;
+            processed = true;
         }
     }
 
@@ -841,7 +998,7 @@ bool wxComboControl::PerformAction(const wxControlAction& action,
         return wxControl::PerformAction(action, numArg, strArg);
     }
 
-    return TRUE;
+    return true;
 }
 
 // ----------------------------------------------------------------------------
@@ -871,11 +1028,11 @@ bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
                 break;
         }
 
-        if ( !!action )
+        if ( !action.IsEmpty() )
         {
             consumer->PerformAction(action);
 
-            return TRUE;
+            return true;
         }
     }