[PATCH 4/5] comctl32/listbox: Implement LBS_NODATA for single-selection listboxes

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Feb 11 05:31:17 CST 2019


On 2/11/19 1:22 PM, Huw Davies wrote:
> On Mon, Feb 11, 2019 at 01:09:14PM +0200, Gabriel Ivăncescu wrote:
>> On 2/11/19 12:10 PM, Huw Davies wrote:
>>> On Fri, Feb 08, 2019 at 02:41:45PM +0200, Gabriel Ivăncescu wrote:
>>>> @@ -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;
>>>
>>> Again, resize_storage will handle the no_data case.  Then add a helper to
>>> actually insert the item.
>>>
>>
>> But in the insert helper, I'd have to ignore everything if it's
>> single-selection LBS_NODATA (because there's nothing to do), so there is no
>> difference to currently except just moving most of the function into a
>> helper (instead of indenting it).
>>
>> Is that what you had in mind?
> 
> Yes.
> 
>>>> @@ -1678,19 +1701,29 @@ static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index )
>>>>        LISTBOX_InvalidateItems( descr, index );
>>>>        descr->nb_items--;
>>>> -    LISTBOX_DeleteItem( descr, index );
>>>
>>> LB_DeleteItem should again handle the no_data case, it'll send LB_RESETCONTENT
>>> as required.
>>>
>>
>> Shouldn't that be RemoveItem? DeleteItem, AFAIK, has to not be called with
>> LBS_NODATA (unless you simply mean an early exit if so) nor send any
>> messages at all.
> 
> It's an earlish exit after sending the LB_RESETCONTENT message if appropriate.
>   
>>>> @@ -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);
>>>
>>> LB_DeleteItems() will cope.
>>>
>>
>> I don't like this solution. That would be slower than needed for large lists
>> (which LBS_NODATA is for) when resetting them, for an operation that should
>> basically be instant and not dependent on the list's size. i.e. from O(1) to
>> O(n)
> 
> We'll revisit it if performance turns out to be an issue.
> 
> Huw.
> 

Well, I find it awkward that sending SetCount to zero first would be far 
faster than LB_RESETCONTENT directly (that's what this will turn out to 
be), or that "growing" the list is instant while ResetContent is not. 
And it's just one line of code, I think when reducing O(n) to O(1) it 
should be worth it, given the point of LBS_NODATA.

(also, a variant of that line of code will also help with 
multi-selection listboxes later, which can also be instant)



More information about the wine-devel mailing list