]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/listbox.cpp
Initialize all fields of struct tm used by wxDateTime::Format().
[wxWidgets.git] / src / univ / listbox.cpp
index 45e5f77e870c4a1db674fdf1c29cd44bb250a3cf..520ae86b20c61e16a44417ddee3e0ee08781e2d7 100644 (file)
 #include "wx/univ/inphand.h"
 #include "wx/univ/theme.h"
 
 #include "wx/univ/inphand.h"
 #include "wx/univ/theme.h"
 
+// ----------------------------------------------------------------------------
+// wxStdListboxInputHandler: handles mouse and kbd in a single or multi
+// selection listbox
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxStdListboxInputHandler : public wxStdInputHandler
+{
+public:
+    // if pressing the mouse button in a multiselection listbox should toggle
+    // the item under mouse immediately, then specify true as the second
+    // parameter (this is the standard behaviour, under GTK the item is toggled
+    // only when the mouse is released in the multi selection listbox)
+    wxStdListboxInputHandler(wxInputHandler *inphand,
+                             bool toggleOnPressAlways = true);
+
+    // base class methods
+    virtual bool HandleKey(wxInputConsumer *consumer,
+                           const wxKeyEvent& event,
+                           bool pressed);
+    virtual bool HandleMouse(wxInputConsumer *consumer,
+                             const wxMouseEvent& event);
+    virtual bool HandleMouseMove(wxInputConsumer *consumer,
+                                 const wxMouseEvent& event);
+
+protected:
+    // return the item under mouse, 0 if the mouse is above the listbox or
+    // GetCount() if it is below it
+    int HitTest(const wxListBox *listbox, const wxMouseEvent& event);
+
+    // parts of HitTest(): first finds the pseudo (because not in range) index
+    // of the item and the second one adjusts it if necessary - that is if the
+    // third one returns false
+    int HitTestUnsafe(const wxListBox *listbox, const wxMouseEvent& event);
+    int FixItemIndex(const wxListBox *listbox, int item);
+    bool IsValidIndex(const wxListBox *listbox, int item);
+
+    // init m_btnCapture and m_actionMouse
+    wxControlAction SetupCapture(wxListBox *lbox,
+                                 const wxMouseEvent& event,
+                                 int item);
+
+    wxRenderer *m_renderer;
+
+    // the button which initiated the mouse capture (currently 0 or 1)
+    int m_btnCapture;
+
+    // the action to perform when the mouse moves while we capture it
+    wxControlAction m_actionMouse;
+
+    // the ctor parameter toggleOnPressAlways (see comments near it)
+    bool m_toggleOnPressAlways;
+
+    // do we track the mouse outside the window when it is captured?
+    bool m_trackMouseOutside;
+};
+
 // ============================================================================
 // implementation of wxListBox
 // ============================================================================
 
 // ============================================================================
 // implementation of wxListBox
 // ============================================================================
 
-IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
 
 BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
     EVT_SIZE(wxListBox::OnSize)
 
 BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
     EVT_SIZE(wxListBox::OnSize)
@@ -59,7 +115,7 @@ void wxListBox::Init()
     m_maxWidth = 0;
     m_scrollRangeY = 0;
     m_maxWidthItem = -1;
     m_maxWidth = 0;
     m_scrollRangeY = 0;
     m_maxWidthItem = -1;
-    m_strings = NULL;
+    m_strings.unsorted = NULL;
 
     // no items hence no current item
     m_current = -1;
 
     // no items hence no current item
     m_current = -1;
@@ -136,11 +192,14 @@ bool wxListBox::Create(wxWindow *parent,
                             validator, name) )
         return false;
 
                             validator, name) )
         return false;
 
-    m_strings = new wxArrayString;
+    if ( IsSorted() )
+        m_strings.sorted = new wxSortedArrayString;
+    else
+        m_strings.unsorted = new wxArrayString;
 
     Set(n, choices);
 
 
     Set(n, choices);
 
-    SetBestSize(size);
+    SetInitialSize(size);
 
     CreateInputHandler(wxINP_HANDLER_LISTBOX);
 
 
     CreateInputHandler(wxINP_HANDLER_LISTBOX);
 
