]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/listbox.cpp
making sure an empty label is not reserving place above, fixes #11123
[wxWidgets.git] / src / univ / listbox.cpp
index a4eda3e861b9d905667adbb23405c1440520a125..520ae86b20c61e16a44417ddee3e0ee08781e2d7 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        univ/listbox.cpp
+// Name:        src/univ/listbox.cpp
 // Purpose:     wxListBox implementation
 // Author:      Vadim Zeitlin
 // Modified by:
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __GNUG__
-    #pragma implementation "univlistbox.h"
-#endif
-
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
 #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
 // ============================================================================
 
-IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
 
 BEGIN_EVENT_TABLE(wxListBox, wxListBoxBase)
     EVT_SIZE(wxListBox::OnSize)
-
-    EVT_IDLE(wxListBox::OnIdle)
 END_EVENT_TABLE()
 
 // ----------------------------------------------------------------------------
@@ -65,11 +115,12 @@ void wxListBox::Init()
     m_maxWidth = 0;
     m_scrollRangeY = 0;
     m_maxWidthItem = -1;
+    m_strings.unsorted = NULL;
 
     // no items hence no current item
     m_current = -1;
     m_selAnchor = -1;
-    m_currentChanged = FALSE;
+    m_currentChanged = false;
 
     // no need to update anything initially
     m_updateCount = 0;
@@ -78,7 +129,37 @@ void wxListBox::Init()
     m_updateScrollbarX =
     m_showScrollbarX =
     m_updateScrollbarY =
-    m_showScrollbarY = FALSE;
+    m_showScrollbarY = false;
+}
+
+wxListBox::wxListBox(wxWindow *parent,
+                     wxWindowID id,
+                     const wxPoint &pos,
+                     const wxSize &size,
+                     const wxArrayString& choices,
+                     long style,
+                     const wxValidator& validator,
+                     const wxString &name)
+          :wxScrollHelper(this)
+{
+    Init();
+
+    Create(parent, id, pos, size, choices, style, validator, name);
+}
+
+bool wxListBox::Create(wxWindow *parent,
+                       wxWindowID id,
+                       const wxPoint &pos,
+                       const wxSize &size,
+                       const wxArrayString& choices,
+                       long style,
+                       const wxValidator& validator,
+                       const wxString &name)
+{
+    wxCArrayString chs(choices);
+
+    return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
+                  style, validator, name);
 }
 
 bool wxListBox::Create(wxWindow *parent,
@@ -101,71 +182,92 @@ bool wxListBox::Create(wxWindow *parent,
     if ( !(style & (wxLB_MULTIPLE | wxLB_EXTENDED)) )
         style |= wxLB_SINGLE;
 
-    if ( !wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name) )
-        return FALSE;
+#if wxUSE_TWO_WINDOWS
+    style |=  wxVSCROLL|wxHSCROLL;
+    if ((style & wxBORDER_MASK) == 0)
+        style |= wxBORDER_SUNKEN;
+#endif
 
-    SetWindow(this);
+    if ( !wxControl::Create(parent, id, pos, size, style,
+                            validator, name) )
+        return false;
 
-    if ( style & wxLB_SORT )
-        m_strings = wxArrayString(TRUE /* auto sort */);
+    if ( IsSorted() )
+        m_strings.sorted = new wxSortedArrayString;
+    else
+        m_strings.unsorted = new wxArrayString;
 
     Set(n, choices);
 
-    SetBestSize(size);
+    SetInitialSize(size);
 
     CreateInputHandler(wxINP_HANDLER_LISTBOX);
 
-    return TRUE;
+    return true;
 }
 
 wxListBox::~wxListBox()
 {
+    // call this just to free the client data -- and avoid leaking memory
+    DoClear();
+
+    if ( IsSorted() )
+        delete m_strings.sorted;
+    else
+        delete m_strings.unsorted;
+
+    m_strings.sorted = NULL;
 }
 
 // ----------------------------------------------------------------------------
