/* * 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_grid { struct mftk_widget parent; int rows; int cols; struct mftk_widget **children; int *alignments; int *rows_h; int *cols_w; int row_spacing; int col_spacing; }; static void _mftk_grid_layout(struct mftk_widget *w) { struct mftk_grid *g = (struct mftk_grid *) w; int r; int c; int sz; int max_sz; w->h = 0; for (r = 0; r < g->rows; ++r) { max_sz = 0; for (c = 0; c < g->cols; ++c) { mftk_widget_layout(g->children[r * g->cols + c]); sz = g->children[r * g->cols + c]->h; if (sz > max_sz) { max_sz = sz; } } g->rows_h[r] = max_sz; if (r > 0) { w->h += g->row_spacing; } w->h += max_sz; } w->w = 0; for (c = 0; c < g->cols; ++c) { max_sz = 0; for (r = 0; r < g->rows; ++r) { sz = g->children[r * g->cols + c]->w; if (sz > max_sz) { max_sz = sz; } } g->cols_w[c] = max_sz; if (c > 0) { w->w += g->col_spacing; } w->w += max_sz; } } static void _mftk_grid_index(struct mftk_widget *w, struct mftk_window *win) { struct mftk_grid *g = (struct mftk_grid *) w; int i; for (i = 0; i < g->rows * g->cols; ++i) { mftk_widget_index(g->children[i], win); } } static int _mftk_grid_mouse_event(struct mftk_widget *w, SDL_Event *e, int x, int y) { struct mftk_grid *g = (struct mftk_grid *) w; SDL_Point p; SDL_Rect rect; int r; int cy; int c; int cx; int i; struct mftk_widget *ch; switch (e->type) { case SDL_MOUSEBUTTONUP: p.x = e->button.x; p.y = e->button.y; cy = y; for (r = 0; r < g->rows; ++r) { if (r > 0) { cy += g->row_spacing; } cx = x; for (c = 0; c < g->cols; ++c) { if (c > 0) { cx += g->col_spacing; } i = r * g->cols + c; ch = g->children[i]; rect.x = cx; rect.y = cy; if (g->alignments != NULL) { if (g->alignments[i] & MFTK_GRID_HALIGN_C) { rect.x += (g->cols_w[c] - ch->w) / 2; } else if (g->alignments[i] & MFTK_GRID_HALIGN_R) { rect.x += g->cols_w[c] - ch->w; } if (g->alignments[i] & MFTK_GRID_VALIGN_M) { rect.y += (g->rows_h[r] - ch->h) / 2; } else if (g->alignments[i] & MFTK_GRID_VALIGN_B) { rect.y += g->rows_h[r] - ch->h; } } rect.w = ch->w; rect.h = ch->h; if (SDL_PointInRect(&p, &rect) == SDL_TRUE) { return mftk_widget_mouse_event( ch, e, rect.x, rect.y); } cx += g->cols_w[c]; } cy += g->rows_h[r]; } break; default: break; } return 0; } static int _mftk_grid_render(struct mftk_widget *w, SDL_Renderer *renderer, int x, int y) { struct mftk_grid *g = (struct mftk_grid *) w; int e = 0; int r; int cy; int c; int cx; int i; struct mftk_widget *ch; int chx; int chy; cy = y; for (r = 0; r < g->rows; ++r) { if (r > 0) { cy += g->row_spacing; } cx = x; for (c = 0; c < g->cols; ++c) { if (c > 0) { cx += g->col_spacing; } i = r * g->cols + c; ch = g->children[i]; chx = cx; chy = cy; if (g->alignments != NULL) { if (g->alignments[i] & MFTK_GRID_HALIGN_C) { chx += (g->cols_w[c] - ch->w) / 2; } else if (g->alignments[i]&MFTK_GRID_HALIGN_R){ chx += g->cols_w[c] - ch->w; } if (g->alignments[i] & MFTK_GRID_VALIGN_M) { chy += (g->rows_h[r] - ch->h) / 2; } else if (g->alignments[i]&MFTK_GRID_VALIGN_B){ chy += g->rows_h[r] - ch->h; } } if (mftk_widget_render(ch, renderer, chx, chy) < 0) { e = -1; } cx += g->cols_w[c]; } cy += g->rows_h[r]; } return e; } static void _mftk_grid_destroy(struct mftk_widget *w) { struct mftk_grid *g = (struct mftk_grid *) w; int r; int c; for (r = 0; r < g->rows; ++r) { for (c = 0; c < g->cols; ++c) { mftk_widget_destroy(&g->children[r * g->cols + c]); } } free(g->children); if (g->alignments != NULL) { free(g->alignments); } free(g->rows_h); free(g->cols_w); } struct mftk_widget * mftk_grid_new_a(int rows, int cols, int row_spacing, int col_spacing, struct mftk_widget **children, int *alignments) { struct mftk_widget *w; struct mftk_grid *g; int i; mftk_widget_init_container(w, g, grid); g->rows_h = calloc(rows, sizeof(*g->rows_h)); if (g->rows_h == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create widget: %s", strerror(errno)); free(g->children); free(g); return NULL; } g->cols_w = calloc(cols, sizeof(*g->cols_w)); if (g->cols_w == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create widget: %s", strerror(errno)); free(g->rows_h); free(g->children); free(g); return NULL; } g->rows = rows; g->cols = cols; g->row_spacing = row_spacing; g->col_spacing = col_spacing; g->children = children; g->alignments = alignments; for (i = 0; i < rows * cols; ++i) { children[i]->container = w; } return w; } struct mftk_widget * mftk_grid_new(int rows, int cols, int row_spacing, int col_spacing, ...) { struct mftk_widget **children; int *alignments; struct mftk_widget *w; va_list ap; int r; int c; children = calloc(rows * cols, sizeof(*children)); if (children == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create widget: %s", strerror(errno)); return NULL; } alignments = calloc(rows * cols, sizeof(*alignments)); if (alignments == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create widget: %s", strerror(errno)); return NULL; } va_start(ap, col_spacing); for (r = 0; r < rows; ++r) { for (c = 0; c < cols; ++c) { children[r*cols + c] = va_arg(ap, struct mftk_widget *); alignments[r*cols + c] = va_arg(ap, int); } } va_end(ap); w = mftk_grid_new_a(rows, cols, row_spacing, col_spacing, children, alignments); if (w == NULL) { free(children); free(alignments); } return w; }