@@ -152,76 +211,59 @@ wxListBox::~wxListBox()
     // call this just to free the client data -- and avoid leaking memory
     DoClear();
 
     // call this just to free the client data -- and avoid leaking memory
     DoClear();
 
-    delete m_strings;
+    if ( IsSorted() )
+        delete m_strings.sorted;
+    else
+        delete m_strings.unsorted;
 
 
-    m_strings = NULL;
+    m_strings.sorted = NULL;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// adding/inserting strings
+// accessing strings
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-int wxCMPFUNC_CONV wxListBoxSortNoCase(wxString* s1, wxString* s2)
+unsigned int wxListBox::GetCount() const
 {
 {
-    return  s1->CmpNoCase(*s2);
+    return IsSorted() ? m_strings.sorted->size()
+                      : m_strings.unsorted->size();
 }
 
 }
 
-int wxListBox::DoAppendOnly(const wxString& item)
+wxString wxListBox::GetString(unsigned int n) const
 {
 {
-    unsigned int index;
-
-    if ( IsSorted() )
-    {
-        m_strings->Add(item);
-        m_strings->Sort(wxListBoxSortNoCase);
-        index = m_strings->Index(item);
-    }
-    else
-    {
-        index = m_strings->GetCount();
-        m_strings->Add(item);
-    }
-
-    return index;
+    return IsSorted() ? m_strings.sorted->Item(n)
+                      : m_strings.unsorted->Item(n);
 }
 
 }
 
