#include "button.h" #include #include #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); }