65 lines
2.0 KiB
Swift
65 lines
2.0 KiB
Swift
import CoreGraphics
|
|
import Foundation
|
|
|
|
/// Where a window is placed within its screen.
|
|
///
|
|
/// Single-edge anchors (`top`, `bottom`, `leading`, `trailing`) pin to that
|
|
/// edge and center along the opposite axis. Corner anchors pin to two edges.
|
|
/// `center` centers the window on both axes.
|
|
enum PHThemeWindowAnchor: String, Decodable {
|
|
case top, bottom, leading, trailing
|
|
case topLeading = "top-leading"
|
|
case topTrailing = "top-trailing"
|
|
case bottomLeading = "bottom-leading"
|
|
case bottomTrailing = "bottom-trailing"
|
|
case center
|
|
}
|
|
|
|
extension PHThemeWindowAnchor {
|
|
/// Compute the top-left origin (in screen coordinates) of a window of `size`
|
|
/// placed against this anchor within `screen`, offset by `margin` along the
|
|
/// anchored edges.
|
|
///
|
|
/// Edges the anchor does not reference are ignored, so margins only affect
|
|
/// the relevant sides.
|
|
func origin(in screen: CGRect, size: CGSize, margin: PHThemeWindowMargin) -> CGPoint {
|
|
let top = margin.top ?? 0
|
|
let bottom = margin.bottom ?? 0
|
|
let leading = margin.leading ?? 0
|
|
let trailing = margin.trailing ?? 0
|
|
|
|
// Default: centered on both axes.
|
|
var point = CGPoint(
|
|
x: screen.midX - size.width / 2,
|
|
y: screen.midY - size.height / 2
|
|
)
|
|
|
|
switch self {
|
|
case .top:
|
|
point.y = screen.maxY - CGFloat(top) - size.height
|
|
case .bottom:
|
|
point.y = screen.minY + CGFloat(bottom)
|
|
case .leading:
|
|
point.x = screen.minX + CGFloat(leading)
|
|
case .trailing:
|
|
point.x = screen.maxX - CGFloat(trailing) - size.width
|
|
case .topLeading:
|
|
point.x = screen.minX + CGFloat(leading)
|
|
point.y = screen.maxY - CGFloat(top) - size.height
|
|
case .topTrailing:
|
|
point.x = screen.maxX - CGFloat(trailing) - size.width
|
|
point.y = screen.maxY - CGFloat(top) - size.height
|
|
case .bottomLeading:
|
|
point.x = screen.minX + CGFloat(leading)
|
|
point.y = screen.minY + CGFloat(bottom)
|
|
case .bottomTrailing:
|
|
point.x = screen.maxX - CGFloat(trailing) - size.width
|
|
point.y = screen.minY + CGFloat(bottom)
|
|
case .center:
|
|
break
|
|
}
|
|
|
|
return point
|
|
}
|
|
}
|