TreeView: onItemSelect, error while trying to right click an element

Started by EngineerBread, 10 May 2024, 04:29:02

EngineerBread

Hi, I hope everybody is doing well.
I've been trying to create a context menu whenever I right click in one of the elements of a TreeView, since TGUI does not have a ContextMenu per se, I created my own using a tgui::Panel, anyway as I was trying to use the function onItemSelect from the TreeView I noticed that the Panel is not being generated, I've tried passing the function a tgui::Vector2f, a tgui::String and even a std::vector<tgui::String> but to no avail, here is my code, if somebody could help me to solve it, I will greatly appreciate it.

Note: if I use a tgui::Vector2f I get the following warning: "TGUI warning: Failed to parse Vector2 'mainWindow.txt'. Expected numbers separated with a comma."

void EditorScene::loadResources()
{
    auto resourceFileTree(gui->get<tgui::TreeView>("Resources"));
    populateTree(resourcesPath, resourceFileTree, nullptr);
    resourceFileTree->onItemSelect([&](const tgui::Vector2f& elem){

        auto contextMenu(tgui::Panel::create());
        contextMenu->setPosition(sf::Mouse::getPosition().x, sf::Mouse::getPosition().y);
        contextMenu->setSize(100, 150);
        contextMenu->getRenderer()->setBackgroundColor(sf::Color::White);
        contextMenu->getRenderer()->setBorderColor(sf::Color::Black);

        auto viewButton(tgui::Label::create("View"));
        viewButton->getRenderer()->setTextColor(sf::Color::Black);
        viewButton->setTextSize(12);
        contextMenu->add(viewButton);

        auto deleteButton(tgui::Label::create("Delete"));
        deleteButton->getRenderer()->setTextColor(sf::Color::Black);
        deleteButton->setTextSize(12);
        contextMenu->add(deleteButton);

        contextMenu->onMouseLeave([&]{
           gui->remove(contextMenu);
        });

        gui->add(contextMenu);
    });

}

texus

onItemSelect is of type SignalItemHierarchy, which only supports a parameter of type tgui::String or std::vector<tgui::String>.

I'm surprised that it is even possible to connect a function with a tgui::Vector2f parameter, but apparently this is because a Vector2f can be created from a string. The string to initialize Vector2f needs to have format "(x,y)", while the element passed to the onItemSelect is the text of the clicked item, which is why you get the "Failed to parse Vector2" error.

In this case you aren't using the "elem" parameter, so you might as well not give the callback function any parameter.

QuoteI noticed that the Panel is not being generated

I tried your code and the panel is being created, just not on the location where you clicked. For you that location might have been outside the window which is why you wouldn't see it.

"sf::Mouse::getPosition()" returns the position on the monitor, you want "sf::Mouse::getPosition(window)" instead. After changing that, the panel did get created at the right location.

After running your code I noticed that it crashed in some cases. The lambda passed to onMouseLeave should have "[=]" instead of "[&]" (and you probably want to do the same for onItemSelect, which is possible since gui is a pointer anyway). While the panel continues to exist inside the gui, the "contextMenu" variable is destroyed when onItemSelect finishes. When the onMouseLeave callback is executed, the variable no longer exists so it crashes. With [=] you aren't refering to the variable anymore but instead are making a copy. In that case, when onMouseLeave is executed you still have a valid pointer to the panel that you can use.