/* * 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 #include #include "../tk.h" #include "widget.h" struct _mftk_radio_state { struct mftk_radio *r; int state; }; struct mftk_radio { struct mftk_widget parent; struct mftk_widget **children; struct mftk_widget *grid; struct _mftk_radio_state *states; int state; int (*action)(void *, int); void *user_data; }; static int _mftk_radio_state_change(void *user_data, int state) { struct _mftk_radio_state *rs = (struct _mftk_radio_state *) user_data; if (state == SDL_FALSE) { /* Radio buttons can't be deselected */ mftk_check_set_state(rs->r->children[rs->r->state], SDL_TRUE); return 0; } else { /* Deselect previous check button */ mftk_check_set_state(rs->r->children[rs->r->state], SDL_FALSE); /* Set and announce new state */ rs->r->state = rs->state; if (rs->r->action == NULL) { return 0; } return rs->r->action(rs->r->user_data, rs->r->state); } } static void _mftk_radio_layout(struct mftk_widget *w) { struct mftk_radio *r = (struct mftk_radio *) w; mftk_widget_layout(r->grid); w->w = r->grid->w; w->h = r->grid->h; } static int _mftk_radio_mouse_event(struct mftk_widget *w, SDL_Event *e, int x, int y) { struct mftk_radio *r = (struct mftk_radio *) w; switch (e->type) { case SDL_MOUSEBUTTONUP: if (e->button.button == SDL_BUTTON_LEFT) { mftk_window_focus(w->window, w); return mftk_widget_mouse_event(r->grid, e, x, y); } break; default: break; } return 0; } static int _mftk_radio_render(struct mftk_widget *w, SDL_Renderer *renderer, int x, int y) { struct mftk_radio *r = (struct mftk_radio *) w; return mftk_widget_render(r->grid, renderer, x, y); } static void _mftk_radio_destroy(struct mftk_widget *w) { struct mftk_radio *r = (struct mftk_radio *) w; mftk_widget_destroy(&r->grid); free(r->states); } struct mftk_widget * mftk_radio_new(int butn_width, int butn_padding, SDL_Color *butn_color, SDL_Color *mark_color, int label_padding, int item_padding, TTF_Font *font, SDL_Color *text_color, int (*action)(void *, int), void *user_data, SDL_Renderer *renderer, int state, int options, ...) { struct mftk_widget *w; struct mftk_radio *r; va_list ap; int i; mftk_widget_init_focusable(w, r, radio); r->children = calloc(options, sizeof(*r->children)); if (r->children == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create widget: %s", strerror(errno)); free(r); return NULL; } r->states = calloc(options, sizeof(*r->states)); if (r->states == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create widget: %s", strerror(errno)); free(r->children); free(r); return NULL; } va_start(ap, options); for (i = 0; i < options; ++i) { r->children[i] = mftk_check_new(butn_width, butn_padding, butn_color, mark_color, (i == state), label_padding, font, va_arg(ap, const char *), text_color, _mftk_radio_state_change, &r->states[i], renderer); if (r->children[i] == NULL) { for (; i >= 0; --i) { mftk_widget_destroy(&r->children[i]); } free(r->children); free(r->states); free(r); va_end(ap); return NULL; } mftk_check_set_shape(r->children[i], MFTK_CHECK_SHAPE_CIR); mftk_check_set_steals_focus(r->children[i], SDL_FALSE); r->states[i].r = r; r->states[i].state = i; } va_end(ap); r->grid = mftk_grid_new_a(options, 1, item_padding, 0, r->children, NULL); if (r->grid == NULL) { for (i = 0; i < options; ++i) { mftk_widget_destroy(&r->children[i]); } free(r->children); free(r->states); free(r); } r->state = state; r->action = action; r->user_data = user_data; return w; }