Page 1 of 1

Overloaded methods wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Tue Jun 30, 2020 5:32 pm
by Titan
Hi,

Is there a way to toggle a wxPopupTransientWindow? I have a simple control with an OnMouseLeftDown and OnMouseLeftUp method, with which I would like to make a wxPopupTransientWindow appear and disappear. But when the popup is shown and I click out, the popup closes (I'm OK with that), so I tried to override the wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown methods ant it doesn't work, I mean the methods are not called... Is it a (known?) problem coming from wxWidgets or am I doing something wrong? Because I simply inherited from wxPopupTransientWindow and overloaded the methods.

Regards,

Titan

Re: Overloaded methods wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Tue Jun 30, 2020 6:29 pm
by catalin
wxPopupWindow has no OnDismiss() member. You're probably aiming for wxPopupTransientWindow::OnDismiss(). But mind that it will be called only when Dismiss() was not called.

At least for wxPopupTransientWindow::ProcessLeftDown(), it sounds like you are doing something wrong. Can you show a piece of code? Or maybe you used the keyboard to dismiss the popup?

Re: Overloaded methods wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Tue Jun 30, 2020 8:22 pm
by Titan
Yes of course I was wrong, it's wxPopupTransientWindow::OnDismiss().

Here's my code:

myPopup.hpp

Code: Select all

#pragma once

#include <wx/popupwin.h>

class myPopup :
    public wxPopupTransientWindow
{
public:

    myPopup(
        wxWindow* parent,
        wxWindowID id = wxID_ANY,
        wxSize const& size = wxDefaultSize);

    virtual void Popup(wxWindow* focus = NULL) override;

    virtual bool ProcessLeftDown(wxMouseEvent& event) override;

protected:

    virtual void OnDismiss(void) override;
};
myPopup.cpp

Code: Select all

#include "myPopup.hpp"

myPopup::myPopup(
    wxWindow* parent,
    wxWindowID id,
    wxSize const& size
) :
    wxPopupTransientWindow(
        parent,
        wxBORDER_NONE
    )
{
    SetId(id);
    SetSize(size);

    SetBackgroundColour(*wxYELLOW); // TMP
}

void myPopup::Popup(wxWindow* focus)
{
    Position(
        m_parent->GetScreenPosition(),
        m_parent->GetSize());

    wxPopupTransientWindow::Popup(focus);
}

/*
 * This method is not called.
 */
bool myPopup::ProcessLeftDown(wxMouseEvent& WXUNUSED(event))
{
    { // To observe a change :
        SetBackgroundColour(
            wxColour(
                rand() % 255,
                rand() % 255,
                rand() % 255));
        Refresh();
        Update();
    }
    return false;
}


/*
 * This method is not called too.
 */
void myPopup::OnDismiss(void)
{
    { // To observe a change :
        SetBackgroundColour(
            wxColour(
                rand() % 255,
                rand() % 255,
                rand() % 255));
        Refresh();
        Update();
    }
}
myButton.hpp

Code: Select all

#pragma once

#include <wx/control.h>

#include "myPopup.hpp"

class myButton :
    public wxControl
{
public:

    myButton(
        wxWindow* parent,
        wxWindowID id = wxID_ANY,
        wxPoint const& position = wxDefaultPosition,
        wxSize const& size = wxDefaultSize);

    ~myButton(void);

private:

    myPopup* m_popup;

    void OnMouseLeftDown(wxMouseEvent& event);
    void OnMouseLeftUp(wxMouseEvent& event);
};
myButton.cpp

Code: Select all

#include "myButton.hpp"

myButton::myButton(
    wxWindow* parent,
    wxWindowID id,
    wxPoint const& position,
    wxSize const& size
) :
    wxControl(
        parent,
        id,
        position,
        size
    )
{
    SetBackgroundColour(*wxRED); // TMP

    m_popup =
        new myPopup(
            this, wxID_ANY,
            wxSize(300, 200));

    Bind(wxEVT_LEFT_DOWN, &myButton::OnMouseLeftDown, this);
    Bind(wxEVT_LEFT_UP, &myButton::OnMouseLeftUp, this);
}

myButton::~myButton(void)
{
    delete m_popup;
}

void myButton::OnMouseLeftDown(wxMouseEvent& WXUNUSED(event))
{
    // Nothing yet.
}

void myButton::OnMouseLeftUp(wxMouseEvent& WXUNUSED(event))
{
    m_popup->Popup();
}

For the moment in myPopup::ProcessLeftDown I return false like wxPopupWindow::ProcessLeftDown to not hide myPopup. In the future, if the mouse is over his myButton, I would like to say to myButton to not open myPopup again in myButton::OnMouseLeftUp and return true to hide. Because the click on the myButton is actually a click outside the myPopup so it will close automatically. But now the method is not called...
Do you see what I'm trying to say?

Thank you for your help.

Re: Overloaded methods wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Tue Jun 30, 2020 10:30 pm
by catalin
Well, FWIW the popup window code is a mess. The "common" code actually contains the OSX and GTK implementations (..not exactly "common"), while the MSW implementation is separate. But you're probably right as it does look like a bug (assuming the reason for not getting those calls is because you're on Windows).

Can you try replacing the Dismiss() call in src/msw/popupwin.cpp, wxPopupTransientWindow::DismissOnDeactivate(), with DismissAndNotify(), and try again?

Re: Overloaded methods wxPopupTransientWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Wed Jul 01, 2020 2:17 pm
by Titan
I changed the Dismiss() call by DismissAndNotify() as you said, and now the overloaded myPopup::OnDismiss() method is called. It's a big step thank you ! But the myPopup::ProcessLeftDown method is not still called... Do you know if there is a way to do the same "hack" for this method?

Re: Overloaded methods wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Wed Jul 01, 2020 5:13 pm
by catalin
Not really, because the latter is used from wxPopupWindowHandler, which is only used by non-MSW implementations.
But it's probably not too difficult to do something similar in your derived class, connecting to the relevant mouse event [and ensure capturing and releasing the mouse when needed].

Re: Overloaded methods wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Wed Jul 01, 2020 5:37 pm
by Titan
I see what you mean, but now I can make appear and disappear the myPopup with myButton using the overloaded OnDismiss() method. I really appreciated your help, thank you very much!

By the way, I just have a small question: Is it a good practice to put more complex controls inside a wxPopupWindow/wxPopupTransientWindow? Like sliders, buttons, custom controls, etc.

Re: Overloaded methods wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Wed Jul 01, 2020 6:24 pm
by catalin
IIRC whatever you put in there will not get focused. So if you intend to interact with them using only the mouse, all should be fine, but if you need kb input then it might not work as you expected.

Re: Overloaded methods wxPopupWindow::OnDismiss and wxPopupTransientWindow::ProcessLeftDown are not called

Posted: Wed Jul 01, 2020 6:46 pm
by Titan
Ok, thank you!