From 22eb5334735f1ce4b68113ffe2a77e261759feda Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 2 Sep 2023 10:59:50 -0700 Subject: [PATCH] content scale change events should also impact viewport padding This calculates the new padding pixel values and propogates those changes to the renderer. --- src/Surface.zig | 51 +++++++++++++++++++++++++++++++++++++--- src/apprt/embedded.zig | 5 +++- src/renderer/Metal.zig | 9 +++++-- src/renderer/OpenGL.zig | 7 +++++- src/renderer/Thread.zig | 4 ++-- src/renderer/message.zig | 10 ++++++-- src/renderer/size.zig | 8 +++++++ 7 files changed, 83 insertions(+), 11 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 046197ea2..f4ed94ba8 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -139,6 +139,8 @@ const DerivedConfig = struct { mouse_interval: u64, macos_non_native_fullscreen: configpkg.NonNativeFullscreen, macos_option_as_alt: configpkg.OptionAsAlt, + window_padding_x: u32, + window_padding_y: u32, pub fn init(alloc_gpa: Allocator, config: *const configpkg.Config) !DerivedConfig { var arena = ArenaAllocator.init(alloc_gpa); @@ -156,6 +158,8 @@ const DerivedConfig = struct { .mouse_interval = config.@"click-repeat-interval" * 1_000_000, // 500ms .macos_non_native_fullscreen = config.@"macos-non-native-fullscreen", .macos_option_as_alt = config.@"macos-option-as-alt", + .window_padding_x = config.@"window-padding-x", + .window_padding_y = config.@"window-padding-y", // Assignments happen sequentially so we have to do this last // so that the memory is captured from allocs above. @@ -871,12 +875,19 @@ pub fn sizeCallback(self: *Surface, size: apprt.SurfaceSize) !void { // changed, so we just return. if (self.screen_size.equals(new_screen_size)) return; + try self.resize(new_screen_size); +} + +fn resize(self: *Surface, size: renderer.ScreenSize) !void { // Save our screen size - self.screen_size = new_screen_size; + self.screen_size = size; // Mail the renderer so that it can update the GPU and re-render _ = self.renderer_thread.mailbox.push(.{ - .screen_size = self.screen_size, + .resize = .{ + .screen_size = self.screen_size, + .padding = self.padding, + }, }, .{ .forever = {} }); try self.queueRender(); @@ -1192,16 +1203,50 @@ pub fn scrollCallback( try self.queueRender(); } -pub fn contentScaleCallback(self: *Surface, content_scale: apprt.ContentScale) void { +/// This is called when the content scale of the surface changes. The surface +/// can then update any DPI-sensitive state. +pub fn contentScaleCallback(self: *Surface, content_scale: apprt.ContentScale) !void { + // Calculate the new DPI const x_dpi = content_scale.x * font.face.default_dpi; const y_dpi = content_scale.y * font.face.default_dpi; + + // Update our font size which is dependent on the DPI const size = size: { var size = self.font_size; size.xdpi = @intFromFloat(x_dpi); size.ydpi = @intFromFloat(y_dpi); break :size size; }; + + // If our DPI didn't actually change, save a lot of work by doing nothing. + if (size.xdpi == self.font_size.xdpi and size.ydpi == self.font_size.ydpi) { + return; + } + self.setFontSize(size); + + // Update our padding which is dependent on DPI. + self.padding = padding: { + const padding_x: u32 = padding_x: { + const padding_x: f32 = @floatFromInt(self.config.window_padding_x); + break :padding_x @intFromFloat(@floor(padding_x * x_dpi / 72)); + }; + const padding_y: u32 = padding_y: { + const padding_y: f32 = @floatFromInt(self.config.window_padding_y); + break :padding_y @intFromFloat(@floor(padding_y * y_dpi / 72)); + }; + + break :padding .{ + .top = padding_y, + .bottom = padding_y, + .right = padding_x, + .left = padding_x, + }; + }; + + // Force a resize event because the change in padding will affect + // pixel-level changes to the renderer and viewport. + try self.resize(self.screen_size); } /// The type of action to report for a mouse event. diff --git a/src/apprt/embedded.zig b/src/apprt/embedded.zig index d0d70686a..bc6bc876e 100644 --- a/src/apprt/embedded.zig +++ b/src/apprt/embedded.zig @@ -350,7 +350,10 @@ pub const Surface = struct { .y = @floatCast(y), }; - self.core_surface.contentScaleCallback(self.content_scale); + self.core_surface.contentScaleCallback(self.content_scale) catch |err| { + log.err("error in content scale callback err={}", .{err}); + return; + }; } pub fn updateSize(self: *Surface, width: u32, height: u32) void { diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 055d5e617..9851f195e 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -1048,9 +1048,14 @@ pub fn changeConfig(self: *Metal, config: *DerivedConfig) !void { } /// Resize the screen. -pub fn setScreenSize(self: *Metal, dim: renderer.ScreenSize) !void { - // Store our screen size +pub fn setScreenSize( + self: *Metal, + dim: renderer.ScreenSize, + pad: renderer.Padding, +) !void { + // Store our sizes self.screen_size = dim; + self.padding.explicit = pad; // Recalculate the rows/columns. This can't fail since we just set // the screen size above. diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index 291fc4727..cfdbf4118 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -1427,12 +1427,17 @@ pub fn changeConfig(self: *OpenGL, config: *DerivedConfig) !void { /// Set the screen size for rendering. This will update the projection /// used for the shader so that the scaling of the grid is correct. -pub fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void { +pub fn setScreenSize( + self: *OpenGL, + dim: renderer.ScreenSize, + pad: renderer.Padding, +) !void { if (single_threaded_draw) self.draw_mutex.lock(); defer if (single_threaded_draw) self.draw_mutex.unlock(); // Store our screen size self.screen_size = dim; + self.padding.explicit = pad; // Recalculate the rows/columns. const grid_size = self.gridSize(dim); diff --git a/src/renderer/Thread.zig b/src/renderer/Thread.zig index e198a8c19..41218791d 100644 --- a/src/renderer/Thread.zig +++ b/src/renderer/Thread.zig @@ -252,8 +252,8 @@ fn drainMailbox(self: *Thread) !void { try self.renderer.setFontSize(size); }, - .screen_size => |size| { - try self.renderer.setScreenSize(size); + .resize => |v| { + try self.renderer.setScreenSize(v.screen_size, v.padding); }, .change_config => |config| { diff --git a/src/renderer/message.zig b/src/renderer/message.zig index 7441380da..19cde4385 100644 --- a/src/renderer/message.zig +++ b/src/renderer/message.zig @@ -20,8 +20,14 @@ pub const Message = union(enum) { /// the size changes. font_size: font.face.DesiredSize, - /// Change the screen size. - screen_size: renderer.ScreenSize, + /// Changes the screen size. + resize: struct { + /// The full screen (drawable) size. This does NOT include padding. + screen_size: renderer.ScreenSize, + + /// The explicit padding values. + padding: renderer.Padding, + }, /// The derived configuration to update the renderer with. change_config: struct { diff --git a/src/renderer/size.zig b/src/renderer/size.zig index b01860334..00766a46b 100644 --- a/src/renderer/size.zig +++ b/src/renderer/size.zig @@ -143,6 +143,14 @@ pub const Padding = struct { .left = self.left + other.left, }; } + + /// Equality test between two paddings. + pub fn eql(self: Padding, other: Padding) bool { + return self.top == other.top and + self.bottom == other.bottom and + self.right == other.right and + self.left == other.left; + } }; test "Padding balanced on zero" {