macos: use dedicated overlay view for resize overlay

This commit is contained in:
Mitchell Hashimoto
2024-08-10 20:56:21 -07:00
parent 9cf247bb3e
commit 1c982278f3

View File

@ -52,9 +52,6 @@ extension Ghostty {
// True if we're hovering over the left URL view, so we can show it on the right. // True if we're hovering over the left URL view, so we can show it on the right.
@State private var isHoveringURLLeft: Bool = false @State private var isHoveringURLLeft: Bool = false
// The last size so we can detect resizes and show our resize overlay
@State private var lastSize: CGSize? = nil
@EnvironmentObject private var ghostty: Ghostty.App @EnvironmentObject private var ghostty: Ghostty.App
var body: some View { var body: some View {
@ -150,51 +147,14 @@ extension Ghostty {
} }
// If our geo size changed then we show the resize overlay as configured. // If our geo size changed then we show the resize overlay as configured.
if (lastSize != geo.size) { if let surfaceSize = surfaceView.surfaceSize {
let resizeOverlay = ghostty.config.resizeOverlay SurfaceResizeOverlay(
if (resizeOverlay != .never) { geoSize: geo.size,
if let surfaceSize = surfaceView.surfaceSize { size: surfaceSize,
let padding: CGFloat = 5 overlay: ghostty.config.resizeOverlay,
let resizeDuration = ghostty.config.resizeOverlayDuration position: ghostty.config.resizeOverlayPosition,
let resizePosition = ghostty.config.resizeOverlayPosition duration: ghostty.config.resizeOverlayDuration)
VStack {
if (!resizePosition.top()) {
Spacer()
}
HStack {
if (!resizePosition.left()) {
Spacer()
}
Text(verbatim: "\(surfaceSize.columns)c \(surfaceSize.rows)r")
.padding(.init(top: padding, leading: padding, bottom: padding, trailing: padding))
.background(
RoundedRectangle(cornerRadius: 4)
.fill(.background)
.shadow(radius: 3)
).lineLimit(1)
.truncationMode(.middle)
if (!resizePosition.right()) {
Spacer()
}
}
if (!resizePosition.bottom()) {
Spacer()
}
}
.allowsHitTesting(false)
.opacity(resizeOverlay == .after_first && lastSize == nil ? 0 : 1)
.onAppear() {
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(resizeDuration))) {
self.lastSize = geo.size
}
}
}
}
} }
} }
.ghosttySurfaceView(surfaceView) .ghosttySurfaceView(surfaceView)
@ -306,6 +266,76 @@ extension Ghostty {
} }
} }
// This is the resize overlay that shows on top of a surface to show the current
// size during a resize operation.
struct SurfaceResizeOverlay: View {
let geoSize: CGSize
let size: ghostty_surface_size_s
let overlay: Ghostty.Config.ResizeOverlay
let position: Ghostty.Config.ResizeOverlayPosition
let duration: UInt
// This is the last size that we processed. This is how we handle our
// timer state.
@State var lastSize: CGSize? = nil
// Fixed value set based on personal taste.
private let padding: CGFloat = 5
// This computed boolean is set to true when the overlay should be hidden.
private var hidden: Bool {
// Hidden if we already processed this size.
if (lastSize == geoSize) { return true; }
// Hidden depending on overlay config
switch (overlay) {
case .never: return true;
case .always: return false;
case .after_first: return lastSize == nil;
}
}
var body: some View {
VStack {
if (!position.top()) {
Spacer()
}
HStack {
if (!position.left()) {
Spacer()
}
Text(verbatim: "\(size.columns)c \(size.rows)r")
.padding(.init(top: padding, leading: padding, bottom: padding, trailing: padding))
.background(
RoundedRectangle(cornerRadius: 4)
.fill(.background)
.shadow(radius: 3)
).lineLimit(1)
.truncationMode(.middle)
if (!position.right()) {
Spacer()
}
}
if (!position.bottom()) {
Spacer()
}
}
.allowsHitTesting(false)
.opacity(hidden ? 0 : 1)
.task(id: geoSize) {
// By ID-ing the task on the geoSize, we get the task to restart if our
// geoSize changes. This also ensures that future resize overlays are shown
// properly.
try? await Task.sleep(nanoseconds: UInt64(duration) * 1_000_000)
lastSize = geoSize
}
}
}
/// A surface is terminology in Ghostty for a terminal surface, or a place where a terminal is actually drawn /// A surface is terminology in Ghostty for a terminal surface, or a place where a terminal is actually drawn
/// and interacted with. The word "surface" is used because a surface may represent a window, a tab, /// and interacted with. The word "surface" is used because a surface may represent a window, a tab,
/// a split, a small preview pane, etc. It is ANYTHING that has a terminal drawn to it. /// a split, a small preview pane, etc. It is ANYTHING that has a terminal drawn to it.