diff --git a/src/inspector/Inspector.zig b/src/inspector/Inspector.zig index cfe6d8771..25d46597b 100644 --- a/src/inspector/Inspector.zig +++ b/src/inspector/Inspector.zig @@ -52,12 +52,6 @@ need_scroll_to_selected: bool = false, /// Flag indicating whether the selection was made by keyboard is_keyboard_selection: bool = false, -/// Windows -windows: struct { - surface: inspector.surface.Window = .{}, - terminal: inspector.terminal.Window = .{}, -} = .{}, - // ImGui state gui: widgets.surface.Inspector = .empty, diff --git a/src/inspector/main.zig b/src/inspector/main.zig index 88d11ee20..636db1829 100644 --- a/src/inspector/main.zig +++ b/src/inspector/main.zig @@ -2,10 +2,8 @@ const std = @import("std"); pub const cell = @import("cell.zig"); pub const key = @import("key.zig"); pub const page = @import("page.zig"); -pub const screen = @import("screen.zig"); pub const surface = @import("surface.zig"); pub const termio = @import("termio.zig"); -pub const terminal = @import("terminal.zig"); pub const Cell = cell.Cell; pub const Inspector = @import("Inspector.zig"); diff --git a/src/inspector/screen.zig b/src/inspector/screen.zig deleted file mode 100644 index 63170722a..000000000 --- a/src/inspector/screen.zig +++ /dev/null @@ -1,378 +0,0 @@ -const std = @import("std"); -const cimgui = @import("dcimgui"); -const terminal = @import("../terminal/main.zig"); -const inspector = @import("main.zig"); -const units = @import("units.zig"); -const widgets = @import("widgets.zig"); - -/// Window to show screen information. -pub const Window = struct { - /// Window name/id. - pub const name = "Screen"; - - /// Grid position inputs for cell inspection. - grid_pos_x: c_int = 0, - grid_pos_y: c_int = 0, - - pub const FrameData = struct { - /// The screen that we're inspecting. - screen: *const terminal.Screen, - - /// Which screen key we're viewing. - key: terminal.ScreenSet.Key, - - /// Which screen is active (primary or alternate). - active_key: terminal.ScreenSet.Key, - - /// Whether xterm modify other keys mode 2 is enabled. - modify_other_keys_2: bool, - - /// Color palette for cursor color resolution. - color_palette: *const terminal.color.DynamicPalette, - }; - - /// Render with custom label and close button. - pub fn render( - self: *Window, - label: [:0]const u8, - open: *bool, - data: FrameData, - ) void { - defer cimgui.c.ImGui_End(); - if (!cimgui.c.ImGui_Begin( - label, - open, - cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing, - )) return; - - self.renderContent(data); - } - - fn renderContent(self: *Window, data: FrameData) void { - const screen = data.screen; - - // Show warning if viewing an inactive screen - if (data.key != data.active_key) { - cimgui.c.ImGui_TextColored( - .{ .x = 1.0, .y = 0.8, .z = 0.0, .w = 1.0 }, - "⚠ Viewing inactive screen", - ); - cimgui.c.ImGui_Separator(); - } - - if (cimgui.c.ImGui_CollapsingHeader( - "Cursor", - cimgui.c.ImGuiTreeNodeFlags_None, - )) { - widgets.screen.cursorTable(&screen.cursor); - widgets.screen.cursorStyle( - &screen.cursor, - &data.color_palette.current, - ); - } // cursor - - if (cimgui.c.ImGui_CollapsingHeader( - "Keyboard", - cimgui.c.ImGuiTreeNodeFlags_None, - )) { - { - _ = cimgui.c.ImGui_BeginTable( - "table_keyboard", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - const kitty_flags = screen.kitty_keyboard.current(); - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Mode"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - const mode = if (kitty_flags.int() != 0) "kitty" else "legacy"; - cimgui.c.ImGui_Text("%s", mode.ptr); - } - } - - if (kitty_flags.int() != 0) { - const Flags = @TypeOf(kitty_flags); - inline for (@typeInfo(Flags).@"struct".fields) |field| { - { - const value = @field(kitty_flags, field.name); - - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - const field_name = std.fmt.comptimePrint("{s}", .{field.name}); - cimgui.c.ImGui_Text("%s", field_name.ptr); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text( - "%s", - if (value) "true".ptr else "false".ptr, - ); - } - } - } - } else { - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Xterm modify keys"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text( - "%s", - if (data.modify_other_keys_2) "true".ptr else "false".ptr, - ); - } - } - } // keyboard mode info - } // table - } // keyboard - - if (cimgui.c.ImGui_CollapsingHeader( - "Grid", - cimgui.c.ImGuiTreeNodeFlags_None, - )) { - self.renderGrid(data); - } // grid - - if (cimgui.c.ImGui_CollapsingHeader( - "Kitty Graphics", - cimgui.c.ImGuiTreeNodeFlags_None, - )) kitty_gfx: { - if (!screen.kitty_images.enabled()) { - cimgui.c.ImGui_TextDisabled("(Kitty graphics are disabled)"); - break :kitty_gfx; - } - - { - _ = cimgui.c.ImGui_BeginTable( - "##kitty_graphics", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - const kitty_images = &screen.kitty_images; - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Memory Usage"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%d bytes (%d KiB)", kitty_images.total_bytes, units.toKibiBytes(kitty_images.total_bytes)); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Memory Limit"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%d bytes (%d KiB)", kitty_images.total_limit, units.toKibiBytes(kitty_images.total_limit)); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Image Count"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%d", kitty_images.images.count()); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Placement Count"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%d", kitty_images.placements.count()); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Image Loading"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%s", if (kitty_images.loading != null) "true".ptr else "false".ptr); - } - } - } // table - } // kitty graphics - - if (cimgui.c.ImGui_CollapsingHeader( - "Internal Terminal State", - cimgui.c.ImGuiTreeNodeFlags_None, - )) { - const pages = &screen.pages; - - { - _ = cimgui.c.ImGui_BeginTable( - "##terminal_state", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Memory Usage"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%d bytes (%d KiB)", pages.page_size, units.toKibiBytes(pages.page_size)); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Memory Limit"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%d bytes (%d KiB)", pages.maxSize(), units.toKibiBytes(pages.maxSize())); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Viewport Location"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%s", @tagName(pages.viewport).ptr); - } - } - } // table - // - if (cimgui.c.ImGui_CollapsingHeader( - "Active Page", - cimgui.c.ImGuiTreeNodeFlags_None, - )) { - inspector.page.render(&pages.pages.last.?.data); - } - } // terminal state - } - - /// Render the grid section. - fn renderGrid(self: *Window, data: FrameData) void { - const screen = data.screen; - const pages = &screen.pages; - - // Clamp values to valid range - const max_x: c_int = @intCast(pages.cols -| 1); - const max_y: c_int = @intCast(pages.rows -| 1); - self.grid_pos_x = std.math.clamp(self.grid_pos_x, 0, max_x); - self.grid_pos_y = std.math.clamp(self.grid_pos_y, 0, max_y); - - // Position inputs - calculate width to split available space evenly - const imgui_style = cimgui.c.ImGui_GetStyle(); - const avail_width = cimgui.c.ImGui_GetContentRegionAvail().x; - const item_spacing = imgui_style.*.ItemSpacing.x; - const label_width = cimgui.c.ImGui_CalcTextSize("x").x + imgui_style.*.ItemInnerSpacing.x; - const item_width = (avail_width - item_spacing - label_width * 2.0) / 2.0; - - cimgui.c.ImGui_PushItemWidth(item_width); - _ = cimgui.c.ImGui_DragIntEx("x", &self.grid_pos_x, 1.0, 0, max_x, "%d", cimgui.c.ImGuiSliderFlags_None); - cimgui.c.ImGui_SameLine(); - _ = cimgui.c.ImGui_DragIntEx("y", &self.grid_pos_y, 1.0, 0, max_y, "%d", cimgui.c.ImGuiSliderFlags_None); - cimgui.c.ImGui_PopItemWidth(); - - cimgui.c.ImGui_Separator(); - - const pin = pages.pin(.{ .viewport = .{ - .x = @intCast(self.grid_pos_x), - .y = @intCast(self.grid_pos_y), - } }) orelse { - cimgui.c.ImGui_TextColored( - .{ .x = 1.0, .y = 0.4, .z = 0.4, .w = 1.0 }, - "Invalid position", - ); - return; - }; - - const row_and_cell = pin.rowAndCell(); - const cell = row_and_cell.cell; - const st = pin.style(cell); - - { - _ = cimgui.c.ImGui_BeginTable( - "##grid_cell_table", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - // Codepoint - { - cimgui.c.ImGui_TableNextRow(); - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Codepoint"); - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - const cp = cell.codepoint(); - if (cp == 0) { - cimgui.c.ImGui_Text("(empty)"); - } else { - cimgui.c.ImGui_Text("U+%X", @as(c_uint, cp)); - } - } - - // Grapheme extras - if (cell.hasGrapheme()) { - if (pin.grapheme(cell)) |cps| { - cimgui.c.ImGui_TableNextRow(); - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Grapheme"); - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - for (cps) |cp| { - cimgui.c.ImGui_Text("U+%X", @as(c_uint, cp)); - } - } - } - - // Width property - { - cimgui.c.ImGui_TableNextRow(); - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Width"); - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%s", @tagName(cell.wide).ptr); - } - } - - cimgui.c.ImGui_Separator(); - widgets.style.table(st, &data.color_palette.current); - } -}; diff --git a/src/inspector/terminal.zig b/src/inspector/terminal.zig deleted file mode 100644 index e21cb2b7f..000000000 --- a/src/inspector/terminal.zig +++ /dev/null @@ -1,673 +0,0 @@ -const std = @import("std"); -const Allocator = std.mem.Allocator; -const cimgui = @import("dcimgui"); -const terminal = @import("../terminal/main.zig"); -const Terminal = terminal.Terminal; -const widgets = @import("widgets.zig"); -const modes = terminal.modes; -const inspector = @import("main.zig"); - -/// Context for our detachable collapsing headers. -const RenderContext = struct { - window: *Window, - terminal: *Terminal, -}; - -/// Window to show terminal state information. -pub const Window = struct { - /// Window name/id. - pub const name = "Terminal"; - - /// Whether the palette window is open. - show_palette: bool = false, - - /// State for detachable headers. - misc_state: widgets.DetachableHeaderState = .{}, - layout_state: widgets.DetachableHeaderState = .{}, - mouse_state: widgets.DetachableHeaderState = .{}, - color_state: widgets.DetachableHeaderState = .{}, - modes_state: widgets.DetachableHeaderState = .{}, - screens_state: widgets.DetachableHeaderState = .{}, - - /// Screen detail windows for each screen key. - screen_windows: std.EnumMap( - terminal.ScreenSet.Key, - inspector.screen.Window, - ) = .{}, - - // Render - pub fn render(self: *Window, t: *Terminal) void { - // Start our window. If we're collapsed we do nothing. - defer cimgui.c.ImGui_End(); - if (!cimgui.c.ImGui_Begin( - name, - null, - cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing, - )) return; - - if (cimgui.c.ImGui_CollapsingHeader( - "Help", - cimgui.c.ImGuiTreeNodeFlags_None, - )) { - cimgui.c.ImGui_TextWrapped( - "This window displays the internal state of the terminal. " ++ - "The terminal state is global to this terminal. Some state " ++ - "is specific to the active screen or other subsystems. Values " ++ - "here reflect the running state and will update as the terminal " ++ - "application modifies them via escape sequences or shell integration. " ++ - "Some can be modified directly for debugging purposes.", - ); - } - - const ctx: RenderContext = .{ .window = self, .terminal = t }; - widgets.detachableHeader("Misc", &self.misc_state, ctx, renderMiscContent); - widgets.detachableHeader("Layout", &self.layout_state, ctx, renderLayoutContent); - widgets.detachableHeader("Mouse", &self.mouse_state, ctx, renderMouseContent); - widgets.detachableHeader("Color", &self.color_state, ctx, renderColorContent); - widgets.detachableHeader("Modes", &self.modes_state, ctx, renderModesContent); - widgets.detachableHeader("Screens", &self.screens_state, ctx, renderScreensContent); - - // Pop-out screen windows - inline for (@typeInfo(terminal.ScreenSet.Key).@"enum".fields) |field| { - const key: terminal.ScreenSet.Key = @enumFromInt(field.value); - if (self.screen_windows.getPtr(key)) |screen_window| { - if (t.screens.get(key)) |screen| { - const label = comptime std.fmt.comptimePrint("Screen: {s}", .{field.name}); - var open: bool = true; - screen_window.render(label, &open, .{ - .screen = screen, - .key = key, - .active_key = t.screens.active_key, - .modify_other_keys_2 = t.flags.modify_other_keys_2, - .color_palette = &t.colors.palette, - }); - if (!open) { - self.screen_windows.remove(key); - } - } - } - } - - if (self.show_palette) { - defer cimgui.c.ImGui_End(); - if (cimgui.c.ImGui_Begin( - "256-Color Palette", - &self.show_palette, - cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing, - )) { - palette("palette", &t.colors.palette.current); - } - } - } -}; - -fn renderMiscContent(ctx: RenderContext) void { - const t = ctx.terminal; - _ = cimgui.c.ImGui_BeginTable( - "table_misc", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Working Directory"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The current working directory reported by the shell."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - if (t.pwd.items.len > 0) { - cimgui.c.ImGui_Text( - "%.*s", - t.pwd.items.len, - t.pwd.items.ptr, - ); - } else { - cimgui.c.ImGui_TextDisabled("(none)"); - } - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Focused"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("Whether the terminal itself is currently focused."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - var value: bool = t.flags.focused; - _ = cimgui.c.ImGui_Checkbox("##focused", &value); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Previous Char"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The previously printed character, used only for the REP sequence."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - if (t.previous_char) |c| { - cimgui.c.ImGui_Text("U+%04X", @as(u32, c)); - } else { - cimgui.c.ImGui_TextDisabled("(none)"); - } - } - } -} - -fn renderLayoutContent(ctx: RenderContext) void { - const t = ctx.terminal; - _ = cimgui.c.ImGui_BeginTable( - "table_layout", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Grid"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The size of the terminal grid in columns and rows."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text( - "%dc x %dr", - t.cols, - t.rows, - ); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Pixels"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The size of the terminal grid in pixels."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text( - "%dw x %dh", - t.width_px, - t.height_px, - ); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Scroll Region"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The scrolling region boundaries (top, bottom, left, right)."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_PushItemWidth(cimgui.c.ImGui_CalcTextSize("00000").x); - defer cimgui.c.ImGui_PopItemWidth(); - - var override = t.scrolling_region; - var changed = false; - - cimgui.c.ImGui_AlignTextToFramePadding(); - cimgui.c.ImGui_Text("T:"); - cimgui.c.ImGui_SameLine(); - if (cimgui.c.ImGui_InputScalar( - "##scroll_top", - cimgui.c.ImGuiDataType_U16, - &override.top, - )) { - override.top = @min(override.top, t.rows -| 1); - changed = true; - } - - cimgui.c.ImGui_SameLine(); - cimgui.c.ImGui_Text("B:"); - cimgui.c.ImGui_SameLine(); - if (cimgui.c.ImGui_InputScalar( - "##scroll_bottom", - cimgui.c.ImGuiDataType_U16, - &override.bottom, - )) { - override.bottom = @min(override.bottom, t.rows -| 1); - changed = true; - } - - cimgui.c.ImGui_SameLine(); - cimgui.c.ImGui_Text("L:"); - cimgui.c.ImGui_SameLine(); - if (cimgui.c.ImGui_InputScalar( - "##scroll_left", - cimgui.c.ImGuiDataType_U16, - &override.left, - )) { - override.left = @min(override.left, t.cols -| 1); - changed = true; - } - - cimgui.c.ImGui_SameLine(); - cimgui.c.ImGui_Text("R:"); - cimgui.c.ImGui_SameLine(); - if (cimgui.c.ImGui_InputScalar( - "##scroll_right", - cimgui.c.ImGuiDataType_U16, - &override.right, - )) { - override.right = @min(override.right, t.cols -| 1); - changed = true; - } - - if (changed and - override.top < override.bottom and - override.left < override.right) - { - t.scrolling_region = override; - } - } - } -} - -fn renderMouseContent(ctx: RenderContext) void { - const t = ctx.terminal; - _ = cimgui.c.ImGui_BeginTable( - "table_mouse", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Event Mode"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The mouse event reporting mode set by the application."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%s", @tagName(t.flags.mouse_event).ptr); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Format"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The mouse event encoding format."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%s", @tagName(t.flags.mouse_format).ptr); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Shape"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The current mouse cursor shape set by the application."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%s", @tagName(t.mouse_shape).ptr); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Shift Capture"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("XTSHIFTESCAPE state for capturing shift in mouse protocol."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - if (t.flags.mouse_shift_capture == .null) { - cimgui.c.ImGui_TextDisabled("(unset)"); - } else { - cimgui.c.ImGui_Text("%s", @tagName(t.flags.mouse_shift_capture).ptr); - } - } - } -} - -fn renderColorContent(ctx: RenderContext) void { - const t = ctx.terminal; - cimgui.c.ImGui_TextWrapped( - "Color state for the terminal. Note these colors only apply " ++ - "to the palette and unstyled colors. Many modern terminal " ++ - "applications use direct RGB colors which are not reflected here.", - ); - cimgui.c.ImGui_Separator(); - - _ = cimgui.c.ImGui_BeginTable( - "table_color", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Background"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("Unstyled cell background color."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - _ = dynamicRGB( - "bg_color", - &t.colors.background, - ); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Foreground"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("Unstyled cell foreground color."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - _ = dynamicRGB( - "fg_color", - &t.colors.foreground, - ); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Cursor"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("Cursor coloring set by escape sequences."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - _ = dynamicRGB( - "cursor_color", - &t.colors.cursor, - ); - } - } - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Palette"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("The 256-color palette."); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - if (cimgui.c.ImGui_Button("View")) { - ctx.window.show_palette = true; - } - } - } -} - -/// Render a DynamicRGB color. -/// -/// Note: this currently can't be modified but we plan to allow that -/// and return a boolean letting you know if anything was modified. -fn dynamicRGB( - label: [:0]const u8, - rgb: *terminal.color.DynamicRGB, -) bool { - _ = cimgui.c.ImGui_BeginTable( - label, - if (rgb.override != null) 2 else 1, - cimgui.c.ImGuiTableFlags_SizingFixedFit, - ); - defer cimgui.c.ImGui_EndTable(); - - if (rgb.override != null) cimgui.c.ImGui_TableSetupColumn( - "##label", - cimgui.c.ImGuiTableColumnFlags_WidthFixed, - ); - cimgui.c.ImGui_TableSetupColumn( - "##value", - cimgui.c.ImGuiTableColumnFlags_WidthStretch, - ); - - if (rgb.override) |c| { - cimgui.c.ImGui_TableNextRow(); - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("override:"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("Overridden color set by escape sequences."); - - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - var col = [3]f32{ - @as(f32, @floatFromInt(c.r)) / 255.0, - @as(f32, @floatFromInt(c.g)) / 255.0, - @as(f32, @floatFromInt(c.b)) / 255.0, - }; - _ = cimgui.c.ImGui_ColorEdit3( - "##override", - &col, - cimgui.c.ImGuiColorEditFlags_None, - ); - } - - cimgui.c.ImGui_TableNextRow(); - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - if (rgb.default) |c| { - if (rgb.override != null) { - cimgui.c.ImGui_Text("default:"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker("Default color from configuration."); - - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - } - - var col = [3]f32{ - @as(f32, @floatFromInt(c.r)) / 255.0, - @as(f32, @floatFromInt(c.g)) / 255.0, - @as(f32, @floatFromInt(c.b)) / 255.0, - }; - _ = cimgui.c.ImGui_ColorEdit3( - "##default", - &col, - cimgui.c.ImGuiColorEditFlags_None, - ); - } else { - cimgui.c.ImGui_TextDisabled("(unset)"); - } - - return false; -} - -/// Render a color palette as a 16x16 grid of color buttons. -fn palette( - label: [:0]const u8, - pal: *const terminal.color.Palette, -) void { - cimgui.c.ImGui_PushID(label); - defer cimgui.c.ImGui_PopID(); - - for (0..16) |row| { - for (0..16) |col| { - const idx = row * 16 + col; - const rgb = pal[idx]; - var col_arr = [3]f32{ - @as(f32, @floatFromInt(rgb.r)) / 255.0, - @as(f32, @floatFromInt(rgb.g)) / 255.0, - @as(f32, @floatFromInt(rgb.b)) / 255.0, - }; - - if (col > 0) cimgui.c.ImGui_SameLine(); - - cimgui.c.ImGui_PushIDInt(@intCast(idx)); - _ = cimgui.c.ImGui_ColorEdit3( - "##color", - &col_arr, - cimgui.c.ImGuiColorEditFlags_NoInputs, - ); - if (cimgui.c.ImGui_IsItemHovered(cimgui.c.ImGuiHoveredFlags_DelayShort)) { - cimgui.c.ImGui_SetTooltip( - "%d: #%02X%02X%02X", - idx, - rgb.r, - rgb.g, - rgb.b, - ); - } - cimgui.c.ImGui_PopID(); - } - } -} - -fn renderModesContent(ctx: RenderContext) void { - const t = ctx.terminal; - - _ = cimgui.c.ImGui_BeginTable( - "table_modes", - 3, - cimgui.c.ImGuiTableFlags_SizingFixedFit | - cimgui.c.ImGuiTableFlags_RowBg, - ); - defer cimgui.c.ImGui_EndTable(); - - { - cimgui.c.ImGui_TableSetupColumn("", cimgui.c.ImGuiTableColumnFlags_NoResize); - cimgui.c.ImGui_TableSetupColumn("Number", cimgui.c.ImGuiTableColumnFlags_PreferSortAscending); - cimgui.c.ImGui_TableSetupColumn("Name", cimgui.c.ImGuiTableColumnFlags_WidthStretch); - cimgui.c.ImGui_TableHeadersRow(); - } - - inline for (@typeInfo(terminal.Mode).@"enum".fields) |field| { - @setEvalBranchQuota(6000); - const tag: modes.ModeTag = @bitCast(@as(modes.ModeTag.Backing, field.value)); - - cimgui.c.ImGui_TableNextRow(); - cimgui.c.ImGui_PushIDInt(@intCast(field.value)); - defer cimgui.c.ImGui_PopID(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - var value: bool = t.modes.get(@field(terminal.Mode, field.name)); - _ = cimgui.c.ImGui_Checkbox("##checkbox", &value); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text( - "%s%d", - if (tag.ansi) "" else "?", - @as(u32, @intCast(tag.value)), - ); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(2); - const name = std.fmt.comptimePrint("{s}", .{field.name}); - cimgui.c.ImGui_Text("%s", name.ptr); - } - } -} - -fn renderScreensContent(ctx: RenderContext) void { - const t = ctx.terminal; - - cimgui.c.ImGui_Text("Screens"); - cimgui.c.ImGui_SameLine(); - widgets.helpMarker( - "A terminal can have multiple screens, only one of which is active at " ++ - "a time. Each screen has its own grid, contents, and other state. " ++ - "This section allows you to inspect the different screens managed by " ++ - "the terminal.", - ); - cimgui.c.ImGui_Separator(); - - _ = cimgui.c.ImGui_BeginTable( - "table_screens", - 3, - cimgui.c.ImGuiTableFlags_Borders | - cimgui.c.ImGuiTableFlags_RowBg | - cimgui.c.ImGuiTableFlags_SizingFixedFit, - ); - defer cimgui.c.ImGui_EndTable(); - - cimgui.c.ImGui_TableSetupColumn("Screen", cimgui.c.ImGuiTableColumnFlags_WidthFixed); - cimgui.c.ImGui_TableSetupColumn("Status", cimgui.c.ImGuiTableColumnFlags_WidthFixed); - cimgui.c.ImGui_TableSetupColumn("", cimgui.c.ImGuiTableColumnFlags_WidthFixed); - cimgui.c.ImGui_TableHeadersRow(); - - inline for (@typeInfo(terminal.ScreenSet.Key).@"enum".fields) |field| { - const key: terminal.ScreenSet.Key = @enumFromInt(field.value); - const is_initialized = t.screens.get(key) != null; - const is_active = t.screens.active_key == key; - - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - const name = comptime std.fmt.comptimePrint("{s}", .{field.name}); - cimgui.c.ImGui_Text("%s", name.ptr); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - if (is_active) { - cimgui.c.ImGui_TextColored( - .{ .x = 0.4, .y = 1.0, .z = 0.4, .w = 1.0 }, - "active", - ); - } else if (is_initialized) { - cimgui.c.ImGui_TextColored( - .{ .x = 0.6, .y = 0.6, .z = 0.6, .w = 1.0 }, - "initialized", - ); - } else { - cimgui.c.ImGui_TextColored( - .{ .x = 0.4, .y = 0.4, .z = 0.4, .w = 1.0 }, - "(not initialized)", - ); - } - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(2); - const id = comptime std.fmt.comptimePrint("{s}", .{field.name}); - cimgui.c.ImGui_PushID(id.ptr); - defer cimgui.c.ImGui_PopID(); - if (is_initialized) { - if (cimgui.c.ImGui_Button("View")) { - ctx.window.screen_windows.put(key, .{}); - } - } else { - cimgui.c.ImGui_BeginDisabled(true); - _ = cimgui.c.ImGui_Button("View"); - cimgui.c.ImGui_EndDisabled(); - } - } - } -}