ghostty/src/DevMode.zig
Mitchell Hashimoto f871630fa4 move Atlas to font
2022-11-28 10:35:46 -08:00

178 lines
6.2 KiB
Zig

//! This file implements the "dev mode" interface for the terminal. This
//! includes state managements and rendering.
const DevMode = @This();
const std = @import("std");
const imgui = @import("imgui");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const font = @import("font/main.zig");
const Window = @import("Window.zig");
const renderer = @import("renderer.zig");
const Config = @import("config.zig").Config;
/// If this is false, the rest of the terminal will be compiled without
/// dev mode support at all.
pub const enabled = true;
/// The global DevMode instance that can be used app-wide. Assume all functions
/// are NOT thread-safe unless otherwise noted.
pub var instance: DevMode = .{};
/// Whether to show the dev mode UI currently.
visible: bool = false,
/// Our app config
config: ?*const Config = null,
/// The window we're tracking.
window: ?*Window = null,
/// Update the state associated with the dev mode. This should generally
/// only be called paired with a render since it otherwise wastes CPU
/// cycles.
///
/// Note: renderers should call their implementation "newFrame" functions
/// prior to this.
pub fn update(self: *const DevMode) !void {
// Buffer that can be used for stuff...
var buf: [1024 * 32]u8 = undefined;
imgui.newFrame();
if (imgui.begin("dev mode", null, .{})) {
defer imgui.end();
if (self.config) |config| {
if (imgui.collapsingHeader("Ghostty Configuration", null, .{})) {
if (imgui.beginTable("config", 2, .{
.row_bg = true,
.borders_inner_h = true,
.borders_outer_h = true,
.borders_inner_v = true,
.borders_outer_v = true,
})) {
defer imgui.endTable();
// Setup headers
imgui.tableSetupColumn("Key", .{}, 0);
imgui.tableSetupColumn("Value", .{}, 0);
imgui.tableHeadersRow();
// Values
imgui.tableNextRow(0);
_ = imgui.tableNextColumn();
imgui.text("font-family");
_ = imgui.tableNextColumn();
imgui.text((try std.fmt.bufPrintZ(&buf, "{any}", .{config.@"font-family"})).ptr);
imgui.tableNextRow(0);
_ = imgui.tableNextColumn();
imgui.text("click-repeat-interval");
_ = imgui.tableNextColumn();
imgui.text((try std.fmt.bufPrintZ(&buf, "{d}", .{config.@"click-repeat-interval"})).ptr);
}
if (imgui.treeNode("Raw Config (Advanced & Ugly)", .{})) {
defer imgui.treePop();
var raw = try std.fmt.bufPrintZ(&buf, "{}", .{config});
imgui.textWrapped("%s", raw.ptr);
}
}
}
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.");
const Renderer = @TypeOf(window.renderer);
if (imgui.treeNode("Atlas: Greyscale", .{ .default_open = true })) {
defer imgui.treePop();
const atlas = &window.font_group.atlas_greyscale;
const tex = switch (Renderer) {
renderer.OpenGL => @intCast(usize, window.renderer.texture.id),
renderer.Metal => @ptrToInt(window.renderer.texture_greyscale.value),
else => @compileError("renderer unsupported, add it!"),
};
try self.atlasInfo(atlas, tex);
}
if (imgui.treeNode("Atlas: Color (Emoji)", .{ .default_open = true })) {
defer imgui.treePop();
const atlas = &window.font_group.atlas_color;
const tex = switch (Renderer) {
renderer.OpenGL => @intCast(usize, window.renderer.texture_color.id),
renderer.Metal => @ptrToInt(window.renderer.texture_color.value),
else => @compileError("renderer unsupported, add it!"),
};
try self.atlasInfo(atlas, tex);
}
}
}
}
// Just demo for now
// imgui.showDemoWindow(null);
}
/// Render the scene and return the draw data. The caller must be imgui-aware
/// in order to render the draw data. This lets this file be renderer/backend
/// agnostic.
pub fn render(self: DevMode) !*imgui.DrawData {
_ = self;
imgui.render();
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: *const DevMode, atlas: *font.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 },
);
}
}