-// adding/inserting strings
+// accessing strings
 // ----------------------------------------------------------------------------
 
-int wxListBox::DoAppend(const wxString& item)
+unsigned int wxListBox::GetCount() const
 {
-    size_t index = m_strings.Add(item);
-    m_itemsClientData.Insert(NULL, index);
-
-    m_updateScrollbarY = TRUE;
-
-    if ( HasHorzScrollbar() )
-    {
-        // has the max width increased?
-        wxCoord width;
-        GetTextExtent(item, &width, NULL);
-        if ( width > m_maxWidth )
-        {
-            m_maxWidth = width;
-            m_maxWidthItem = index;
-            m_updateScrollbarX = TRUE;
-        }
-    }
+    return IsSorted() ? m_strings.sorted->size()
+                      : m_strings.unsorted->size();
+}
 
-    RefreshFromItemToEnd(index);
+wxString wxListBox::GetString(unsigned int n) const
+{
+    return IsSorted() ? m_strings.sorted->Item(n)
+                      : m_strings.unsorted->Item(n);
+}
 
-    return index;
+int wxListBox::FindString(const wxString& s, bool bCase) const
+{
+    return IsSorted() ? m_strings.sorted->Index(s, bCase)
+                      : m_strings.unsorted->Index(s, bCase);
 }
 
-void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
+// ----------------------------------------------------------------------------
+// adding/inserting strings
+// ----------------------------------------------------------------------------
+
+int wxListBox::DoInsertItems(const wxArrayStringsAdapter& items,
+                             unsigned int pos,
+                             void **clientData,
+                             wxClientDataType type)
 {
-    // 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") );
+    int idx = wxNOT_FOUND;
 
-    size_t count = items.GetCount();
-    for ( size_t n = 0; n < count; n++ )
+    const unsigned int numItems = items.GetCount();
+    for ( unsigned int i = 0; i < numItems; ++i )
     {
-        m_strings.Insert(items[n], pos + n);
-        m_itemsClientData.Insert(NULL, pos + n);
+        const wxString& item = items[i];
+        idx = IsSorted() ? m_strings.sorted->Add(item)
+                         : (m_strings.unsorted->Insert(item, pos), pos++);
+
+        m_itemsClientData.Insert(NULL, idx);
+        AssignNewItemClientData(idx, clientData, i, type);
+
+        // call the wxCheckListBox hook
+        OnItemInserted(idx);
     }
 
     // the number of items has changed so we might have to show the scrollbar
-    m_updateScrollbarY = TRUE;
+    m_updateScrollbarY = true;
 
     // the max width also might have changed - just recalculate it instead of
     // keeping track of it here, this is probably more efficient for a typical
@@ -175,37 +277,25 @@ void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
     // note that we have to refresh all the items after the ones we inserted,
     // not just these items
     RefreshFromItemToEnd(pos);
+
+    return idx;
 }
 
-void wxListBox::DoSetItems(const wxArrayString& items, void **clientData)
+void wxListBox::SetString(unsigned int n, const wxString& s)
 {
-    DoClear();
+    wxCHECK_RET( !IsSorted(), wxT("can't set string in sorted listbox") );
 
-    size_t count = items.GetCount();
-    if ( !count )
-        return;
-
-    m_strings.Alloc(count);
-    m_itemsClientData.Alloc(count);
-    for ( size_t n = 0; n < count; n++ )
-    {
-        size_t index = m_strings.Add(items[n]);
-        m_itemsClientData.Insert(clientData ? clientData[n] : NULL, index);
-    }
-
-    m_updateScrollbarY = TRUE;
-
-    RefreshAll();
-}
+    if ( IsSorted() )
+        (*m_strings.sorted)[n] = s;
+    else
+        (*m_strings.unsorted)[n] = s;
 
