171 lines
5.8 KiB
C
171 lines
5.8 KiB
C
|
#include "button.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#define ERROR(...) fprintf(stderr, __VA_ARGS__)
|
||
|
|
||
|
Button *buttonNew(const char *text, float x, float y, float w, float h,
|
||
|
SDL_Texture *inactive, SDL_Texture *active,
|
||
|
SDL_Color textColor, TTF_Font *font, ButtonSoundSet sounds,
|
||
|
const Window *window) {
|
||
|
Button *button = malloc(sizeof(Button));
|
||
|
if (!button) {
|
||
|
ERROR("error: out of memory\n");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
if (text) {
|
||
|
button->text = strdup(text);
|
||
|
if (!text) {
|
||
|
ERROR("error: out of memory\n");
|
||
|
free(button);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
} else {
|
||
|
button->text = NULL;
|
||
|
}
|
||
|
button->x = x;
|
||
|
button->y = y;
|
||
|
button->w = w;
|
||
|
button->h = h;
|
||
|
button->inactive = inactive;
|
||
|
button->active = active;
|
||
|
button->current = inactive;
|
||
|
button->font = font;
|
||
|
button->textColor = textColor;
|
||
|
button->sounds = sounds;
|
||
|
button->action = NULL;
|
||
|
button->renderedText = NULL;
|
||
|
button->down = 0;
|
||
|
buttonUpdate(button, window);
|
||
|
return button;
|
||
|
}
|
||
|
|
||
|
void buttonDelete(Button *button) {
|
||
|
if (button->text && strlen(button->text)) {
|
||
|
free(button->text);
|
||
|
SDL_DestroyTexture(button->renderedText);
|
||
|
}
|
||
|
free(button);
|
||
|
}
|
||
|
|
||
|
void buttonDraw(const Button *button, const Window *window) {
|
||
|
float bw = button->w;
|
||
|
float bh = button->h;
|
||
|
int ww, wh;
|
||
|
SDL_GetWindowSize(window->obj, &ww, &wh);
|
||
|
if (button->w == 0 && button->h == 0) {
|
||
|
bh = (float)button->textW / ww;
|
||
|
bw = (float)button->textH / wh;
|
||
|
} else if (button->w == 0) {
|
||
|
bw = (((wh * button->h) * button->textH) / button->textW) / ww;
|
||
|
} else if (button->h == 0) {
|
||
|
bh = (((ww * button->w) * button->textH) / button->textW) / wh;
|
||
|
}
|
||
|
SDL_Rect backArea = {ww * button->x, wh * button->y, ww * bw, wh * bh};
|
||
|
SDL_RenderCopy(window->render, button->current, NULL, &backArea);
|
||
|
if (button->text && strlen(button->text)) {
|
||
|
SDL_Rect textArea = {backArea.x * (1.0f + BUTTON_PADDING),
|
||
|
backArea.y * (1.0f + BUTTON_PADDING),
|
||
|
backArea.w * (1.0f - (2 * BUTTON_PADDING)),
|
||
|
backArea.h * (1.0f - (2 * BUTTON_PADDING))};
|
||
|
SDL_RenderCopy(window->render, button->renderedText, NULL, &textArea);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void buttonUpdate(Button *button, const Window *window) {
|
||
|
if (button->renderedText) {
|
||
|
SDL_DestroyTexture(button->renderedText);
|
||
|
}
|
||
|
if (button->text && strlen(button->text)) {
|
||
|
SDL_Surface *surface = TTF_RenderText_Blended(
|
||
|
button->font, button->text, button->textColor);
|
||
|
if (!surface) {
|
||
|
ERROR("error: sdl2: ttf: %s\n", TTF_GetError());
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
button->textW = surface->w;
|
||
|
button->textH = surface->h;
|
||
|
button->renderedText =
|
||
|
SDL_CreateTextureFromSurface(window->render, surface);
|
||
|
SDL_FreeSurface(surface);
|
||
|
if (!button->renderedText) {
|
||
|
ERROR("error: sdl2: %s\n", SDL_GetError());
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int intersectsButton(const Button *button, float bw, float bh, float x,
|
||
|
float y) {
|
||
|
return x >= button->x && y >= button->y && x <= button->x + bw &&
|
||
|
y <= button->y + bh;
|
||
|
}
|
||
|
|
||
|
void buttonProcessInput(Button *button, Window *window,
|
||
|
const SDL_Event *event) {
|
||
|
int ww, wh;
|
||
|
SDL_GetWindowSize(window->obj, &ww, &wh);
|
||
|
float bw = button->w;
|
||
|
float bh = button->h;
|
||
|
if (button->w == 0 && button->h == 0) {
|
||
|
bh = (float)button->textW / ww;
|
||
|
bw = (float)button->textH / wh;
|
||
|
} else if (button->w == 0) {
|
||
|
bw = (((wh * button->h) * button->textH) / button->textW) / ww;
|
||
|
} else if (button->h == 0) {
|
||
|
bh = (((ww * button->w) * button->textH) / button->textW) / wh;
|
||
|
}
|
||
|
if (event->type == SDL_MOUSEMOTION) {
|
||
|
float x = (float)event->motion.x / ww;
|
||
|
float y = (float)event->motion.y / wh;
|
||
|
if (intersectsButton(button, bw, bh, x, y)) {
|
||
|
if (button->active && button->current != button->active) {
|
||
|
if (button->sounds.hover) {
|
||
|
Mix_PlayChannel(-1, button->sounds.hover, 0);
|
||
|
}
|
||
|
button->current = button->active;
|
||
|
}
|
||
|
} else {
|
||
|
if (button->current != button->inactive) {
|
||
|
if (button->sounds.hover) {
|
||
|
Mix_PlayChannel(-1, button->sounds.hover, 0);
|
||
|
}
|
||
|
button->current = button->inactive;
|
||
|
}
|
||
|
if (button->down) {
|
||
|
button->down = 0;
|
||
|
}
|
||
|
}
|
||
|
} else if (event->type == SDL_MOUSEBUTTONDOWN &&
|
||
|
event->button.button == SDL_BUTTON_LEFT) {
|
||
|
float x = (float)event->button.x / ww;
|
||
|
float y = (float)event->button.y / wh;
|
||
|
if (intersectsButton(button, bw, bh, x, y)) {
|
||
|
button->down = 1;
|
||
|
if (button->sounds.down) {
|
||
|
Mix_PlayChannel(-1, button->sounds.down, 0);
|
||
|
}
|
||
|
}
|
||
|
} else if (event->type == SDL_MOUSEBUTTONUP &&
|
||
|
event->button.button == SDL_BUTTON_LEFT) {
|
||
|
float x = (float)event->button.x / ww;
|
||
|
float y = (float)event->button.y / wh;
|
||
|
if (intersectsButton(button, bw, bh, x, y) && button->down) {
|
||
|
button->down = 0;
|
||
|
if (button->sounds.up) {
|
||
|
Mix_PlayChannel(-1, button->sounds.up, 0);
|
||
|
}
|
||
|
if (button->action) {
|
||
|
button->action(button, window, x - button->x, y - button->y);
|
||
|
}
|
||
|
button->current = button->inactive;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void buttonGetCenter(const Button *button, Point *point) {
|
||
|
point->x = button->x + (button->w / 2);
|
||
|
point->y = button->y + (button->w / 2);
|
||
|
}
|