mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-14 11:35:48 +00:00
inspector: trying new stuff
This commit is contained in:
@@ -14,6 +14,7 @@ const input = @import("../input.zig");
|
||||
const renderer = @import("../renderer.zig");
|
||||
const terminal = @import("../terminal/main.zig");
|
||||
const inspector = @import("main.zig");
|
||||
const widgets = @import("widgets.zig");
|
||||
|
||||
/// The window names. These are used with docking so we need to have access.
|
||||
const window_cell = "Cell";
|
||||
@@ -57,6 +58,9 @@ windows: struct {
|
||||
terminal: inspector.terminal.Window = .{},
|
||||
} = .{},
|
||||
|
||||
// ImGui state
|
||||
gui: widgets.surface.Inspector = .empty,
|
||||
|
||||
/// Enum representing keyboard navigation actions
|
||||
const KeyAction = enum {
|
||||
down,
|
||||
@@ -216,9 +220,7 @@ pub fn recordPtyRead(self: *Inspector, data: []const u8) !void {
|
||||
|
||||
/// Render the frame.
|
||||
pub fn render(self: *Inspector) void {
|
||||
const widgets = @import("widgets.zig");
|
||||
var s: widgets.surface.Inspector = .{ .surface = self.surface };
|
||||
s.draw();
|
||||
self.gui.draw(self.surface);
|
||||
if (true) return;
|
||||
|
||||
const dock_id = cimgui.c.ImGui_DockSpaceOverViewport();
|
||||
|
||||
@@ -16,6 +16,120 @@ pub fn helpMarker(text: [:0]const u8) void {
|
||||
cimgui.c.ImGui_TextUnformatted(text.ptr);
|
||||
}
|
||||
|
||||
/// DetachableHeader allows rendering a collapsing header that can be
|
||||
/// detached into its own window.
|
||||
pub const DetachableHeader = struct {
|
||||
/// Set whether the window is detached.
|
||||
detached: bool = false,
|
||||
|
||||
/// If true, detaching will move the item into a docking position
|
||||
/// to the right.
|
||||
dock: bool = true,
|
||||
|
||||
// Internal state do not touch.
|
||||
window_first: bool = true,
|
||||
|
||||
pub fn windowEnd(self: *DetachableHeader) void {
|
||||
_ = self;
|
||||
|
||||
// If we started the window, we need to end it.
|
||||
cimgui.c.ImGui_End();
|
||||
}
|
||||
|
||||
/// Returns null if there is no window created (not detached).
|
||||
/// Otherwise returns whether the window is open.
|
||||
pub fn window(
|
||||
self: *DetachableHeader,
|
||||
label: [:0]const u8,
|
||||
) ?bool {
|
||||
// If we're not detached, we don't create a window.
|
||||
if (!self.detached) {
|
||||
self.window_first = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
// If this is our first time showing the window then we need to
|
||||
// setup docking. We only do this on the first time because we
|
||||
// don't want to reset a user's docking behavior later.
|
||||
if (self.window_first) dock: {
|
||||
self.window_first = false;
|
||||
if (!self.dock) break :dock;
|
||||
const dock_id = cimgui.c.ImGui_GetWindowDockID();
|
||||
if (dock_id == 0) break :dock;
|
||||
var dock_id_right: cimgui.c.ImGuiID = 0;
|
||||
var dock_id_left: cimgui.c.ImGuiID = 0;
|
||||
_ = cimgui.ImGui_DockBuilderSplitNode(
|
||||
dock_id,
|
||||
cimgui.c.ImGuiDir_Right,
|
||||
0.4,
|
||||
&dock_id_right,
|
||||
&dock_id_left,
|
||||
);
|
||||
cimgui.ImGui_DockBuilderDockWindow(label, dock_id_right);
|
||||
cimgui.ImGui_DockBuilderFinish(dock_id);
|
||||
}
|
||||
|
||||
return cimgui.c.ImGui_Begin(
|
||||
label,
|
||||
&self.detached,
|
||||
cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn header(
|
||||
self: *DetachableHeader,
|
||||
label: [:0]const u8,
|
||||
) bool {
|
||||
// If we're detached, create a separate window.
|
||||
if (self.detached) return false;
|
||||
|
||||
// Make sure all headers have a unique ID in the stack. We only
|
||||
// need to do this for the header side because creating a window
|
||||
// automatically creates an ID.
|
||||
cimgui.c.ImGui_PushID(label);
|
||||
defer cimgui.c.ImGui_PopID();
|
||||
|
||||
// Create the collapsing header with the pop out button overlaid.
|
||||
cimgui.c.ImGui_SetNextItemAllowOverlap();
|
||||
const is_open = cimgui.c.ImGui_CollapsingHeader(
|
||||
label,
|
||||
cimgui.c.ImGuiTreeNodeFlags_None,
|
||||
);
|
||||
|
||||
// Place pop-out button inside the header bar
|
||||
const header_max = cimgui.c.ImGui_GetItemRectMax();
|
||||
const header_min = cimgui.c.ImGui_GetItemRectMin();
|
||||
const frame_height = cimgui.c.ImGui_GetFrameHeight();
|
||||
const button_size = frame_height - 4;
|
||||
const padding = 4;
|
||||
|
||||
cimgui.c.ImGui_SameLine();
|
||||
cimgui.c.ImGui_SetCursorScreenPos(.{
|
||||
.x = header_max.x - button_size - padding,
|
||||
.y = header_min.y + 2,
|
||||
});
|
||||
{
|
||||
cimgui.c.ImGui_PushStyleVarImVec2(
|
||||
cimgui.c.ImGuiStyleVar_FramePadding,
|
||||
.{ .x = 0, .y = 0 },
|
||||
);
|
||||
defer cimgui.c.ImGui_PopStyleVar();
|
||||
if (cimgui.c.ImGui_ButtonEx(
|
||||
">>##detach",
|
||||
.{ .x = button_size, .y = button_size },
|
||||
)) {
|
||||
self.detached = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (cimgui.c.ImGui_IsItemHovered(cimgui.c.ImGuiHoveredFlags_DelayShort)) {
|
||||
cimgui.c.ImGui_SetTooltip("Detach into separate window");
|
||||
}
|
||||
|
||||
return is_open;
|
||||
}
|
||||
};
|
||||
|
||||
pub const DetachableHeaderState = struct {
|
||||
show_window: bool = false,
|
||||
|
||||
|
||||
@@ -12,10 +12,14 @@ const window_imgui_demo = "Dear ImGui Demo";
|
||||
const window_terminal = "Terminal";
|
||||
|
||||
pub const Inspector = struct {
|
||||
/// The surface being inspected.
|
||||
surface: *const Surface,
|
||||
/// Internal GUI state
|
||||
terminal_info: widgets.terminal.Info,
|
||||
|
||||
pub fn draw(self: *Inspector) void {
|
||||
pub const empty: Inspector = .{
|
||||
.terminal_info = .empty,
|
||||
};
|
||||
|
||||
pub fn draw(self: *Inspector, surface: *const Surface) void {
|
||||
// Create our dockspace first. If we had to setup our dockspace,
|
||||
// then it is a first render.
|
||||
const dockspace_id = cimgui.c.ImGui_GetID("Main Dockspace");
|
||||
@@ -30,10 +34,20 @@ pub const Inspector = struct {
|
||||
|
||||
// Draw everything that requires the terminal state mutex.
|
||||
{
|
||||
self.surface.renderer_state.mutex.lock();
|
||||
defer self.surface.renderer_state.mutex.unlock();
|
||||
const t = self.surface.renderer_state.terminal;
|
||||
drawTerminalWindow(.{ .terminal = t });
|
||||
surface.renderer_state.mutex.lock();
|
||||
defer surface.renderer_state.mutex.unlock();
|
||||
const t = surface.renderer_state.terminal;
|
||||
|
||||
// Terminal info window
|
||||
{
|
||||
const open = cimgui.c.ImGui_Begin(
|
||||
window_terminal,
|
||||
null,
|
||||
cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing,
|
||||
);
|
||||
defer cimgui.c.ImGui_End();
|
||||
self.terminal_info.draw(open, t);
|
||||
}
|
||||
}
|
||||
|
||||
if (first_render) {
|
||||
@@ -86,18 +100,3 @@ pub const Inspector = struct {
|
||||
return setup;
|
||||
}
|
||||
};
|
||||
|
||||
fn drawTerminalWindow(state: struct {
|
||||
terminal: *terminal.Terminal,
|
||||
}) void {
|
||||
defer cimgui.c.ImGui_End();
|
||||
if (!cimgui.c.ImGui_Begin(
|
||||
window_terminal,
|
||||
null,
|
||||
cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing,
|
||||
)) return;
|
||||
|
||||
widgets.terminal.drawInfo(.{
|
||||
.terminal = state.terminal,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,27 +3,115 @@ const builtin = @import("builtin");
|
||||
const assert = @import("../../quirks.zig").inlineAssert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const cimgui = @import("dcimgui");
|
||||
const widgets = @import("../widgets.zig");
|
||||
const terminal = @import("../../terminal/main.zig");
|
||||
const Terminal = terminal.Terminal;
|
||||
|
||||
pub const Info = struct {
|
||||
terminal: *Terminal,
|
||||
};
|
||||
misc_header: widgets.DetachableHeader,
|
||||
|
||||
pub fn drawInfo(data: Info) void {
|
||||
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.",
|
||||
);
|
||||
pub const empty: Info = .{
|
||||
.misc_header = .{},
|
||||
};
|
||||
|
||||
const misc_header_label = "Misc";
|
||||
|
||||
/// Draw the terminal info window.
|
||||
pub fn draw(
|
||||
self: *Info,
|
||||
open: bool,
|
||||
t: *Terminal,
|
||||
) void {
|
||||
// Draw our open state if we're open.
|
||||
if (open) self.drawOpen(t);
|
||||
|
||||
// Draw our detached state that draws regardless of if
|
||||
// we're open or not.
|
||||
if (self.misc_header.window(misc_header_label)) |visible| {
|
||||
defer self.misc_header.windowEnd();
|
||||
if (visible) miscTable(t);
|
||||
}
|
||||
}
|
||||
|
||||
_ = data;
|
||||
fn drawOpen(self: *Info, t: *Terminal) void {
|
||||
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.",
|
||||
);
|
||||
}
|
||||
|
||||
if (self.misc_header.header(misc_header_label)) miscTable(t);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn miscTable(t: *Terminal) void {
|
||||
_ = 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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user