ic-explorer/button.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);
}