Main Menu

Recent posts

#41
Help requests / Combobox with many many items
Last post by orborneroberts - 20 December 2024, 10:53:14
Hello, I need a combobox with many items, (say over 1000), but if I add all the creation is very slow and even change item is a pain (better in release, but debug it's unusable). It there a workaround for this? Maybe I can load a little number of items (say 20) and when moving the list reload the correct ones. How can I do something like that? Or if are there better solution...
#42
Help requests / Re: Custom canvas keyboard inp...
Last post by InvisibleShoe - 20 December 2024, 05:43:24
Understandable. I've figured out a way to make the GUI and controller work together overnight after looking at how a couple of games manage this.
But it is handy to know how to hook up keyboard input handling to CanvasSFML for other uses :)

Thanks for the help mate
#43
Help requests / Re: Custom canvas keyboard inp...
Last post by texus - 19 December 2024, 16:50:02
The thing to note it that TGUI technically isn't stealing your event. The handleEvent function just returns true, and your code is deciding not to handle the event if that is the case.

It's very difficult for me to decide what handleEvent should return. On one hand, people would only expect it to return true when the key event was actually used, but on the other hand you might not expect it to return false when an edit box is focused and you press backspace while the cursor is at the front or you try to type text in a numeric field.

The return value of handleEvent is something that can help your code decide whether it still needs to process it separately from the gui, but it doesn't has to be the only check. For example you could only execute the "continue;" line if the event wasn't a controller input, or even skip gui.handleEvent altogether for controller inputs.

So you should probably try to first think about when a key event should be handled by your code and when it should be dealt by the GUI. If you can properly define a rule about where the event needs to go to, then it might be more clear for me what you need exactly in case you are stuck implementing it.
#44
Help requests / Re: Custom canvas keyboard inp...
Last post by InvisibleShoe - 19 December 2024, 12:14:17
I just rolled back to an earlier commit where I was rendering to SFML view and the issue appears to be "gui->handleEvent(event)" trying to handle all keyboard events once a widget is clicked.
Mouse events are handled by my controller as they should be.
But clicking on a GUI panel or button will cause the gui to consume all keyboard events until I click on the game area again.

...After some tinkering, it's definitely the "HudRoot" widget stealing focus. I hooked up "gui->unFocusAllWidgets()" to a button and that fixes the issue.

What is best practice for unfocusing widgets to allow other forms of input handling? Is there a way to detect unhandled input events so that unFocusAllWidgets can be called?
#45
Help requests / Re: Custom canvas keyboard inp...
Last post by InvisibleShoe - 19 December 2024, 10:42:45
Excellent. Glad its an easy fix  ;) I'll give it a go.

I did have the game area rendered to a regular SFML view before but I was thinking that my game being fairly GUI heavy and the fact that I want interactive graphs and a minimap rendered to GUI widgets, it would be best to create a custom canvas widget that can gain focus and be interacted with.

While that info does help with creating a custom canvas for graphs and minimaps, I would prefer to have the game area rendering and input handling managed outside of GUI operations.
When I tried this before I had difficulty with TGUI consuming all input events, even when the only thing focused was an empty panel.

In the code below, I previously used insertSpace to create an area for the SFML view to be rendered and everything worked fine, input handling fell through to my controller until I click on any TGUI widget at which point TGUI starts consuming all actions and nothing falls through to my controller anymore.

Do you have any idea how to address this? I would love to go back to using a plain SFML view to render to.

GUI code:

auto gui = world.get_mut<Tag::GuiRoot>();
auto hudRoot = tgui::HorizontalLayout::create();

auto leftPanel = tgui::VerticalLayout::create();

auto topLeft = tgui::Panel::create();
topLeft->getRenderer()->setBackgroundColor(sf::Color::Green);
leftPanel->add(topLeft);

// auto canvas = GameCanvas::create(world);
// leftPanel->add(canvas, "GameCanvas");
// world.set( Tag::GameCanvas{canvas} );

// leftPanel->setRatio(canvas, 15.0f);

auto bottomLeft = tgui::Panel::create();
bottomLeft->getRenderer()->setBackgroundColor(sf::Color::Blue);
leftPanel->add(bottomLeft);

leftPanel->insertSpace(1, 80.0f);

hudRoot->add(leftPanel, "LeftPanel");

auto rightPanel = tgui::VerticalLayout::create();

auto topRight = tgui::Panel::create();
topRight->getRenderer()->setBackgroundColor(sf::Color::Green);
rightPanel->add(topRight);

auto button = tgui::Button::create("Steal Focus");
button->onMousePress(
[button](){
    button->setFocused(true);
}
);
topRight->add(button);

