render font info in dev mode

This commit is contained in:
Mitchell Hashimoto
2022-10-17 14:47:51 -07:00
parent 7cb3f2267f
commit c103a278f1
5 changed files with 245 additions and 17 deletions

View File

@ -3,18 +3,140 @@ const c = @import("c.zig");
const imgui = @import("main.zig"); const imgui = @import("main.zig");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
pub fn newFrame() void { pub const newFrame = c.igNewFrame;
c.igNewFrame(); pub const endFrame = c.igEndFrame;
} pub const render = c.igRender;
pub const end = c.igEnd;
pub fn endFrame() void { pub const beginTooltip = c.igBeginTooltip;
c.igEndFrame(); pub const endTooltip = c.igEndTooltip;
} pub const spacing = c.igSpacing;
pub const text = c.igText;
pub fn render() void { pub const textDisabled = c.igTextDisabled;
c.igRender(); pub const textWrapped = c.igTextWrapped;
} pub const button = c.igButton;
pub const sameLine = c.igSameLine;
pub const getFontSize = c.igGetFontSize;
pub const pushTextWrapPos = c.igPushTextWrapPos;
pub const popTextWrapPos = c.igPopTextWrapPos;
pub const treePop = c.igTreePop;
pub fn showDemoWindow(open: ?*bool) void { pub fn showDemoWindow(open: ?*bool) void {
c.igShowDemoWindow(@ptrCast([*c]bool, if (open) |v| v else null)); c.igShowDemoWindow(@ptrCast([*c]bool, if (open) |v| v else null));
} }
pub fn begin(name: [:0]const u8, open: ?*bool, flags: WindowFlags) bool {
return c.igBegin(
name.ptr,
@ptrCast([*c]bool, if (open) |v| v else null),
@bitCast(c_int, flags),
);
}
pub fn collapsingHeader(
label: [:0]const u8,
visible: ?*bool,
flags: TreeNodeFlags,
) bool {
return c.igCollapsingHeader_BoolPtr(
label.ptr,
@ptrCast([*c]bool, if (visible) |v| v else null),
@bitCast(c_int, flags),
);
}
pub fn isItemHovered(flags: HoveredFlags) bool {
return c.igIsItemHovered(
@bitCast(c_int, flags),
);
}
pub fn treeNode(
label: [:0]const u8,
flags: TreeNodeFlags,
) bool {
return c.igTreeNodeEx_Str(
label.ptr,
@bitCast(c_int, flags),
);
}
pub const WindowFlags = packed struct {
no_title_bar: bool = false,
no_resize: bool = false,
no_move: bool = false,
no_scrollbar: bool = false,
no_scrollbar_with_mouse: bool = false,
no_collapse: bool = false,
always_auto_resize: bool = false,
no_background: bool = false,
no_saved_settings: bool = false,
no_mouse_inputs: bool = false,
menu_bar: bool = false,
horizontal_scroll_bar: bool = false,
no_focus_on_appearing: bool = false,
no_bring_to_front_on_focus: bool = false,
always_vertical_scrollbar: bool = false,
always_horizontal_scrollbar: bool = false,
always_use_window_padding: bool = false,
no_nav_inputs: bool = false,
no_nav_focus: bool = false,
unsaved_document: bool = false,
no_docking: bool = false,
_unusued_1: u1 = 0,
nav_flattened: bool = false,
child_window: bool = false,
tooltip: bool = false,
popup: bool = false,
modal: bool = false,
child_menu: bool = false,
dock_node_host: bool = false,
_padding: u3 = 0,
test {
try std.testing.expectEqual(@bitSizeOf(c_int), @bitSizeOf(WindowFlags));
}
};
pub const TreeNodeFlags = packed struct {
selected: bool = false,
framed: bool = false,
allow_item_overlap: bool = false,
no_tree_push_on_open: bool = false,
no_auto_open_on_log: bool = false,
default_open: bool = false,
open_on_double_click: bool = false,
open_on_arrow: bool = false,
leaf: bool = false,
bullet: bool = false,
frame_padding: bool = false,
span_avail_width: bool = false,
span_full_width: bool = false,
nav_left_jumps_back_here: bool = false,
_padding: u18 = 0,
test {
try std.testing.expectEqual(@bitSizeOf(c_int), @bitSizeOf(TreeNodeFlags));
}
};
pub const HoveredFlags = packed struct {
child_windows: bool = false,
root_window: bool = false,
any_window: bool = false,
no_popup_hierarchy: bool = false,
dock_hierarchy: bool = false,
allow_when_blocked_by_popup: bool = false,
allow_when_blocked_by_active_item: bool = false,
allow_when_overlapped: bool = false,
allow_when_disabled: bool = false,
no_nav_override: bool = false,
_padding: u22 = 0,
test {
try std.testing.expectEqual(@bitSizeOf(c_int), @bitSizeOf(HoveredFlags));
}
};
test {
@import("std").testing.refAllDecls(@This());
}

