mirror of
https://github.com/phranck/TUIkit.git
synced 2026-05-21 09:50:35 +00:00
e214215610
- Migrate 20 Equatable conformances across 17 files from nonisolated + MainActor.assumeIsolated to @preconcurrency Equatable (SE-0423) - Remove unnecessary import Foundation from 29 source files - Extract TextFieldHandler clipboard ops into TextFieldHandler+Clipboard.swift - Extract RenderContext into RenderContext.swift (Renderable.swift 553 -> 279 lines) - Extract ANSIColor enum into ANSIColor.swift (Color.swift 600 -> 533 lines) - Add deprecation timeline note for progressBarStyle(_:) - Migrate test usages from progressBarStyle to trackStyle
85 lines
2.7 KiB
Swift
85 lines
2.7 KiB
Swift
// 🖥️ TUIKit — Terminal UI Kit for Swift
|
||
// OverlayModifier.swift
|
||
//
|
||
// Created by LAYERED.work
|
||
// License: MIT
|
||
|
||
/// Internal modifier that layers an overlay view on top of the base content.
|
||
///
|
||
/// The overlay is rendered on top of the base content. Both views are rendered
|
||
/// to their natural size, and the overlay is positioned according to the
|
||
/// specified alignment within the base content's bounds.
|
||
public struct OverlayModifier<Base: View, Overlay: View>: View {
|
||
/// The base content.
|
||
let base: Base
|
||
|
||
/// The overlay content.
|
||
let overlay: Overlay
|
||
|
||
/// The alignment of the overlay within the base bounds.
|
||
let alignment: Alignment
|
||
|
||
public var body: Never {
|
||
fatalError("OverlayModifier renders via Renderable")
|
||
}
|
||
}
|
||
|
||
// MARK: - Equatable Conformance
|
||
|
||
extension OverlayModifier: @preconcurrency Equatable where Base: Equatable, Overlay: Equatable {
|
||
public static func == (lhs: OverlayModifier<Base, Overlay>, rhs: OverlayModifier<Base, Overlay>) -> Bool {
|
||
lhs.base == rhs.base &&
|
||
lhs.overlay == rhs.overlay &&
|
||
lhs.alignment == rhs.alignment
|
||
}
|
||
}
|
||
|
||
// MARK: - Renderable
|
||
|
||
extension OverlayModifier: Renderable {
|
||
func renderToBuffer(context: RenderContext) -> FrameBuffer {
|
||
// Render both contents
|
||
let baseBuffer = TUIkit.renderToBuffer(base, context: context)
|
||
let overlayBuffer = TUIkit.renderToBuffer(overlay, context: context)
|
||
|
||
guard !baseBuffer.isEmpty else {
|
||
return overlayBuffer
|
||
}
|
||
|
||
guard !overlayBuffer.isEmpty else {
|
||
return baseBuffer
|
||
}
|
||
|
||
// Calculate the position of the overlay based on alignment
|
||
let baseWidth = baseBuffer.width
|
||
let baseHeight = baseBuffer.height
|
||
let overlayWidth = overlayBuffer.width
|
||
let overlayHeight = overlayBuffer.height
|
||
|
||
// Calculate horizontal position
|
||
let horizontalOffset: Int
|
||
switch alignment.horizontal {
|
||
case .leading:
|
||
horizontalOffset = 0
|
||
case .center:
|
||
horizontalOffset = max(0, (baseWidth - overlayWidth) / 2)
|
||
case .trailing:
|
||
horizontalOffset = max(0, baseWidth - overlayWidth)
|
||
}
|
||
|
||
// Calculate vertical position
|
||
let verticalOffset: Int
|
||
switch alignment.vertical {
|
||
case .top:
|
||
verticalOffset = 0
|
||
case .center:
|
||
verticalOffset = max(0, (baseHeight - overlayHeight) / 2)
|
||
case .bottom:
|
||
verticalOffset = max(0, baseHeight - overlayHeight)
|
||
}
|
||
|
||
// Composite the overlay onto the base
|
||
return baseBuffer.composited(with: overlayBuffer, at: (x: horizontalOffset, y: verticalOffset))
|
||
}
|
||
}
|