button = tgui::Button::create("Quit");
button->onMousePress(
[world](){
    world.add<Tag::ActiveScene, Tag::MenuScene>();
}
);
topRight->add(button);

auto txtArea = tgui::EditBox::create();
txtArea->setPosition(0, 50);
topRight->add(txtArea);

auto bottomRight = tgui::Panel::create();
bottomRight->getRenderer()->setBackgroundColor(sf::Color::Blue);
rightPanel->add(bottomRight);

hudRoot->add(rightPanel, "RightPanel");
hudRoot->setRatio(rightPanel, 0.3f);

hudRoot->setVisible(false);

gui->gui->add(hudRoot, "HudRoot");

(Previous) Input handling:

sf::Event event;

while(window.window->pollEvent(event)){
    if(event.type == sf::Event::Closed){
         e.world().set( Tag::Status{ Tag::Status::QUIT });
    }
    if(gui.gui->handleEvent(event)){
         continue;
    }
               
    ctrl.ctrl->checkInput(event);
}

Cheers and thanks for the help  :D
#46
Help requests / Re: Custom canvas keyboard inp...
Last post by texus - 19 December 2024, 09:50:34
Key events are only send to the focused widget (and its chain of parents). There were a handful of widgets (like Picture and Canvas) that I considered "unfocusable". Since they never get focused, they never receive the key events. This isn't really documented properly anywhere, I never expected someone to inherit from these classes and turn them into functional widgets instead of just drawings.

You can fix your code by adding the following function to your class:
Code (cpp) Select
bool GameCanvas::canGainFocus() const override
{
    return true;
}

Of course you will only receive the key presses after you clicked the canvas or called canvas->setFocused(true), and you will no longer receive them once the user clicks on a button and the button receives focus. If this isn't what you want, then you should process the key events somewhere else. Either in your event loop, or make a Group/Panel widget that contains all other widgets and already handle key presses in that container.
#47
Help requests / Custom canvas keyboard input
Last post by InvisibleShoe - 19 December 2024, 06:02:32
Hi again,
I'm trying to hookup a controller to a custom CanvasSFML widget and can't get key events to register. Mouse move and click work fine.

Header:
class GameCanvas : public tgui::CanvasSFML{
public:
    using Ptr = std::shared_ptr<GameCanvas>;

    GameCanvas(flecs::world& w);
    static GameCanvas::Ptr create(flecs::world& w);

    bool canHandleKeyPress(const tgui::Event::KeyEvent& event) override;
    void keyPressed (const tgui::Event::KeyEvent& event) override;
    bool leftMousePressed(tgui::Vector2f pos) override;
    void leftMouseReleased(tgui::Vector2f pos) override;
    void rightMousePressed(tgui::Vector2f pos) override;
    void rightMouseReleased(tgui::Vector2f pos) override;
    void mouseMoved(tgui::Vector2f pos) override;

    bool isFocused() const{
        bool f = tgui::CanvasSFML::isFocused();
        std::cout << "GameCanvas::isFocused(): " << (f ? "True" : "False") << std::endl;

        return f;
    }

    tgui::SignalTyped<tgui::Event::KeyEvent> onKeyPress = {"onKeyPress"};
protected:
    tgui::Signal& getSignal(tgui::String signalName) override;
private:
    flecs::world world;
};

src:
#include "gameCanvas.hpp"

GameCanvas::GameCanvas(flecs::world& w) : tgui::CanvasSFML(), world(w) {
    onKeyPress(
        [this](const tgui::Event::KeyEvent& event){
            Tag::InputCtrl* ctrl = world.lookup("Tag::GameScene").get_mut<Tag::InputCtrl>();
            ctrl->ctrl->onKeyEvent(event);
        }
    );
}

GameCanvas::Ptr GameCanvas::create(flecs::world& w){
    auto canvas = std::make_shared<GameCanvas>(w);
    return canvas;
}

void GameCanvas::keyPressed (const tgui::Event::KeyEvent& event){
    std::cout << "GameCanvas::keyPressed()" << std::endl;
    tgui::CanvasSFML::keyPressed(event);

    onKeyPress.emit(this, event);
}
bool GameCanvas::leftMousePressed(tgui::Vector2f pos){
    tgui::CanvasSFML::leftMousePressed(pos);

    return false;
}
void GameCanvas::leftMouseReleased(tgui::Vector2f pos){
    tgui::CanvasSFML::leftMouseReleased(pos);

    std::cout << "GameCanvas::leftMouseReleased()" << std::endl;
}
void GameCanvas::rightMousePressed(tgui::Vector2f pos){
    tgui::CanvasSFML::rightMousePressed(pos);
}
void GameCanvas::rightMouseReleased(tgui::Vector2f pos){
    tgui::CanvasSFML::rightMouseReleased(pos);
}
void GameCanvas::mouseMoved(tgui::Vector2f pos){
    tgui::CanvasSFML::mouseMoved(pos);

    Tag::InputCtrl* ctrl = world.lookup("Tag::GameScene").get_mut<Tag::InputCtrl>();
    ctrl->ctrl->onMouseMoveEvent(pos - getPosition());
}

