diff --git a/src/inspector/terminal.zig b/src/inspector/terminal.zig index 352ae6a03..9b601f1a1 100644 --- a/src/inspector/terminal.zig +++ b/src/inspector/terminal.zig @@ -20,12 +20,12 @@ pub const Window = struct { /// Whether the palette window is open. show_palette: bool = false, - /// Whether sections are shown in their own windows. - show_misc_window: bool = false, - show_layout_window: bool = false, - show_mouse_window: bool = false, - show_color_window: bool = false, - show_modes_window: 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 = .{}, // Render pub fn render(self: *Window, t: *Terminal) void { @@ -53,36 +53,11 @@ pub const Window = struct { } const ctx: RenderContext = .{ .window = self, .terminal = t }; - widgets.collapsingHeaderDetachable( - "Misc", - &self.show_misc_window, - ctx, - renderMiscContent, - ); - widgets.collapsingHeaderDetachable( - "Layout", - &self.show_layout_window, - ctx, - renderLayoutContent, - ); - widgets.collapsingHeaderDetachable( - "Mouse", - &self.show_mouse_window, - ctx, - renderMouseContent, - ); - widgets.collapsingHeaderDetachable( - "Color", - &self.show_color_window, - ctx, - renderColorContent, - ); - widgets.collapsingHeaderDetachable( - "Modes", - &self.show_modes_window, - ctx, - renderModesContent, - ); + 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); if (self.show_palette) { defer cimgui.c.ImGui_End(); diff --git a/src/inspector/widgets.zig b/src/inspector/widgets.zig index d3424e9ef..45c35f6c4 100644 --- a/src/inspector/widgets.zig +++ b/src/inspector/widgets.zig @@ -13,32 +13,63 @@ pub fn helpMarker(text: [:0]const u8) void { cimgui.c.ImGui_TextUnformatted(text.ptr); } +pub const DetachableHeaderState = struct { + show_window: bool = false, + + /// Internal state. Don't touch. + first_show: bool = false, +}; + /// Render a collapsing header that can be detached into its own window. /// When detached, renders as a separate window with a close button. /// When attached, renders as a collapsing header with a pop-out button. -pub fn collapsingHeaderDetachable( +pub fn detachableHeader( label: [:0]const u8, - show: *bool, + state: *DetachableHeaderState, ctx: anytype, comptime contentFn: fn (@TypeOf(ctx)) void, ) void { cimgui.c.ImGui_PushID(label); defer cimgui.c.ImGui_PopID(); - if (show.*) { + if (state.show_window) { + // On first show, dock this window to the right of the parent window's dock. + // We only do this once so the user can freely reposition the window afterward + // without it snapping back to the right on every frame. + if (!state.first_show) { + state.first_show = true; + const current_dock_id = cimgui.c.ImGui_GetWindowDockID(); + if (current_dock_id != 0) { + var dock_id_right: cimgui.c.ImGuiID = 0; + var dock_id_left: cimgui.c.ImGuiID = 0; + _ = cimgui.ImGui_DockBuilderSplitNode( + current_dock_id, + cimgui.c.ImGuiDir_Right, + 0.3, + &dock_id_right, + &dock_id_left, + ); + cimgui.ImGui_DockBuilderDockWindow(label, dock_id_right); + cimgui.ImGui_DockBuilderFinish(current_dock_id); + } + } + defer cimgui.c.ImGui_End(); if (cimgui.c.ImGui_Begin( label, - show, + &state.show_window, cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing, )) contentFn(ctx); return; } + // Reset first_show when window is closed so next open docks again + state.first_show = false; + cimgui.c.ImGui_SetNextItemAllowOverlap(); const is_open = cimgui.c.ImGui_CollapsingHeader( label, - cimgui.c.ImGuiTreeNodeFlags_DefaultOpen, + cimgui.c.ImGuiTreeNodeFlags_None, ); // Place pop-out button inside the header bar @@ -61,7 +92,7 @@ pub fn collapsingHeaderDetachable( ">>##detach", .{ .x = button_size, .y = button_size }, )) { - show.* = true; + state.show_window = true; } cimgui.c.ImGui_PopStyleVar(); if (cimgui.c.ImGui_IsItemHovered(cimgui.c.ImGuiHoveredFlags_DelayShort)) {