xolatilization/xui.h
2025-04-14 19:49:49 +02:00

393 lines
18 KiB
C
Executable File

/// _
/// __ ___ _(_)
/// \ \/ / | | | |
/// > <| |_| | |
/// /_/\_\\__,_|_|
///
/// Copyright (c) 1997 - Ognjen 'xolatile' Milan Robovic
///
/// xolatile@chud.cyou - xui - Tiny GUI unity header, I'm not sure if it's immediate or not... Probably not.
///
/// This program is free software, free as in freedom and as in free beer, 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 any later version if you wish...
///
/// This program is distributed in the hope that it will be useful, but it is probably not, and without any warranty, without even the implied
/// warranty of merchantability or fitness for a particular purpose, because it is pointless. Please see the GNU (Geenoo) General Public License
/// for more details, if you dare, it is a lot of text that nobody wants to read...
typedef enum {
ui_window_left, ui_window_right, ui_window_upper, ui_window_lower,
ui_window_upper_left, ui_window_upper_right, ui_window_lower_left, ui_window_lower_right,
ui_frame_left, ui_frame_right, ui_frame_upper, ui_frame_lower,
ui_frame_upper_left, ui_frame_upper_right, ui_frame_lower_left, ui_frame_lower_right,
ui_status_left, ui_status_right, ui_status_upper, ui_status_lower,
ui_status_upper_left, ui_status_upper_right, ui_status_lower_left, ui_status_lower_right,
ui_status_middle,
ui_menu_left, ui_menu_right, ui_menu_upper, ui_menu_lower,
ui_menu_upper_left, ui_menu_upper_right, ui_menu_lower_left, ui_menu_lower_right,
ui_menu_middle,
ui_button_left, ui_button_right, ui_button_upper, ui_button_lower,
ui_button_upper_left, ui_button_upper_right, ui_button_lower_left, ui_button_lower_right,
ui_button_middle,
ui_fill_bar_left, ui_fill_bar_middle, ui_fill_bar_right, ui_fill_bar_base,
ui_tiny_fill_bar_middle, ui_tiny_fill_bar_left, ui_tiny_fill_bar_right, ui_tiny_fill_middle,
ui_check_box_off, ui_check_box_on,
ui_end_turn_button,
ui_icon_frame, ui_overicon_frame, ui_ubericon_frame,
ui_scroll_bar_lower, ui_scroll_bar_middle, ui_scroll_bar_upper, ui_scroll_bar_slider,
ui_separator_left, ui_separator_middle, ui_separator_right, ui_separator_center,
ui_title_bar_left, ui_title_bar_middle, ui_title_bar_right,
ui_subcount
} ui_subtype;
typedef enum {
ui_window = ui_window_left,
ui_frame = ui_frame_left,
ui_status = ui_status_left,
ui_menu = ui_menu_left,
ui_button = ui_button_left
} ui_type;
typedef struct {
bool freeview;
uint ignore;
uint camera_x;
uint camera_y;
char * help_box_none;
char * help_box_text;
uint help_box_icon;
uint side_panel;
uint font;
uint monofont;
uint sprite [ui_subcount];
uint width [ui_subcount];
uint height [ui_subcount];
uint separator_size;
uint icon_size;
uint overicon_size;
uint ubericon_size;
uint title_bar_size;
uint fill_bar_size;
uint scroll_bar_size;
uint camera_speed;
} ui_structure;
static ui_structure * ui_initialize (cross_structure * cross) {
char * subtype_file_name [ui_subcount] = {
"window_left", "window_right", "window_upper", "window_lower",
"window_upper_left", "window_upper_right", "window_lower_left", "window_lower_right",
"frame_left", "frame_right", "frame_upper", "frame_lower",
"frame_upper_left", "frame_upper_right", "frame_lower_left", "frame_lower_right",
"status_left", "status_right", "status_upper", "status_lower",
"status_upper_left", "status_upper_right", "status_lower_left", "status_lower_right",
"status_middle",
"menu_left", "menu_right", "menu_upper", "menu_lower",
"menu_upper_left", "menu_upper_right", "menu_lower_left", "menu_lower_right",
"menu_middle",
"button_left", "button_right", "button_upper", "button_lower",
"button_upper_left", "button_upper_right", "button_lower_left", "button_lower_right",
"button_middle",
"fill_bar_left", "fill_bar_middle", "fill_bar_right", "fill_bar_base",
"tiny_fill_bar_left", "tiny_fill_bar_middle", "tiny_fill_bar_right", "tiny_fill_bar_base",
"check_box_off", "check_box_on",
"end_turn_button",
"cursor",
"icon_frame", "overicon_frame", "ubericon_frame",
"scroll_bar_lower", "scroll_bar_middle", "scroll_bar_upper", "scroll_bar_slider",
"separator_left", "separator_middle", "separator_right", "separator_center",
"title_bar_left", "title_bar_middle", "title_bar_right"
};
ui_structure * ui = allocate (sizeof (* ui));
ui->freeview = false;
ui->ignore = ~ 0u;
ui->camera_x = 0;
ui->camera_y = 0;
ui->help_box_none = string_duplicate ("---");
ui->help_box_text = ui->help_box_none;
ui->help_box_icon = ui->ignore;
ui->side_panel = 400;
ui->font = cross_font_import (cross, configuration_format ("xui/regular"), ' ', '~', 0xffee0000u);
ui->monofont = cross_font_import (cross, configuration_format ("xui/monospace"), ' ', '~', 0xffeeee00u);
for (uint index = 0; index < ui_subcount; ++index) {
char * file_name = configuration_format (format ("xui/%s", subtype_file_name [index]));
ui->sprite [index] = cross_sprite_import (cross, file_name);
ui->width [index] = cross_sprite_width (cross, ui->sprite [index]);
ui->height [index] = cross_sprite_height (cross, ui->sprite [index]);
}
ui->separator_size = ui->height [ui_separator_middle];
ui->icon_size = ui->height [ui_icon_frame];
ui->overicon_size = ui->height [ui_overicon_frame];
ui->ubericon_size = ui->height [ui_ubericon_frame];
ui->title_bar_size = ui->height [ui_title_bar_middle];
ui->fill_bar_size = ui->height [ui_fill_bar_middle];
ui->scroll_bar_size = ui->width [ui_scroll_bar_middle];
print ("[/2Success/-] Initialized UI structure.\n");
return (ui);
}
static ui_structure * ui_deinitialize (ui_structure * ui) {
ui->help_box_none = deallocate (ui->help_box_none);
print ("[/2Success/-] Deinitialized UI information.\n");
return (deallocate (ui));
}
static int ui_offset_x (cross_structure * cross, ui_structure * ui) {
return (ui->camera_x - cross->window_width / 2);
}
static int ui_offset_y (cross_structure * cross, ui_structure * ui) {
return (ui->camera_y - cross->window_height / 2);
}
static uint ui_side_panel (ui_structure * ui) {
return (ui->side_panel); /// MAKE IT WINDOW SIZE DEPENDENT?
}
static void ui_camera_upper (ui_structure * ui) { ui->freeview = true; ui->camera_y -= ui->camera_speed; }
static void ui_camera_lower (ui_structure * ui) { ui->freeview = true; ui->camera_y += ui->camera_speed; }
static void ui_camera_left (ui_structure * ui) { ui->freeview = true; ui->camera_x -= ui->camera_speed; }
static void ui_camera_right (ui_structure * ui) { ui->freeview = true; ui->camera_x += ui->camera_speed; }
static void ui_render (cross_structure * cross, ui_structure * ui, ui_subtype index, int x, int y) {
cross_render_sprite (cross, ui->sprite [index], x, y);
}
static void ui_render_colour (cross_structure * cross, ui_structure * ui, ui_subtype index, uint colour, int x, int y) {
cross_render_sprite_colour (cross, ui->sprite [index], colour, x, y);
}
static void ui_subrender (cross_structure * cross, ui_structure * ui, ui_subtype index, int x, int y, uint u, uint v, uint width, uint height) {
cross_render_sprite_crop (cross, ui->sprite [index], x, y, u, v, width, height);
}
static void ui_subrender_colour (cross_structure * cross, ui_structure * ui, ui_subtype index, uint colour, int x, int y, uint u, uint v, uint width, uint height) {
cross_render_sprite_crop_colour (cross, ui->sprite [index], colour, x, y, u, v, width, height);
}
static void ui_render_horizontal (cross_structure * cross, ui_structure * ui, ui_subtype index, int x, int y, uint width) {
int entire = (width / ui->width [index]) * ui->width [index];
for (uint margin = 0; margin < width / ui->width [index]; ++margin) {
ui_render (cross, ui, index, x + margin * ui->width [index], y);
}
if (width % ui->width [index] > 0) {
ui_subrender (cross, ui, index, x + entire, y, 0, 0, width % ui->width [index], ui->height [index]);
}
}
static void ui_render_horizontal_colour (cross_structure * cross, ui_structure * ui, ui_subtype index, uint colour, int x, int y, uint width) {
int entire = (width / ui->width [index]) * ui->width [index];
for (uint margin = 0; margin < width / ui->width [index]; ++margin) {
ui_render_colour (cross, ui, index, colour, x + margin * ui->width [index], y);
}
if (width % ui->width [index] > 0) {
ui_subrender_colour (cross, ui, index, colour, x + entire, y, 0, 0, width % ui->width [index], ui->height [index]);
}
}
static void ui_render_vertical (cross_structure * cross, ui_structure * ui, ui_subtype index, int x, int y, uint height) {
int entire = (height / ui->height [index]) * ui->height [index];
for (uint margin = 0; margin < height / ui->height [index]; ++margin) {
ui_render (cross, ui, index, x, y + margin * ui->height [index]);
}
if (height % ui->height [index] > 0) {
ui_subrender (cross, ui, index, x, y + entire, 0, 0, ui->width [index], height % ui->height [index]);
}
}
static void ui_render_background (cross_structure * cross, ui_structure * ui, ui_subtype index, int x, int y, uint width, uint height) {
uint offset_x = (width / ui->width [index]) * ui->width [index];
uint offset_y = (height / ui->height [index]) * ui->height [index];
uint cutoff_x = width % ui->width [index];
uint cutoff_y = height % ui->height [index];
for (uint vertical = 0; vertical < height / ui->height [index]; ++vertical) {
for (uint horizontal = 0; horizontal < width / ui->width [index]; ++horizontal) {
ui_render (cross, ui, index, x + horizontal * ui->width [index], y + vertical * ui->height [index]);
}
if (width % ui->width [index] > 0) {
ui_subrender (cross, ui, index, x + offset_x, y + vertical * ui->height [index], 0, 0, cutoff_x, ui->height [index]);
}
}
for (uint horizontal = 0; horizontal < width / ui->width [index]; ++horizontal) {
ui_subrender (cross, ui, index, x + horizontal * ui->width [index], y + offset_y, 0, 0, ui->width [index], cutoff_y);
}
if (width % ui->width [index] > 0) {
ui_subrender (cross, ui, index, x + offset_x, y + offset_y, 0, 0, cutoff_x, cutoff_y);
}
}
static void ui_screen_overlay (cross_structure * cross) {
cross_render_rectangle_vertical_gradient (cross, 0, 0, cross->window_width, cross->window_height / 2, 0xcc, 0x00);
cross_render_rectangle_vertical_gradient (cross, 0, cross->window_height / 2, cross->window_width, cross->window_height / 2, 0x00, 0xcc);
}
static void ui_render_grid (cross_structure * cross, ui_structure * ui, ui_type element, int x, int y, uint width, uint height, uint margin, bool background) {
uint upper_length = width - ui->width [element + 4] - ui->width [element + 5];
uint lower_length = width - ui->width [element + 6] - ui->width [element + 7];
uint left_length = height - ui->height [element + 4] - ui->height [element + 6];
uint right_length = height - ui->height [element + 5] - ui->height [element + 7];
int upper_offset_x = ui->width [element + 4];
int lower_offset_x = ui->width [element + 6];
int lower_offset_y = height - ui->height [element + 3];
int right_offset_x = width - ui->width [element + 1];
int left_offset_y = ui->height [element + 4];
int right_offset_y = ui->height [element + 5];
int upper_right_offset_x = width - ui->width [element + 5];
int lower_right_offset_x = width - ui->width [element + 7];
int lower_left_offset_y = height - ui->height [element + 6];
int lower_right_offset_y = height - ui->height [element + 7];
if ((background == true) && (width > 2 * margin) && (height > 2 * margin)) {
ui_render_background (cross, ui, element + 8, x + margin, y + margin, width - 2 * margin, height - 2 * margin);
}
ui_render_vertical (cross, ui, element + 0, x, y + left_offset_y, left_length);
ui_render_vertical (cross, ui, element + 1, x + right_offset_x, y + right_offset_y, right_length);
ui_render_horizontal (cross, ui, element + 2, x + upper_offset_x, y, upper_length);
ui_render_horizontal (cross, ui, element + 3, x + lower_offset_x, y + lower_offset_y, lower_length);
ui_render (cross, ui, element + 4, x, y);
ui_render (cross, ui, element + 5, x + upper_right_offset_x, y);
ui_render (cross, ui, element + 6, x, y + lower_left_offset_y);
ui_render (cross, ui, element + 7, x + lower_right_offset_x, y + lower_right_offset_y);
}
static void ui_render_window (cross_structure * cross, ui_structure * ui, int x, int y, uint width, uint height) {
ui_render_grid (cross, ui, ui_window, x, y, width, height, 0, false);
}
static void ui_render_frame (cross_structure * cross, ui_structure * ui, int x, int y, uint width, uint height) {
ui_render_grid (cross, ui, ui_frame, x, y, width, height, 0, false);
}
static void ui_render_status (cross_structure * cross, ui_structure * ui, int x, int y, uint width, uint height) {
ui_render_grid (cross, ui, ui_status, x, y, width, height, 16, true);
}
static void ui_render_menu (cross_structure * cross, ui_structure * ui, int x, int y, uint width, uint height) {
ui_render_grid (cross, ui, ui_menu, x, y, width, height, 24, true);
}
static void ui_render_button (cross_structure * cross, ui_structure * ui, int x, int y, uint width, uint height) {
ui_render_grid (cross, ui, ui_button, x, y, width, height, 16, true);
}
static void ui_render_separator (cross_structure * cross, ui_structure * ui, int x, int y, uint width) {
uint margin = ui->width [ui_separator_left];
uint length = width - margin - ui->width [ui_separator_right];
ui_render (cross, ui, ui_separator_left, x, y);
ui_render_horizontal (cross, ui, ui_separator_middle, x + margin, y, length);
ui_render (cross, ui, ui_separator_right, x + margin + length, y);
ui_render (cross, ui, ui_separator_center, x + (width - ui->width [ui_separator_center]) / 2, y);
}
static void ui_render_title_bar (cross_structure * cross, ui_structure * ui, char * title, int x, int y, uint width) {
uint margin = ui->width [ui_title_bar_left];
uint length = width - margin - ui->width [ui_title_bar_right];
ui_render (cross, ui, ui_title_bar_left, x, y);
ui_render_horizontal (cross, ui, ui_title_bar_middle, x + margin, y, length);
ui_render (cross, ui, ui_title_bar_right, x + margin + length, y);
cross_render_string (cross, title, ui->font, x + margin + 8, y + 8, 1, 0x112233ff);
}
static void ui_render_icon_and_text (cross_structure * cross, ui_structure * ui, char * title, uint icon, int x, int y) {
cross_render_sprite (cross, icon, x, y);
cross_render_string (cross, title, ui->font, x - 2 + ui->icon_size, y + 2, 1, 0x112233ffu);
}
static void ui_render_scroll_bar (cross_structure * cross, ui_structure * ui, float slider, int x, int y, uint height) {
uint margin = ui->height [ui_scroll_bar_upper];
uint length = height - margin - ui->height [ui_scroll_bar_lower];
ui_render (cross, ui, ui_scroll_bar_upper, x, y);
ui_render_vertical (cross, ui, ui_scroll_bar_middle, x, y + margin, length);
ui_render (cross, ui, ui_scroll_bar_lower, x, y + margin + length);
ui_render (cross, ui, ui_scroll_bar_slider, x, y + margin + (uint) (slider * (float) (length - ui->height [ui_scroll_bar_slider])));
}
static void ui_render_fill_bar (cross_structure * cross, ui_structure * ui, float fill, uint colour, int x, int y, uint width) {
uint margin = ui->width [ui_fill_bar_left];
uint length = width - margin - ui->width [ui_fill_bar_right];
ui_render (cross, ui, ui_fill_bar_left, x, y);
ui_render_horizontal (cross, ui, ui_fill_bar_middle, x + margin, y, length);
ui_render (cross, ui, ui_fill_bar_right, x + margin + length, y);
ui_render_horizontal_colour (cross, ui, ui_fill_bar_base, colour, x + margin, y, (uint) (fill * (float) length));
}
static void ui_render_icon (cross_structure * cross, ui_structure * ui, uint icon, int x, int y) {
cross_render_sprite (cross, ui->sprite [ui_icon_frame], x, y);
if (icon != ui->ignore) {
cross_render_sprite (cross, icon, x, y);
}
}
static void ui_render_overicon (cross_structure * cross, ui_structure * ui, uint icon, int x, int y) {
if (icon != ui->ignore) {
cross_render_sprite (cross, icon, x, y);
}
cross_render_sprite (cross, ui->sprite [ui_overicon_frame], x, y);
}
static void ui_render_ubericon (cross_structure * cross, ui_structure * ui, uint icon, int x, int y) {
cross_render_sprite (cross, ui->sprite [ui_ubericon_frame], x, y);
if (icon != ui->ignore) {
cross_render_sprite (cross, icon, x + 16, y + 16);
}
}
static void ui_render_menu_full (cross_structure * cross, ui_structure * ui, char * title, int x, int y, uint width, uint height) {
uint margin = 24;
ui_screen_overlay (cross);
ui_render_menu (cross, ui, x, y, width, height);
if (title != null) {
ui_render_title_bar (cross, ui, format ("<%s>", title), x + margin, y + margin / 2 - ui->title_bar_size, width - 2 * margin);
}
}