X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6c8a980fc412792e64256724e02e9d387ee38e21..e136b7476372a2ce0a51a43a0ffc3f31a1e2b2d5:/src/msw/listbox.cpp diff --git a/src/msw/listbox.cpp b/src/msw/listbox.cpp index 06aae2979a..662b86359f 100644 --- a/src/msw/listbox.cpp +++ b/src/msw/listbox.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: listbox.cpp +// Name: src/msw/listbox.cpp // Purpose: wxListBox // Author: Julian Smart // Modified by: Vadim Zeitlin (owner drawn stuff) @@ -20,8 +20,7 @@ #pragma hdrstop #endif -#include "wx/window.h" -#include "wx/msw/private.h" +#if wxUSE_LISTBOX #ifndef WX_PRECOMP #include "wx/listbox.h" @@ -32,13 +31,10 @@ #include "wx/utils.h" #endif -#include +#include "wx/window.h" +#include "wx/msw/private.h" -#ifdef __WXWINE__ - #if defined(GetWindowStyle) - #undef GetWindowStyle - #endif -#endif +#include #include "wx/dynarray.h" #include "wx/log.h" @@ -48,43 +44,12 @@ #endif #ifndef __TWIN32__ - #if defined(__GNUWIN32__) - #ifndef wxUSE_NORLANDER_HEADERS - #include - #endif + #ifdef __GNUWIN32_OLD__ + #include "wx/msw/gnuwin32/extra.h" #endif #endif -#ifdef __WXWINE__ - #ifndef ListBox_SetItemData - #define ListBox_SetItemData(hwndCtl, index, data) \ - ((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMDATA, (WPARAM)(int)(index), (LPARAM)(data))) - #endif - #ifndef ListBox_GetHorizontalExtent - #define ListBox_GetHorizontalExtent(hwndCtl) \ - ((int)(DWORD)SendMessage((hwndCtl), LB_GETHORIZONTALEXTENT, 0L, 0L)) - #endif - #ifndef ListBox_GetSelCount - #define ListBox_GetSelCount(hwndCtl) \ - ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELCOUNT, 0L, 0L)) - #endif - #ifndef ListBox_GetSelItems - #define ListBox_GetSelItems(hwndCtl, cItems, lpItems) \ - ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELITEMS, (WPARAM)(int)(cItems), (LPARAM)(int *)(lpItems))) - #endif - #ifndef ListBox_GetTextLen - #define ListBox_GetTextLen(hwndCtl, index) \ - ((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXTLEN, (WPARAM)(int)(index), 0L)) - #endif - #ifndef ListBox_GetText - #define ListBox_GetText(hwndCtl, index, lpszBuffer) \ - ((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXT, (WPARAM)(int)(index), (LPARAM)(LPCTSTR)(lpszBuffer))) - #endif -#endif - -#if !USE_SHARED_LIBRARY - IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl) -#endif +IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl) // ============================================================================ // list box item declaration and implementation @@ -95,7 +60,7 @@ class wxListBoxItem : public wxOwnerDrawn { public: - wxListBoxItem(const wxString& str = ""); + wxListBoxItem(const wxString& str = wxEmptyString); }; wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE) @@ -104,7 +69,7 @@ wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE) SetMarginWidth(0); } -wxOwnerDrawn *wxListBox::CreateItem(size_t n) +wxOwnerDrawn *wxListBox::CreateLboxItem(size_t WXUNUSED(n)) { return new wxListBoxItem(); } @@ -140,13 +105,14 @@ bool wxListBox::Create(wxWindow *parent, m_selected = 0; SetName(name); +#if wxUSE_VALIDATORS SetValidator(validator); +#endif // wxUSE_VALIDATORS if (parent) parent->AddChild(this); - wxSystemSettings settings; - SetBackgroundColour(settings.GetSystemColour(wxSYS_COLOUR_WINDOW)); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); SetForegroundColour(parent->GetForegroundColour()); m_windowId = ( id == -1 ) ? (int)NewControlId() : id; @@ -158,7 +124,17 @@ bool wxListBox::Create(wxWindow *parent, m_windowStyle = style; DWORD wstyle = WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | - LBS_NOTIFY | LBS_HASSTRINGS; + LBS_NOTIFY | LBS_HASSTRINGS /* | WS_CLIPSIBLINGS */; + + wxASSERT_MSG( !(style & wxLB_MULTIPLE) || !(style & wxLB_EXTENDED), + _T("only one of listbox selection modes can be specified") ); + + if ( (m_windowStyle & wxBORDER_MASK) == wxBORDER_DEFAULT ) + m_windowStyle |= wxBORDER_SUNKEN; + + if ( m_windowStyle & wxCLIP_SIBLINGS ) + wstyle |= WS_CLIPSIBLINGS; + if (m_windowStyle & wxLB_MULTIPLE) wstyle |= LBS_MULTIPLESEL; else if (m_windowStyle & wxLB_EXTENDED) @@ -223,24 +199,17 @@ bool wxListBox::Create(wxWindow *parent, SetSize(x, y, width, height); - Show(TRUE); - return TRUE; } wxListBox::~wxListBox() { -#if wxUSE_OWNER_DRAWN - size_t uiCount = m_aItems.Count(); - while ( uiCount-- != 0 ) { - delete m_aItems[uiCount]; - } -#endif // wxUSE_OWNER_DRAWN + Free(); } void wxListBox::SetupColours() { - SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); SetForegroundColour(GetParent()->GetForegroundColour()); } @@ -261,20 +230,20 @@ void wxListBox::Delete(int N) wxCHECK_RET( N >= 0 && N < m_noItems, wxT("invalid index in wxListBox::Delete") ); -#if wxUSE_OWNER_DRAWN - delete m_aItems[N]; - m_aItems.Remove(N); -#else // !wxUSE_OWNER_DRAWN - if ( HasClientObjectData() ) - { - delete GetClientObject(N); - } -#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN + // for owner drawn objects, the data is used for storing wxOwnerDrawn + // pointers and we shouldn't touch it +#if !wxUSE_OWNER_DRAWN + if ( !(m_windowStyle & wxLB_OWNERDRAW) ) +#endif // !wxUSE_OWNER_DRAWN + if ( HasClientObjectData() ) + { + delete GetClientObject(N); + } SendMessage(GetHwnd(), LB_DELETESTRING, N, 0); m_noItems--; - SetHorizontalExtent(""); + SetHorizontalExtent(wxEmptyString); } int wxListBox::DoAppend(const wxString& item) @@ -284,12 +253,13 @@ int wxListBox::DoAppend(const wxString& item) #if wxUSE_OWNER_DRAWN if ( m_windowStyle & wxLB_OWNERDRAW ) { - wxOwnerDrawn *pNewItem = CreateItem(index); // dummy argument + wxOwnerDrawn *pNewItem = CreateLboxItem(index); // dummy argument pNewItem->SetName(item); - m_aItems.Add(pNewItem); + m_aItems.Insert(pNewItem, index); ListBox_SetItemData(GetHwnd(), index, pNewItem); + pNewItem->SetFont(GetFont()); } -#endif +#endif // wxUSE_OWNER_DRAWN SetHorizontalExtent(item); @@ -298,7 +268,12 @@ int wxListBox::DoAppend(const wxString& item) void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData) { - ShowWindow(GetHwnd(), SW_HIDE); + // avoid flicker - but don't need to do this for a hidden listbox + bool hideAndShow = IsShown(); + if ( hideAndShow ) + { + ShowWindow(GetHwnd(), SW_HIDE); + } ListBox_ResetContent(GetHwnd()); @@ -309,27 +284,18 @@ void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData) ListBox_AddString(GetHwnd(), choices[i]); if ( clientData ) { -#if wxUSE_OWNER_DRAWN - wxASSERT_MSG(clientData[ui] == NULL, - wxT("Can't use client data with owner-drawn listboxes")); -#else // !wxUSE_OWNER_DRAWN - ListBox_SetItemData(GetHwnd(), i, clientData[i]); -#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN + SetClientData(i, clientData[i]); } } #if wxUSE_OWNER_DRAWN if ( m_windowStyle & wxLB_OWNERDRAW ) { // first delete old items - size_t ui = m_aItems.Count(); - while ( ui-- != 0 ) { - delete m_aItems[ui]; - } - m_aItems.Empty(); + WX_CLEAR_ARRAY(m_aItems); // then create new ones - for ( ui = 0; ui < (size_t)m_noItems; ui++ ) { - wxOwnerDrawn *pNewItem = CreateItem(ui); + for ( size_t ui = 0; ui < (size_t)m_noItems; ui++ ) { + wxOwnerDrawn *pNewItem = CreateLboxItem(ui); pNewItem->SetName(choices[ui]); m_aItems.Add(pNewItem); ListBox_SetItemData(GetHwnd(), ui, pNewItem); @@ -339,7 +305,11 @@ void wxListBox::DoSetItems(const wxArrayString& choices, void** clientData) SetHorizontalExtent(); - ShowWindow(GetHwnd(), SW_SHOW); + if ( hideAndShow ) + { + // show the listbox back if we hid it + ShowWindow(GetHwnd(), SW_SHOW); + } } int wxListBox::FindString(const wxString& s) const @@ -352,15 +322,24 @@ int wxListBox::FindString(const wxString& s) const } void wxListBox::Clear() +{ + Free(); + + ListBox_ResetContent(GetHwnd()); + + m_noItems = 0; + SetHorizontalExtent(); +} + +void wxListBox::Free() { #if wxUSE_OWNER_DRAWN - size_t uiCount = m_aItems.Count(); - while ( uiCount-- != 0 ) { - delete m_aItems[uiCount]; + if ( m_windowStyle & wxLB_OWNERDRAW ) + { + WX_CLEAR_ARRAY(m_aItems); } - - m_aItems.Clear(); -#else // !wxUSE_OWNER_DRAWN + else +#endif // wxUSE_OWNER_DRAWN if ( HasClientObjectData() ) { for ( size_t n = 0; n < (size_t)m_noItems; n++ ) @@ -368,12 +347,6 @@ void wxListBox::Clear() delete GetClientObject(n); } } -#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN - - ListBox_ResetContent(GetHwnd()); - - m_noItems = 0; - SetHorizontalExtent(); } void wxListBox::SetSelection(int N, bool select) @@ -435,11 +408,6 @@ void wxListBox::DoSetItemClientData(int n, void *clientData) wxLogDebug(wxT("LB_SETITEMDATA failed")); } -bool wxListBox::HasMultipleSelection() const -{ - return (m_windowStyle & wxLB_MULTIPLE) || (m_windowStyle & wxLB_EXTENDED); -} - // Return number of selections and an array of selected integers int wxListBox::GetSelections(wxArrayInt& aSelections) const { @@ -447,27 +415,39 @@ int wxListBox::GetSelections(wxArrayInt& aSelections) const if ( HasMultipleSelection() ) { - int no_sel = ListBox_GetSelCount(GetHwnd()); - if (no_sel != 0) { - int *selections = new int[no_sel]; - int rc = ListBox_GetSelItems(GetHwnd(), no_sel, selections); - - wxCHECK_MSG(rc != LB_ERR, -1, wxT("ListBox_GetSelItems failed")); + int countSel = ListBox_GetSelCount(GetHwnd()); + if ( countSel == LB_ERR ) + { + wxLogDebug(_T("ListBox_GetSelCount failed")); + } + else if ( countSel != 0 ) + { + int *selections = new int[countSel]; - aSelections.Alloc(no_sel); - for ( int n = 0; n < no_sel; n++ ) - aSelections.Add(selections[n]); + if ( ListBox_GetSelItems(GetHwnd(), + countSel, selections) == LB_ERR ) + { + wxLogDebug(wxT("ListBox_GetSelItems failed")); + countSel = -1; + } + else + { + aSelections.Alloc(countSel); + for ( int n = 0; n < countSel; n++ ) + aSelections.Add(selections[n]); + } delete [] selections; } - return no_sel; + return countSel; } else // single-selection listbox { - aSelections.Add(ListBox_GetCurSel(GetHwnd())); + if (ListBox_GetCurSel(GetHwnd()) > -1) + aSelections.Add(ListBox_GetCurSel(GetHwnd())); - return 1; + return aSelections.Count(); } } @@ -476,8 +456,7 @@ int wxListBox::GetSelection() const { wxCHECK_MSG( !HasMultipleSelection(), -1, - wxT("GetSelection() can't be used with multiple-selection " - "listboxes, use GetSelections() instead.") ); + wxT("GetSelection() can't be used with multiple-selection listboxes, use GetSelections() instead.") ); return ListBox_GetCurSel(GetHwnd()); } @@ -485,7 +464,7 @@ int wxListBox::GetSelection() const // Find string for position wxString wxListBox::GetString(int N) const { - wxCHECK_MSG( N >= 0 && N < m_noItems, "", + wxCHECK_MSG( N >= 0 && N < m_noItems, wxEmptyString, wxT("invalid index in wxListBox::GetClientData") ); int len = ListBox_GetTextLen(GetHwnd(), N); @@ -506,7 +485,22 @@ wxListBox::DoInsertItems(const wxArrayString& items, int pos) int nItems = items.GetCount(); for ( int i = 0; i < nItems; i++ ) - ListBox_InsertString(GetHwnd(), i + pos, items[i]); + { + int idx = ListBox_InsertString(GetHwnd(), i + pos, items[i]); + +#if wxUSE_OWNER_DRAWN + if ( m_windowStyle & wxLB_OWNERDRAW ) + { + wxOwnerDrawn *pNewItem = CreateLboxItem(idx); + pNewItem->SetName(items[i]); + pNewItem->SetFont(GetFont()); + m_aItems.Insert(pNewItem, idx); + + ListBox_SetItemData(GetHwnd(), idx, pNewItem); + } +#endif // wxUSE_OWNER_DRAWN + } + m_noItems += nItems; SetHorizontalExtent(); @@ -522,9 +516,9 @@ void wxListBox::SetString(int N, const wxString& s) void *oldData = NULL; wxClientData *oldObjData = NULL; - if ( m_clientDataItemsType == ClientData_Void ) + if ( m_clientDataItemsType == wxClientData_Void ) oldData = GetClientData(N); - else if ( m_clientDataItemsType == ClientData_Object ) + else if ( m_clientDataItemsType == wxClientData_Object ) oldObjData = GetClientObject(N); // delete and recreate it @@ -548,8 +542,13 @@ void wxListBox::SetString(int N, const wxString& s) #if wxUSE_OWNER_DRAWN if ( m_windowStyle & wxLB_OWNERDRAW ) + { // update item's text m_aItems[N]->SetName(s); + + // reassign the item's data + ListBox_SetItemData(GetHwnd(), N, m_aItems[N]); + } #endif //USE_OWNER_DRAWN } @@ -620,7 +619,7 @@ void wxListBox::SetHorizontalExtent(const wxString& s) } } -wxSize wxListBox::DoGetBestSize() +wxSize wxListBox::DoGetBestSize() const { // find the widest string int wLine; @@ -644,7 +643,10 @@ wxSize wxListBox::DoGetBestSize() wListbox += 3*cx; - int hListbox = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)*(wxMax(m_noItems, 7)); + // don't make the listbox too tall (limit height to 10 items) but don't + // make it too small neither + int hListbox = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy)* + wxMin(wxMax(m_noItems, 3), 10); return wxSize(wListbox, hListbox); } @@ -655,73 +657,40 @@ wxSize wxListBox::DoGetBestSize() bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) { - /* - if (param == LBN_SELCANCEL) - { - event.extraLong = FALSE; - } - */ - if (param == LBN_SELCHANGE) + wxEventType evtType; + if ( param == LBN_SELCHANGE ) { - wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId); - wxArrayInt aSelections; - int count = GetSelections(aSelections); - if ( count > 0 ) - { - event.m_commandInt = aSelections[0]; - event.m_clientData = GetClientData(event.m_commandInt); - wxString str(GetString(event.m_commandInt)); - if (str != wxT("")) - { - event.m_commandString = str; - } - } - else - { - event.m_commandInt = -1; - event.m_commandString.Empty(); - } - - event.SetEventObject( this ); - ProcessCommand(event); - return TRUE; + evtType = wxEVT_COMMAND_LISTBOX_SELECTED; } - else if (param == LBN_DBLCLK) + else if ( param == LBN_DBLCLK ) { - wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, m_windowId); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); - return TRUE; + evtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED; } - - return FALSE; -} - -WXHBRUSH wxListBox::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor, - WXUINT message, WXWPARAM wParam, WXLPARAM lParam) -{ -#if wxUSE_CTL3D - if ( m_useCtl3D ) + else { - HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam); - return (WXHBRUSH) hbrush; + // some event we're not interested in + return FALSE; } -#endif - if (GetParent()->GetTransparentBackground()) - SetBkMode((HDC) pDC, TRANSPARENT); - else - SetBkMode((HDC) pDC, OPAQUE); + wxCommandEvent event(evtType, m_windowId); + event.SetEventObject( this ); + + // retrieve the affected item + int n = SendMessage(GetHwnd(), LB_GETCARETINDEX, 0, 0); + if ( n != LB_ERR ) + { + if ( HasClientObjectData() ) + event.SetClientObject( GetClientObject(n) ); + else if ( HasClientUntypedData() ) + event.SetClientData( GetClientData(n) ); - ::SetBkColor((HDC) pDC, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); - ::SetTextColor((HDC) pDC, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue())); + event.SetString( GetString(n) ); + event.SetExtraLong( HasMultipleSelection() ? IsSelected(n) : TRUE ); + } - wxBrush *backgroundBrush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID); + event.m_commandInt = n; - // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush - // has a zero usage count. - backgroundBrush->RealizeResource(); - return (WXHBRUSH) backgroundBrush->GetResourceHandle(); + return GetEventHandler()->ProcessEvent(event); } // ---------------------------------------------------------------------------- @@ -749,13 +718,19 @@ bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item) MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item; + HDC hdc = CreateIC(wxT("DISPLAY"), NULL, NULL, 0); + wxDC dc; - dc.SetHDC((WXHDC)CreateIC(wxT("DISPLAY"), NULL, NULL, 0)); - dc.SetFont(wxSystemSettings::GetSystemFont(wxSYS_ANSI_VAR_FONT)); + dc.SetHDC((WXHDC)hdc); + dc.SetFont(wxSystemSettings::GetFont(wxSYS_ANSI_VAR_FONT)); pStruct->itemHeight = dc.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE; pStruct->itemWidth = dc.GetCharWidth(); + dc.SetHDC(0); + + DeleteDC(hdc); + return TRUE; } @@ -766,6 +741,11 @@ bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT *item) wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE ); DRAWITEMSTRUCT *pStruct = (DRAWITEMSTRUCT *)item; + UINT itemID = pStruct->itemID; + + // the item may be -1 for an empty listbox + if ( itemID == (UINT)-1 ) + return FALSE; long data = ListBox_GetItemData(GetHwnd(), pStruct->itemID); @@ -773,15 +753,15 @@ bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT *item) wxListBoxItem *pItem = (wxListBoxItem *)data; - wxDC dc; - dc.SetHDC((WXHDC)pStruct->hDC, FALSE); + wxDCTemp dc((WXHDC)pStruct->hDC); wxRect rect(wxPoint(pStruct->rcItem.left, pStruct->rcItem.top), - wxPoint(pStruct->rcItem.right, pStruct->rcItem.bottom)); + wxPoint(pStruct->rcItem.right, pStruct->rcItem.bottom)); return pItem->OnDrawItem(dc, rect, - (wxOwnerDrawn::wxODAction)pStruct->itemAction, - (wxOwnerDrawn::wxODStatus)pStruct->itemState); + (wxOwnerDrawn::wxODAction)pStruct->itemAction, + (wxOwnerDrawn::wxODStatus)pStruct->itemState); } -#endif - // wxUSE_OWNER_DRAWN +#endif // wxUSE_OWNER_DRAWN + +#endif // wxUSE_LISTBOX