[PATCH v2 1/2] comctl32/listbox: Implement LBS_NODATA for single-selection listboxes
Nikolay Sivov
nsivov at codeweavers.com
Tue Nov 20 16:38:37 CST 2018
On 11/20/18 4:40 PM, Gabriel Ivăncescu wrote:
> I reduced the patch to just single-selection changes so that it still
> works. After these are in, the multi-selection patches should be smaller.
This should be reduced further.
>
> Please note that the new helper functions (such as NODATA_is_sel) should
> remain as-is because they will be extended later for multi-selection
> listboxes, even if they seem redundant for now, so that I can really trim
> down the size of the multi-selection patches.:-)
>
> By the way, this patch really looks larger than it is. Most of the changes
> are in SetCount and the helper functions. InsertItem and RemoveItem seem
> large, but the changes are minor -- it's mostly just indentation, so it
> should be simple to review.
It is large, and again for no good reason.
For example painting part:
> @@ -494,7 +559,7 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect,
> RECT r;
> HRGN hrgn;
>
> - if (!item)
> + if (index >= descr->nb_items)
> {
'index' should be made unsigned throughout, unless there is a reason not to.
> if (action == ODA_FOCUS)
> DrawFocusRect( hdc, rect );
> @@ -517,16 +582,19 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect,
> dis.hDC = hdc;
> dis.itemID = index;
> dis.itemState = 0;
> - if (item->selected) dis.itemState |= ODS_SELECTED;
> + if ( ( is_singlesel_NODATA(descr) && NODATA_is_sel(descr, index)) ||
> + (!is_singlesel_NODATA(descr) && item->selected) )
> + dis.itemState |= ODS_SELECTED;
> +
This is really ugly.
> if (!ignoreFocus && (descr->focus_item == index) &&
> (descr->caret_on) &&
> (descr->in_focus)) dis.itemState |= ODS_FOCUS;
> if (!IsWindowEnabled(descr->self)) dis.itemState |= ODS_DISABLED;
> - dis.itemData = item->data;
> + dis.itemData = (descr->style & LBS_NODATA) ? 0 : item->data;
> dis.rcItem = *rect;
> TRACE("[%p]: drawitem %d (%s) action=%02x state=%02x rect=%s\n",
> - descr->self, index, debugstr_w(item->str), action,
> - dis.itemState, wine_dbgstr_rect(rect) );
> + descr->self, index, debugstr_w((descr->style & LBS_NODATA) ? NULL : item->str),
> + action, dis.itemState, wine_dbgstr_rect(rect) );
> SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
> SelectClipRgn( hdc, hrgn );
> if (hrgn) DeleteObject( hrgn );
Instead of spreading style checks just make sure 'item' is unset correctly.
> @@ -1678,28 +1757,38 @@ 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;
> -
> - /* Remove the item */
> + if (is_singlesel_NODATA(descr))
> + {
> + if (!descr->nb_items)
> + {
> + SendMessageW(descr->self, LB_RESETCONTENT, 0, 0);
> + return LB_OKAY;
> + }
> + }
We'll need additional test for that.
> - for(i = descr->nb_items - 1; i>=0; i--) LISTBOX_DeleteItem( descr, i);
> + if (!is_singlesel_NODATA(descr))
> + for (i = descr->nb_items - 1; i >= 0; i--) LISTBOX_DeleteItem(descr, i);
Is it the same as testing for null items array?
> static LRESULT LISTBOX_SetCount( LB_DESCR *descr, INT count )
> {
> - LRESULT ret;
> + INT orig_num;
>
> if (!(descr->style & LBS_NODATA)) return LB_ERR;
> + count = max(count, 0);
Do we have tests for that?
> case LB_GETSEL:
> if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
> return LB_ERR;
> + if (is_singlesel_NODATA(descr))
> + return NODATA_is_sel(descr, wParam);
> return descr->items[wParam].selected;
Do you need this? For single selection case you'll only need to check
wParam == selected_item, regardless of LBS_NODATA presence.
Regarding item storage, it's important to test what happens when
multiselection styles are changed after window creation.
Speaking of optimizations, having additional field for a number of
selected items could improve LB_GETSELCOUNT and LB_GETSELITEMS.
More information about the wine-devel
mailing list