-void wxListBox::SetString(int n, const wxString& s)
-{
     if ( HasHorzScrollbar() )
     {
         // we need to update m_maxWidth as changing the string may cause the
         // horz scrollbar [dis]appear
         wxCoord width;
-        m_strings[n] = s;
+
         GetTextExtent(s, &width, NULL);
 
         // it might have increased if the new string is long
@@ -213,18 +303,14 @@ void wxListBox::SetString(int n, const wxString& s)
         {
             m_maxWidth = width;
             m_maxWidthItem = n;
-            m_updateScrollbarX = TRUE;
+            m_updateScrollbarX = true;
         }
         // or also decreased if the old string was the longest one
-        else if ( n == m_maxWidthItem )
+        else if ( n == (unsigned int)m_maxWidthItem )
         {
             RefreshHorzScrollbar();
         }
     }
-    else // no horz scrollbar
-    {
-        m_strings[n] = s;
-    }
 
     RefreshItem(n);
 }
@@ -235,57 +321,45 @@ void wxListBox::SetString(int n, const wxString& s)
 
 void wxListBox::DoClear()
 {
-    m_strings.Clear();
-
-    if ( HasClientObjectData() )
-    {
-        size_t count = m_itemsClientData.GetCount();
-        for ( size_t 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;
-}
-
-void wxListBox::Clear()
-{
-    DoClear();
 
-    m_updateScrollbarY = TRUE;
+    m_updateScrollbarY = true;
 
     RefreshHorzScrollbar();
 
     RefreshAll();
 }
 
-void wxListBox::Delete(int n)
+void wxListBox::DoDeleteOneItem(unsigned int n)
 {
-    wxCHECK_RET( n < GetCount(), _T("invalid index in wxListBox::Delete") );
+    wxCHECK_RET( IsValid(n),
+                 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);
 
-    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);
 
     // when the item disappears we must not keep using its index
-    if ( n == m_current )
+    if ( (int)n == m_current )
     {
         m_current = -1;
     }
-    else if ( n < m_current )
+    else if ( (int)n < m_current )
     {
         m_current--;
     }
@@ -294,15 +368,15 @@ void wxListBox::Delete(int n)
     // update the selections array: the indices of all seletected items after
     // the one being deleted must change and the item itselfm ust be removed
     int index = wxNOT_FOUND;
-    size_t count = m_selections.GetCount();
-    for ( size_t item = 0; item < count; item++ )
+    unsigned int count = m_selections.GetCount();
+    for ( unsigned int item = 0; item < count; item++ )
     {
-        if ( m_selections[item] == n )
+        if ( m_selections[item] == (int)n )
         {
             // remember to delete it later
             index = item;
         }
-        else if ( m_selections[item] > n )
+        else if ( m_selections[item] > (int)n )
         {
             // to account for the index shift
             m_selections[item]--;
@@ -316,10 +390,10 @@ void wxListBox::Delete(int n)
     }
 
     // the number of items has changed, hence the scrollbar may disappear
-    m_updateScrollbarY = TRUE;
+    m_updateScrollbarY = true;
 
     // finally, if the longest item was deleted the scrollbar may disappear
-    if ( n == m_maxWidthItem )
+    if ( (int)n == m_maxWidthItem )
     {
         RefreshHorzScrollbar();
     }
@@ -329,35 +403,34 @@ void wxListBox::Delete(int n)
 // client data handling
 // ----------------------------------------------------------------------------
 
-void wxListBox::DoSetItemClientData(int n, void* clientData)
+void wxListBox::DoSetItemClientData(unsigned int n, void* clientData)
 {
     m_itemsClientData[n] = clientData;
 }
 
-void *wxListBox::DoGetItemClientData(int n) const
+void *wxListBox::DoGetItemClientData(unsigned int n) const
 {
     return m_itemsClientData[n];
 }
 
-void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData)
-{
-    m_itemsClientData[n] = clientData;
-}
-
-wxClientData* wxListBox::DoGetItemClientObject(int n) const
-{
-    return (wxClientData *)m_itemsClientData[n];
-}
-
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
 
-void wxListBox::SetSelection(int n, bool select)
+void wxListBox::DoSetSelection(int n, bool 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() )
             {
@@ -387,7 +460,7 @@ void wxListBox::SetSelection(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),
-                  _T("multiple selected items in single selection lbox?") );
+                  wxT("multiple selected items in single selection lbox?") );
 
     if ( select )
     {
@@ -398,13 +471,13 @@ void wxListBox::SetSelection(int n, bool select)
 
 int wxListBox::GetSelection() const
 {
-    wxCHECK_MSG( !HasMultipleSelection(), -1,
-                 _T("use wxListBox::GetSelections for ths listbox") );
+    wxCHECK_MSG( !HasMultipleSelection(), wxNOT_FOUND,
+                 wxT("use wxListBox::GetSelections for ths listbox") );
 
-    return m_selections.IsEmpty() ? -1 : 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;
 }
@@ -413,7 +486,7 @@ int wxListBox::GetSelections(wxArrayInt& selections) const
 {
     // always return sorted array to the user
     selections = m_selections;
-    size_t count = m_selections.GetCount();
+    unsigned int count = m_selections.GetCount();
 
     // don't call sort on an empty array
     if ( count )
@@ -503,7 +576,7 @@ void wxListBox::RefreshAll()
 void wxListBox::RefreshHorzScrollbar()
 {
     m_maxWidth = 0; // recalculate it
-    m_updateScrollbarX = TRUE;
+    m_updateScrollbarX = true;
 }
 
 void wxListBox::UpdateScrollbars()
@@ -511,9 +584,9 @@ void wxListBox::UpdateScrollbars()
     wxSize size = GetClientSize();
 
     // is our height enough to show all items?
-    int nLines = GetCount();
+    unsigned int nLines = GetCount();
     wxCoord lineHeight = GetLineHeight();
-    bool showScrollbarY = nLines*lineHeight > size.y;
+    bool showScrollbarY = (int)nLines*lineHeight > size.y;
 
     // check the width too if required
     wxCoord charWidth, maxWidth;
@@ -527,7 +600,7 @@ void wxListBox::UpdateScrollbars()
     else // never show it
     {
         charWidth = maxWidth = 0;
-        showScrollbarX = FALSE;
+        showScrollbarX = false;
     }
 
     // what should be the scrollbar range now?
@@ -566,7 +639,7 @@ void wxListBox::UpdateItems()
     if ( m_updateCount == -1 )
     {
         // refresh all
-        wxLogTrace(_T("listbox"), _T("Refreshing all"));
+        wxLogTrace(wxT("listbox"), wxT("Refreshing all"));
 
         Refresh();
     }
@@ -583,29 +656,29 @@ void wxListBox::UpdateItems()
         // 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());
 
-        Refresh(TRUE, &rect);
+        Refresh(true, &rect);
     }
 }
 
-void wxListBox::OnIdle(wxIdleEvent& event)
+void wxListBox::OnInternalIdle()
 {
     if ( m_updateScrollbarY || m_updateScrollbarX )
     {
         UpdateScrollbars();
 
         m_updateScrollbarX =
-        m_updateScrollbarY = FALSE;
+        m_updateScrollbarY = false;
     }
 
     if ( m_currentChanged )
     {
         DoEnsureVisible(m_current);
 
-        m_currentChanged = FALSE;
+        m_currentChanged = false;
     }
 
     if ( m_updateCount )
@@ -614,8 +687,7 @@ void wxListBox::OnIdle(wxIdleEvent& event)
 
         m_updateCount = 0;
     }
-
-    event.Skip();
+    wxListBoxBase::OnInternalIdle();
 }
 
 // ----------------------------------------------------------------------------
