diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/render.c | 19 | ||||
| -rw-r--r-- | src/render.h | 128 | ||||
| -rw-r--r-- | src/ui.c | 84 | ||||
| -rw-r--r-- | src/ui.h | 11 |
4 files changed, 169 insertions, 73 deletions
diff --git a/src/render.c b/src/render.c index 3a681d9..6eafa7b 100644 --- a/src/render.c +++ b/src/render.c @@ -496,13 +496,24 @@ s32 calculate_text_width(font *font, char *text) return x;
}
-void render_triangle(s32 x, s32 y, s32 w, s32 h, color tint)
+void render_triangle(s32 x, s32 y, s32 w, s32 h, color tint, triangle_direction dir)
{
glBegin(GL_TRIANGLES);
glColor4f(tint.r/255.0f, tint.g/255.0f, tint.b/255.0f, tint.a/255.0f);
- glVertex3i(x+(w/2), y+h, render_depth);
- glVertex3i(x, y, render_depth);
- glVertex3i(x+w, y, render_depth);
+
+ if (dir == TRIANGLE_DOWN)
+ {
+ glVertex3i(x+(w/2), y+h, render_depth);
+ glVertex3i(x, y, render_depth);
+ glVertex3i(x+w, y, render_depth);
+ }
+ else if (dir == TRIANGLE_UP)
+ {
+ glVertex3i(x+(w/2), y, render_depth);
+ glVertex3i(x+w, y+h, render_depth);
+ glVertex3i(x, y+h, render_depth);
+ }
+
glEnd();
}
diff --git a/src/render.h b/src/render.h index de6ff6d..addd0a1 100644 --- a/src/render.h +++ b/src/render.h @@ -1,62 +1,68 @@ -/* -* BSD 2-Clause “Simplified” License -* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com -* All rights reserved. -*/ - -#ifndef INCLUDE_RENDER -#define INCLUDE_RENDER - -typedef struct t_color { - u8 r; - u8 g; - u8 b; - u8 a; -} color; - -typedef struct t_vec4 -{ - s32 x; - s32 y; - s32 w; - s32 h; -} vec4; - -s32 render_depth = 1; -void set_render_depth(s32 depth); - -#define rgb(r_,g_,b_) (color){ r_, g_, b_, 255 } -#define rgba(r_,g_,b_,a_) (color){r_,g_,b_,a_} - -void render_clear(); - -// images -void render_image(image *image, s32 x, s32 y, s32 width, s32 height); -void render_image_tint(image *image, s32 x, s32 y, s32 width, s32 height, color tint); - -// text -s32 render_text(font *font, s32 x, s32 y, char *text, color tint); -s32 render_text_ellipsed(font *font, s32 x, s32 y, s32 maxw, char *text, color tint); -s32 render_text_cutoff(font *font, s32 x, s32 y, char *text, color tint, u16 cutoff_width); -s32 render_text_vertical(font *font, s32 x, s32 y, char *text, color tint); -s32 render_text_with_cursor(font *font, s32 x, s32 y, char *text, color tint, s32 cursor_pos); - -s32 calculate_cursor_position(font *font, char *text, s32 click_x); -s32 calculate_text_width(font *font, char *text); -s32 calculate_text_width_upto(font *font, char *text, s32 index); -s32 calculate_text_width_from_upto(font *font, char *text, s32 from, s32 index); - -// primitives -void render_rectangle(s32 x, s32 y, s32 width, s32 height, color tint); -void render_rectangle_tint(s32 x, s32 y, s32 width, s32 height, color tint[4]); -void render_rectangle_outline(s32 x, s32 y, s32 width, s32 height, u16 outline_w, color tint); -void render_triangle(s32 x, s32 y, s32 w, s32 h, color tint); - -// utils -void render_set_scissor(platform_window *window, s32 x, s32 y, s32 w, s32 h); -vec4 render_get_scissor(); -void render_reset_scissor(); - -void render_set_rotation(float32 rotation, float32 x, float32 y, s32 depth); - +/*
+* BSD 2-Clause “Simplified” License
+* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com
+* All rights reserved.
+*/
+
+#ifndef INCLUDE_RENDER
+#define INCLUDE_RENDER
+
+typedef struct t_color {
+ u8 r;
+ u8 g;
+ u8 b;
+ u8 a;
+} color;
+
+typedef struct t_vec4
+{
+ s32 x;
+ s32 y;
+ s32 w;
+ s32 h;
+} vec4;
+
+typedef enum t_triangle_direction
+{
+ TRIANGLE_DOWN,
+ TRIANGLE_UP,
+} triangle_direction;
+
+s32 render_depth = 1;
+void set_render_depth(s32 depth);
+
+#define rgb(r_,g_,b_) (color){ r_, g_, b_, 255 }
+#define rgba(r_,g_,b_,a_) (color){r_,g_,b_,a_}
+
+void render_clear();
+
+// images
+void render_image(image *image, s32 x, s32 y, s32 width, s32 height);
+void render_image_tint(image *image, s32 x, s32 y, s32 width, s32 height, color tint);
+
+// text
+s32 render_text(font *font, s32 x, s32 y, char *text, color tint);
+s32 render_text_ellipsed(font *font, s32 x, s32 y, s32 maxw, char *text, color tint);
+s32 render_text_cutoff(font *font, s32 x, s32 y, char *text, color tint, u16 cutoff_width);
+s32 render_text_vertical(font *font, s32 x, s32 y, char *text, color tint);
+s32 render_text_with_cursor(font *font, s32 x, s32 y, char *text, color tint, s32 cursor_pos);
+
+s32 calculate_cursor_position(font *font, char *text, s32 click_x);
+s32 calculate_text_width(font *font, char *text);
+s32 calculate_text_width_upto(font *font, char *text, s32 index);
+s32 calculate_text_width_from_upto(font *font, char *text, s32 from, s32 index);
+
+// primitives
+void render_rectangle(s32 x, s32 y, s32 width, s32 height, color tint);
+void render_rectangle_tint(s32 x, s32 y, s32 width, s32 height, color tint[4]);
+void render_rectangle_outline(s32 x, s32 y, s32 width, s32 height, u16 outline_w, color tint);
+void render_triangle(s32 x, s32 y, s32 w, s32 h, color tint, triangle_direction dir);
+
+// utils
+void render_set_scissor(platform_window *window, s32 x, s32 y, s32 w, s32 h);
+vec4 render_get_scissor();
+void render_reset_scissor();
+
+void render_set_rotation(float32 rotation, float32 x, float32 y, s32 depth);
+
#endif
\ No newline at end of file @@ -4,6 +4,20 @@ * All rights reserved.
*/
+void ui_set_hovered(u32 id, s32 x, s32 y)
+{
+ global_ui_context.item_hovered = true;
+ global_ui_context.tooltip.x = x;
+ global_ui_context.tooltip.y = y;
+
+ if (global_ui_context.item_hovered_id == id)
+ global_ui_context.item_hovered_duration++;
+ else
+ global_ui_context.item_hovered_duration = 0;
+
+ global_ui_context.item_hovered_id = id;
+}
+
inline void ui_begin(s32 id)
{
global_ui_context.item_hovered = false;
@@ -18,7 +32,7 @@ inline void ui_begin(s32 id) inline void ui_end()
{
-
+ if (!global_ui_context.item_hovered) global_ui_context.item_hovered_duration = 0;
}
inline submenu_state ui_create_submenu()
@@ -186,10 +200,18 @@ inline void ui_create(platform_window *window, keyboard_input *keyboard, mouse_i global_ui_context.keyboard = keyboard;
global_ui_context.mouse = mouse;
+ global_ui_context.camera = camera;
global_ui_context.font_small = font_small;
global_ui_context.active_menus = array_create(sizeof(s32));
global_ui_context.menu_item_count = 0;
- global_ui_context.camera = camera;
+
+ global_ui_context.active_dropdown = 0;
+ global_ui_context.confirming_button_id = -1;
+ global_ui_context.current_active_textbox = 0;
+
+ global_ui_context.item_hovered = false;
+ global_ui_context.item_hovered_id = -1;
+ global_ui_context.item_hovered_duration = 0;
array_reserve(&global_ui_context.active_menus, 100);
}
@@ -213,6 +235,7 @@ static void ui_pop_scissor() inline void ui_block_begin(layout_direction direction)
{
+ u32 id = ui_get_id();
global_ui_context.layout.layout_direction = direction;
global_ui_context.layout.block_height = 0;
global_ui_context.layout.start_offset_y = global_ui_context.layout.offset_y;
@@ -277,6 +300,7 @@ inline void ui_push_separator() void ui_push_vertical_dragbar()
{
+ u32 id = ui_get_id();
s32 x = global_ui_context.layout.offset_x + global_ui_context.camera->x + global_ui_context.layout.width;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y - WIDGET_PADDING;
s32 h = global_ui_context.layout.height;
@@ -303,6 +327,7 @@ bool ui_push_color_button(char *text, bool selected, color c) {
bool result = false;
+ u32 id = ui_get_id();
s32 x = global_ui_context.layout.offset_x + WIDGET_PADDING + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll();
s32 text_x = x + BUTTON_HORIZONTAL_TEXT_PADDING;
@@ -385,7 +410,7 @@ bool ui_push_dropdown_item(image *icon, char *title, s32 index) if (mouse_x >= x && mouse_x < x + total_w && mouse_y > y && mouse_y < y + h)
{
- global_ui_context.item_hovered = true;
+ ui_set_hovered(id, x+(total_w/2) + WIDGET_PADDING, y-WIDGET_PADDING);
platform_set_cursor(global_ui_context.layout.active_window, CURSOR_POINTER);
if (is_left_clicked(global_ui_context.mouse))
@@ -444,7 +469,8 @@ bool ui_push_dropdown(dropdown_state *state, char *title) if (mouse_x >= x && mouse_x < x + total_w && mouse_y >= y && mouse_y < y + h && !global_ui_context.item_hovered)
{
- global_ui_context.item_hovered = true;
+ ui_set_hovered(id, x+(total_w/2), y+h);
+
platform_set_cursor(global_ui_context.layout.active_window, CURSOR_POINTER);
if (is_left_clicked(global_ui_context.mouse))
{
@@ -464,7 +490,7 @@ bool ui_push_dropdown(dropdown_state *state, char *title) render_rectangle_outline(x, y, total_w, BUTTON_HEIGHT, 1, global_ui_context.style.border);
render_text(global_ui_context.font_small, text_x, text_y, title, global_ui_context.style.foreground);
- render_triangle(x+total_w - h, y+(h-(h-12))/2, h-12, h-12, global_ui_context.style.border);
+ render_triangle(x+total_w - h, y+(h-(h-12))/2, h-12, h-12, global_ui_context.style.border, TRIANGLE_DOWN);
global_ui_context.layout.dropdown_x = global_ui_context.layout.offset_x;
if (global_ui_context.layout.layout_direction == LAYOUT_HORIZONTAL)
global_ui_context.layout.offset_x += total_w + WIDGET_PADDING;
@@ -563,6 +589,7 @@ bool ui_push_textbox(textbox_state *state, char *placeholder) if (!global_ui_context.layout.active_window->has_focus)
state->state = false;
+ u32 id = ui_get_id();
s32 x = global_ui_context.layout.offset_x + WIDGET_PADDING + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll();
s32 text_x = x + 5;
@@ -992,6 +1019,7 @@ bool ui_push_hypertext_link(char *text) {
bool result = false;
+ u32 id = ui_get_id();
s32 spacing_y = (BLOCK_HEIGHT - CHECKBOX_SIZE)/2;
s32 x = global_ui_context.layout.offset_x + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll() - spacing_y;
@@ -1031,6 +1059,7 @@ bool ui_push_hypertext_link(char *text) void ui_push_textf(font *f, char *text)
{
+ u32 id = ui_get_id();
s32 spacing_y = (BLOCK_HEIGHT - CHECKBOX_SIZE)/2;
s32 x = global_ui_context.layout.offset_x + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll() - spacing_y;
@@ -1053,6 +1082,7 @@ void ui_push_textf(font *f, char *text) void ui_push_textf_width(font *f, char *text, s32 maxw)
{
+ u32 id = ui_get_id();
s32 spacing_y = (BLOCK_HEIGHT - CHECKBOX_SIZE)/2;
s32 x = global_ui_context.layout.offset_x + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll() - spacing_y;
@@ -1075,6 +1105,7 @@ void ui_push_textf_width(font *f, char *text, s32 maxw) void ui_push_text(char *text)
{
+ u32 id = ui_get_id();
s32 spacing_y = (BLOCK_HEIGHT - CHECKBOX_SIZE)/2;
s32 x = global_ui_context.layout.offset_x + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll() - spacing_y;
@@ -1096,6 +1127,7 @@ void ui_push_text(char *text) void ui_push_rect(s32 w, color c)
{
+ u32 id = ui_get_id();
s32 spacing_y = (BLOCK_HEIGHT - CHECKBOX_SIZE)/2;
s32 x = global_ui_context.layout.offset_x + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll();
@@ -1132,6 +1164,7 @@ bool ui_push_text_width(char *text, s32 maxw, bool active) {
bool result = false;
+ u32 id = ui_get_id();
s32 spacing_y = (BLOCK_HEIGHT - CHECKBOX_SIZE)/2;
s32 x = global_ui_context.layout.offset_x + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll() - spacing_y;
@@ -1192,6 +1225,7 @@ bool ui_push_checkbox(checkbox_state *state, char *title) {
bool result = false;
+ u32 id = ui_get_id();
s32 spacing_y = (BLOCK_HEIGHT - CHECKBOX_SIZE)/2;
s32 x = global_ui_context.layout.offset_x + WIDGET_PADDING + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll() - spacing_y;
@@ -1219,8 +1253,10 @@ bool ui_push_checkbox(checkbox_state *state, char *title) virt_top = top;
}
- if (mouse_x >= x && mouse_x < x + CHECKBOX_SIZE && mouse_y >= virt_top && mouse_y < virt_bottom && !global_ui_context.item_hovered)
+ if (mouse_x >= x && mouse_x < x + total_w && mouse_y >= virt_top && mouse_y < virt_bottom && !global_ui_context.item_hovered)
{
+ ui_set_hovered(id, x+(total_w/2), y+CHECKBOX_SIZE);
+
platform_set_cursor(global_ui_context.layout.active_window, CURSOR_POINTER);
if (is_left_clicked(global_ui_context.mouse))
{
@@ -1255,6 +1291,7 @@ void ui_begin_menu_submenu(submenu_state *state, char *title) {
bool result = ui_push_menu_item(title, "");
+ u32 id = ui_get_id();
s32 w = state->w;
s32 h = MENU_BAR_HEIGHT;
s32 x = global_ui_context.layout.prev_offset_x + global_ui_context.camera->x;
@@ -1333,6 +1370,7 @@ bool ui_push_menu_item(char *title, char *shortcut) set_render_depth(30);
+ u32 id = ui_get_id();
s32 x = global_ui_context.layout.prev_offset_x + global_ui_context.camera->x;
s32 w = MENU_ITEM_WIDTH;
s32 text_h = global_ui_context.font_small->px_h;
@@ -1381,7 +1419,8 @@ bool ui_push_menu_item(char *title, char *shortcut) {
platform_set_cursor(global_ui_context.layout.active_window, CURSOR_POINTER);
bg_color = global_ui_context.style.menu_hover_background;
- global_ui_context.item_hovered = true;
+
+ ui_set_hovered(id, x+w + WIDGET_PADDING, y - WIDGET_PADDING);
if (is_left_clicked(global_ui_context.mouse))
{
@@ -1413,6 +1452,7 @@ bool ui_push_image(image *img, s32 w, s32 h, s32 outline, color tint) if (!img->loaded) return result;
+ u32 id = ui_get_id();
s32 x = global_ui_context.layout.offset_x + WIDGET_PADDING + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll();
s32 total_w = w;
@@ -1463,6 +1503,7 @@ bool ui_push_button(button_state *state, char *title) {
bool result = false;
+ u32 id = ui_get_id();
s32 x = global_ui_context.layout.offset_x + WIDGET_PADDING + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll();
s32 text_x = x + BUTTON_HORIZONTAL_TEXT_PADDING;
@@ -1526,8 +1567,8 @@ bool ui_push_button(button_state *state, char *title) bool ui_push_button_image_with_confirmation(button_state *state, char *title, image *img)
{
bool result = false;
- u32 id = ui_get_id();
+ u32 id = ui_get_id();
s32 x = global_ui_context.layout.offset_x + WIDGET_PADDING + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll();
s32 text_x = x + BUTTON_HORIZONTAL_TEXT_PADDING;
@@ -1657,6 +1698,7 @@ bool ui_push_button_image(button_state *state, char *title, image *img) {
bool result = false;
+ u32 id = ui_get_id();
s32 x = global_ui_context.layout.offset_x + WIDGET_PADDING + global_ui_context.camera->x;
s32 y = global_ui_context.layout.offset_y + global_ui_context.camera->y + ui_get_scroll();
s32 text_x = x + BUTTON_HORIZONTAL_TEXT_PADDING;
@@ -1715,6 +1757,8 @@ bool ui_push_button_image(button_state *state, char *title, image *img) if (mouse_x >= x && mouse_x < x + total_w && mouse_y >= virt_top && mouse_y < virt_bottom && !global_ui_context.item_hovered)
{
+ ui_set_hovered(id, x+(total_w/2), y+h);
+
platform_set_cursor(global_ui_context.layout.active_window, CURSOR_POINTER);
bg_color = global_ui_context.style.widget_hover_background;
@@ -1878,3 +1922,27 @@ void ui_scroll_end() render_reset_scissor();
global_ui_context.layout.scroll->in_scroll = false;
}
+
+void ui_push_tooltip(char *text)
+{
+ if (global_ui_context.item_hovered && global_ui_context.item_hovered_id == global_ui_context.next_id-1)
+ {
+ if (global_ui_context.item_hovered_duration > (1000/TARGET_FRAMERATE)/2)
+ {
+ s32 total_w = calculate_text_width(global_ui_context.font_small, text) +
+ WIDGET_PADDING + WIDGET_PADDING;
+ s32 x = global_ui_context.tooltip.x - (total_w/2);
+ s32 y = global_ui_context.tooltip.y + WIDGET_PADDING+3;
+
+ set_render_depth(30);
+
+ s32 triangle_s = 20;
+ render_triangle(x+(total_w/2)-(triangle_s/2), y-6,triangle_s,9, rgb(40,40,40), TRIANGLE_UP);
+ render_rectangle(x, y,total_w,TEXTBOX_HEIGHT, rgb(40,40,40));
+
+
+ render_text(global_ui_context.font_small, x + WIDGET_PADDING, y + (TEXTBOX_HEIGHT/2)- (global_ui_context.font_small->px_h/2), text, rgb(240,240,240));
+ set_render_depth(1);
+ }
+ }
+}
\ No newline at end of file @@ -153,6 +153,12 @@ typedef struct t_submenus submenu_state *submenu_stack[5];
} submenus;
+typedef struct t_ui_tooltip
+{
+ s32 x;
+ s32 y;
+} ui_tooltip;
+
typedef struct t_ui_context
{
ui_style style;
@@ -169,6 +175,9 @@ typedef struct t_ui_context textbox_state *current_active_textbox;
submenus submenus;
bool item_hovered;
+ u32 item_hovered_id;
+ u32 item_hovered_duration;
+ ui_tooltip tooltip;
} ui_context;
ui_context global_ui_context;
@@ -224,7 +233,9 @@ bool ui_push_checkbox(checkbox_state *state, char *title); bool ui_push_textbox(textbox_state *state, char *title);
bool ui_push_button(button_state *button, char *title);
bool ui_push_button_image(button_state *button, char *title, image *img);
+bool ui_push_button_image_with_confirmation(button_state *state, char *title, image *img);
void ui_scroll_begin(scroll_state *state);
+void ui_push_tooltip(char *text);
void ui_scroll_end();
#endif
\ No newline at end of file |
