Files
Termind/TFM/Features/Metrics/MetricsDetailLayout.swift

52 lines
2.0 KiB
Swift

// SPDX-FileCopyrightText: 2026 Kaede Akino
// SPDX-License-Identifier: GPL-3.0-only
import SwiftUI
nonisolated enum MetricsDetailPage: CaseIterable {
case status, processes
static func showsBothColumns(width: CGFloat) -> Bool { width >= 700 }
}
/// Both native scroll views stay mounted. A covered panel keeps its last visible
/// size so switching pages or resizing cannot reset its table or scroll position.
struct MetricsDetailLayout: Layout {
var split: Bool
var page: MetricsDetailPage
struct Cache {
var statusSize: CGSize?
var processSize: CGSize?
}
func makeCache(subviews: Subviews) -> Cache { Cache() }
func updateCache(_ cache: inout Cache, subviews: Subviews) {}
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) -> CGSize {
proposal.replacingUnspecifiedDimensions()
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) {
guard subviews.count == 2 else { return }
let statusWidth = split ? min(400, max(270, (bounds.width + 32) * 0.38)) : bounds.width
let processWidth = split ? max(0, bounds.width - statusWidth - 16) : bounds.width
let showsStatus = split || page == .status
let showsProcesses = split || page == .processes
let statusSize =
showsStatus
? CGSize(width: statusWidth, height: bounds.height) : cache.statusSize ?? bounds.size
let processSize =
showsProcesses
? CGSize(width: processWidth, height: bounds.height) : cache.processSize ?? bounds.size
if showsStatus { cache.statusSize = statusSize }
if showsProcesses { cache.processSize = processSize }
subviews[0].place(at: bounds.origin, anchor: .topLeading, proposal: ProposedViewSize(statusSize))
subviews[1].place(
at: CGPoint(x: split ? bounds.minX + statusWidth + 16 : bounds.minX, y: bounds.minY),
anchor: .topLeading, proposal: ProposedViewSize(processSize))
}
}