mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 22:43:02 +02:00
232 lines
7.5 KiB
C
232 lines
7.5 KiB
C
#include "gui.h"
|
|
#include <SDL2/SDL.h>
|
|
#include <stdio.h>
|
|
|
|
const SDL_Color COLOR_LIGHT = {238, 238, 210, 255}; // light square (not pure white)
|
|
const SDL_Color COLOR_DARK = {118, 150, 86, 255}; // dark square (not pure black)
|
|
const SDL_Color COLOR_GRID = {20, 20, 20, 255}; // thick outline
|
|
const SDL_Color COLOR_SEL = {200, 50, 50, 200}; // selection highlight
|
|
const SDL_Color COLOR_TEXT = {10, 10, 10, 255};
|
|
|
|
static void set_color(SDL_Renderer *r, SDL_Color c)
|
|
{
|
|
SDL_SetRenderDrawColor(r, c.r, c.g, c.b, c.a);
|
|
}
|
|
|
|
bool gui_init(Gui *g, int w, int h, const char *title)
|
|
{
|
|
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
|
{
|
|
(void)fprintf(stderr, "SDL_Init error: %s\n", SDL_GetError());
|
|
return false;
|
|
}
|
|
g->window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h,
|
|
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
|
if (!g->window)
|
|
{
|
|
(void)fprintf(stderr, "SDL_CreateWindow error: %s\n", SDL_GetError());
|
|
return false;
|
|
}
|
|
g->renderer =
|
|
SDL_CreateRenderer(g->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
|
if (!g->renderer)
|
|
{
|
|
(void)fprintf(stderr, "SDL_CreateRenderer error: %s\n", SDL_GetError());
|
|
return false;
|
|
}
|
|
g->win_w = w;
|
|
g->win_h = h;
|
|
g->flipped = false;
|
|
return true;
|
|
}
|
|
|
|
void gui_destroy(Gui *g)
|
|
{
|
|
if (g->renderer)
|
|
SDL_DestroyRenderer(g->renderer);
|
|
if (g->window)
|
|
SDL_DestroyWindow(g->window);
|
|
SDL_Quit();
|
|
}
|
|
|
|
void gui_set_flipped(Gui *g, bool flipped) { g->flipped = flipped; }
|
|
|
|
static void draw_rect(SDL_Renderer *r, int x, int y, int w, int h, SDL_Color c)
|
|
{
|
|
set_color(r, c);
|
|
SDL_Rect rc = {x, y, w, h};
|
|
SDL_RenderFillRect(r, &rc);
|
|
}
|
|
|
|
static void draw_outline(SDL_Renderer *r, SDL_Rect bounds, int thickness, SDL_Color c)
|
|
{
|
|
set_color(r, c);
|
|
for (int i = 0; i < thickness; i++)
|
|
{
|
|
SDL_Rect rc = {bounds.x + i, bounds.y + i, bounds.w - 2 * i, bounds.h - 2 * i};
|
|
SDL_RenderDrawRect(r, &rc);
|
|
}
|
|
}
|
|
|
|
static void draw_piece_letter(SDL_Renderer *r, SDL_Point origin, int cell_size, char piece)
|
|
{
|
|
// Minimal: draw a filled circle/square plus an initial letter approximated with rectangles.
|
|
// To keep dependencies minimal, no TTF. Ensure contrast: white pieces light, black pieces dark.
|
|
SDL_Color fill = (piece >= 'A' && piece <= 'Z') ? (SDL_Color){250, 250, 250, 255}
|
|
: (SDL_Color){30, 30, 30, 255};
|
|
SDL_Color glyph = (piece >= 'A' && piece <= 'Z') ? (SDL_Color){30, 30, 30, 255}
|
|
: (SDL_Color){240, 240, 240, 255};
|
|
// Base disk
|
|
int disk_offset = (int)(cell_size * 0.15f);
|
|
int disk_size = (int)(cell_size * 0.7f);
|
|
draw_rect(r, origin.x + disk_offset, origin.y + disk_offset, disk_size, disk_size, fill);
|
|
// Glyph: draw a simple letter-like mark
|
|
set_color(r, glyph);
|
|
// vertical bar
|
|
SDL_Rect bar1 = {origin.x + cell_size / 2 - cell_size / 16, origin.y + cell_size / 3,
|
|
cell_size / 8, cell_size / 3};
|
|
SDL_RenderFillRect(r, &bar1);
|
|
// top bar
|
|
SDL_Rect bar2 = {origin.x + cell_size / 3, origin.y + cell_size / 3 - cell_size / 10,
|
|
cell_size / 3, cell_size / 10};
|
|
SDL_RenderFillRect(r, &bar2);
|
|
}
|
|
|
|
void gui_draw(Gui *g, const char board[64], const GuiSelection *sel, const char *status_line)
|
|
{
|
|
SDL_GetWindowSize(g->window, &g->win_w, &g->win_h);
|
|
|
|
set_color(g->renderer, (SDL_Color){35, 35, 35, 255});
|
|
SDL_RenderClear(g->renderer);
|
|
|
|
int size = (g->win_w < g->win_h ? g->win_w : g->win_h) - 40; // margins
|
|
if (size < 200)
|
|
size = 200;
|
|
int cell = size / 8;
|
|
size = cell * 8;
|
|
int ox = (g->win_w - size) / 2;
|
|
int oy = (g->win_h - size) / 2;
|
|
|
|
// Board outline (thick)
|
|
SDL_Rect board_bounds = {ox - 6, oy - 6, size + 12, size + 12};
|
|
draw_outline(g->renderer, board_bounds, 6, COLOR_GRID);
|
|
|
|
// Squares
|
|
for (int r = 0; r < 8; r++)
|
|
{
|
|
for (int f = 0; f < 8; f++)
|
|
{
|
|
int idx = g->flipped ? (63 - (r * 8 + f)) : (r * 8 + f);
|
|
SDL_Color c = ((r + f) & 1) ? COLOR_DARK : COLOR_LIGHT;
|
|
int cell_x = ox + f * cell;
|
|
int cell_y = oy + r * cell;
|
|
draw_rect(g->renderer, cell_x, cell_y, cell, cell, c);
|
|
|
|
char piece = board[idx];
|
|
if (piece != '.' && piece != '\0')
|
|
{
|
|
SDL_Point origin = {cell_x, cell_y};
|
|
draw_piece_letter(g->renderer, origin, cell, piece);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Selection overlay
|
|
if (sel && sel->clicked && sel->from_sq >= 0)
|
|
{
|
|
int s = sel->from_sq;
|
|
int rr = g->flipped ? 7 - (s / 8) : (s / 8);
|
|
int ff = g->flipped ? 7 - (s % 8) : (s % 8);
|
|
SDL_Rect sel_bounds = {ox + ff * cell + 2, oy + rr * cell + 2, cell - 4, cell - 4};
|
|
draw_outline(g->renderer, sel_bounds, 3, COLOR_SEL);
|
|
}
|
|
|
|
// Status strip
|
|
SDL_Rect status_bounds = {10, g->win_h - 40, g->win_w - 20, 30};
|
|
draw_outline(g->renderer, status_bounds, 2, COLOR_GRID);
|
|
// Without TTF, we can't render text; draw a minimal indicator bar to signal state.
|
|
// If status_line indicates success/failure, alter color.
|
|
SDL_Color bar = {80, 120, 200, 255};
|
|
if (status_line && status_line[0])
|
|
{
|
|
if (SDL_strstr(status_line, "Correct"))
|
|
bar = (SDL_Color){80, 200, 120, 255};
|
|
else if (SDL_strstr(status_line, "Wrong"))
|
|
bar = (SDL_Color){200, 80, 80, 255};
|
|
}
|
|
draw_rect(g->renderer, 12, g->win_h - 38, g->win_w - 24, 26, bar);
|
|
|
|
SDL_RenderPresent(g->renderer);
|
|
}
|
|
|
|
int gui_coord_to_sq(Gui *g, int x, int y)
|
|
{
|
|
int w, h;
|
|
SDL_GetWindowSize(g->window, &w, &h);
|
|
int size = (w < h ? w : h) - 40;
|
|
if (size < 200)
|
|
size = 200;
|
|
int cell = size / 8;
|
|
size = cell * 8;
|
|
int ox = (w - size) / 2;
|
|
int oy = (h - size) / 2;
|
|
if (x < ox || y < oy || x >= ox + size || y >= oy + size)
|
|
return -1;
|
|
int f = (x - ox) / cell;
|
|
int r = (y - oy) / cell;
|
|
int sq = r * 8 + f;
|
|
if (g->flipped)
|
|
sq = 63 - sq;
|
|
return sq;
|
|
}
|
|
|
|
bool gui_poll_move(Gui *g, GuiSelection *sel, bool *quit_requested, int *key_out)
|
|
{
|
|
SDL_Event e;
|
|
bool updated = false;
|
|
if (key_out)
|
|
*key_out = 0;
|
|
while (SDL_PollEvent(&e))
|
|
{
|
|
if (e.type == SDL_QUIT)
|
|
{
|
|
if (quit_requested)
|
|
*quit_requested = true;
|
|
}
|
|
else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
|
|
{
|
|
updated = true;
|
|
}
|
|
else if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_LEFT)
|
|
{
|
|
int sq = gui_coord_to_sq(g, e.button.x, e.button.y);
|
|
if (sq >= 0)
|
|
{
|
|
if (!sel->clicked)
|
|
{
|
|
sel->from_sq = sq;
|
|
sel->to_sq = -1;
|
|
sel->clicked = true;
|
|
}
|
|
else
|
|
{
|
|
sel->to_sq = sq;
|
|
updated = true;
|
|
}
|
|
}
|
|
}
|
|
else if (e.type == SDL_KEYDOWN)
|
|
{
|
|
if (e.key.keysym.sym == SDLK_ESCAPE)
|
|
{
|
|
sel->clicked = false;
|
|
sel->from_sq = sel->to_sq = -1;
|
|
updated = true;
|
|
}
|
|
if (key_out)
|
|
*key_out = e.key.keysym.sym;
|
|
}
|
|
}
|
|
return updated;
|
|
}
|