View File

@ -2,7 +2,13 @@
//! includes state managements and rendering. //! includes state managements and rendering.
const DevMode = @This(); const DevMode = @This();
const std = @import("std");
const imgui = @import("imgui"); const imgui = @import("imgui");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Atlas = @import("Atlas.zig");
const Window = @import("Window.zig");
/// If this is false, the rest of the terminal will be compiled without /// If this is false, the rest of the terminal will be compiled without
/// dev mode support at all. /// dev mode support at all.
@ -15,17 +21,44 @@ pub var instance: DevMode = .{};
/// Whether to show the dev mode UI currently. /// Whether to show the dev mode UI currently.
visible: bool = false, visible: bool = false,
/// The window we're tracking.
window: ?*Window = null,
/// Update the state associated with the dev mode. This should generally /// Update the state associated with the dev mode. This should generally
/// only be called paired with a render since it otherwise wastes CPU /// only be called paired with a render since it otherwise wastes CPU
/// cycles. /// cycles.
pub fn update(self: DevMode) void { pub fn update(self: *DevMode) !void {
_ = self;
imgui.ImplOpenGL3.newFrame(); imgui.ImplOpenGL3.newFrame();
imgui.ImplGlfw.newFrame(); imgui.ImplGlfw.newFrame();
imgui.newFrame(); imgui.newFrame();
if (imgui.begin("dev mode", null, .{})) {
defer imgui.end();
if (self.window) |window| {
if (imgui.collapsingHeader("Font Manager", null, .{})) {
imgui.text("Glyphs: %d", window.font_group.glyphs.count());
imgui.sameLine(0, -1);
helpMarker("The number of glyphs loaded and rendered into a " ++
"font atlas currently.");
if (imgui.treeNode("Atlas: Greyscale", .{ .default_open = true })) {
defer imgui.treePop();
const atlas = &window.font_group.atlas_greyscale;
try self.atlasInfo(atlas, @intCast(usize, window.grid.texture.id));
}
if (imgui.treeNode("Atlas: Color (Emoji)", .{ .default_open = true })) {
defer imgui.treePop();
const atlas = &window.font_group.atlas_color;
try self.atlasInfo(atlas, @intCast(usize, window.grid.texture_color.id));
}
}
}
}
// Just demo for now // Just demo for now
imgui.showDemoWindow(null); //imgui.showDemoWindow(null);
} }
/// Render the scene and return the draw data. The caller must be imgui-aware /// Render the scene and return the draw data. The caller must be imgui-aware
@ -36,3 +69,50 @@ pub fn render(self: DevMode) !*imgui.DrawData {
imgui.render(); imgui.render();
return try imgui.DrawData.get(); return try imgui.DrawData.get();
} }
/// Helper to render a tooltip.
fn helpMarker(desc: [:0]const u8) void {
imgui.textDisabled("(?)");
if (imgui.isItemHovered(.{})) {
imgui.beginTooltip();
defer imgui.endTooltip();
imgui.pushTextWrapPos(imgui.getFontSize() * 35);
defer imgui.popTextWrapPos();
imgui.text(desc.ptr);
}
}
fn atlasInfo(self: *DevMode, atlas: *Atlas, tex: ?usize) !void {
_ = self;
imgui.text("Dimensions: %d x %d", atlas.size, atlas.size);
imgui.sameLine(0, -1);
helpMarker("The pixel dimensions of the atlas texture.");
imgui.text("Size: %d KB", atlas.data.len >> 10);
imgui.sameLine(0, -1);
helpMarker("The byte size of the atlas texture.");
var buf: [1024]u8 = undefined;
imgui.text(
"Format: %s (depth = %d)",
(try std.fmt.bufPrintZ(&buf, "{}", .{atlas.format})).ptr,
atlas.format.depth(),
);
imgui.sameLine(0, -1);
helpMarker("The internal storage format of this atlas.");
if (tex) |id| {
imgui.c.igImage(
@intToPtr(*anyopaque, id),
.{
.x = @intToFloat(f32, atlas.size),
.y = @intToFloat(f32, atlas.size),
},
.{ .x = 0, .y = 0 },
.{ .x = 1, .y = 1 },
.{ .x = 1, .y = 1, .z = 1, .w = 1 },
.{ .x = 0, .y = 0, .z = 0, .w = 0 },
);
}
}