@@ -643,9 +715,9 @@ void wxListBox::DoDraw(wxControlRenderer *renderer)
 
     // get the items which must be redrawn
     wxCoord lineHeight = GetLineHeight();
-    size_t itemFirst = yTop / lineHeight,
-           itemLast = (yBottom + lineHeight - 1) / lineHeight,
-           itemMax = m_strings.GetCount();
+    unsigned int itemFirst = yTop / lineHeight,
+                 itemLast = (yBottom + lineHeight - 1) / lineHeight,
+                 itemMax = GetCount();
 
     if ( itemFirst >= itemMax )
         return;
@@ -654,7 +726,7 @@ void wxListBox::DoDraw(wxControlRenderer *renderer)
         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);
@@ -673,13 +745,13 @@ void wxListBox::DoDrawRange(wxControlRenderer *renderer,
 bool wxListBox::SetFont(const wxFont& font)
 {
     if ( !wxControl::SetFont(font) )
-        return FALSE;
+        return false;
 
     CalcItemsPerPage();
 
     RefreshAll();
 
-    return TRUE;
+    return true;
 }
 
 void wxListBox::CalcItemsPerPage()
@@ -714,10 +786,10 @@ wxCoord wxListBox::GetMaxWidth() const
     {
         wxListBox *self = wxConstCast(this, wxListBox);
         wxCoord width;
-        size_t count = m_strings.GetCount();
-        for ( size_t n = 0; n < count; n++ )
+        unsigned int count = GetCount();
+        for ( unsigned int n = 0; n < count; n++ )
         {
-            GetTextExtent(m_strings[n], &width, NULL);
+            GetTextExtent(this->GetString(n), &width, NULL);
             if ( width > m_maxWidth )
             {
                 self->m_maxWidth = width;
@@ -736,7 +808,7 @@ void wxListBox::OnSize(wxSizeEvent& event)
 
     // the scrollbars might [dis]appear
     m_updateScrollbarX =
-    m_updateScrollbarY = TRUE;
+    m_updateScrollbarY = true;
 
     event.Skip();
 }
@@ -763,7 +835,7 @@ void wxListBox::DoSetSize(int x, int y,
         height = ((height - hBorders + hLine - 1) / hLine)*hLine + hBorders;
     }
 
-    wxListBoxBase::DoSetSize(x, y, width, height);
+    wxListBoxBase::DoSetSize(x, y, width, height, sizeFlags);
 }
 
 wxSize wxListBox::DoGetBestClientSize() const
@@ -771,11 +843,11 @@ wxSize wxListBox::DoGetBestClientSize() const
     wxCoord width = 0,
             height = 0;
 
-    size_t count = m_strings.GetCount();
-    for ( size_t n = 0; n < count; n++ )
+    unsigned int count = GetCount();
+    for ( unsigned int n = 0; n < count; n++ )
     {
         wxCoord w,h;
-        GetTextExtent(m_strings[n], &w, &h);
+        GetTextExtent(this->GetString(n), &w, &h);
 
         if ( w > width )
             width = w;
@@ -805,11 +877,6 @@ wxSize wxListBox::DoGetBestClientSize() const
 
 bool wxListBox::SendEvent(wxEventType type, int item)
 {
-    // don't generate select events while the mouse is captured, we will only
-    // send them once it is released
-    if ( (type == wxEVT_COMMAND_LISTBOX_SELECTED) && (GetCapture() == this) )
-        return FALSE;
-
     wxCommandEvent event(type, m_windowId);
     event.SetEventObject(this);
 
@@ -830,7 +897,7 @@ bool wxListBox::SendEvent(wxEventType type, int item)
         event.SetString(GetString(item));
     }
 
-    event.m_commandInt = item;
+    event.SetInt(item);
 
     return GetEventHandler()->ProcessEvent(event);
 }
@@ -846,7 +913,7 @@ void wxListBox::SetCurrentItem(int n)
 
         if ( m_current != -1 )
         {
-            m_currentChanged = TRUE;
+            m_currentChanged = true;
 
             RefreshItem(m_current);
         }
@@ -856,11 +923,11 @@ void wxListBox::SetCurrentItem(int n)
 
 bool wxListBox::FindItem(const wxString& prefix, bool strictlyAfter)
 {
-    int count = GetCount();
-    if ( !count )
+    unsigned int count = GetCount();
+    if ( count==0 )
     {
         // empty listbox, we can't find anything in it
-        return FALSE;
+        return false;
     }
 
     // start either from the current item or from the next one if strictlyAfter
@@ -870,7 +937,7 @@ bool wxListBox::FindItem(const wxString& prefix, bool strictlyAfter)
     {
         // the following line will set first correctly to 0 if there is no
         // selection (m_current == -1)
-        first = m_current == count - 1 ? 0 : m_current + 1;
+        first = m_current == (int)(count - 1) ? 0 : m_current + 1;
     }
     else // start with the current
     {
@@ -880,15 +947,15 @@ 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!
-    wxASSERT_MSG( first < count && last < 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();
 
     // loop over all items in the listbox
-    for ( int item = first; item != last; item < count - 1 ? item++ : item = 0 )
+    for ( int item = first; item != (int)last; item < (int)(count - 1) ? item++ : item = 0 )
     {
-        if ( wxStrnicmp(m_strings[item], prefix, len) == 0 )
+        if ( wxStrnicmp(this->GetString(item).c_str(), prefix, len) == 0 )
         {
             SetCurrentItem(item);
 
@@ -901,12 +968,12 @@ bool wxListBox::FindItem(const wxString& prefix, bool strictlyAfter)
                     AnchorSelection(item);
             }
 
-            return TRUE;
+            return true;
         }
     }
 
     // nothing found
-    return FALSE;
+    return false;
 }
 
 void wxListBox::EnsureVisible(int n)
@@ -916,7 +983,7 @@ void wxListBox::EnsureVisible(int n)
         UpdateScrollbars();
 
         m_updateScrollbarX =
-        m_updateScrollbarY = FALSE;
+        m_updateScrollbarY = false;
     }
 
     DoEnsureVisible(n);
@@ -998,14 +1065,14 @@ void wxListBox::ExtendSelection(int itemTo)
         SetSelection(n);
     }
 
-    int count = GetCount();
-    for ( ; n < count; n++ )
+    unsigned int count = GetCount();
+    for ( ; n < (int)count; n++ )
     {
         Deselect(n);
     }
 }
 
