diff --git a/src/Window.zig b/src/Window.zig index 6d8b87f68..d03137016 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -260,7 +260,12 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window { errdefer font_group.deinit(alloc); // Create our terminal grid with the initial window size - var renderer_impl = try Renderer.init(alloc, font_group); + var renderer_impl = try Renderer.init(alloc, .{ + .font_group = font_group, + .padding = .{ + .balance = config.@"window-padding-balance", + }, + }); errdefer renderer_impl.deinit(); renderer_impl.background = .{ .r = config.background.r, diff --git a/src/config.zig b/src/config.zig index 341b41bb8..796894d37 100644 --- a/src/config.zig +++ b/src/config.zig @@ -89,6 +89,27 @@ pub const Config = struct { /// keybind: Keybinds = .{}, + /// Window padding. This applies padding between the terminal cells and + /// the window border. The "x" option applies to the left and right + /// padding and the "y" option is top and bottom. The value is in points, + /// meaning that it will be scaled appropriately for screen DPI. + @"window-padding-x": u32 = 0, + @"window-padding-y": u32 = 0, + + /// The viewport dimensions are usually not perfectly divisible by + /// the cell size. In this case, some extra padding on the end of a + /// column and the bottom of the final row may exist. If this is true, + /// then this extra padding is automatically balanced between all four + /// edges to minimize imbalance on one side. If this is false, the top + /// left grid cell will always hug the edge with zero padding other than + /// what may be specified with the other "window-padding" options. + /// + /// If other "window-padding" fields are set and this is true, this will + /// still apply. The other padding is applied first and may affect how + /// many grid cells actually exist, and this is applied last in order + /// to balance the padding given a certain viewport size and grid cell size. + @"window-padding-balance": bool = true, + /// Additional configuration files to read. @"config-file": RepeatableString = .{}, diff --git a/src/renderer.zig b/src/renderer.zig index 8d2a2fe40..f52cff302 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -14,6 +14,7 @@ pub usingnamespace @import("renderer/message.zig"); pub usingnamespace @import("renderer/size.zig"); pub const Metal = @import("renderer/Metal.zig"); pub const OpenGL = @import("renderer/OpenGL.zig"); +pub const Options = @import("renderer/Options.zig"); pub const Thread = @import("renderer/Thread.zig"); pub const State = @import("renderer/State.zig"); diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index 076bcd2bb..fea033d9b 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -77,6 +77,9 @@ background: terminal.color.RGB, /// True if the window is focused focused: bool, +/// Padding options +padding: renderer.Options.Padding, + /// The raw structure that maps directly to the buffer sent to the vertex shader. /// This must be "extern" so that the field order is not reordered by the /// Zig compiler. @@ -146,7 +149,7 @@ const GPUCellMode = enum(u8) { } }; -pub fn init(alloc: Allocator, font_group: *font.GroupCache) !OpenGL { +pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL { // Create the initial font shaper var shape_buf = try alloc.alloc(font.Shaper.Cell, 1); errdefer alloc.free(shape_buf); @@ -157,8 +160,8 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !OpenGL { // Doesn't matter, any normal ASCII will do we're just trying to make // sure we use the regular font. const metrics = metrics: { - const index = (try font_group.indexForCodepoint(alloc, 'M', .regular, .text)).?; - const face = try font_group.group.faceFromIndex(index); + const index = (try options.font_group.indexForCodepoint(alloc, 'M', .regular, .text)).?; + const face = try options.font_group.group.faceFromIndex(index); break :metrics face.metrics; }; log.debug("cell dimensions={}", .{metrics}); @@ -248,12 +251,12 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !OpenGL { try texbind.image2D( 0, .Red, - @intCast(c_int, font_group.atlas_greyscale.size), - @intCast(c_int, font_group.atlas_greyscale.size), + @intCast(c_int, options.font_group.atlas_greyscale.size), + @intCast(c_int, options.font_group.atlas_greyscale.size), 0, .Red, .UnsignedByte, - font_group.atlas_greyscale.data.ptr, + options.font_group.atlas_greyscale.data.ptr, ); } @@ -269,12 +272,12 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !OpenGL { try texbind.image2D( 0, .RGBA, - @intCast(c_int, font_group.atlas_color.size), - @intCast(c_int, font_group.atlas_color.size), + @intCast(c_int, options.font_group.atlas_color.size), + @intCast(c_int, options.font_group.atlas_color.size), 0, .BGRA, .UnsignedByte, - font_group.atlas_color.data.ptr, + options.font_group.atlas_color.data.ptr, ); } @@ -289,13 +292,14 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !OpenGL { .vbo = vbo, .texture = tex, .texture_color = tex_color, - .font_group = font_group, + .font_group = options.font_group, .font_shaper = shaper, .cursor_visible = true, .cursor_style = .box, .background = .{ .r = 0, .g = 0, .b = 0 }, .foreground = .{ .r = 255, .g = 255, .b = 255 }, .focused = true, + .padding = options.padding, }; } @@ -952,7 +956,9 @@ fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void { // Determine if we need to pad the window. For "auto" padding, we take // the leftover amounts on the right/bottom that don't fit a full grid cell // and we split them equal across all boundaries. - const padding = renderer.Padding.balanced(dim, grid_size, self.cell_size); + const padding: renderer.Padding = if (self.padding.balance) + renderer.Padding.balanced(dim, grid_size, self.cell_size) + else .{}; const padded_dim = dim.subPadding(padding); log.debug("screen size padded={} screen={} grid={} cell={}", .{ padded_dim, dim, grid_size, self.cell_size }); diff --git a/src/renderer/Options.zig b/src/renderer/Options.zig new file mode 100644 index 000000000..f4e083537 --- /dev/null +++ b/src/renderer/Options.zig @@ -0,0 +1,21 @@ +//! The options that are used to configure a renderer. + +const font = @import("../font/main.zig"); + +/// The font group that should be used. +font_group: *font.GroupCache, + +/// Padding options for the viewport. +padding: Padding, + +pub const Padding = struct { + // Explicit padding options, in pixels. The windowing thread is + // expected to convert points to pixels for a given DPI. + top: u32 = 0, + bottom: u32 = 0, + right: u32 = 0, + left: u32 = 0, + + // Balance options + balance: bool = false, +}; diff --git a/src/renderer/size.zig b/src/renderer/size.zig index 849603941..c59ffb944 100644 --- a/src/renderer/size.zig +++ b/src/renderer/size.zig @@ -78,10 +78,10 @@ pub const GridSize = struct { /// The padding to add to a screen. pub const Padding = struct { - top: f32, - bottom: f32, - right: f32, - left: f32, + top: f32 = 0, + bottom: f32 = 0, + right: f32 = 0, + left: f32 = 0, /// Returns padding that balances the whitespace around the screen /// for the given grid and cell sizes.