[PATCH 4/5] comctl32/listbox: Implement LBS_NODATA for single-selection listboxes
Gabriel Ivăncescu
gabrielopcode at gmail.com
Fri Feb 8 06:41:45 CST 2019
The LBS_NODATA style's purpose is to drastically improve performance and
memory usage on very large lists, since they should function as virtual
lists. Thus, don't store any data for single-selection listboxes (descr->items
always NULL).
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=32374
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
Most of the changes are just indentation in InsertItem/RemoveItem.
dlls/comctl32/listbox.c | 140 ++++++++++++++++++++++++++--------------
1 file changed, 90 insertions(+), 50 deletions(-)
diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
index d115617..fd3bfa6 100644
--- a/dlls/comctl32/listbox.c
+++ b/dlls/comctl32/listbox.c
@@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* TODO:
- * - LBS_NODATA
+ * - LBS_NODATA for multi-selection listboxes
*/
#include <string.h>
@@ -154,6 +154,12 @@ static BOOL is_item_selected( const LB_DESCR *descr, UINT index )
return descr->items[index].selected;
}
+static BOOL is_singlesel_NODATA(const LB_DESCR *descr)
+{
+ return (descr->style & LBS_NODATA) &&
+ !(descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL));
+}
+
/***********************************************************************
* LISTBOX_GetCurrentPageSize
*
@@ -547,6 +553,7 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect,
GetClientRect(descr->self, &r);
hrgn = set_control_clipping( hdc, &r );
+ if (is_singlesel_NODATA(descr)) item = NULL;
dis.CtlType = ODT_LISTBOX;
dis.CtlID = GetWindowLongPtrW( descr->self, GWLP_ID );
dis.hwndItem = descr->self;
@@ -709,8 +716,15 @@ static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items )
{
UINT new_size = descr->nb_items + nb_items;
- if (new_size > descr->items_size && !resize_storage(descr, new_size))
- return LB_ERRSPACE;
+ /* Windows keeps track of (unaligned) reserved space
+ for LBS_NODATA, despite the fact it is useless */
+ if (new_size > descr->items_size)
+ {
+ if (is_singlesel_NODATA(descr))
+ descr->items_size = new_size;
+ else if (!resize_storage(descr, new_size))
+ return LB_ERRSPACE;
+ }
return descr->items_size;
}
@@ -1460,10 +1474,13 @@ static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
{
INT oldsel = descr->selected_item;
if (index == oldsel) return LB_OKAY;
- if (oldsel != -1) descr->items[oldsel].selected = FALSE;
- if (index != -1) descr->items[index].selected = TRUE;
- if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
+ if (!(descr->style & LBS_NODATA))
+ {
+ if (oldsel != -1) descr->items[oldsel].selected = FALSE;
+ if (index != -1) descr->items[index].selected = TRUE;
+ }
descr->selected_item = index;
+ if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT );
if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr,
(index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
@@ -1535,36 +1552,42 @@ static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index,
if (index == -1) index = descr->nb_items;
else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
- if (!resize_storage(descr, descr->nb_items + 1)) return LB_ERR;
-
- /* Insert the item structure */
-
- item = &descr->items[index];
- if (index < descr->nb_items)
- RtlMoveMemory( item + 1, item,
- (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
- item->str = str;
- item->data = HAS_STRINGS(descr) ? 0 : data;
- item->height = 0;
- item->selected = FALSE;
- descr->nb_items++;
-
- /* Get item height */
-
- if (descr->style & LBS_OWNERDRAWVARIABLE)
+ if (is_singlesel_NODATA(descr))
{
- MEASUREITEMSTRUCT mis;
- UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
+ descr->nb_items++;
+ descr->items_size = max(descr->items_size, descr->nb_items);
+ }
+ else
+ {
+ if (!resize_storage(descr, descr->nb_items + 1)) return LB_ERR;
+
+ /* Insert the item structure */
+ item = &descr->items[index];
+ if (index < descr->nb_items)
+ RtlMoveMemory( item + 1, item,
+ (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
+ item->str = str;
+ item->data = HAS_STRINGS(descr) ? 0 : data;
+ item->height = 0;
+ item->selected = FALSE;
+ descr->nb_items++;
+
+ /* Get item height */
+ if (descr->style & LBS_OWNERDRAWVARIABLE)
+ {
+ MEASUREITEMSTRUCT mis;
+ UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
- mis.CtlType = ODT_LISTBOX;
- mis.CtlID = id;
- mis.itemID = index;
- mis.itemData = data;
- mis.itemHeight = descr->item_height;
- SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
- item->height = mis.itemHeight ? mis.itemHeight : 1;
- TRACE("[%p]: measure item %d (%s) = %d\n",
- descr->self, index, str ? debugstr_w(str) : "", item->height );
+ mis.CtlType = ODT_LISTBOX;
+ mis.CtlID = id;
+ mis.itemID = index;
+ mis.itemData = data;
+ mis.itemHeight = descr->item_height;
+ SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
+ item->height = mis.itemHeight ? mis.itemHeight : 1;
+ TRACE("[%p]: measure item %d (%s) = %d\n",
+ descr->self, index, str ? debugstr_w(str) : "", item->height );
+ }
}
/* Repaint the items */
@@ -1678,19 +1701,29 @@ static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index )
LISTBOX_InvalidateItems( descr, index );
descr->nb_items--;
- LISTBOX_DeleteItem( descr, index );
-
- if (!descr->nb_items) return LB_OKAY;
+ if (is_singlesel_NODATA(descr))
+ {
+ if (!descr->nb_items)
+ {
+ SendMessageW(descr->self, LB_RESETCONTENT, 0, 0);
+ return LB_OKAY;
+ }
+ }
+ else
+ {
+ LISTBOX_DeleteItem( descr, index );
- /* Remove the item */
+ if (!descr->nb_items) return LB_OKAY;
- item = &descr->items[index];
- if (index < descr->nb_items)
- RtlMoveMemory( item, item + 1,
- (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
- if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
+ /* Remove the item */
+ item = &descr->items[index];
+ if (index < descr->nb_items)
+ RtlMoveMemory( item, item + 1,
+ (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
- resize_storage(descr, descr->nb_items);
+ resize_storage(descr, descr->nb_items);
+ }
+ descr->anchor_item = min(descr->anchor_item, descr->nb_items - 1);
/* Repaint the items */
@@ -1729,7 +1762,8 @@ static void LISTBOX_ResetContent( LB_DESCR *descr )
{
INT i;
- for(i = descr->nb_items - 1; i>=0; i--) LISTBOX_DeleteItem( descr, i);
+ if (descr->items)
+ for (i = descr->nb_items - 1; i >= 0; i--) LISTBOX_DeleteItem(descr, i);
HeapFree( GetProcessHeap(), 0, descr->items );
descr->nb_items = 0;
descr->top_item = 0;
@@ -1752,9 +1786,14 @@ static LRESULT LISTBOX_SetCount( LB_DESCR *descr, UINT count )
if (count > orig_num)
{
- if (!resize_storage(descr, count))
- return LB_ERRSPACE;
- memset(&descr->items[orig_num], 0, (count - orig_num) * sizeof(LB_ITEMDATA));
+ if (descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
+ {
+ if (!resize_storage(descr, count))
+ return LB_ERRSPACE;
+ memset(&descr->items[orig_num], 0, (count - orig_num) * sizeof(LB_ITEMDATA));
+ }
+ else
+ descr->items_size = max(descr->items_size, count);
descr->nb_items = count;
LISTBOX_UpdateScroll(descr);
@@ -1773,8 +1812,9 @@ static LRESULT LISTBOX_SetCount( LB_DESCR *descr, UINT count )
{
descr->anchor_item = min(descr->anchor_item, count - 1);
- resize_storage(descr, count);
- if (descr->selected_item >= count)
+ if (descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
+ resize_storage(descr, count);
+ else if (descr->selected_item >= descr->nb_items)
descr->selected_item = -1;
LISTBOX_UpdateScroll(descr);
--
2.19.1
More information about the wine-devel
mailing list