/*
* 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;
}