The1Dev
The1Dev

Reputation: 11

How to set a GUI Button in the win32 window using SDL C++?

Iam soo newbie in SDL and games developement. I want to make a game and I need to put a "Start" button in the game's window. So please can anyone help me on how to do it? No mouse event in the whole screen I want just to create a button to click on it, where can I insert the code of the button? this is my code:

 int main (int argc, char *argv[]){
    int quit = 0;
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = NULL;
    window = SDL_CreateWindow("Snaykie v1.0",350, 150, 800, 500,    SDL_WINDOW_SHOWN);
    if (window == NULL){
        std::cout << "Can not open the game" << std::endl;
        return 0;
    }
    SDL_Renderer* renderer = NULL;
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    SDL_Event* evt = new SDL_Event();

    SDL_Texture* txt = NULL;
    txt = IMG_LoadTexture(renderer, "mainview.bmp");

    SDL_Rect rct;
    rct.x = 0 ;
    rct.y = 0;
    rct.h = 500;
    rct.w = 800;

    SDL_Surface *button = NULL;

    while (!quit && evt->type != SDL_QUIT){
        SDL_PollEvent(evt);
       SDL_RenderClear(renderer);
       SDL_RenderCopy(renderer, txt, NULL, &rct);
       SDL_RenderPresent(renderer);
    }
    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);
    delete evt;
    return 0;
}

Upvotes: 1

Views: 13060

Answers (1)

keltar
keltar

Reputation: 18399

It's not as simple as one or two lines. Here is an example:

#include <SDL2/SDL.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

typedef struct {
    SDL_Rect draw_rect;    // dimensions of button
    struct {
        Uint8 r, g, b, a;
    } colour;

    bool pressed;
} button_t;

static void button_process_event(button_t *btn, const SDL_Event *ev) {
    // react on mouse click within button rectangle by setting 'pressed'
    if(ev->type == SDL_MOUSEBUTTONDOWN) {
        if(ev->button.button == SDL_BUTTON_LEFT &&
                ev->button.x >= btn->draw_rect.x &&
                ev->button.x <= (btn->draw_rect.x + btn->draw_rect.w) &&
                ev->button.y >= btn->draw_rect.y &&
                ev->button.y <= (btn->draw_rect.y + btn->draw_rect.h)) {
            btn->pressed = true;
        }
    }
}

static bool button(SDL_Renderer *r, button_t *btn) {
    // draw button
    SDL_SetRenderDrawColor(r, btn->colour.r, btn->colour.g, btn->colour.b, btn->colour.a);
    SDL_RenderFillRect(r, &btn->draw_rect);

    // if button press detected - reset it so it wouldn't trigger twice
    if(btn->pressed) {
        btn->pressed = false;
        return true;
    }
    return false;
}

int main (int argc, char *argv[]){
    int quit = 0;
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = NULL;
    window = SDL_CreateWindow("",350, 150, 800, 500,    SDL_WINDOW_SHOWN);
    if (window == NULL){
        fprintf(stderr, "create window failed: %s\n", SDL_GetError());
        return 1;   // 'error' return status is !0. 1 is good enough
    }

    SDL_Renderer* renderer = NULL;
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if(!renderer) {   // renderer creation may fail too
        fprintf(stderr, "create renderer failed: %s\n", SDL_GetError());
        return 1;
    }

    SDL_Texture* txt = NULL;

    SDL_Rect rct;
    rct.x = 0 ;
    rct.y = 0;
    rct.h = 500;
    rct.w = 800;

    // button state - colour and rectangle
    button_t start_button = {
        .colour = { .r = 255, .g = 255, .b = 255, .a = 255, },
        .draw_rect = { .x = 128, .y = 128, .w = 128, .h = 128 },
    };

    enum {
        STATE_IN_MENU,
        STATE_IN_GAME,
    } state = 0;

    while(!quit) {
        SDL_Event evt;    // no need for new/delete, stack is fine

        // event loop and draw loop are separate things, don't mix them
        while(SDL_PollEvent(&evt)) {
            // quit on close, window close, or 'escape' key hit
            if(evt.type == SDL_QUIT ||
                    (evt.type == SDL_WINDOWEVENT && evt.window.event == SDL_WINDOWEVENT_CLOSE) ||
                    (evt.type == SDL_KEYDOWN && evt.key.keysym.sym == SDLK_ESCAPE)) {
                quit = 1;
            }

            // pass event to button
            button_process_event(&start_button, &evt);
        }

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

//      SDL_RenderCopy(renderer, txt, NULL, &rct);

        if(state == STATE_IN_MENU) {
            if(button(renderer, &start_button)) {
                printf("start button pressed\n");
                state = STATE_IN_GAME;   // state change - button will not be drawn anymore
            }
        } else if(state == STATE_IN_GAME) {
            /* your game logic */
        }

        SDL_RenderPresent(renderer);
    }
    SDL_DestroyWindow(window);
    SDL_DestroyRenderer(renderer);
    return 0;
}

(it is C but it's not a point here). It draws a simple constant-colour rectangle and detects clicks on it. It is trivial to replace rectangle with e.g. texture; adding text may be a bit harder, using SDL_ttf is probably simplest way to do it.

It may be improved in many ways depending on what you wanted to get. E.g. it reacts on mouse button down, while in some cases you might want to react to button release, and track where it was pressed and released. And if you'll have many buttons, calling event update on each one is ugly, so you might want to come with different system for that. You might also want to have non-rectangular buttons (e.g. some shape specified by image) - that will need quite different approach as you'll need to check mouse click against shape mask.

I would recommend taking a look at imgui.

As a side note, don't new SDL_Event, there is absolutely no point in that.

Upvotes: 13

Related Questions