Raylib backend widgets added are not drawing.

Started by MattDA, 09 October 2024, 20:28:08

MattDA

Hi again. I am trying to make a basic set up with headers to test my new build using the raylib backend. I have app class that holds the backend object (tgui::RAYLIB::gui). All the logic is nearly the same as the working example. I get no errors and everything loads. I can see that the container of the gui has 2 elements, (canvas and menubar) but I can't get them to draw. What am I doing wrong?
main.cpp
//#include <iostream>
//#include "raylib.h"
//#include <filesystem>


//namespace fs = std::filesystem;

//#include <SFML/Graphics.hpp>
#include <iostream>
//#include <UI.h>
//#include <TGUI/TGUI.hpp>
//#include <TGUI/Backend/raylib.hpp>
#include "Game.h"


int main()
{

    Game game;
    //float ar = (1080.0 / 1920.0) * 1.25;
    game.init(900, 600);

    game.runFixed();

    return 0;
}
game.cpp
#ifndef GAME_H
#define GAME_H
#include <iostream>
//#include <filesystem>
//#include <unordered_map>
//#include <string>
//#include <cassert> // for assert()
//#include "raylib.h"
//#include "raymath.h"

#include <TGUI/TGUI.hpp>
#include <TGUI/Backend/raylib.hpp>

//#include "VecUtil.h"
//#include "MapMan.h"
//#include "AssetMan.h"
//#include "GameObjects.hpp"

#include "AppUI.h"

class Game
{
public:

    Game();
    ~Game();
    void init(int,int);
    void runFixed();
private:

    ui::App m_ui;
};
#endif

Game.cpp
#include "Game.h"

Game::Game()
{

    std::cout << "Game Created" << std::endl;
   
    //m_ui = nullptr;
}
Game::~Game(){CloseWindow();}

void Game::init(int screenWidth,int screenHeight)
{
    SetTraceLogLevel(LOG_WARNING);
    std::cout << "Game Initializing" << std::endl;
    InitWindow(screenWidth, screenHeight, "Raylib is the master");

    SetTargetFPS(60);
    m_ui.init();

    tgui::RAYLIB::Gui* ui = m_ui.getUI();
    if (ui == nullptr)
        std::cout << "UI is null" << std::endl;

   
}

void Game::runFixed()
{

    while (!WindowShouldClose())    // Detect window close button or ESC key
    {

        auto ui = m_ui.getUI();
        ui->handleEvents();

        int pressedChar = GetCharPressed();
        while (pressedChar)
        {
            ui->handleCharPressed(pressedChar);
            pressedChar = GetCharPressed();
        }

        int pressedKey = GetKeyPressed();
        while (pressedKey)
        {
            ui->handleKeyPressed(pressedKey);
            pressedKey = GetKeyPressed();
        }
       
       BeginDrawing();
       
            ClearBackground({40, 60, 40, 255});
            DrawCircle(200, 120, 50, Color{100,10,10,255});
            m_ui.draw();
           
       EndDrawing();
     
       // ui.mainLoop();

    }
}


AppUI.h
#ifndef HEADER_APP_UI
#define HEADER_APP_UI



#pragma once

#include <iostream>
#include <unordered_map>
#include <map>
#include <string>
#include <filesystem>

//#include "raylib.h"
//#include "rlgl.h"
#include <TGUI/TGUI.hpp>
#include <TGUI/Backend/raylib.hpp>

//#include "VecUtil.h"
//#include "AssetMan.h"


namespace ui
{
    namespace fs = std::filesystem;

class App
{
public:
        App();
~App();
void init();
tgui::RAYLIB::Gui* getUI();
void draw();
void update();

private:


tgui::RAYLIB::Gui m_ui;
};


}


#endif // header guard



AppUI.cpp
#include "AppUI.h"

ui::App::App(){

}

ui::App::~App()
{

}