-void wxListBox::Select(bool sel, int item)
+void wxListBox::DoSelect(int item, bool sel)
 {
     if ( item != -1 )
     {
@@ -1025,7 +1092,7 @@ void wxListBox::Select(bool sel, int item)
 
 void wxListBox::SelectAndNotify(int item)
 {
-    Select(TRUE, item);
+    DoSelect(item);
 
     SendEvent(wxEVT_COMMAND_LISTBOX_SELECTED);
 }
@@ -1044,7 +1111,7 @@ void wxListBox::Activate(int item)
 
     if ( item != -1 )
     {
-        Select(TRUE, item);
+        DoSelect(item);
 
         SendEvent(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED);
     }
@@ -1054,6 +1121,19 @@ void wxListBox::Activate(int item)
 // input handling
 // ----------------------------------------------------------------------------
 
+/*
+   The numArg here is the listbox item index while the strArg is used
+   differently for the different actions:
+
+   a) for wxACTION_LISTBOX_FIND it has the natural meaning: this is the string
+      to find
+
+   b) for wxACTION_LISTBOX_SELECT and wxACTION_LISTBOX_EXTENDSEL it is used
+      to decide if the listbox should send the notification event (it is empty)
+      or not (it is not): this allows us to reuse the same action for when the
+      user is dragging the mouse when it has been released although in the
+      first case no notification is sent while in the second it is sent.
+ */
 bool wxListBox::PerformAction(const wxControlAction& action,
                               long numArg,
                               const wxString& strArg)
@@ -1061,28 +1141,36 @@ bool wxListBox::PerformAction(const wxControlAction& action,
     int item = (int)numArg;
 
     if ( action == wxACTION_LISTBOX_SETFOCUS )
+    {
         SetCurrentItem(item);
+    }
     else if ( action == wxACTION_LISTBOX_ACTIVATE )
+    {
         Activate(item);
+    }
     else if ( action == wxACTION_LISTBOX_TOGGLE )
     {
         if ( item == -1 )
             item = m_current;
 
         if ( IsSelected(item) )
-            Unselect(item);
+            DoUnselect(item);
         else
             SelectAndNotify(item);
     }
     else if ( action == wxACTION_LISTBOX_SELECT )
     {
         DeselectAll(item);
-        SelectAndNotify(item);
+
+        if ( strArg.empty() )
+            SelectAndNotify(item);
+        else
+            DoSelect(item);
     }
     else if ( action == wxACTION_LISTBOX_SELECTADD )
-        Select(TRUE, item);
+        DoSelect(item);
     else if ( action == wxACTION_LISTBOX_UNSELECT )
-        Select(FALSE, item);
+        DoUnselect(item);
     else if ( action == wxACTION_LISTBOX_MOVEDOWN )
         ChangeCurrent(1);
     else if ( action == wxACTION_LISTBOX_MOVEUP )
@@ -1105,11 +1193,19 @@ bool wxListBox::PerformAction(const wxControlAction& action,
         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;
+    return true;
+}
+
+/* static */
+wxInputHandler *wxListBox::GetStdInputHandler(wxInputHandler *handlerDef)
+{
+    static wxStdListboxInputHandler s_handler(handlerDef);
+
+    return &s_handler;
 }
 
 // ============================================================================
@@ -1123,7 +1219,7 @@ wxStdListboxInputHandler::wxStdListboxInputHandler(wxInputHandler *handler,
     m_btnCapture = 0;
     m_toggleOnPressAlways = toggleOnPressAlways;
     m_actionMouse = wxACTION_NONE;
-    m_trackMouseOutside = TRUE;
+    m_trackMouseOutside = true;
 }
 
 int wxStdListboxInputHandler::HitTest(const wxListBox *lbox,
@@ -1152,7 +1248,7 @@ int wxStdListboxInputHandler::FixItemIndex(const wxListBox *lbox,
         // mouse is above the first item
         item = 0;
     }
-    else if ( item >= lbox->GetCount() )
+    else if ( (unsigned int)item >= lbox->GetCount() )
     {
         // mouse is below the last item
         item = lbox->GetCount() - 1;
@@ -1163,7 +1259,7 @@ int wxStdListboxInputHandler::FixItemIndex(const wxListBox *lbox,
 
 bool wxStdListboxInputHandler::IsValidIndex(const wxListBox *lbox, int item)
 {
-    return item >= 0 && item < lbox->GetCount();
+    return item >= 0 && (unsigned int)item < lbox->GetCount();
 }
 
 wxControlAction
@@ -1231,7 +1327,7 @@ wxStdListboxInputHandler::SetupCapture(wxListBox *lbox,
     }
 
     // by default we always do track it
-    m_trackMouseOutside = TRUE;
+    m_trackMouseOutside = true;
 
     return action;
 }
@@ -1243,7 +1339,7 @@ bool wxStdListboxInputHandler::HandleKey(wxInputConsumer *consumer,
     // we're only interested in the key press events
     if ( pressed && !event.AltDown() )
     {
-        bool isMoveCmd = TRUE;
+        bool isMoveCmd = true;
         int style = consumer->GetInputWindow()->GetWindowStyle();
 
         wxControlAction action;
@@ -1253,36 +1349,53 @@ bool wxStdListboxInputHandler::HandleKey(wxInputConsumer *consumer,
         switch ( keycode )
         {
             // movement
-            case WXK_UP:    action = wxACTION_LISTBOX_MOVEUP; break;
-            case WXK_DOWN:  action = wxACTION_LISTBOX_MOVEDOWN; break;
-            case WXK_PRIOR: action = wxACTION_LISTBOX_PAGEUP; break;
-            case WXK_NEXT:  action = wxACTION_LISTBOX_PAGEDOWN; break;
-            case WXK_HOME:  action = wxACTION_LISTBOX_START; break;
-            case WXK_END:   action = wxACTION_LISTBOX_END; break;
+            case WXK_UP:
+                action = wxACTION_LISTBOX_MOVEUP;
+                break;
+
+            case WXK_DOWN:
+                action = wxACTION_LISTBOX_MOVEDOWN;
+                break;
+
+            case WXK_PAGEUP:
+                action = wxACTION_LISTBOX_PAGEUP;
+                break;
+
+            case WXK_PAGEDOWN:
+                action = wxACTION_LISTBOX_PAGEDOWN;
+                break;
+
+            case WXK_HOME:
+                action = wxACTION_LISTBOX_START;
+                break;
+
+            case WXK_END:
+                action = wxACTION_LISTBOX_END;
+                break;
 
             // selection
             case WXK_SPACE:
                 if ( style & wxLB_MULTIPLE )
                 {
                     action = wxACTION_LISTBOX_TOGGLE;
-                    isMoveCmd = FALSE;
+                    isMoveCmd = false;
                 }
                 break;
 
             case WXK_RETURN:
                 action = wxACTION_LISTBOX_ACTIVATE;
-                isMoveCmd = FALSE;
+                isMoveCmd = false;
                 break;
 
             default:
-                if ( (keycode < 255) && wxIsalnum(keycode) )
+                if ( (keycode < 255) && wxIsalnum((wxChar)keycode) )
                 {
                     action = wxACTION_LISTBOX_FIND;
                     strArg = (wxChar)keycode;
                 }
         }
 
-        if ( !!action )
+        if ( !action.IsEmpty() )
         {
             consumer->PerformAction(action, -1, strArg);
 
@@ -1307,7 +1420,7 @@ bool wxStdListboxInputHandler::HandleKey(wxInputConsumer *consumer,
                 //else: nothing to do for multiple selection listboxes
             }
 
-            return TRUE;
+            return true;
         }
     }
 
@@ -1340,7 +1453,6 @@ bool wxStdListboxInputHandler::HandleMouse(wxInputConsumer *consumer,
             winCapture->ReleaseMouse();
             m_btnCapture = 0;
 
-            // generate the last event to triiger sending the selection event
             action = m_actionMouse;
         }
         //else: the mouse wasn't presed over the listbox, only released here
@@ -1350,11 +1462,11 @@ bool wxStdListboxInputHandler::HandleMouse(wxInputConsumer *consumer,
         action = wxACTION_LISTBOX_ACTIVATE;
     }
 
-    if ( !!action )
+    if ( !action.IsEmpty() )
     {
         lbox->PerformAction(action, item);
 
-        return TRUE;
+        return true;
     }
 
     return wxStdInputHandler::HandleMouse(consumer, event);
@@ -1374,7 +1486,7 @@ bool wxStdListboxInputHandler::HandleMouseMove(wxInputConsumer *consumer,
             // when we do it ourselves): in this case we only react to
             // the mouse messages when they happen inside the listbox
             if ( lbox->HitTest(event.GetPosition()) != wxHT_WINDOW_INSIDE )
-                return FALSE;
+                return false;
         }
 
         int item = HitTest(lbox, event);
@@ -1385,12 +1497,14 @@ bool wxStdListboxInputHandler::HandleMouseMove(wxInputConsumer *consumer,
             // events
             SetupCapture(lbox, event, item);
 
-            m_trackMouseOutside = FALSE;
+            m_trackMouseOutside = false;
         }
 
         if ( IsValidIndex(lbox, item) )
         {
-            lbox->PerformAction(m_actionMouse, item);
+            // pass something into strArg to tell the listbox that it shouldn't
+            // send the notification message: see PerformAction() above
+            lbox->PerformAction(m_actionMouse, item, wxT("no"));
         }
         // else: don't pass invalid index to the listbox
     }