From dfd9723d1a8a68f339730b792e1fee5d61f0a6f8 Mon Sep 17 00:00:00 2001 From: Mitchell Date: Tue, 21 Jul 2026 23:43:34 -0500 Subject: [PATCH] chore: add version to UI, Report Issue/Source link --- README.md | 14 ++--- src/ui/draw_bottom_panel.zig | 61 +++++++++++-------- src/ui/draw_left_column.zig | 80 +++++++++++++++++++------ src/ui/imgui_util.zig | 36 ++++++++++++ src/ui/theme.zig | 99 ++++++++++++++++--------------- src/ui/ui.zig | 110 +++++++++++++++++------------------ src/util.zig | 3 +- 7 files changed, 250 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index ed011eb..2a6a7e9 100644 --- a/README.md +++ b/README.md @@ -29,19 +29,19 @@ curl -LsSf https://spacecap.org/install | sh -s -- --uninstall - Desktop/window capture. - Screen recording. +- Screenshots. - Replay buffer - save last n seconds of video (buffered in memory). - Capture preview. - Global keybinds. ## Roadmap -- ~~Screenshots~~ -- File browser -- Video editor - - Trim clips - - Export in a variety of formats - - Adjust audio levels -- Windows support +- File browser. +- Video editor. + - Trim clips. + - Export in a variety of formats. + - Adjust audio levels. +- Windows support. ## Requirements diff --git a/src/ui/draw_bottom_panel.zig b/src/ui/draw_bottom_panel.zig index bcb46b0..bd625fc 100644 --- a/src/ui/draw_bottom_panel.zig +++ b/src/ui/draw_bottom_panel.zig @@ -7,7 +7,7 @@ const AudioDevice = @import("../store/audio_session.zig").AudioDevice; const UIStorage = @import("./ui_storage.zig").UIStorage; const imgui_util = @import("./imgui_util.zig"); const util = @import("../util.zig"); -const theme = @import("./theme.zig"); +const Colors = @import("./theme.zig").Colors; const AUDIO_GAIN_DB_MIN: f32 = -60.0; const AUDIO_GAIN_DB_MAX: f32 = 12.0; @@ -16,6 +16,19 @@ pub fn draw_bottom_panel(allocator: Allocator, ui_storage: *UIStorage, store: *S _ = c.ImGui_Begin(dockspace.BOTTOM_WINDOW_NAME, null, c.ImGuiWindowFlags_None); defer c.ImGui_End(); + { + _ = c.ImGui_BeginChild( + "##bottom_panel_content", + .{ .x = 0, .y = 0 }, + c.ImGuiChildFlags_None, + c.ImGuiWindowFlags_None, + ); + defer c.ImGui_EndChild(); + try draw_bottom_panel_content(allocator, ui_storage, store, state); + } +} + +fn draw_bottom_panel_content(allocator: Allocator, ui_storage: *UIStorage, store: *Store, state: *Store.State) !void { // ---------------------------------------------------------------------------- // Video collapsing header. // ---------------------------------------------------------------------------- @@ -79,18 +92,18 @@ pub fn draw_bottom_panel(allocator: Allocator, ui_storage: *UIStorage, store: *S c.ImGui_TableNextRow(); _ = c.ImGui_TableNextColumn(); const replay_buffer_button_label = if (state.capture.replay_buffer_active) " Replay Buffer" else " Replay Buffer"; - const replay_buffer_button_color = if (state.capture.replay_buffer_active) theme.red.as_vec4() else theme.green.as_vec4(); - const replay_buffer_button_hover_color = if (state.capture.replay_buffer_active) theme.light_red.as_vec4() else theme.light_green.as_vec4(); const replay_buffer_button_disabled = !state.capture.replay_buffer_active and !video_capture_ready; - c.ImGui_PushStyleColorImVec4(c.ImGuiCol_Button, replay_buffer_button_color); - c.ImGui_PushStyleColorImVec4(c.ImGuiCol_ButtonHovered, replay_buffer_button_hover_color); - c.ImGui_PushStyleColorImVec4(c.ImGuiCol_ButtonActive, replay_buffer_button_color); - c.ImGui_BeginDisabled(replay_buffer_button_disabled); - if (c.ImGui_ButtonEx(replay_buffer_button_label, .{ .x = c.ImGui_GetContentRegionAvail().x, .y = 0 })) { - store.dispatch(.{ .capture = if (state.capture.replay_buffer_active) .stop_replay_buffer else .start_replay_buffer }); + + { + imgui_util.push_button_color(if (state.capture.replay_buffer_active) .red else .green); + defer imgui_util.pop_button_color(); + c.ImGui_BeginDisabled(replay_buffer_button_disabled); + if (c.ImGui_ButtonEx(replay_buffer_button_label, .{ .x = c.ImGui_GetContentRegionAvail().x, .y = 0 })) { + store.dispatch(.{ .capture = if (state.capture.replay_buffer_active) .stop_replay_buffer else .start_replay_buffer }); + } + c.ImGui_EndDisabled(); } - c.ImGui_EndDisabled(); - c.ImGui_PopStyleColorEx(3); + _ = c.ImGui_TableNextColumn(); c.ImGui_Text("%.2fMB", state.capture.replay_buffer_metrics.size_in_mb(.total)); if (c.ImGui_BeginItemTooltip()) { @@ -110,18 +123,16 @@ pub fn draw_bottom_panel(allocator: Allocator, ui_storage: *UIStorage, store: *S c.ImGui_TableNextRow(); _ = c.ImGui_TableNextColumn(); const recording_button_label = if (state.capture.recording_to_disk) " Record" else " Record"; - const recording_button_color = if (state.capture.recording_to_disk) theme.red.as_vec4() else theme.green.as_vec4(); - const recording_button_hover_color = if (state.capture.recording_to_disk) theme.light_red.as_vec4() else theme.light_green.as_vec4(); - const recording_button_disabled = !state.capture.recording_to_disk and !video_capture_ready; - c.ImGui_PushStyleColorImVec4(c.ImGuiCol_Button, recording_button_color); - c.ImGui_PushStyleColorImVec4(c.ImGuiCol_ButtonHovered, recording_button_hover_color); - c.ImGui_PushStyleColorImVec4(c.ImGuiCol_ButtonActive, recording_button_color); - c.ImGui_BeginDisabled(recording_button_disabled); - if (c.ImGui_ButtonEx(recording_button_label, .{ .x = c.ImGui_GetContentRegionAvail().x, .y = 0 })) { - store.dispatch(.{ .capture = if (state.capture.recording_to_disk) .stop_recording_to_disk else .start_recording_to_disk }); + { + imgui_util.push_button_color(if (state.capture.recording_to_disk) .red else .green); + defer imgui_util.pop_button_color(); + const recording_button_disabled = !state.capture.recording_to_disk and !video_capture_ready; + c.ImGui_BeginDisabled(recording_button_disabled); + if (c.ImGui_ButtonEx(recording_button_label, .{ .x = c.ImGui_GetContentRegionAvail().x, .y = 0 })) { + store.dispatch(.{ .capture = if (state.capture.recording_to_disk) .stop_recording_to_disk else .start_recording_to_disk }); + } + c.ImGui_EndDisabled(); } - c.ImGui_EndDisabled(); - c.ImGui_PopStyleColorEx(3); _ = c.ImGui_TableNextColumn(); c.ImGui_Text("%.2fMB", state.capture.recording_metrics.size_in_mb(.total)); if (c.ImGui_BeginItemTooltip()) { @@ -338,11 +349,11 @@ fn draw_audio_device_audio_level(ui_storage: *UIStorage, audio_device: *AudioDev // Pick the meter color and draw the progress bar. // ---------------------------------------------------------------------------- const color = if (audio_level_linear >= 0.9) - theme.red.as_vec4() + Colors.red.as_vec4() else if (audio_level_linear >= 0.75) - theme.accent.as_vec4() + Colors.accent.as_vec4() else - theme.green.as_vec4(); + Colors.green.as_vec4(); const size = c.ImVec2{ .x = c.ImGui_GetContentRegionAvail().x, .y = c.ImGui_GetFrameHeight(), diff --git a/src/ui/draw_left_column.zig b/src/ui/draw_left_column.zig index becf4bf..5a3145e 100644 --- a/src/ui/draw_left_column.zig +++ b/src/ui/draw_left_column.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const build_options = @import("build_options"); const c = @import("imguiz").imguiz; const imgui_util = @import("./imgui_util.zig"); const util = @import("../util.zig"); @@ -35,36 +36,65 @@ pub fn draw_left_column(allocator: std.mem.Allocator, store: *Store, state: *Sto _ = c.ImGui_Begin(dockspace.LEFT_WINDOW_NAME, null, c.ImGuiWindowFlags_None); defer c.ImGui_End(); - if (c.ImGui_BeginTabBar("MainTabBar", 0)) { - defer c.ImGui_EndTabBar(); - - if (c.ImGui_BeginTabItem(" Settings", null, 0)) { - defer c.ImGui_EndTabItem(); + const footer_height = c.ImGui_GetFrameHeight(); + // ---------------------------------------------------------------------------- + // Content + // ---------------------------------------------------------------------------- + { + _ = c.ImGui_BeginChild( + "##left_column_content", + .{ .x = 0, .y = -footer_height }, + c.ImGuiChildFlags_None, + c.ImGuiWindowFlags_None, + ); + defer c.ImGui_EndChild(); + if (c.ImGui_BeginTabBar("main_tab_bar", 0)) { + defer c.ImGui_EndTabBar(); - try draw_capture_settings(allocator, store, state); + if (c.ImGui_BeginTabItem(" Settings", null, 0)) { + defer c.ImGui_EndTabItem(); - c.ImGui_Dummy(.{ .x = 0, .y = GROUP_SPACING }); + try draw_capture_settings(allocator, store, state); - try draw_output_settings(allocator, store); + c.ImGui_Dummy(.{ .x = 0, .y = GROUP_SPACING }); - c.ImGui_Dummy(.{ .x = 0, .y = GROUP_SPACING }); - draw_misc_settings(); + try draw_output_settings(allocator, store); - if (util.DEBUG) { c.ImGui_Dummy(.{ .x = 0, .y = GROUP_SPACING }); - c.ImGui_SeparatorText("IMGUI Debug"); + draw_misc_settings(); - if (c.ImGui_ButtonEx("Show Demo", .{ .x = c.ImGui_GetContentRegionAvail().x, .y = 0 })) { - store.dispatch(.show_demo); - } + if (util.DEBUG) { + c.ImGui_Dummy(.{ .x = 0, .y = GROUP_SPACING }); + c.ImGui_SeparatorText("IMGUI Debug"); + + if (c.ImGui_ButtonEx("Show Demo", .{ .x = c.ImGui_GetContentRegionAvail().x, .y = 0 })) { + store.dispatch(.show_demo); + } - c.ImGui_Spacing(); - const io = c.ImGui_GetIO(); - c.ImGui_TextDisabled("%.3f ms/frame", 1000.0 / io.*.Framerate); - c.ImGui_TextDisabled("%.1f fps", io.*.Framerate); + c.ImGui_Spacing(); + const io = c.ImGui_GetIO(); + c.ImGui_TextDisabled("%.3f ms/frame", 1000.0 / io.*.Framerate); + c.ImGui_TextDisabled("%.1f fps", io.*.Framerate); + } } } } + + // ---------------------------------------------------------------------------- + // Footer + // ---------------------------------------------------------------------------- + { + _ = c.ImGui_BeginChild( + "##left_column_footer", + .{ .x = 0, .y = 0 }, + c.ImGuiChildFlags_None, + c.ImGuiWindowFlags_None, + ); + defer c.ImGui_EndChild(); + const version_label = std.fmt.comptimePrint("{s}", .{build_options.version}); + imgui_util.center_next_text(version_label); + c.ImGui_TextDisabled(version_label); + } } fn draw_misc_settings() void { @@ -75,6 +105,18 @@ fn draw_misc_settings() void { c.ImGui_OpenPopup(popup_title, c.ImGuiPopupFlags_None); } + c.ImGui_Dummy(.{ .x = 0, .y = GROUP_SPACING }); + + const report_an_issue_text = "Report Issue"; + imgui_util.center_next_text(report_an_issue_text); + _ = c.ImGui_TextLinkOpenURLEx(report_an_issue_text, "https://github.com/mgerb/spacecap/issues/new"); + + c.ImGui_Dummy(.{ .x = 0, .y = GROUP_SPACING }); + + const source_text = " Source"; + imgui_util.center_next_text(source_text); + _ = c.ImGui_TextLinkOpenURLEx(source_text, "https://github.com/mgerb/spacecap"); + const viewport_size = c.ImGui_GetMainViewport().*.Size; c.ImGui_SetNextWindowSize(.{ .x = @min(800, viewport_size.x), .y = @min(600, viewport_size.y) }, c.ImGuiCond_Appearing); var popup_open = true; // Enables the close icon in the top right. diff --git a/src/ui/imgui_util.zig b/src/ui/imgui_util.zig index aac75d4..76f66ce 100644 --- a/src/ui/imgui_util.zig +++ b/src/ui/imgui_util.zig @@ -1,5 +1,6 @@ const std = @import("std"); const imguiz = @import("imguiz").imguiz; +const Colors = @import("./theme.zig").Colors; pub const WIDTH_FILL = -std.math.floatMin(f32); @@ -31,3 +32,38 @@ pub fn item_tooltip(text: [*:0]const u8) void { pub fn set_next_item_width_fill() void { imguiz.ImGui_SetNextItemWidth(WIDTH_FILL); } + +pub fn center_next_text(text: [*:0]const u8) void { + const text_width = imguiz.ImGui_CalcTextSizeEx(text, null, true, -1).x; + const available_width = imguiz.ImGui_GetContentRegionAvail().x; + imguiz.ImGui_SetCursorPosX( + imguiz.ImGui_GetCursorPosX() + @max(0, (available_width - text_width) / 2), + ); +} + +/// NOTE: Must be followed by `pop_button_color`. +pub fn push_button_color(color: Colors.Enum) void { + const colors = blk: { + switch (color) { + .red => { + break :blk .{ Colors.red.as_vec4(), Colors.light_red.as_vec4() }; + }, + .green => { + break :blk .{ Colors.green.as_vec4(), Colors.light_green.as_vec4() }; + }, + .transparent => { + break :blk .{ Colors.transparent.as_vec4(), Colors.transparent.as_vec4() }; + }, + else => { + @panic("Color not implemented."); + }, + } + }; + imguiz.ImGui_PushStyleColorImVec4(imguiz.ImGuiCol_Button, colors.@"0"); + imguiz.ImGui_PushStyleColorImVec4(imguiz.ImGuiCol_ButtonHovered, colors.@"1"); + imguiz.ImGui_PushStyleColorImVec4(imguiz.ImGuiCol_ButtonActive, colors.@"0"); +} + +pub fn pop_button_color() void { + imguiz.ImGui_PopStyleColorEx(3); +} diff --git a/src/ui/theme.zig b/src/ui/theme.zig index 94db4c4..9938149 100644 --- a/src/ui/theme.zig +++ b/src/ui/theme.zig @@ -1,53 +1,27 @@ +const std = @import("std"); const c = @import("imguiz").imguiz; -pub const red = Color.init("#c24d3f"); -pub const light_red = Color.init("#cf625a"); -pub const green = Color.init("#29ae62"); -pub const light_green = Color.init("#36c37d"); -pub const light_blue = Color.init("#5bbcff"); -pub const blue = Color.init("#3791d2"); -pub const dark_blue = Color.init("#2a7cb7"); -pub const text = Color.init("#faf4eb"); -pub const light_accent = Color.init("#f2e6cf"); -pub const accent = Color.init("#e1ccad"); -pub const dark_1 = Color.init("#0a0a0a"); -pub const dark_2 = Color.init("#212121"); -pub const dark_3 = Color.init("#363636"); +pub const Colors = struct { + pub const red = Color.init("#c24d3f"); + pub const light_red = Color.init("#cf625a"); + pub const green = Color.init("#29ae62"); + pub const light_green = Color.init("#36c37d"); + pub const light_blue = Color.init("#5bbcff"); + pub const blue = Color.init("#3791d2"); + pub const dark_blue = Color.init("#2a7cb7"); + pub const text = Color.init("#faf4eb"); + pub const light_accent = Color.init("#f2e6cf"); + pub const accent = Color.init("#e1ccad"); + pub const dark_1 = Color.init("#0a0a0a"); + pub const dark_2 = Color.init("#212121"); + pub const dark_3 = Color.init("#363636"); + // pub const transparent: Color = .{ .r = 0, .g = 0, .b = 0, .a = 0 }; + pub const transparent = Color.init("#00000000"); -fn hex_to_imvec4(comptime hex: []const u8) c.ImVec4 { - const start = if (hex.len > 0 and hex[0] == '#') 1 else 0; - const digits = hex.len - start; - if (digits != 6 and digits != 8) { - @compileError("hex color must be rrggbb, #rrggbb, rrggbbaa, or #rrggbbaa"); - } - - const r = hex_byte(hex[start], hex[start + 1]); - const g = hex_byte(hex[start + 2], hex[start + 3]); - const b = hex_byte(hex[start + 4], hex[start + 5]); - const a = if (digits == 8) hex_byte(hex[start + 6], hex[start + 7]) else 255; - - return .{ - .x = @as(f32, @floatFromInt(r)) / 255.0, - .y = @as(f32, @floatFromInt(g)) / 255.0, - .z = @as(f32, @floatFromInt(b)) / 255.0, - .w = @as(f32, @floatFromInt(a)) / 255.0, - }; -} - -fn hex_byte(comptime high: u8, comptime low: u8) u8 { - return hex_digit(high) * 16 + hex_digit(low); -} - -fn hex_digit(comptime digit: u8) u8 { - return switch (digit) { - '0'...'9' => digit - '0', - 'a'...'f' => digit - 'a' + 10, - 'A'...'F' => digit - 'A' + 10, - else => @compileError("hex color contains a non-hex digit"), - }; -} + pub const Enum = std.meta.DeclEnum(@This()); +}; -pub const Color = struct { +const Color = struct { hex: []const u8, r: u8, g: u8, @@ -83,4 +57,37 @@ pub const Color = struct { vec.w = alpha; return vec; } + + fn hex_to_imvec4(comptime hex: []const u8) c.ImVec4 { + const start = if (hex.len > 0 and hex[0] == '#') 1 else 0; + const digits = hex.len - start; + if (digits != 6 and digits != 8) { + @compileError("hex color must be rrggbb, #rrggbb, rrggbbaa, or #rrggbbaa"); + } + + const r = hex_byte(hex[start], hex[start + 1]); + const g = hex_byte(hex[start + 2], hex[start + 3]); + const b = hex_byte(hex[start + 4], hex[start + 5]); + const a = if (digits == 8) hex_byte(hex[start + 6], hex[start + 7]) else 255; + + return .{ + .x = @as(f32, @floatFromInt(r)) / 255.0, + .y = @as(f32, @floatFromInt(g)) / 255.0, + .z = @as(f32, @floatFromInt(b)) / 255.0, + .w = @as(f32, @floatFromInt(a)) / 255.0, + }; + } + + fn hex_byte(comptime high: u8, comptime low: u8) u8 { + return hex_digit(high) * 16 + hex_digit(low); + } + + fn hex_digit(comptime digit: u8) u8 { + return switch (digit) { + '0'...'9' => digit - '0', + 'a'...'f' => digit - 'a' + 10, + 'A'...'F' => digit - 'A' + 10, + else => @compileError("hex color contains a non-hex digit"), + }; + } }; diff --git a/src/ui/ui.zig b/src/ui/ui.zig index 6788e7f..633a17d 100644 --- a/src/ui/ui.zig +++ b/src/ui/ui.zig @@ -19,7 +19,7 @@ const WaylandPresentGate = @import("./wayland_present_gate.zig").WaylandPresentG const AppIcon = @import("./app_icon.zig").AppIcon; const Store = @import("../store/store.zig").Store; const util = @import("../util.zig"); -const theme = @import("./theme.zig"); +const Colors = @import("./theme.zig").Colors; // TODO: save and restore window size const WIDTH = 1600; @@ -66,60 +66,60 @@ fn setup_imgui_style() void { style.*.ButtonTextAlign = c.ImVec2{ .x = 0.5, .y = 0.5 }; style.*.SelectableTextAlign = c.ImVec2{ .x = 0.0, .y = 0.0 }; - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Text))] = theme.text.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TextDisabled))] = theme.text.as_vec4_with_alpha(0.5); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_WindowBg))] = theme.dark_1.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ChildBg))] = theme.dark_1.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PopupBg))] = theme.dark_1.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Border))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_BorderShadow))] = theme.dark_1.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_FrameBg))] = theme.dark_2.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_FrameBgHovered))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_FrameBgActive))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TitleBg))] = theme.dark_1.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TitleBgActive))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TitleBgCollapsed))] = theme.dark_1.as_vec4_with_alpha(0.5); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_MenuBarBg))] = theme.dark_2.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ScrollbarBg))] = theme.dark_1.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ScrollbarGrab))] = theme.accent.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ScrollbarGrabHovered))] = theme.light_accent.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ScrollbarGrabActive))] = theme.light_accent.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_CheckMark))] = theme.light_accent.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_CheckboxSelectedBg))] = theme.dark_blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_SliderGrab))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_SliderGrabActive))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Button))] = theme.dark_blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ButtonHovered))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ButtonActive))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Header))] = theme.dark_2.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_HeaderHovered))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_HeaderActive))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Separator))] = theme.dark_2.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_SeparatorHovered))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_SeparatorActive))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ResizeGrip))] = theme.dark_2.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ResizeGripHovered))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ResizeGripActive))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Tab))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TabHovered))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TabActive))] = theme.dark_blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TabUnfocused))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TabUnfocusedActive))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PlotLines))] = theme.accent.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PlotLinesHovered))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PlotHistogram))] = theme.accent.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PlotHistogramHovered))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableHeaderBg))] = theme.dark_2.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableBorderStrong))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableBorderLight))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableRowBg))] = theme.dark_1.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableRowBgAlt))] = theme.text.as_vec4_with_alpha(0.06); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TextSelectedBg))] = theme.dark_3.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_DragDropTarget))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_NavHighlight))] = theme.blue.as_vec4(); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_NavWindowingHighlight))] = theme.text.as_vec4_with_alpha(0.19607843); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_NavWindowingDimBg))] = theme.text.as_vec4_with_alpha(0.19742489); - style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ModalWindowDimBg))] = theme.text.as_vec4_with_alpha(0.19742489); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Text))] = Colors.text.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TextDisabled))] = Colors.text.as_vec4_with_alpha(0.5); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_WindowBg))] = Colors.dark_1.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ChildBg))] = Colors.dark_1.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PopupBg))] = Colors.dark_1.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Border))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_BorderShadow))] = Colors.dark_1.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_FrameBg))] = Colors.dark_2.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_FrameBgHovered))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_FrameBgActive))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TitleBg))] = Colors.dark_1.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TitleBgActive))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TitleBgCollapsed))] = Colors.dark_1.as_vec4_with_alpha(0.5); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_MenuBarBg))] = Colors.dark_2.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ScrollbarBg))] = Colors.dark_1.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ScrollbarGrab))] = Colors.accent.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ScrollbarGrabHovered))] = Colors.light_accent.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ScrollbarGrabActive))] = Colors.light_accent.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_CheckMark))] = Colors.light_accent.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_CheckboxSelectedBg))] = Colors.dark_blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_SliderGrab))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_SliderGrabActive))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Button))] = Colors.dark_blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ButtonHovered))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ButtonActive))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Header))] = Colors.dark_2.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_HeaderHovered))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_HeaderActive))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Separator))] = Colors.dark_2.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_SeparatorHovered))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_SeparatorActive))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ResizeGrip))] = Colors.dark_2.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ResizeGripHovered))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ResizeGripActive))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_Tab))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TabHovered))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TabActive))] = Colors.dark_blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TabUnfocused))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TabUnfocusedActive))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PlotLines))] = Colors.accent.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PlotLinesHovered))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PlotHistogram))] = Colors.accent.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_PlotHistogramHovered))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableHeaderBg))] = Colors.dark_2.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableBorderStrong))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableBorderLight))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableRowBg))] = Colors.dark_1.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TableRowBgAlt))] = Colors.text.as_vec4_with_alpha(0.06); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_TextSelectedBg))] = Colors.dark_3.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_DragDropTarget))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_NavHighlight))] = Colors.blue.as_vec4(); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_NavWindowingHighlight))] = Colors.text.as_vec4_with_alpha(0.19607843); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_NavWindowingDimBg))] = Colors.text.as_vec4_with_alpha(0.19742489); + style.*.Colors[0][@as(usize, @intCast(c.ImGuiCol_ModalWindowDimBg))] = Colors.text.as_vec4_with_alpha(0.19742489); } pub const UI = struct { diff --git a/src/util.zig b/src/util.zig index 77006d9..2c41b3e 100644 --- a/src/util.zig +++ b/src/util.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const Allocator = std.mem.Allocator; const assert = std.debug.assert; const log = std.log.scoped(.util); const Env = @import("./env.zig"); @@ -23,7 +24,7 @@ pub fn print_elapsed(io: std.Io, start_time: i128, prefix: []const u8) void { pub fn format_duration_label(allocator: std.mem.Allocator, args: struct { seconds: f64, max: ?u32 = null, -}) ![:0]u8 { +}) Allocator.Error![:0]u8 { const input_seconds = @max(args.seconds, 0.0); // If max is provided, round seconds up and then take // the min of the two. This prevents any flicker on the UI