2024-12-27 21:11:18 -06:00

277 lines
7.7 KiB
C

#if BB_CI == 0
#include <bloat-buster/bb_core.h>
#include <std/virtual_buffer.h>
#include <std/window.h>
#include <std/render.h>
#include <std/image_loader.h>
#include <std/font_provider.h>
#include <std/ui_core.h>
#include <std/ui_builder.h>
#define default_font_height (24)
auto proportional_font_height = default_font_height;
auto monospace_font_height = default_font_height;
fn TextureIndex white_texture_create(Arena* arena, Renderer* renderer)
{
u32 white_texture_width = 1024;
u32 white_texture_height = white_texture_width;
auto* white_texture_buffer = arena_allocate(arena, u32, white_texture_width * white_texture_height);
memset(white_texture_buffer, 0xff, white_texture_width * white_texture_height * sizeof(u32));
auto white_texture = renderer_texture_create(renderer, (TextureMemory) {
.pointer = white_texture_buffer,
.width = white_texture_width,
.height = white_texture_height,
.depth = 1,
.format = TEXTURE_FORMAT_R8G8B8A8_SRGB,
});
return white_texture;
}
STRUCT(BBPanel)
{
BBPanel* first;
BBPanel* last;
BBPanel* next;
BBPanel* previous;
BBPanel* parent;
f32 parent_percentage;
Axis2 split_axis;
};
STRUCT(BBWindow)
{
OSWindow os;
RenderWindow* render;
BBWindow* previous;
BBWindow* next;
BBPanel* root_panel;
UI_State* ui;
};
STRUCT(BBGUIState)
{
Arena* arena;
Timestamp last_frame_timestamp;
BBWindow* first_window;
BBWindow* last_window;
Renderer* renderer;
// TODO: should this not be thread local?
OSEventQueue event_queue;
};
global_variable BBGUIState state;
fn void ui_top_bar()
{
ui_push(pref_height, ui_em(1, 1));
{
ui_push(child_layout_axis, AXIS2_X);
auto* top_bar = ui_widget_make((UI_WidgetFlags) {
}, strlit("top_bar"));
ui_push(parent, top_bar);
{
ui_button(strlit("Button 1"));
ui_button(strlit("Button 2"));
ui_button(strlit("Button 3"));
}
ui_pop(parent);
ui_pop(child_layout_axis);
}
ui_pop(pref_height);
}
STRUCT(UI_Node)
{
String name;
String type;
String value;
String namespace;
String function;
};
fn void ui_node(UI_Node node)
{
auto* node_widget = ui_widget_make_format((UI_WidgetFlags) {
.draw_background = 1,
.draw_text = 1,
}, "{s} : {s} = {s}##{s}{s}", node.name, node.type, node.value, node.function, node.namespace);
}
fn void app_update()
{
auto frame_end = os_timestamp();
os_poll_events(&state.event_queue);
auto frame_ms = os_resolve_timestamps(state.last_frame_timestamp, frame_end, TIME_UNIT_MILLISECONDS);
state.last_frame_timestamp = frame_end;
Renderer* renderer = state.renderer;
BBWindow* window = state.first_window;
while (likely(window))
{
auto* previous = window->previous;
auto* next = window->next;
auto* render_window = window->render;
renderer_window_frame_begin(renderer, render_window);
ui_state_select(window->ui);
if (likely(ui_build_begin(window->os, frame_ms, &state.event_queue)))
{
ui_push(font_size, default_font_height);
ui_top_bar();
ui_push(child_layout_axis, AXIS2_X);
auto* workspace_widget = ui_widget_make_format((UI_WidgetFlags) {}, "workspace{u64}", window->os);
ui_push(parent, workspace_widget);
{
// Node visualizer
ui_push(child_layout_axis, AXIS2_Y);
auto* node_visualizer_widget = ui_widget_make_format((UI_WidgetFlags) {
.draw_background = 1,
}, "node_visualizer{u64}", window->os);
ui_push(parent, node_visualizer_widget);
{
ui_node((UI_Node) {
.name = strlit("a"),
.type = strlit("s32"),
.value = strlit("1"),
.namespace = strlit("foo"),
.function = strlit("main"),
});
ui_node((UI_Node) {
.name = strlit("b"),
.type = strlit("s32"),
.value = strlit("2"),
.namespace = strlit("foo"),
.function = strlit("main"),
});
}
ui_pop(parent);
ui_pop(child_layout_axis);
// Side-panel stub
ui_button(strlit("Options"));
}
ui_pop(parent);
ui_pop(child_layout_axis);
ui_build_end();
ui_draw();
ui_pop(font_size);
renderer_window_frame_end(renderer, render_window);
}
else
{
if (previous)
{
previous->next = next;
}
if (next)
{
next->previous = previous;
}
if (state.first_window == window)
{
state.first_window = next;
}
if (state.last_window == window)
{
state.last_window = previous;
}
}
window = next;
}
}
fn void window_refresh_callback(OSWindow window, void* context)
{
unused(window);
unused(context);
app_update();
}
void run_app()
{
state.arena = arena_init(MB(512), MB(2), MB(2));
os_windowing_init((OSWindowingInitializationOptions) {
#ifdef __linux__
.should_use_x11 = 1,
#else
.should_use_x11 = 0,
#endif
});
state.renderer = renderer_initialize(state.arena);
state.first_window = state.last_window = arena_allocate(state.arena, BBWindow, 1);
state.first_window->os = os_window_create((OSWindowCreate) {
.name = strlit("Bloat Buster"),
.size = {
.width = 1600,
.height= 900,
},
.refresh_callback = &window_refresh_callback,
});
if (!state.first_window->os)
{
failed_execution();
}
state.first_window->render = renderer_window_initialize(state.renderer, state.first_window->os);
state.first_window->ui = ui_state_allocate(state.renderer, state.first_window->render);
state.first_window->root_panel = arena_allocate(state.arena, BBPanel, 1);
state.first_window->root_panel->parent_percentage = 1.0f;
state.first_window->root_panel->split_axis = AXIS2_X;
auto font_path =
#ifdef _WIN32
strlit("C:/Users/David/Downloads/Fira_Sans/FiraSans-Regular.ttf");
#elif defined(__linux__)
strlit("/usr/share/fonts/TTF/FiraSans-Regular.ttf");
#elif defined(__APPLE__)
strlit("/Users/david/Library/Fonts/FiraSans-Regular.ttf");
#else
strlit("WRONG_PATH");
#endif
window_rect_texture_update_begin(state.first_window->render);
auto white_texture = white_texture_create(state.arena, state.renderer);
auto monospace_font = font_texture_atlas_create(state.arena, state.renderer, (TextureAtlasCreate) {
.font_path = font_path,
.text_height = monospace_font_height,
});
auto proportional_font = monospace_font;
window_queue_rect_texture_update(state.first_window->render, RECT_TEXTURE_SLOT_WHITE, white_texture);
renderer_queue_font_update(state.renderer, state.first_window->render, RENDER_FONT_TYPE_MONOSPACE, monospace_font);
renderer_queue_font_update(state.renderer, state.first_window->render, RENDER_FONT_TYPE_PROPORTIONAL, proportional_font);
window_rect_texture_update_end(state.renderer, state.first_window->render);
state.last_frame_timestamp = os_timestamp();
while (state.first_window)
{
app_update();
}
// TODO: deinitialization
}
#endif