-int wxListBox::DoAppend(const wxString& item)
+int wxListBox::FindString(const wxString& s, bool bCase) const
 {
 {
-    size_t index = DoAppendOnly( item );
+    return IsSorted() ? m_strings.sorted->Index(s, bCase)
+                      : m_strings.unsorted->Index(s, bCase);
+}
 
 
-    m_itemsClientData.Insert(NULL, index);
+// ----------------------------------------------------------------------------
+// adding/inserting strings
+// ----------------------------------------------------------------------------
 
 
-    m_updateScrollbarY = true;
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
+{
+    int idx = wxNOT_FOUND;
 
 
-    if ( HasHorzScrollbar() )
+    const unsigned int numItems = items.GetCount();
+    for ( unsigned int i = 0; i < numItems; ++i )
     {
     {
-        // has the max width increased?
-        wxCoord width;
-        GetTextExtent(item, &width, NULL);
-        if ( width > m_maxWidth )
-        {
-            m_maxWidth = width;
-            m_maxWidthItem = index;
-            m_updateScrollbarX = true;
-        }
-    }
-
-    RefreshFromItemToEnd(index);
-
-    return index;
-}
+        const wxString& item = items[i];
+        idx = IsSorted() ? m_strings.sorted->Add(item)
+                         : (m_strings.unsorted->Insert(item, pos), pos++);
 
 
-void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
-{
-    // the position of the item being added to a sorted listbox can't be
-    // specified
-    wxCHECK_RET( !IsSorted(), _T("can't insert items into sorted listbox") );
+        m_itemsClientData.Insert(NULL, idx);
+        AssignNewItemClientData(idx, clientData, i, type);
 
 
-    unsigned int count = items.GetCount();
-    for ( unsigned int n = 0; n < count; n++ )
-    {
-        m_strings->Insert(items[n], pos + n);
-        m_itemsClientData.Insert(NULL, pos + n);
+        // call the wxCheckListBox hook
+        OnItemInserted(idx);
     }
 
     // the number of items has changed so we might have to show the scrollbar
     }
 
     // the number of items has changed so we might have to show the scrollbar
@@ -235,36 +277,18 @@ void wxListBox::DoInsertItems(const wxArrayString& items, unsigned int pos)
     // note that we have to refresh all the items after the ones we inserted,
     // not just these items
     RefreshFromItemToEnd(pos);
     // note that we have to refresh all the items after the ones we inserted,
     // not just these items
     RefreshFromItemToEnd(pos);
-}
-
-void wxListBox::DoSetItems(const wxArrayString& items, void **clientData)
-{
-    DoClear();
-
-    unsigned int count = items.GetCount();
-    if ( !count )
-        return;
-
-    m_strings->Alloc(count);
 
 
-    m_itemsClientData.Alloc(count);
-    for ( unsigned int n = 0; n < count; n++ )
-    {
-        unsigned int index = DoAppendOnly(items[n]);
-
-        m_itemsClientData.Insert(clientData ? clientData[n] : NULL, index);
-    }
-
-    m_updateScrollbarY = true;
-
-    RefreshAll();
+    return idx;
 }
 
 void wxListBox::SetString(unsigned int n, const wxString& s)
 {
 }
 
 void wxListBox::SetString(unsigned int n, const wxString& s)
 {
-    wxCHECK_RET( !IsSorted(), _T("can't set string in sorted listbox") );
+    wxCHECK_RET( !IsSorted(), wxT("can't set string in sorted listbox") );
 
 
-    (*m_strings)[n] = s;
+    if ( IsSorted() )
+        (*m_strings.sorted)[n] = s;
+    else
+        (*m_strings.unsorted)[n] = s;
 
     if ( HasHorzScrollbar() )
     {
 
     if ( HasHorzScrollbar() )
     {
@@ -297,26 +321,15 @@ void wxListBox::SetString(unsigned int n, const wxString& s)
 
 void wxListBox::DoClear()
 {
 
 void wxListBox::DoClear()
 {
-    m_strings->Clear();
-
-    if ( HasClientObjectData() )
-    {
-        unsigned int count = m_itemsClientData.GetCount();
-        for ( unsigned int n = 0; n < count; n++ )
-        {
-            delete (wxClientData *) m_itemsClientData[n];
-        }
-    }
+    if ( IsSorted() )
+        m_strings.sorted->Clear();
+    else
+        m_strings.unsorted->Clear();
 
     m_itemsClientData.Clear();
     m_selections.Clear();
 
     m_current = -1;
 
     m_itemsClientData.Clear();
     m_selections.Clear();
 
     m_current = -1;
-}
-
-void wxListBox::Clear()
-{
-    DoClear();
 
     m_updateScrollbarY = true;
 
 
     m_updateScrollbarY = true;
 
@@ -325,21 +338,19 @@ void wxListBox::Clear()
     RefreshAll();
 }
 
     RefreshAll();
 }
 
-void wxListBox::Delete(unsigned int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
     wxCHECK_RET( IsValid(n),
 {
     wxCHECK_RET( IsValid(n),
-                 _T("invalid index in wxListBox::Delete") );
+                 wxT("invalid index in wxListBox::Delete") );
 
     // do it before removing the index as otherwise the last item will not be
     // refreshed (as GetCount() will be decremented)
     RefreshFromItemToEnd(n);
 
 
     // do it before removing the index as otherwise the last item will not be
     // refreshed (as GetCount() will be decremented)
     RefreshFromItemToEnd(n);
 
-    m_strings->RemoveAt(n);
-
-    if ( HasClientObjectData() )
-    {
-        delete (wxClientData *)m_itemsClientData[n];
-    }
+    if ( IsSorted() )
+        m_strings.sorted->RemoveAt(n);
+    else
+        m_strings.unsorted->RemoveAt(n);
 
     m_itemsClientData.RemoveAt(n);
 
 
     m_itemsClientData.RemoveAt(n);
 
@@ -402,16 +413,6 @@ void *wxListBox::DoGetItemClientData(unsigned int n) const
     return m_itemsClientData[n];
 }
 
     return m_itemsClientData[n];
 }
 
-void wxListBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
-{
-    m_itemsClientData[n] = clientData;
-}
-
-wxClientData* wxListBox::DoGetItemClientObject(unsigned int n) const
-{
-    return (wxClientData *)m_itemsClientData[n];
-}
-
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
@@ -420,7 +421,16 @@ void wxListBox::DoSetSelection(int n, bool select)
 {
     if ( select )
     {
 {
     if ( select )
     {
-        if ( m_selections.Index(n) == wxNOT_FOUND )
+        if ( n == wxNOT_FOUND )
+        {
+            if ( !HasMultipleSelection() )
+            {
+                // selecting wxNOT_FOUND is documented to deselect all items
+                DeselectAll();
+                return;
+            }
+        }
+        else if ( m_selections.Index(n) == wxNOT_FOUND )
         {
             if ( !HasMultipleSelection() )
             {
         {
             if ( !HasMultipleSelection() )
             {
@@ -450,7 +460,7 @@ void wxListBox::DoSetSelection(int n, bool select)
     // sanity check: a single selection listbox can't have more than one item
     // selected
     wxASSERT_MSG( HasMultipleSelection() || (m_selections.GetCount() < 2),
     // sanity check: a single selection listbox can't have more than one item
     // selected
     wxASSERT_MSG( HasMultipleSelection() || (m_selections.GetCount() < 2),
-                  _T("multiple selected items in single selection lbox?") );
+                  wxT("multiple selected items in single selection lbox?") );
 
     if ( select )
     {
 
     if ( select )
     {
@@ -462,12 +472,12 @@ void wxListBox::DoSetSelection(int n, bool select)
 int wxListBox::GetSelection() const
 {
     wxCHECK_MSG( !HasMultipleSelection(), wxNOT_FOUND,
 int wxListBox::GetSelection() const
 {
     wxCHECK_MSG( !HasMultipleSelection(), wxNOT_FOUND,
-                 _T("use wxListBox::GetSelections for ths listbox") );
+                 wxT("use wxListBox::GetSelections for ths listbox") );
 
     return m_selections.IsEmpty() ? wxNOT_FOUND : m_selections[0];
 }
 
 
     return m_selections.IsEmpty() ? wxNOT_FOUND : m_selections[0];
 }
 
-int wxCMPFUNC_CONV wxCompareInts(int *n, int *m)
+static int wxCMPFUNC_CONV wxCompareInts(int *n, int *m)
 {
     return *n - *m;
 }
 {
     return *n - *m;
 }
@@ -629,7 +639,7 @@ void wxListBox::UpdateItems()
     if ( m_updateCount == -1 )
     {
         // refresh all
     if ( m_updateCount == -1 )
     {
         // refresh all
-        wxLogTrace(_T("listbox"), _T("Refreshing all"));
+        wxLogTrace(wxT("listbox"), wxT("Refreshing all"));
 
         Refresh();
     }
 
         Refresh();
     }
@@ -646,7 +656,7 @@ void wxListBox::UpdateItems()
         // entire line(s)
         CalcScrolledPosition(0, rect.y, NULL, &rect.y);
 
         // entire line(s)
         CalcScrolledPosition(0, rect.y, NULL, &rect.y);
 
-        wxLogTrace(_T("listbox"), _T("Refreshing items %d..%d (%d-%d)"),
+        wxLogTrace(wxT("listbox"), wxT("Refreshing items %d..%d (%d-%d)"),
                    m_updateFrom, m_updateFrom + m_updateCount - 1,
                    rect.GetTop(), rect.GetBottom());
 
                    m_updateFrom, m_updateFrom + m_updateCount - 1,
                    rect.GetTop(), rect.GetBottom());
 
@@ -707,7 +717,7 @@ void wxListBox::DoDraw(wxControlRenderer *renderer)
     wxCoord lineHeight = GetLineHeight();
     unsigned int itemFirst = yTop / lineHeight,
                  itemLast = (yBottom + lineHeight - 1) / lineHeight,
     wxCoord lineHeight = GetLineHeight();
     unsigned int itemFirst = yTop / lineHeight,
                  itemLast = (yBottom + lineHeight - 1) / lineHeight,
-                 itemMax = m_strings->GetCount();
+                 itemMax = GetCount();
 
     if ( itemFirst >= itemMax )
         return;
 
     if ( itemFirst >= itemMax )
         return;
@@ -716,7 +726,7 @@ void wxListBox::DoDraw(wxControlRenderer *renderer)
         itemLast = itemMax;
 
     // do draw them
         itemLast = itemMax;
 
     // do draw them
-    wxLogTrace(_T("listbox"), _T("Repainting items %d..%d"),
+    wxLogTrace(wxT("listbox"), wxT("Repainting items %d..%d"),
                itemFirst, itemLast);
 
     DoDrawRange(renderer, itemFirst, itemLast);
                itemFirst, itemLast);
 
     DoDrawRange(renderer, itemFirst, itemLast);
@@ -776,7 +786,7 @@ wxCoord wxListBox::GetMaxWidth() const
     {
         wxListBox *self = wxConstCast(this, wxListBox);
         wxCoord width;
     {
         wxListBox *self = wxConstCast(this, wxListBox);
         wxCoord width;
-        unsigned int count = m_strings->GetCount();
+        unsigned int count = GetCount();
         for ( unsigned int n = 0; n < count; n++ )
         {
             GetTextExtent(this->GetString(n), &width, NULL);
         for ( unsigned int n = 0; n < count; n++ )
         {
             GetTextExtent(this->GetString(n), &width, NULL);
@@ -833,7 +843,7 @@ wxSize wxListBox::DoGetBestClientSize() const
     wxCoord width = 0,
             height = 0;
 
     wxCoord width = 0,
             height = 0;
 
-    unsigned int count = m_strings->GetCount();
+    unsigned int count = GetCount();
     for ( unsigned int n = 0; n < count; n++ )
     {
         wxCoord w,h;
     for ( unsigned int n = 0; n < count; n++ )
     {
         wxCoord w,h;
@@ -937,7 +947,7 @@ bool wxListBox::FindItem(const wxString& prefix, bool strictlyAfter)
     int last = first == 0 ? count - 1 : first - 1;
 
     // if this is not true we'd never exit from the loop below!
     int last = first == 0 ? count - 1 : first - 1;
 
     // if this is not true we'd never exit from the loop below!
-    wxASSERT_MSG( first < (int)count && last < (int)count, _T("logic error") );
+    wxASSERT_MSG( first < (int)count && last < (int)count, wxT("logic error") );
 
     // precompute it outside the loop
     size_t len = prefix.length();
 
     // precompute it outside the loop
     size_t len = prefix.length();
@@ -1183,13 +1193,21 @@ bool wxListBox::PerformAction(const wxControlAction& action,
         AnchorSelection(item == -1 ? m_current : item);
     else if ( action == wxACTION_LISTBOX_SELECTALL ||
               action == wxACTION_LISTBOX_SELTOGGLE )
         AnchorSelection(item == -1 ? m_current : item);
     else if ( action == wxACTION_LISTBOX_SELECTALL ||
               action == wxACTION_LISTBOX_SELTOGGLE )
-        wxFAIL_MSG(_T("unimplemented yet"));
+        wxFAIL_MSG(wxT("unimplemented yet"));
     else
         return wxControl::PerformAction(action, numArg, strArg);
 
     return true;
 }
 
     else
         return wxControl::PerformAction(action, numArg, strArg);
 
     return true;
 }
 
+/* static */
+wxInputHandler *wxListBox::GetStdInputHandler(wxInputHandler *handlerDef)
+{
+    static wxStdListboxInputHandler s_handler(handlerDef);
+
+    return &s_handler;
+}
+
 // ============================================================================
 // implementation of wxStdListboxInputHandler
 // ============================================================================
 // ============================================================================
 // implementation of wxStdListboxInputHandler
 // ============================================================================
@@ -1486,7 +1504,7 @@ bool wxStdListboxInputHandler::HandleMouseMove(wxInputConsumer *consumer,
         {
             // pass something into strArg to tell the listbox that it shouldn't
             // send the notification message: see PerformAction() above
         {
             // pass something into strArg to tell the listbox that it shouldn't
             // send the notification message: see PerformAction() above
-            lbox->PerformAction(m_actionMouse, item, _T("no"));
+            lbox->PerformAction(m_actionMouse, item, wxT("no"));
         }
         // else: don't pass invalid index to the listbox
     }
         }
         // else: don't pass invalid index to the listbox
     }