void ui::App::init()
{

    std::cout << "Initializing App User Interface." << std::endl;
try {
tgui::Theme blackTheme{ "../../themes/Black.txt" };

tgui::CanvasRaylib::Ptr MainCanvas = tgui::CanvasRaylib::create({ "100%", "100%" });

m_ui.add(MainCanvas, "main_canvas");


tgui::MenuBar::Ptr MainMenuBar = tgui::MenuBar::create();
MainMenuBar->setRenderer(blackTheme.getRenderer("MenuBar"));

MainMenuBar->setHeight(22.f);
MainMenuBar->setPosition("1%", "1%");
MainMenuBar->addMenu("File");
MainMenuBar->addMenuItem("New");
MainMenuBar->addMenuItem("Load");
MainMenuBar->addMenuItem("Save");
MainMenuBar->addMenuItem("Exit");

MainMenuBar->addMenu("Window");
MainMenuBar->addMenuItem("Map Object Tree");//Show a tree view of the map in a child window
MainMenuBar->addMenuItem("Object Properties");//Show Properties of an object

MainMenuBar->addMenu("Help");
MainMenuBar->addMenuItem("About");
MainMenuBar->setVisible(true);

m_ui.add(MainMenuBar, "main_menu_bar");


//MainMenuBar->connectMenuItem({ "File", "New" }, &UI::createWizard, this);
}
catch (const tgui::Exception& e)
{
std::cerr << "TGUI Exception: " << e.what() << std::endl;
exit(1);
}


}
tgui::RAYLIB::Gui* ui::App::getUI()
{
   
    return &m_ui;
}

void ui::App::draw()
{
auto MainCanvas = m_ui.get<tgui::CanvasRaylib>("main_canvas");
BeginTextureMode(MainCanvas->getTextureTarget());

m_ui.draw();
EndTextureMode();

}


void ui::App::update()
{
    //m_screenSize.x = static_cast<float>(GetScreenWidth());
    //m_screenSize.y = static_cast<float>(GetScreenHeight());
}



texus

"m_ui.draw();" should not be placed between BeginTextureMode and EndTextureMode. You trying to render the entire gui (including the canvas) onto the canvas widget and are drawing nothing to the window.

I placed the "m_ui.draw();" line below "EndTextureMode()" and it crashed here, but I haven't checked yet if that's due to the code or just because I have some other issue in my quickly created test program.

texus

The gui object is being created in your code before InitWindow is called. This causes it to think that the window is 0x0 pixels, which prevents rendering.

I can get the gui to render something if I call InitWindow before creating the Game object.

MattDA

I moved the main window into main so it is made in the right order. Also moved the drawing into AppUI, which I guess makes more sense anyhow. Now everything draws and widgets function. I was expecting the MenuBar to be drawn onto the canvas. Is this the way its supposed to work? Can I draw just the menu bar to the canvas?

main.cpp
int main()
{
    SetTraceLogLevel(LOG_WARNING);
   
    InitWindow(900, 600, "Raylib is the master");
    SetTargetFPS(60);

    std::cout << "Game Initializing" << std::endl;
    Game game;
    //float ar = (1080.0 / 1920.0) * 1.25;
    game.init(900, 600);

    game.runFixed();
    CloseWindow();
    return 0;
}

game.h
#ifndef GAME_H
#define GAME_H
#include <iostream>

#include <TGUI/TGUI.hpp>
#include <TGUI/Backend/raylib.hpp>

#include "AppUI.h"

class Game
{
public:

    Game();
    ~Game();
    void init(int,int);
    void runFixed();
private:

    ui::App m_app;
};
#endif

game.cpp
#include "Game.h"

Game::Game()
{

    std::cout << "Game Created" << std::endl;
   
    //m_ui = nullptr;
}
Game::~Game(){}

void Game::init(int screenWidth,int screenHeight)
{
   
    m_app.init(screenWidth, screenHeight);
    tgui::RAYLIB::Gui& ui = m_app.getGUI();

   
}

