feat: tmux 动态 resize(iPadOS 拖拽窗口/旋转自适应)
- ContentView 观测 onChange(geo.size)/onAppear → controller.containerResized - containerResized: 点尺寸 × displayScale ÷ cell 像素 = 目标 cols×rows,去重 + debounce(200ms) → refresh-client -C WxH → tmux 重排回 %layout-change → 更新 pane frame - cell 像素来自 raw 终端/pane surface metrics(InMemoryTerminalViewport.cellWidthPixels); surface resize 回调只 noteCellPixels 不驱动 tmux(防反馈环,单向数据流) - 验证:容器 1032x1280@2x cell16x35→129x73,tmux 根 rect 精确采纳,2 pane 复用不重建 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -167,31 +167,39 @@ struct TmuxTabChip: View {
|
||||
struct TmuxWindowView: View {
|
||||
@ObservedObject var window: TmuxWindow
|
||||
let controller: TmuxController
|
||||
@Environment(\.displayScale) private var displayScale
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geo in
|
||||
if let layout = window.visibleLayout {
|
||||
let root = layout.root.rect
|
||||
let cw = geo.size.width / CGFloat(max(1, root.width))
|
||||
let ch = geo.size.height / CGFloat(max(1, root.height))
|
||||
ZStack(alignment: .topLeading) {
|
||||
ForEach(leaves(layout.root), id: \.pane.raw) { item in
|
||||
if let surface = window.panes[item.pane] {
|
||||
TmuxPaneView(
|
||||
surface: surface,
|
||||
isActive: window.activePane == item.pane,
|
||||
onTap: { controller.selectPane(item.pane, in: window.id) },
|
||||
onReady: { controller.markPaneReady(item.pane) }
|
||||
)
|
||||
.frame(width: CGFloat(item.rect.width) * cw,
|
||||
height: CGFloat(item.rect.height) * ch)
|
||||
.position(x: (CGFloat(item.rect.x) + CGFloat(item.rect.width) / 2) * cw,
|
||||
y: (CGFloat(item.rect.y) + CGFloat(item.rect.height) / 2) * ch)
|
||||
Group {
|
||||
if let layout = window.visibleLayout {
|
||||
let root = layout.root.rect
|
||||
let cw = geo.size.width / CGFloat(max(1, root.width))
|
||||
let ch = geo.size.height / CGFloat(max(1, root.height))
|
||||
ZStack(alignment: .topLeading) {
|
||||
ForEach(leaves(layout.root), id: \.pane.raw) { item in
|
||||
if let surface = window.panes[item.pane] {
|
||||
TmuxPaneView(
|
||||
surface: surface,
|
||||
isActive: window.activePane == item.pane,
|
||||
onTap: { controller.selectPane(item.pane, in: window.id) },
|
||||
onReady: { controller.markPaneReady(item.pane) }
|
||||
)
|
||||
.frame(width: CGFloat(item.rect.width) * cw,
|
||||
height: CGFloat(item.rect.height) * ch)
|
||||
.position(x: (CGFloat(item.rect.x) + CGFloat(item.rect.width) / 2) * cw,
|
||||
y: (CGFloat(item.rect.y) + CGFloat(item.rect.height) / 2) * ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Color.clear
|
||||
}
|
||||
} else {
|
||||
Color.clear
|
||||
}
|
||||
// iPadOS 可自由拖拽窗口尺寸 → 容器变化即重算总格子并 refresh-client -C(controller 内 debounce)。
|
||||
.onAppear { controller.containerResized(widthPt: geo.size.width, heightPt: geo.size.height, scale: displayScale) }
|
||||
.onChange(of: geo.size) { _, s in
|
||||
controller.containerResized(widthPt: s.width, heightPt: s.height, scale: displayScale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user