/// _ /// __ ___ _(_) /// \ \/ / | | | | /// > <| |_| | | /// /_/\_\\__,_|_| /// /// 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_left, ui_tiny_fill_bar_middle, ui_tiny_fill_bar_right, ui_tiny_fill_bar_base, ui_check_box_off, ui_check_box_on, ui_cursor, 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_enumeration; 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_enumeration; typedef struct { natural count; natural limit; natural active; natural ignore; natural help_box_icon; character * help_box_none; character * help_box_text; character * * folder; natural * * sprite; natural * * width; natural * * height; natural * font; natural * monofont; natural * separator_size; natural * icon_size; natural * overicon_size; natural * ubericon_size; natural * title_bar_size; natural * fill_bar_size; natural * tiny_fill_bar_size; natural * scroll_bar_size; } ui_structure; static character * ui_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", "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" }; static ui_structure * ui_initialize (cross_structure * cross, natural limit) { ui_structure * ui = allocate (sizeof (* ui)); ui->limit = limit; ui->ignore = ~ 0u; ui->help_box_none = string_duplicate ("---"); ui->help_box_text = ui->help_box_none; ui->help_box_icon = ui->ignore; ui->folder = allocate (limit * sizeof (* ui->folder)); ui->sprite = allocate (limit * sizeof (* ui->sprite)); ui->width = allocate (limit * sizeof (* ui->width)); ui->height = allocate (limit * sizeof (* ui->height)); ui->font = allocate (limit * sizeof (* ui->font)); ui->monofont = allocate (limit * sizeof (* ui->monofont)); ui->separator_size = allocate (limit * sizeof (* ui->separator_size)); ui->icon_size = allocate (limit * sizeof (* ui->icon_size)); ui->overicon_size = allocate (limit * sizeof (* ui->overicon_size)); ui->ubericon_size = allocate (limit * sizeof (* ui->ubericon_size)); ui->title_bar_size = allocate (limit * sizeof (* ui->title_bar_size)); ui->fill_bar_size = allocate (limit * sizeof (* ui->fill_bar_size)); ui->tiny_fill_bar_size = allocate (limit * sizeof (* ui->tiny_fill_bar_size)); ui->scroll_bar_size = allocate (limit * sizeof (* ui->scroll_bar_size)); for (natural index = 0; index < limit; ++index) { ui->sprite [index] = allocate (ui_subcount * sizeof (* * ui->sprite)); ui->width [index] = allocate (ui_subcount * sizeof (* * ui->width)); ui->height [index] = allocate (ui_subcount * sizeof (* * ui->height)); } print ("/s Initialized UI structure.\n"); return (ui); } static ui_structure * ui_deinitialize (ui_structure * ui) { for (natural index = 0; index < ui->limit; ++index) { ui->sprite [index] = deallocate (ui->sprite [index]); ui->width [index] = deallocate (ui->width [index]); ui->height [index] = deallocate (ui->height [index]); if (ui->folder [index] != null) { ui->folder [index] = deallocate (ui->folder [index]); } } ui->folder = deallocate (ui->folder); ui->sprite = deallocate (ui->sprite); ui->width = deallocate (ui->width); ui->height = deallocate (ui->height); ui->font = deallocate (ui->font); ui->monofont = deallocate (ui->monofont); ui->separator_size = deallocate (ui->separator_size); ui->icon_size = deallocate (ui->icon_size); ui->overicon_size = deallocate (ui->overicon_size); ui->ubericon_size = deallocate (ui->ubericon_size); ui->title_bar_size = deallocate (ui->title_bar_size); ui->fill_bar_size = deallocate (ui->fill_bar_size); ui->tiny_fill_bar_size = deallocate (ui->tiny_fill_bar_size); ui->scroll_bar_size = deallocate (ui->scroll_bar_size); ui->help_box_none = deallocate (ui->help_box_none); print ("/s Deinitialized UI structure.\n"); return (deallocate (ui)); } static boolean ui_validate_dimensions (ui_structure * ui, ui_subtype_enumeration subtype) { if (ui->width [ui->active] [subtype] != ui->height [ui->active] [subtype]) { print ("/w Mismatching sizes for sprite '%s', in UI '%s'.\n", ui_subtype_file_name [subtype], ui->folder [ui->active]); } } static boolean ui_validate_width_dimensions (ui_structure * ui, ui_subtype_enumeration begin, ui_subtype_enumeration end) { for (ui_subtype_enumeration index = begin; index <= end; ++index) { if (ui->width [ui->active] [index] != ui->width [ui->active] [begin]) { print ("/w Mismatching width for sprite '%s', in UI '%s'.\n", ui_subtype_file_name [index], ui->folder [ui->active]); } } } static boolean ui_validate_height_dimensions (ui_structure * ui, ui_subtype_enumeration begin, ui_subtype_enumeration end) { for (ui_subtype_enumeration index = begin; index <= end; ++index) { if (ui->height [ui->active] [index] != ui->height [ui->active] [begin]) { print ("/w Mismatching height for sprite '%s', in UI '%s'.\n", ui_subtype_file_name [index], ui->folder [ui->active]); } } } static boolean ui_validate_grid_dimensions (ui_structure * ui, ui_subtype_enumeration begin, ui_subtype_enumeration end) { for (ui_subtype_enumeration index = begin; index <= end; ++index) { if ((ui->width [ui->active] [index] != ui->width [ui->active] [begin]) || (ui->height [ui->active] [index] != ui->height [ui->active] [begin])) { print ("/w Mismatching grid for sprite '%s', in UI '%s'.\n", ui_subtype_file_name [index], ui->folder [ui->active]); } } } static procedure ui_configure (cross_structure * cross, ui_structure * ui, character * folder) { if (ui->count >= ui->limit) { print ("/w You are trying to configure more UIs than you set the limit to.\n"); return; } natural current = ui->active = ++ui->count - 1; if (cross->very_verbose_spam == true) { print ("/c Importing UI sprites from '%s' at index %i...\n", folder, current); } if (folder != null) { ui->folder [current] = string_duplicate (folder); } ui->font [current] = cross_font_import (cross, (folder == null) ? configuration_format ("xui/regular") : format ("%s/regular", folder), ' ', '~' + 0, 0); ui->monofont [current] = cross_font_import (cross, (folder == null) ? configuration_format ("xui/monospace") : format ("%s/monospace", folder), ' ', '~' + 1, 0); for (natural index = 0; index < ui_subcount; ++index) { character * file_name = (folder == null) ? configuration_format (format ("xui/%s", ui_subtype_file_name [index])) : format ("%s/%s", folder, ui_subtype_file_name [index]); ui->sprite [current] [index] = cross_sprite_import (cross, file_name); ui->width [current] [index] = cross_sprite_width (cross, ui->sprite [current] [index]); ui->height [current] [index] = cross_sprite_height (cross, ui->sprite [current] [index]); if ((ui->width [current] [index] == 0) || (ui->height [current] [index] == 0)) { print ("/f UI sprite '%s' has width or height zero.\n", file_name); exit (log_failure); } } ui_validate_dimensions (ui, ui_cursor); ui_validate_dimensions (ui, ui_icon_frame); ui_validate_dimensions (ui, ui_overicon_frame); ui_validate_dimensions (ui, ui_ubericon_frame); ui_validate_grid_dimensions (ui, ui_status_left, ui_status_lower_right); ui_validate_grid_dimensions (ui, ui_menu_left, ui_menu_lower_right); ui_validate_grid_dimensions (ui, ui_button_left, ui_button_lower_right); ui_validate_width_dimensions (ui, ui_scroll_bar_lower, ui_scroll_bar_slider); ui_validate_height_dimensions (ui, ui_fill_bar_left, ui_fill_bar_base); ui_validate_height_dimensions (ui, ui_tiny_fill_bar_left, ui_tiny_fill_bar_base); ui_validate_height_dimensions (ui, ui_separator_left, ui_separator_center); ui_validate_height_dimensions (ui, ui_title_bar_left, ui_title_bar_right); ui->separator_size [current] = ui->height [current] [ui_separator_middle]; ui->icon_size [current] = ui->height [current] [ui_icon_frame]; ui->overicon_size [current] = ui->height [current] [ui_overicon_frame]; ui->ubericon_size [current] = ui->height [current] [ui_ubericon_frame]; ui->title_bar_size [current] = ui->height [current] [ui_title_bar_middle]; ui->fill_bar_size [current] = ui->height [current] [ui_fill_bar_middle]; ui->tiny_fill_bar_size [current] = ui->height [current] [ui_tiny_fill_bar_middle]; ui->scroll_bar_size [current] = ui->width [current] [ui_scroll_bar_middle]; if (cross->very_verbose_spam == true) { print ("/c Imported UI sprites from '%s' at index %i.\n", folder, ui->count); } } static procedure ui_render (cross_structure * cross, ui_structure * ui, ui_subtype_enumeration index, integer x, integer y) { cross_render_sprite (cross, ui->sprite [ui->active] [index], x, y); } static procedure ui_render_colour (cross_structure * cross, ui_structure * ui, ui_subtype_enumeration index, natural colour, integer x, integer y) { cross_render_sprite_colour (cross, ui->sprite [ui->active] [index], colour, x, y); } static procedure ui_subrender (cross_structure * cross, ui_structure * ui, ui_subtype_enumeration index, integer x, integer y, natural u, natural v, natural width, natural height) { cross_render_sprite_crop (cross, ui->sprite [ui->active] [index], x, y, u, v, width, height); } static procedure ui_subrender_colour (cross_structure * cross, ui_structure * ui, ui_subtype_enumeration index, natural colour, integer x, integer y, natural u, natural v, natural width, natural height) { cross_render_sprite_crop_colour (cross, ui->sprite [ui->active] [index], colour, x, y, u, v, width, height); } static procedure ui_render_horizontal (cross_structure * cross, ui_structure * ui, ui_subtype_enumeration index, integer x, integer y, natural width) { integer entire = (width / ui->width [ui->active] [index]) * ui->width [ui->active] [index]; for (natural margin = 0; margin < width / ui->width [ui->active] [index]; ++margin) { ui_render (cross, ui, index, x + margin * ui->width [ui->active] [index], y); } if (width % ui->width [ui->active] [index] > 0) { ui_subrender (cross, ui, index, x + entire, y, 0, 0, width % ui->width [ui->active] [index], ui->height [ui->active] [index]); } } static procedure ui_render_horizontal_colour (cross_structure * cross, ui_structure * ui, ui_subtype_enumeration index, natural colour, integer x, integer y, natural width) { //~natural width_divisor = width / ui->width [ui->active] [index]; //~natural width_remainder = width % ui->width [ui->active] [index]; //~for (natural offset = 0; offset < width_divisor; ++offset) { //~ui_render_colour (cross, ui, index, colour, x + offset * ui->width [ui->active] [index], y); //~} //~if (width_remainder > 0) { //~ui_subrender_colour (cross, ui, index, colour, x + width - width_remainder, y, 0, 0, width_remainder, ui->height [ui->active] [index]); //~} integer entire = (width / ui->width [ui->active] [index]) * ui->width [ui->active] [index]; for (natural margin = 0; margin < width / ui->width [ui->active] [index]; ++margin) { ui_render (cross, ui, index, x + margin * ui->width [ui->active] [index], y); } if (width % ui->width [ui->active] [index] > 0) { ui_subrender (cross, ui, index, x + entire, y, 0, 0, width % ui->width [ui->active] [index], ui->height [ui->active] [index]); } } static procedure ui_render_vertical (cross_structure * cross, ui_structure * ui, ui_subtype_enumeration index, integer x, integer y, natural height) { integer entire = (height / ui->height [ui->active] [index]) * ui->height [ui->active] [index]; for (natural margin = 0; margin < height / ui->height [ui->active] [index]; ++margin) { ui_render (cross, ui, index, x, y + margin * ui->height [ui->active] [index]); } if (height % ui->height [ui->active] [index] > 0) { ui_subrender (cross, ui, index, x, y + entire, 0, 0, ui->width [ui->active] [index], height % ui->height [ui->active] [index]); } } static procedure ui_render_background (cross_structure * cross, ui_structure * ui, ui_subtype_enumeration index, integer x, integer y, natural width, natural height) { natural offset_x = (width / ui->width [ui->active] [index]) * ui->width [ui->active] [index]; natural offset_y = (height / ui->height [ui->active] [index]) * ui->height [ui->active] [index]; natural cutoff_x = width % ui->width [ui->active] [index]; natural cutoff_y = height % ui->height [ui->active] [index]; for (natural vertical = 0; vertical < height / ui->height [ui->active] [index]; ++vertical) { for (natural horizontal = 0; horizontal < width / ui->width [ui->active] [index]; ++horizontal) { ui_render (cross, ui, index, x + horizontal * ui->width [ui->active] [index], y + vertical * ui->height [ui->active] [index]); } if (width % ui->width [ui->active] [index] > 0) { ui_subrender (cross, ui, index, x + offset_x, y + vertical * ui->height [ui->active] [index], 0, 0, cutoff_x, ui->height [ui->active] [index]); } } for (natural horizontal = 0; horizontal < width / ui->width [ui->active] [index]; ++horizontal) { ui_subrender (cross, ui, index, x + horizontal * ui->width [ui->active] [index], y + offset_y, 0, 0, ui->width [ui->active] [index], cutoff_y); } if (width % ui->width [ui->active] [index] > 0) { ui_subrender (cross, ui, index, x + offset_x, y + offset_y, 0, 0, cutoff_x, cutoff_y); } } static procedure ui_screen_overlay (cross_structure * cross, natural colour) { cross_render_rectangle (cross, 0, 0, cross->window_width, cross->window_height, colour); } static procedure ui_render_grid (cross_structure * cross, ui_structure * ui, ui_type_enumeration element, integer x, integer y, natural width, natural height, boolean background) { if ((width < ui->width [ui->active] [element + 4] + ui->width [ui->active] [element + 5] + ui->width [ui->active] [element + 2]) || (height < ui->height [ui->active] [element + 4] + ui->height [ui->active] [element + 6] + ui->height [ui->active] [element + 0])) { return; } natural upper_length = width - ui->width [ui->active] [element + 4] - ui->width [ui->active] [element + 5]; natural lower_length = width - ui->width [ui->active] [element + 6] - ui->width [ui->active] [element + 7]; natural left_length = height - ui->height [ui->active] [element + 4] - ui->height [ui->active] [element + 6]; natural right_length = height - ui->height [ui->active] [element + 5] - ui->height [ui->active] [element + 7]; integer upper_offset_x = ui->width [ui->active] [element + 4]; integer lower_offset_x = ui->width [ui->active] [element + 6]; integer lower_offset_y = height - ui->height [ui->active] [element + 3]; integer right_offset_x = width - ui->width [ui->active] [element + 1]; integer left_offset_y = ui->height [ui->active] [element + 4]; integer right_offset_y = ui->height [ui->active] [element + 5]; integer upper_right_offset_x = width - ui->width [ui->active] [element + 5]; integer lower_right_offset_x = width - ui->width [ui->active] [element + 7]; integer lower_left_offset_y = height - ui->height [ui->active] [element + 6]; integer lower_right_offset_y = height - ui->height [ui->active] [element + 7]; 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); if (background == true) { ui_render_background (cross, ui, element + 8, x + upper_offset_x, y + left_offset_y, upper_length, left_length); } } static procedure ui_render_window (cross_structure * cross, ui_structure * ui, integer x, integer y, natural width, natural height) { ui_render_grid (cross, ui, ui_window, x, y, width, height, false); } static procedure ui_render_frame (cross_structure * cross, ui_structure * ui, integer x, integer y, natural width, natural height) { ui_render_grid (cross, ui, ui_frame, x, y, width, height, false); } static procedure ui_render_status (cross_structure * cross, ui_structure * ui, integer x, integer y, natural width, natural height) { ui_render_grid (cross, ui, ui_status, x, y, width, height, true); } static procedure ui_render_menu (cross_structure * cross, ui_structure * ui, integer x, integer y, natural width, natural height) { ui_render_grid (cross, ui, ui_menu, x, y, width, height, true); } static procedure ui_render_button (cross_structure * cross, ui_structure * ui, integer x, integer y, natural width, natural height) { ui_render_grid (cross, ui, ui_button, x, y, width, height, true); } static procedure ui_render_separator (cross_structure * cross, ui_structure * ui, integer x, integer y, natural width) { natural margin = ui->width [ui->active] [ui_separator_left]; natural length = width - margin - ui->width [ui->active] [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->active] [ui_separator_center]) / 2, y); } static procedure ui_render_title_bar (cross_structure * cross, ui_structure * ui, character * title, integer x, integer y, natural width) { natural margin = ui->width [ui->active] [ui_title_bar_left]; natural length = width - margin - ui->width [ui->active] [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 [ui->active], x + margin + 8, y + 8, 1, 0x112233ff); } static procedure ui_render_icon_and_text (cross_structure * cross, ui_structure * ui, character * title, natural icon, integer x, integer y, natural colour) { cross_render_sprite (cross, icon, x, y); ////////////////////////////////////////// cross_render_string (cross, title, ui->font [ui->active], x - 2 + ui->icon_size [ui->active], y + 2, 1.0f, colour); } static procedure ui_render_scroll_bar (cross_structure * cross, ui_structure * ui, real slider, integer x, integer y, natural height) { natural margin = ui->height [ui->active] [ui_scroll_bar_upper]; natural length = height - margin - ui->height [ui->active] [ui_scroll_bar_lower]; real slider_offset = slider * (real) (length - ui->height [ui->active] [ui_scroll_bar_slider]); 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 + (natural) slider_offset); } static procedure ui_render_fill_bar (cross_structure * cross, ui_structure * ui, real fill, natural colour, integer x, integer y, natural width) { natural margin = ui->width [ui->active] [ui_fill_bar_left]; natural length = width - margin - ui->width [ui->active] [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, (natural) (fill * (real) length)); } static procedure ui_render_icon (cross_structure * cross, ui_structure * ui, natural icon, integer x, integer y) { cross_render_sprite (cross, ui->sprite [ui->active] [ui_icon_frame], x, y); if (icon != ui->ignore) { cross_render_sprite (cross, icon, x, y); } } static procedure ui_render_overicon (cross_structure * cross, ui_structure * ui, natural icon, integer x, integer y) { if (icon != ui->ignore) { cross_render_sprite (cross, icon, x, y); } cross_render_sprite (cross, ui->sprite [ui->active] [ui_overicon_frame], x, y); } static procedure ui_render_ubericon (cross_structure * cross, ui_structure * ui, natural icon, integer x, integer y, natural offset) { cross_render_sprite (cross, ui->sprite [ui->active] [ui_ubericon_frame], x, y); if (icon != ui->ignore) { cross_render_sprite (cross, icon, x + offset, y + offset); } } static procedure ui_render_menu_full (cross_structure * cross, ui_structure * ui, character * title, integer x, integer y, natural width, natural height, natural overlay_colour, natural margin) { if (overlay_colour != 0x00000000u) { ui_screen_overlay (cross, overlay_colour); } ui_render_menu (cross, ui, x, y, width, height); if (title != null) { ui_render_title_bar (cross, ui, title, x + margin, y + margin / 2 - ui->title_bar_size [ui->active], width - 2 * margin); } }