debug_log :: (severity: Severity, format: str, args: ..any) {
if severity < minimum_severity do return;
- buffer1: [4096] u8;
+ buffer1, buffer2: [4096] u8;
s := conv.str_format_va(buffer1, format, args);
lines := string.split(s, #char "\n", context.temp_allocator);
for l: lines {
if l.count == 0 do continue;
- buffer2: [4096] u8;
s = conv.str_format(buffer2, "[{}] {}\n", severity, l);
line := string.alloc_copy(s, line_alloc);
draw_debug_log :: (window_rectangle: ui.Rectangle, site := #callsite) {
if debug_log_y_offset == 0.0f do return;
+ Font_Size :: 0.75f;
+
+ ui.use_font(config.Fonts.FiraCode.index);
+ line_height := ui.get_text_height("M", size=Font_Size);
+
r, _ := ui.Flow.split_horizontal(window_rectangle, top_percent=.5);
height := ui.Rectangle.height(r);
r.y0 -= height * (1 - debug_log_y_offset);
r.y1 -= height * (1 - debug_log_y_offset);
sh := ui.scrollable_region_start(r, state=^scrollable_region, .{
- minimum_x = 0, maximum_x = 0,
- minimum_y = 32.0f * ~~(log_buffer.lines.count - ~~(height / 32)),
+ minimum_x = 0, maximum_x = ui.Rectangle.width(window_rectangle),
+ minimum_y = line_height * ~~(log_buffer.lines.count - ~~(height / line_height)),
maximum_y = 0,
});
defer ui.scrollable_region_stop();
- r.y0 -= 32.0f * ~~log_buffer.lines.count;
+ r.y0 -= line_height * ~~log_buffer.lines.count;
visible_rectangle := sh->get_visible_rectangle();
- background_color := config.Colors.background;
- background_color.a = 0.8;
+ // background_color := config.Colors.background;
+ // background_color.a = 0.8;
+ background_color := gfx.Color4.{ 0, 0, 0, 0.8 };
ui.draw_rect(visible_rectangle, color=background_color);
text_theme := ui.default_text_theme;
text_theme.font = config.Fonts.FiraCode.index;
- text_theme.text_color = .{ 0.2, 0.5, 0.2 };
+ text_theme.font_size = Font_Size;
+ text_theme.text_color = .{ 0.2, 0.8, 0.2 };
text_rect: ui.Rectangle;
while i := cast(i32) log_buffer.lines.count - 1; i >= 0 {
- r, text_rect = ui.Flow.split_horizontal(r, bottom_height=32);
+ r, text_rect = ui.Flow.split_horizontal(r, bottom_height=line_height);
if ui.Rectangle.intersects(text_rect, visible_rectangle) {
ui.draw_text(text_rect, log_buffer.lines[i], theme=^text_theme);
}
r = visible_rectangle;
+ text_theme.font_size = 1;
clear_button_rect := ui.Rectangle.{
x0 = r.x1 - 200, x1 = r.x1,
y0 = r.y0, y1 = r.y0 + 50,
Application_Settings :: struct {
colorscheme := Colorscheme.Undefined;
+
+ coolness : Slider_Option(i32) = .{ 5, 0, 5 };
+ badness : Slider_Option(f32) = .{ 0, 0, 10 };
+
+ test : Test = .{ 5, 5 };
+ test2 : Test = .{ 0, 0 };
+ wrapped : Wrapper = .{ value = 40 };
+
+ Test :: struct { x: i32; y: f32; }
+ Wrapper :: struct {
+ test := Test.{ 10, 10 };
+ value: i32;
+ }
+}
+
+Slider_Option :: struct (T: type_expr) {
+ value: T;
+ min, max: T;
}
settings_save :: (settings: ^Application_Settings) {
if colorscheme != .Undefined do settings.colorscheme = colorscheme;
else do settings.colorscheme = .Dark;
}
+
+
+
+
+//
+// Settings Window
+//
+
+#private_file {
+ window_id :: "settings"
+ window_name :: "Settings"
+
+ ui :: package ui
+
+ @Temporary
+ settings_any: any;
+}
+
+make_any :: macro (v: $T) => any.{ ^v, T };
+
+settings_window_show :: () {
+ settings_any = make_any(state.settings);
+
+ open_window(window_id, window_name, .{ 0, 0 }, settings_window_draw, draw_data=^settings_any);
+ focus_window(window_id);
+ move_window_to_top(window_id);
+
+ open_window("settings_dummy", "Settings Dummy", .{ 0, 0 }, (_, win) => {
+ buffer: [1024] u8;
+ msg := conv.str_format(buffer, "{*p}", ^state.settings);
+ ui.draw_text(.{ 0, 0, win.window_state.size.x, win.window_state.size.y }, msg);
+ });
+}
+
+settings_window_draw :: (obj: ^any, win: ^Application_Window) {
+ // Uniqueness counter
+ #persist counter: i32;
+ counter = 0;
+
+ rect := ui.Rectangle.{ 0, 0, win.window_state.size.x, win.window_state.size.y };
+
+ #persist scrollable_region := ui.Scrollable_Region_State.{};
+ handle := ui.scrollable_region_start(rect, state=^scrollable_region, .{
+ minimum_x = 0, maximum_x = 0,
+ minimum_y = 0, maximum_y = 100000.0f,
+ });
+ defer ui.scrollable_region_stop();
+
+ // Rectangle of the visible scroll region, transformed to have the top-left of
+ // the window at 0, 0
+ win_rect := handle->get_visible_rectangle();
+
+ rect = ui.Flow.padding(rect, left=8, right=8);
+ rect.y1 = 1000000.0f;
+
+ render_settings(^rect, win_rect, obj);
+
+ // Needs to be separate because this part is recursive
+ render_settings :: (rect: ^ui.Rectangle, win_rect: ui.Rectangle, obj: ^any) {
+ use type_info;
+
+ #persist msg_buffer : [512] u8;
+ #persist tmp_rect : ui.Rectangle;
+
+ type := get_type_info(obj.type);
+ assert(type.kind == .Struct, "Expected a struct type");
+
+ settings_type := cast(^Type_Info_Struct) type;
+
+ heading_theme := ui.default_text_theme;
+ heading_theme.font_size = 1.25f;
+
+ for ^member: settings_type.members {
+ counter += 1;
+ member_type := get_type_info(member.type);
+
+ tmp_rect, *rect = ui.Flow.split_horizontal(*rect, top_height=48);
+ if ui.Rectangle.intersects(tmp_rect, win_rect) {
+ ui.draw_text(tmp_rect, member.name, theme=^heading_theme);
+ }
+
+ switch member_type.kind {
+ case .Enum {
+ value := cast(^i32) (cast(^u8) obj.data + member.offset);
+
+ enum_type := cast(^Type_Info_Enum) member_type;
+ for ^enum_member: enum_type.members {
+ counter += 1;
+ tmp_rect, *rect = ui.Flow.split_horizontal(*rect, top_height=32);
+
+ if ui.Rectangle.intersects(tmp_rect, win_rect) {
+ ui.radio(ui.Flow.padding(tmp_rect, left=32),
+ value, cast(i32) enum_member.value,
+ enum_member.name, increment=counter);
+ }
+ }
+ }
+
+ case .Struct {
+ struct_type := cast(^Type_Info_Struct) member_type;
+ sub_object := cast(rawptr) (cast(^u8) obj.data + member.offset);
+
+ switch member.type {
+ case #type Slider_Option(i32) do render_slider_option(i32, sub_object);
+ case #type Slider_Option(f32) do render_slider_option(f32, sub_object);
+
+ case #default {
+ rect.x0 += 32;
+ defer rect.x0 -= 32;
+
+ sub_object_any := any.{ sub_object, member.type };
+ render_settings(rect, win_rect, ^sub_object_any);
+ }
+ }
+ }
+
+ case .Basic do switch member.type {
+ case i32 {
+ value := cast(^i32) (cast(^u8) obj.data + member.offset);
+
+ tmp_rect, *rect = ui.Flow.split_horizontal(*rect, top_height=32);
+ if ui.Rectangle.intersects(tmp_rect, win_rect) {
+ ui.slider(tmp_rect, value, -10, 10, increment=counter);
+ ui.draw_text(tmp_rect, conv.str_format(msg_buffer, " Current: {}", *value));
+ }
+ }
+
+ case f32 {
+ value := cast(^f32) (cast(^u8) obj.data + member.offset);
+
+ tmp_rect, *rect = ui.Flow.split_horizontal(*rect, top_height=32);
+ if ui.Rectangle.intersects(tmp_rect, win_rect) {
+ ui.slider(tmp_rect, value, 0, 100, increment=counter);
+ ui.draw_text(tmp_rect, conv.str_format(msg_buffer, " Current: {}", *value));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ render_slider_option :: macro ($T: type_expr, so: rawptr) {
+ so_ := cast(^Slider_Option(T)) so;
+
+ tmp_rect, *rect = ui.Flow.split_horizontal(*rect, top_height=32);
+
+ if ui.Rectangle.intersects(tmp_rect, win_rect) {
+ ui.slider(tmp_rect, ^so_.value, so_.min, so_.max, increment=counter);
+ ui.draw_text(tmp_rect, conv.str_format(msg_buffer, " Current: {}", so_.value));
+ }
+ }
+}