void Game::runFixed()
{

    while (!WindowShouldClose())    // Detect window close button or ESC key
    {

        auto& ui = m_app.getGUI();
        ui.handleEvents();

        int pressedChar = GetCharPressed();
        while (pressedChar)
        {
            ui.handleCharPressed(pressedChar);
            pressedChar = GetCharPressed();
        }

        int pressedKey = GetKeyPressed();
        while (pressedKey)
        {
            ui.handleKeyPressed(pressedKey);
            pressedKey = GetKeyPressed();
        }
       
        m_app.draw();
     
       // ui.mainLoop();

    }
}

AppUI.h
#include <map>
#include <string>
#include <filesystem>

#include <TGUI/TGUI.hpp>
#include <TGUI/Backend/raylib.hpp>


namespace ui
{
    namespace fs = std::filesystem;

class App
{
public:
        App();
~App();
void init(int,int);
tgui::RAYLIB::Gui& getGUI();
void draw();
void update();

private:


tgui::RAYLIB::Gui m_gui;
};


}


#endif // header guard


AppUI.cpp
#include "AppUI.h"

ui::App::App(){

}

ui::App::~App()
{

}

void ui::App::init(int screenWidth, int screenHeight)
{
    std::cout << "Initializing App User Interface." << std::endl;
try {
tgui::Theme blackTheme{ "../../themes/Black.txt" };

tgui::CanvasRaylib::Ptr MainCanvas = tgui::CanvasRaylib::create({ "80%", "80%" });

m_gui.add(MainCanvas, "main_canvas");


tgui::MenuBar::Ptr MainMenuBar = tgui::MenuBar::create();
MainMenuBar->setRenderer(blackTheme.getRenderer("MenuBar"));

MainMenuBar->setHeight(22.f);
MainMenuBar->setPosition("1%", "1%");
MainMenuBar->addMenu("File");
MainMenuBar->addMenuItem("New");
MainMenuBar->addMenuItem("Load");
MainMenuBar->addMenuItem("Save");
MainMenuBar->addMenuItem("Exit");

MainMenuBar->addMenu("Window");
MainMenuBar->addMenuItem("Map Object Tree");//Show a tree view of the map in a child window
MainMenuBar->addMenuItem("Object Properties");//Show Properties of an object

MainMenuBar->addMenu("Help");
MainMenuBar->addMenuItem("About");
MainMenuBar->setVisible(true);

m_gui.add(MainMenuBar, "main_menu_bar");



//MainMenuBar->connectMenuItem({ "File", "New" }, &UI::createWizard, this);
}
catch (const tgui::Exception& e)
{
std::cerr << "TGUI Exception: " << e.what() << std::endl;
exit(1);
}


}
tgui::RAYLIB::Gui& ui::App::getGUI()
{
   
    return m_gui;
}

void ui::App::draw()
{
auto MainCanvas = m_gui.get<tgui::CanvasRaylib>("main_canvas");
//auto MainMenuBar = m_gui.get<tgui::MenuBar>("main_canvas");
BeginTextureMode(MainCanvas->getTextureTarget());

ClearBackground({ 40, 160, 140, 255 });
DrawCircle(100, 120, 20, Color{ 100,10,10,255 });

EndTextureMode();

BeginDrawing();

ClearBackground({ 40, 60, 40, 255 });
DrawCircle(200, 120, 50, Color{ 100,10,10,255 });
m_gui.draw();//TGUI draw

EndDrawing();

}


void ui::App::update()
{
    //m_screenSize.x = static_cast<float>(GetScreenWidth());
    //m_screenSize.y = static_cast<float>(GetScreenHeight());
}



texus

The purpose of the Canvas widget is so that you can render custom raylib draws into a TGUI widget. So no, you can't render TGUI stuff into a canvas, the widget does the exact opposite.

If you wanted to draw TGUI to a raylib RenderTexture and then draw that that texture to the screen later, that could technically be done. However you end up with issues where mouse coordinates are wrong because TGUI can't know where on the window you would be rendering the texture.

So if you want TGUI to only render to a part of the screen then you should check out setAbsoluteViewport or setRelativeViewport (and maybe also look at the setAbsoluteView and setRelativeView function to see if you need those or not)