/* * Copyright (C) 2021 P. J. McDermott * * This file is part of Maze Fight * * Maze Fight is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Maze Fight is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Maze Fight. If not, see . */ #include #include #include "../tk.h" #include "widget.h" struct mftk_check { struct mftk_widget parent; enum mftk_check_shape shape; int butn_width; int butn_padding; SDL_Color *butn_color; SDL_Color *mark_color; int state; int label_padding; struct mftk_widget *label; int steals_focus; int (*action)(void *, int); void *user_data; }; void mftk_check_set_shape(struct mftk_widget *w, enum mftk_check_shape shape) { struct mftk_check *c = (struct mftk_check *) w; c->shape = shape; } void mftk_check_set_state(struct mftk_widget *w, int state) { struct mftk_check *c = (struct mftk_check *) w; c->state = state; } void mftk_check_set_steals_focus(struct mftk_widget *w, int steals_focus) { struct mftk_check *c = (struct mftk_check *) w; c->steals_focus = steals_focus; } static void _mftk_check_layout(struct mftk_widget *w) { struct mftk_check *c = (struct mftk_check *) w; if (c->label != NULL) { mftk_widget_layout(c->label); } w->w = c->butn_width; if (c->label != NULL) { w->w += c->label_padding + c->label->w; } w->h = c->butn_width; if (c->label != NULL && c->label->h > w->h) { w->h = c->label->h; } } static void _mftk_check_focus(struct mftk_widget *w __attribute__((__unused__))) { /* Nothing to do */ } static void _mftk_check_defocus(struct mftk_widget *w __attribute__((__unused__))) { /* Nothing to do */ } static int _mftk_check_key_event(struct mftk_widget *w, SDL_Event *e) { struct mftk_check *c = (struct mftk_check *) w; switch (e->type) { case SDL_KEYDOWN: switch (e->key.keysym.sym) { case SDLK_SPACE: case SDLK_RETURN: c->state = !c->state; if (c->action == NULL) { return 0; } return c->action(c->user_data,c->state); default: break; } default: break; } return 0; } static int _mftk_check_mouse_event(struct mftk_widget *w, SDL_Event *e, int x __attribute__((__unused__)), int y __attribute__((__unused__))) { struct mftk_check *c = (struct mftk_check *) w; switch (e->type) { case SDL_MOUSEBUTTONUP: if (e->button.button == SDL_BUTTON_LEFT) { if (c->steals_focus == SDL_TRUE) { mftk_window_focus(w->window, w); } c->state = !c->state; if (c->action == NULL) { return 0; } return c->action(c->user_data, c->state); } break; default: break; } return 0; } static int _mftk_check_render_box(SDL_Rect *rect, SDL_Color *color, SDL_Renderer *renderer) { if (SDL_SetRenderDrawColor(renderer, color->r, color->g, color->b, color->a) < 0 || SDL_RenderFillRect(renderer, rect) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't render widget: %s", SDL_GetError()); return -1; } return 0; } static int _mftk_check_render_cir(SDL_Rect *rect, SDL_Color *color, SDL_Renderer *renderer) { int e = 0; int r; int x; int y; int i; if (SDL_SetRenderDrawColor(renderer, color->r, color->g, color->b, color->a) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't render widget: %s", SDL_GetError()); e = -1; } #define _mftk_check_px(X, Y) \ do { \ if (SDL_RenderDrawPoint(renderer, \ rect->x + r + X, rect->y + r + Y) < 0){\ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ "Couldn't render widget: %s", \ SDL_GetError()); \ e = -1; \ } \ } while (0) r = rect->w / 2; for (x = 0, y = r; y > x; ++x) { y = round(sqrt((r-0.5)*(r-0.5) - (x-0.5)*(x-0.5)) + 0.5); for (i = 0; i <= y; ++i) _mftk_check_px( x, i); for (i = 0; i >= 0-y; --i) _mftk_check_px( x, i); for (i = 0; i <= y; ++i) _mftk_check_px(0-x, i); for (i = 0; i >= 0-y; --i) _mftk_check_px(0-x, i); for (i = 0; i <= y; ++i) _mftk_check_px( i, x); for (i = 0; i <= y; ++i) _mftk_check_px( i, 0-x); for (i = 0; i >= 0-y; --i) _mftk_check_px( i, x); for (i = 0; i >= 0-y; --i) _mftk_check_px( i, 0-x); } #undef _mftk_check_px return e; } static int _mftk_check_render(struct mftk_widget *w, SDL_Renderer *renderer, int x, int y) { struct mftk_check *c = (struct mftk_check *) w; SDL_Rect rect; int e = 0; rect.x = x; rect.y = y; rect.w = c->butn_width; rect.h = c->butn_width; if (c->shape == MFTK_CHECK_SHAPE_BOX) { if (_mftk_check_render_box(&rect, c->butn_color, renderer) < 0){ e = -1; } } else { if (_mftk_check_render_cir(&rect, c->butn_color, renderer) < 0){ e = -1; } } if (c->state == SDL_TRUE) { rect.x += c->butn_padding; rect.y += c->butn_padding; rect.w -= c->butn_padding * 2; rect.h -= c->butn_padding * 2; if (c->shape == MFTK_CHECK_SHAPE_BOX) { if (_mftk_check_render_box(&rect, c->mark_color, renderer) < 0) { e = -1; } } else { if (_mftk_check_render_cir(&rect, c->mark_color, renderer) < 0) { e = -1; } } } if (c->label != NULL && mftk_widget_render(c->label, renderer, x + c->butn_width + c->label_padding, y) < 0) { e = -1; } return e; } static void _mftk_check_destroy(struct mftk_widget *w) { struct mftk_check *c = (struct mftk_check *) w; if (c->label != NULL) { mftk_widget_destroy(&c->label); } } struct mftk_widget * mftk_check_new(int butn_width, int butn_padding, SDL_Color *butn_color, SDL_Color *mark_color, int state, int label_padding, TTF_Font *font, const char *text, SDL_Color *text_color, int (*action)(void *, int), void *user_data, SDL_Renderer *renderer) { struct mftk_widget *w; struct mftk_check *c; mftk_widget_init_focusable(w, c, check); if (font != NULL && text != NULL && text_color != NULL) { c->label = mftk_label_new(font, text, text_color, renderer); if (c->label == NULL) { free(c); return NULL; } } c->shape = MFTK_CHECK_SHAPE_BOX; c->butn_width = butn_width; c->butn_padding = butn_padding; c->butn_color = butn_color; c->mark_color = mark_color; c->state = state; c->label_padding = label_padding; c->steals_focus = SDL_TRUE; c->action = action; c->user_data = user_data; return w; }