From afa08ffc02857ac62c414c98b0453c721ac1f24f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 21 Oct 2023 22:35:05 -0700 Subject: [PATCH] initial work on basic inspector information --- src/Inspector.zig | 202 ++++++++++++++++++++++++++++++++-- src/Surface.zig | 2 +- src/apprt/gtk/ImguiWidget.zig | 2 +- src/apprt/gtk/Surface.zig | 1 + src/apprt/gtk/inspector.zig | 7 ++ 5 files changed, 205 insertions(+), 9 deletions(-) diff --git a/src/Inspector.zig b/src/Inspector.zig index beb10d282..7091e4ba1 100644 --- a/src/Inspector.zig +++ b/src/Inspector.zig @@ -8,8 +8,18 @@ const Surface = @import("Surface.zig"); /// The window names. These are used with docking so we need to have access. const window_modes = "Modes"; +const window_size = "Surface Info"; +const window_imgui_demo = "Dear ImGui Demo"; + +/// The surface that we're inspecting. +surface: *Surface, + +/// This is used to track whether we're rendering for the first time. This +/// is used to set up the initial window positions. +first_render: bool = true, show_modes_window: bool = true, +show_size_window: bool = true, /// Setup the ImGui state. This requires an ImGui context to be set. pub fn setup() void { @@ -45,8 +55,8 @@ pub fn setup() void { } } -pub fn init() Inspector { - return .{}; +pub fn init(surface: *Surface) Inspector { + return .{ .surface = surface }; } pub fn deinit(self: *Inspector) void { @@ -61,17 +71,57 @@ pub fn render(self: *Inspector) void { null, ); + // We want the modes window to have the initial focus + self.renderModesWindow(); + self.renderSizeWindow(); + // Flip this boolean to true whenever you want to see the ImGui demo // window which can help you figure out how to use various ImGui widgets. - if (false) { + if (true) { var show: bool = true; cimgui.c.igShowDemoWindow(&show); } - self.renderModesWindow(); + // On first render we set up the layout. We can actually do this at + // the end of the frame, allowing the individual rendering to also + // observe the first render flag. + if (self.first_render) { + self.first_render = false; + self.setupLayout(dock_id); + } +} - // Setup our dock. We want all our main windows to be tabs in the main bar. - cimgui.c.igDockBuilderDockWindow(window_modes, dock_id); +fn setupLayout(self: *Inspector, dock_id_main: cimgui.c.ImGuiID) void { + _ = self; + + // Our initial focus should always be the modes window + cimgui.c.igSetWindowFocus_Str(window_modes); + + // Setup our initial layout. + const dock_id: struct { + left: cimgui.c.ImGuiID, + right: cimgui.c.ImGuiID, + } = dock_id: { + var dock_id_left: cimgui.c.ImGuiID = undefined; + var dock_id_right: cimgui.c.ImGuiID = undefined; + _ = cimgui.c.igDockBuilderSplitNode( + dock_id_main, + cimgui.c.ImGuiDir_Left, + 0.7, + &dock_id_left, + &dock_id_right, + ); + + break :dock_id .{ + .left = dock_id_left, + .right = dock_id_right, + }; + }; + + cimgui.c.igDockBuilderDockWindow(window_modes, dock_id.left); + cimgui.c.igDockBuilderDockWindow(window_imgui_demo, dock_id.left); + cimgui.c.igDockBuilderDockWindow(window_size, dock_id.right); + cimgui.c.igDockBuilderFinish(dock_id_main); } /// The modes window shows the currently active terminal modes and allows @@ -84,6 +134,144 @@ fn renderModesWindow(self: *Inspector) void { if (!cimgui.c.igBegin( window_modes, &self.show_modes_window, - cimgui.c.ImGuiWindowFlags_None, + cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing, )) return; } + +fn renderSizeWindow(self: *Inspector) void { + if (!self.show_size_window) return; + + // Start our window. If we're collapsed we do nothing. + defer cimgui.c.igEnd(); + if (!cimgui.c.igBegin( + window_size, + &self.show_size_window, + cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing, + )) return; + + cimgui.c.igSeparatorText("Dimensions"); + + { + _ = cimgui.c.igBeginTable( + "table_size", + 2, + cimgui.c.ImGuiTableFlags_None, + .{ .x = 0, .y = 0 }, + 0, + ); + defer cimgui.c.igEndTable(); + + // Screen Size + { + cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0); + { + _ = cimgui.c.igTableSetColumnIndex(0); + cimgui.c.igText("Screen Size"); + } + { + _ = cimgui.c.igTableSetColumnIndex(1); + cimgui.c.igText( + "%d x %d", + self.surface.screen_size.width, + self.surface.screen_size.height, + ); + } + } + + // Grid Size + { + cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0); + { + _ = cimgui.c.igTableSetColumnIndex(0); + cimgui.c.igText("Grid Size"); + } + { + _ = cimgui.c.igTableSetColumnIndex(1); + cimgui.c.igText( + "%d x %d", + self.surface.grid_size.columns, + self.surface.grid_size.rows, + ); + } + } + + // Cell Size + { + cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0); + { + _ = cimgui.c.igTableSetColumnIndex(0); + cimgui.c.igText("Cell Size"); + } + { + _ = cimgui.c.igTableSetColumnIndex(1); + cimgui.c.igText( + "%d x %d", + self.surface.cell_size.width, + self.surface.cell_size.height, + ); + } + } + + // Padding + { + cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0); + { + _ = cimgui.c.igTableSetColumnIndex(0); + cimgui.c.igText("Window Padding"); + } + { + _ = cimgui.c.igTableSetColumnIndex(1); + cimgui.c.igText( + "T=%d B=%d L=%d R=%d", + self.surface.padding.top, + self.surface.padding.bottom, + self.surface.padding.left, + self.surface.padding.right, + ); + } + } + } + + cimgui.c.igSeparatorText("Font"); + + { + _ = cimgui.c.igBeginTable( + "table_font", + 2, + cimgui.c.ImGuiTableFlags_None, + .{ .x = 0, .y = 0 }, + 0, + ); + defer cimgui.c.igEndTable(); + + { + cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0); + { + _ = cimgui.c.igTableSetColumnIndex(0); + cimgui.c.igText("Size (Points)"); + } + { + _ = cimgui.c.igTableSetColumnIndex(1); + cimgui.c.igText( + "%d pt", + self.surface.font_size.points, + ); + } + } + + { + cimgui.c.igTableNextRow(cimgui.c.ImGuiTableRowFlags_None, 0); + { + _ = cimgui.c.igTableSetColumnIndex(0); + cimgui.c.igText("Size (Pixels)"); + } + { + _ = cimgui.c.igTableSetColumnIndex(1); + cimgui.c.igText( + "%d px", + self.surface.font_size.pixels(), + ); + } + } + } +} diff --git a/src/Surface.zig b/src/Surface.zig index 23845321f..5cb08de89 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -580,7 +580,7 @@ pub fn activateInspector(self: *Surface) !void { // Setup the inspector var ptr = try self.alloc.create(Inspector); errdefer self.alloc.destroy(ptr); - ptr.* = Inspector.init(); + ptr.* = Inspector.init(self); self.inspector = ptr; // Put the inspector onto the render state diff --git a/src/apprt/gtk/ImguiWidget.zig b/src/apprt/gtk/ImguiWidget.zig index 38efad289..eb9b97f06 100644 --- a/src/apprt/gtk/ImguiWidget.zig +++ b/src/apprt/gtk/ImguiWidget.zig @@ -112,7 +112,7 @@ pub fn deinit(self: *ImguiWidget) void { /// This should be called anytime the underlying data for the UI changes /// so that the UI can be refreshed. -pub fn queueRender(self: *ImguiWidget) void { +pub fn queueRender(self: *const ImguiWidget) void { c.gtk_gl_area_queue_render(self.gl_area); } diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 90e033664..688a48c29 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -239,6 +239,7 @@ pub fn deinit(self: *Surface) void { } fn render(self: *Surface) !void { + if (self.inspector) |v| v.queueRender(); try self.core_surface.renderer.draw(); } diff --git a/src/apprt/gtk/inspector.zig b/src/apprt/gtk/inspector.zig index e5e3eb750..8d9560bed 100644 --- a/src/apprt/gtk/inspector.zig +++ b/src/apprt/gtk/inspector.zig @@ -104,6 +104,13 @@ pub const Inspector = struct { if (self.destroy_on_close) self.destroy(); } + pub fn queueRender(self: *const Inspector) void { + switch (self.location) { + .hidden => {}, + .window => |v| v.imgui_widget.queueRender(), + } + } + fn allocator(self: *const Inspector) Allocator { return self.surface.app.core_app.alloc; }