ComboBox with pop-up menu above


#1

I was having a problem with a combo box with a large menu (17 entries). If the window was too close to the bottom of the screen, the pop-up menu does correctly appear above the combo box, but would vanish as soon as I released the mouse.

If the pop-up menu was below the combo box, then it would remain after I did the first mouse-up and would only vanish after clicking an entry in the pop-up menu.

Looking at ComboBox::mouseUp, I found an if statement that decides whether or not to dispatch the mouse-up to the pop-up menu. So I changed this:

      if (activePopup != 0)
		{
            activePopup->handleMouseUp (e);
		}

to this:

      if ((activePopup != 0) && activePopup->contains (e.getScreenX() - activePopup->getScreenX(),
                                          e.getScreenY() - activePopup->getScreenY()))
		{
            activePopup->handleMouseUp (e);
		}

That seems to have done the trick.

There might be a cleaner way to do this, but this is fine for now.

Strangely, this problem doesn’t occur with the combo box in the JUCE demo.

Matt


#2

That’s very odd, and I can’t find a way of making it happen here. But your fix isn’t quite right, as it’ll stop it dismissing the popup correctly - the popup box still needs mouse events that are off its edge. I had a scan through that method and tidied it up, so try these snippets, (though I couldn’t see any bugs in what was there before):

[code] void handleMouseUp (const MouseEvent& e)
{
const MouseEvent e2 (e.getEventRelativeTo (list));

    if (contains (e2.x, e2.y))
    {
        dismiss();

        const int rowUnderMouse = list->getRowContainingPosition (e2.x, e2.y);

        if (rowUnderMouse >= 0)
        {
            returnKeyPressed (rowUnderMouse);

            // (this component might now have been deleted)
            return;
        }
    }
    else if (e.getDistanceFromDragStart() > 8)
    {
        dismiss();
    }
}[/code]

[code]
void ComboBox::mouseUp (const MouseEvent& e2)
{
if (popupDeletionWatcher != 0 && popupDeletionWatcher->hasBeenDeleted())
deletePopup();

// need to watch out for repeated mouse-ups arriving in succession because this is a mouselistener -
// so only the fist mouse-up afer a mouse-down will be responded to..
if (isButtonDown)
{
    isButtonDown = false;

    repaint();
    const MouseEvent e (e2.getEventRelativeTo (this));

    if (Component::reallyContains (e.x, e.y, true)
         && (e2.component == this || ! label->isEditable()))
    {
        Component* const lastFocusedComponent = Component::getCurrentlyFocusedComponent();

        if (activePopup == 0)
            createPopup();

        activePopup->grabKeyboardFocus();

        activePopup->runModalLoop();

        if (lastFocusedComponent->isValidComponent())
            lastFocusedComponent->grabKeyboardFocus();
    }
    else if (activePopup != 0)
    {
        activePopup->handleMouseUp (e);
    }
}

}[/code]


#3

I looked at this some more; it looks like it only happens if you have a native title bar on your window.

It’s easily reproduced with the JUCE demo without any code changes:

-open the demo, select the “misc widgets” tab
-drag the window down so the combo box is just above the bottom of the screen
-select “Use native window title bar” from the menu
-click on the combo box

I’ll try your fix; thanks!

Matt


#4

I tried the new code; unfortunately, the problem persists.

Matt


#5

aha! I didn’t think of trying it with a title bar! It’s a very subtle bug in juce_win32_Windowing.cpp - replace this method:

[code] void doCaptureChanged()
{
RECT wr;
GetWindowRect (hwnd, &wr);

    currentModifiers &= ~ModifierKeys::allMouseButtonModifiers;
    isDragging = false;

    const DWORD mp = GetMessagePos();

    handleMouseExit (GET_X_LPARAM (mp) - wr.left - windowBorder.getLeft(),
                     GET_Y_LPARAM (mp) - wr.top - windowBorder.getTop(),
                     getMouseEventTime());
}

[/code]


#6

Thanks! That did it. I don’t think I would have found that one on my own.

Matt


#7