218 lines
5.8 KiB
C
218 lines
5.8 KiB
C
#include <std/ui_core.h>
|
|
#include <std/format.h>
|
|
|
|
global_variable UI_State* ui_state = 0;
|
|
|
|
void ui_state_select(UI_State* state)
|
|
{
|
|
ui_state = state;
|
|
}
|
|
|
|
UI_State* ui_state_get()
|
|
{
|
|
return ui_state;
|
|
}
|
|
|
|
u8 ui_build_begin(OSWindow window, f64 frame_time, OSEventQueue* event_queue)
|
|
{
|
|
u8 open = 1;
|
|
for (u32 generic_event_index = 0; generic_event_index < event_queue->descriptors.length; generic_event_index += 1)
|
|
{
|
|
auto event_descriptor = event_queue->descriptors.pointer[generic_event_index];
|
|
u32 event_index = event_descriptor.index;
|
|
|
|
switch (event_descriptor.type)
|
|
{
|
|
case OS_EVENT_TYPE_MOUSE_BUTTON:
|
|
{
|
|
auto button = event_queue->mouse_buttons.pointer[event_index];
|
|
auto previous_button_event = ui_state->mouse_button_events[button.button];
|
|
switch (button.event.action)
|
|
{
|
|
case OS_EVENT_MOUSE_RELAX:
|
|
unreachable();
|
|
case OS_EVENT_MOUSE_RELEASE:
|
|
{
|
|
assert(previous_button_event.action == OS_EVENT_MOUSE_PRESS);
|
|
} break;
|
|
case OS_EVENT_MOUSE_PRESS:
|
|
{
|
|
assert(previous_button_event.action == OS_EVENT_MOUSE_RELAX);
|
|
} break;
|
|
case OS_EVENT_MOUSE_REPEAT:
|
|
{
|
|
unreachable();
|
|
} break;
|
|
}
|
|
|
|
ui_state->mouse_button_events[button.button] = button.event;
|
|
} break;
|
|
case OS_EVENT_TYPE_WINDOW_FOCUS:
|
|
{
|
|
} break;
|
|
case OS_EVENT_TYPE_CURSOR_POSITION:
|
|
{
|
|
auto mouse_position = event_queue->cursor_positions.pointer[event_index];
|
|
ui_state->mouse_position = (UI_MousePosition) {
|
|
.x = mouse_position.x,
|
|
.y = mouse_position.y,
|
|
};
|
|
} break;
|
|
case OS_EVENT_TYPE_CURSOR_ENTER:
|
|
{
|
|
todo();
|
|
} break;
|
|
case OS_EVENT_TYPE_WINDOW_POSITION:
|
|
{
|
|
// event_queue->window_positions.pointer[event_index];
|
|
// todo();
|
|
} break;
|
|
case OS_EVENT_TYPE_WINDOW_CLOSE:
|
|
{
|
|
open = 0;
|
|
} break;
|
|
}
|
|
}
|
|
|
|
auto framebuffer_size = os_window_framebuffer_size_get(window);
|
|
|
|
ui_state->root = ui_widget_make(
|
|
(UI_WidgetFlags) {},
|
|
strlit(""),
|
|
(UI_Rect) {
|
|
.x0 = 0,
|
|
.y0 = 0,
|
|
.x1 = framebuffer_size.width,
|
|
.y1 = framebuffer_size.height,
|
|
}
|
|
);
|
|
|
|
return open;
|
|
}
|
|
|
|
void ui_build_end()
|
|
{
|
|
// Clear release button presses
|
|
for (u32 i = 0; i < array_length(ui_state->mouse_button_events); i += 1)
|
|
{
|
|
auto* event = &ui_state->mouse_button_events[i];
|
|
if (event->action == OS_EVENT_MOUSE_RELEASE)
|
|
{
|
|
event->action = OS_EVENT_MOUSE_RELAX;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn RenderRect render_rect(UI_Rect rect)
|
|
{
|
|
return (RenderRect) {
|
|
.x0 = rect.x0,
|
|
.y0 = rect.y0,
|
|
.x1 = rect.x1,
|
|
.y1 = rect.y1,
|
|
};
|
|
}
|
|
|
|
void ui_draw()
|
|
{
|
|
UI_Widget* root = ui_state->root;
|
|
|
|
UI_Widget* widget = root;
|
|
RenderWindow* window = ui_state->render;
|
|
Renderer* renderer = ui_state->renderer;
|
|
|
|
while (1)
|
|
{
|
|
if (widget->flags.draw_background)
|
|
{
|
|
window_render_rect(window, (RectDraw) {
|
|
.color = widget->background_color,
|
|
.vertex = render_rect(widget->rect),
|
|
});
|
|
}
|
|
|
|
if (widget->flags.draw_text)
|
|
{
|
|
window_render_text(renderer, window, widget->string, Color4(1, 1, 1, 1), RENDER_FONT_TYPE_PROPORTIONAL, widget->rect.x0, widget->rect.y0);
|
|
}
|
|
|
|
if (widget->first)
|
|
{
|
|
widget = widget->first;
|
|
}
|
|
else if (widget->next)
|
|
{
|
|
widget = widget->next;
|
|
}
|
|
else if (widget->parent == ui_state->root)
|
|
{
|
|
break;
|
|
}
|
|
else if (widget->parent)
|
|
{
|
|
widget = widget->parent;
|
|
}
|
|
else
|
|
{
|
|
unreachable();
|
|
}
|
|
}
|
|
}
|
|
|
|
UI_Widget* ui_widget_make(UI_WidgetFlags flags, String string, UI_Rect rect)
|
|
{
|
|
auto* widget = arena_allocate(ui_state->arena, UI_Widget, 1);
|
|
*widget = (UI_Widget)
|
|
{
|
|
.string = string,
|
|
.flags = flags,
|
|
.rect = rect,
|
|
.background_color = Color4(0, 0, 0, 1),
|
|
// TODO: modify
|
|
.parent = ui_state->root,
|
|
};
|
|
|
|
auto* parent = widget->parent;
|
|
if (parent)
|
|
{
|
|
auto* ptr = &parent->last;
|
|
auto* previous_last = *ptr;
|
|
if (previous_last)
|
|
{
|
|
previous_last->next = widget;
|
|
}
|
|
*ptr = widget;
|
|
|
|
if (!parent->first)
|
|
{
|
|
parent->first = widget;
|
|
}
|
|
parent->last = widget;
|
|
}
|
|
|
|
return widget;
|
|
}
|
|
|
|
UI_Widget* ui_widget_make_format(UI_WidgetFlags flags, UI_Rect rect, const char* format, ...)
|
|
{
|
|
va_list args;
|
|
u8 buffer[4096];
|
|
va_start(args, format);
|
|
auto string = format_string_va((String)array_to_slice(buffer), format, args);
|
|
va_end(args);
|
|
|
|
auto* result = ui_widget_make(flags, string, rect);
|
|
return result;
|
|
}
|
|
|
|
UI_Signal ui_signal_from_widget(UI_Widget* widget)
|
|
{
|
|
UI_Rect rect = widget->rect;
|
|
UI_Signal signal = {
|
|
.clicked_left = (widget->flags.clickable & (ui_state->mouse_button_events[OS_EVENT_MOUSE_LEFT].action == OS_EVENT_MOUSE_RELEASE)) &
|
|
(ui_state->mouse_position.x >= rect.x0 & ui_state->mouse_position.x <= rect.x1) &
|
|
(ui_state->mouse_position.y >= rect.y0 & ui_state->mouse_position.y <= rect.y1),
|
|
};
|
|
return signal;
|
|
}
|