bool GameCanvas::canHandleKeyPress(const tgui::Event::KeyEvent& event){
    std::cout << "GameCanvas::canHandleKeyPress()" << std::endl;

    return true;
}

tgui::Signal& GameCanvas::getSignal(tgui::String signalName) {
    std::cout << "GameCanvas::getSignal()" << std::endl;

    if (signalName == onKeyPress.getName())
        return onKeyPress;
    else
        return tgui::CanvasSFML::getSignal(std::move(signalName));
}


The log messages from isFocused, keyPressed, canHandleKeyPress and getSignal never get called but the messages/actions in mouseMoved and leftMouseReleased do.

The canvas hierarchy is: GameCanvas > VerticalLayout["LeftPanel"] > HorizontalLayout["HudRoot"] > RootContainer.



I've looked through the forums, the tutorial pages on signals and custom widgets, and TGUI source code, especially EditBox, but I just can't seem to figure out how to get the canvas to receive keyboard input.

If someone could point out what I'm doing wrong in the above code or provide me some basic code showing how to create a custom canvas with keyPress functionality, I'd greatly appreciate it.
Cheers 
#48
Help requests / Re: CanvasSFML rendering froze...
Last post by InvisibleShoe - 16 December 2024, 10:37:52
Did some more investigating and its a problem with the gui capturing input events before they can get to the game controller.

Going to have to think about this one.
#49
Help requests / CanvasSFML rendering frozen
Last post by InvisibleShoe - 16 December 2024, 10:07:17
Hi
I have my game screen setup as below:

    auto gui = world.get_mut<Tag::GuiRoot>();
    auto hudRoot = tgui::HorizontalLayout::create();

// LEFT WIDGETS

    auto leftPanel = tgui::VerticalLayout::create();
    leftPanel->setFocusable(false);

    auto topLeft = tgui::Panel::create();
    topLeft->getRenderer()->setBackgroundColor(sf::Color::Green);
    leftPanel->add(topLeft);

    auto canvas = tgui::CanvasSFML::create();
    leftPanel->add(canvas, "GameCanvas");
    world.set( Tag::GameCanvas{canvas} );

    leftPanel->setRatio(canvas, 15.0f);

    auto bottomLeft = tgui::Panel::create();
    bottomLeft->getRenderer()->setBackgroundColor(sf::Color::Blue);
    leftPanel->add(bottomLeft);

    hudRoot->add(leftPanel, "LeftPanel");

// RIGHT WIDGETS
    auto rightPanel = tgui::VerticalLayout::create();
    // rightPanel->setFocusable(false);

    auto topRight = tgui::Panel::create();
    topRight->getRenderer()->setBackgroundColor(sf::Color::Green);
    rightPanel->add(topRight);

    auto bottomRight = tgui::Panel::create();
    bottomRight->getRenderer()->setBackgroundColor(sf::Color::Blue);
    rightPanel->add(bottomRight);

    hudRoot->add(rightPanel, "RightPanel");
    hudRoot->setRatio(rightPanel, 0.3f);

    hudRoot->setVisible(false);

    gui->gui->add(hudRoot, "HudRoot");

The render process looks similar to:

canvas->clear(sf::Color::Black);
window->clear(sf::Color::White);

// render sprites to canvas

canvas->display();

gui->draw();

window->display()


Canvas rendering works fine on startup but as soon as I click on a gui widget(eg the right panel above) the canvas stops redrawing and won't unfreeze.
If I disable focus on the widget then the canvas stops freezing, so it seems to be an issue with widgets stealing focus from the canvas.
I've run my code in debug with breakpoints and the sprite rendering system is running in the background but the window stops responding to input and the canvas rendering stops.

Can anyone help with this? I was hoping to embed canvas widgets in a few places in a similar manner.

Cheers
#50
General Discussion / Re: showWithEffect for colaps...
Last post by texus - 21 November 2024, 20:28:01
With TreeView you could collapse things in your code when receiving a callback from onExpand.
Smooth transitions is something that isn't supported and won't be possible unless you write it yourself entirely.