ListBox::selectedRowsChanged() request (isMouseClick)


#1

Hi Jules,

I’ve got a TableListBox where I need to know if the selection has changed with a mouse click or via the Up/Down keys…. so I was wondering if you would consider changing (or adding):

//==============================================================================
    /** Override this to be informed when rows are selected or deselected.
        @see ListBox::selectedRowsChanged()
    */
    virtual void selectedRowsChanged (int lastRowSelected);

to

//==============================================================================
    /** Override this to be informed when rows are selected or deselected.
        @see ListBox::selectedRowsChanged()
    */
    virtual void selectedRowsChanged (int lastRowSelected, bool isMouseClick);

and in Listbox::selectRowInternal() change the call to:

void ListBox::selectRowInternal (const int row,
                                 bool dontScroll,
                                 bool deselectOthersFirst,
                                 bool isMouseClick)
{
    if (! multipleSelection)
        deselectOthersFirst = true;

    if ((! isRowSelected (row))
         || (deselectOthersFirst && getNumSelectedRows() > 1))
    {
        if (isPositiveAndBelow (row, totalItems))
        {
            if (deselectOthersFirst)
                selected.clear();

            selected.addRange (Range<int> (row, row + 1));

            if (getHeight() == 0 || getWidth() == 0)
                dontScroll = true;

            viewport->selectRow (row, getRowHeight(), dontScroll,
                                 lastRowSelected, totalItems, isMouseClick);

            lastRowSelected = row;
            model->selectedRowsChanged (row, isMouseClick);
        }
        else
        {
            if (deselectOthersFirst)
                deselectAllRows();
        }
    }
}

BTW - I know we have cellClicked() but it’s called after selectedRowsChanged() - so I can do what I want using a private boolean value which I set in selectedRowsChanged() and check for in cellClicked()… but it would be cleaner with the above change.

Thanks,

Rail


#2

So dealing with the edge cases between a mouse click and keyboard selection changed was much easier dealt with by adding:

void ListBoxModel::selectedRowsChanged (int lastRowSelected, bool /* isMouseClick */) { selectedRowsChanged (lastRowSelected); }

around line 963 in juce_ListBox.cpp and changing line 511 to

model->selectedRowsChanged (row, isMouseClick);

And also add the definition in the juce_ListBox.h header

virtual void selectedRowsChanged (int lastRowSelected, bool isMouseClick);

Rail


#3

There will be hundreds of people out there with code that would break if I changed this, so I'm not really keen to do it! Couldn't you cheat and just check whether the mouse button is down at the time when the selection happens?


#4

I’ll check if that’ll work – but my suggestion above in post 2 will not affect any existing code.

It adds a new overloaded member function and the default implementation calls the original (I tested for that to make sure it was a safe change).

Thanks,

Rail


#5

See my post #6

Thanks,

Rail


#6

I take that back…

void CGroupTable::selectedRowsChanged (int iNewRow)
{
    bool isMouseClick = isMouseButtonDown();
    :
}

isMouseButtonDown () doesn’t always return true when making a selection with the mouse.

My changes in post #2 above work 100% and are backward compatible.

void CGroupTable::selectedRowsChanged (int iNewRow, bool isMouseClick)
{
    bool bTemp = isMouseButtonDown();
    
    DBG ("isMouseButtonDown: " + String (bTemp) + ", isMouseClick: " + String (isMouseClick));

logs:

As you can see using isMouseButtonDown() is unreliable.

Thanks,

Rail


#7

Yes, obviously your suggestion would work, but like I said, it'd be a breaking change that would impact hundreds/thousands of projects, which is why I'm reluctant to do it!

Also it doesn't feel right to me for it to matter what the cause of the selection change was.. I can't really imagine a situation where I'd write code where that would be right way to do it. What's your actual use-case for this?


#8

Hi Jules,

I sent you a PM with a video showing the use-case.

I still think the overloaded method I posted in post #2 should not break existing code.

Cheers,

Rail