View File

@ -515,16 +515,24 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
// Add our built-in fonts so it looks slightly better // Add our built-in fonts so it looks slightly better
const dev_atlas = @ptrCast(*imgui.FontAtlas, io.cval().Fonts); const dev_atlas = @ptrCast(*imgui.FontAtlas, io.cval().Fonts);
dev_atlas.addFontFromMemoryTTF(face_ttf, @intToFloat(f32, font_size.pixels())); dev_atlas.addFontFromMemoryTTF(
face_ttf,
@intToFloat(f32, font_size.pixels()),
);
// Default dark style
const style = try imgui.Style.get(); const style = try imgui.Style.get();
style.colorsDark(); style.colorsDark();
// Initialize for our window
assert(imgui.ImplGlfw.initForOpenGL( assert(imgui.ImplGlfw.initForOpenGL(
@ptrCast(*imgui.ImplGlfw.GLFWWindow, window.handle), @ptrCast(*imgui.ImplGlfw.GLFWWindow, window.handle),
true, true,
)); ));
assert(imgui.ImplOpenGL3.init("#version 330 core")); assert(imgui.ImplOpenGL3.init("#version 330 core"));
// Add our window to the instance
DevMode.instance.window = self;
} }
return self; return self;
@ -532,6 +540,9 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
pub fn destroy(self: *Window) void { pub fn destroy(self: *Window) void {
if (DevMode.enabled) { if (DevMode.enabled) {
// Clear the window
DevMode.instance.window = null;
// Uninitialize imgui // Uninitialize imgui
imgui.ImplOpenGL3.shutdown(); imgui.ImplOpenGL3.shutdown();
imgui.ImplGlfw.shutdown(); imgui.ImplGlfw.shutdown();
@ -792,6 +803,7 @@ fn keyCallback(
.end => .end, .end => .end,
.page_up => .page_up, .page_up => .page_up,
.page_down => .page_down, .page_down => .page_down,
.escape => .escape,
.F1 => .f1, .F1 => .f1,
.F2 => .f2, .F2 => .f2,
.F3 => .f3, .F3 => .f3,
@ -809,6 +821,7 @@ fn keyCallback(
}, },
}; };
//log.warn("BINDING TRIGGER={}", .{trigger});
if (win.config.keybind.set.get(trigger)) |binding_action| { if (win.config.keybind.set.get(trigger)) |binding_action| {
//log.warn("BINDING ACTION={}", .{binding_action}); //log.warn("BINDING ACTION={}", .{binding_action});
@ -964,6 +977,18 @@ fn scrollCallback(window: glfw.Window, xoff: f64, yoff: f64) void {
const win = window.getUserPointer(Window) orelse return; const win = window.getUserPointer(Window) orelse return;
// If our dev mode window is visible then we always schedule a render on
// cursor move because the cursor might touch our windows.
if (DevMode.enabled and DevMode.instance.visible) {
win.render_timer.schedule() catch |err|
log.err("error scheduling render timer err={}", .{err});
// If the mouse event was handled by imgui, ignore it.
if (imgui.IO.get()) |io| {
if (io.cval().WantCaptureMouse) return;
} else |_| {}
}
// If we're scrolling up or down, then send a mouse event // If we're scrolling up or down, then send a mouse event
if (yoff != 0) { if (yoff != 0) {
const pos = window.getCursorPos() catch |err| { const pos = window.getCursorPos() catch |err| {
@ -1613,7 +1638,7 @@ fn renderTimerCallback(t: *libuv.Timer) void {
}; };
if (DevMode.enabled and DevMode.instance.visible) { if (DevMode.enabled and DevMode.instance.visible) {
DevMode.instance.update(); DevMode.instance.update() catch unreachable;
const data = DevMode.instance.render() catch unreachable; const data = DevMode.instance.render() catch unreachable;
imgui.ImplOpenGL3.renderDrawData(data); imgui.ImplOpenGL3.renderDrawData(data);
} }

View File

@ -123,7 +123,7 @@ pub const Config = struct {
// Dev Mode // Dev Mode
try result.keybind.set.put( try result.keybind.set.put(
alloc, alloc,
.{ .key = .grave_accent, .mods = .{ .shift = true, .super = true } }, .{ .key = .down, .mods = .{ .shift = true, .super = true } },
.{ .toggle_dev_mode = 0 }, .{ .toggle_dev_mode = 0 },
); );

View File

@ -61,6 +61,7 @@ pub const Key = enum {
end, end,
page_up, page_up,
page_down, page_down,
escape,
f1, f1,
f2, f2,