use std::sync::Arc;
use super::types::{LayoutRuntime, StrategySource, base};
use crate::breakpoint::BreakpointEntry;
use crate::error::{PaneError, TreeError};
use crate::layout::Layout;
use crate::node::{Node, NodeId, PanelId};
use crate::overlay::{self, OverlayDef};
use crate::sequence::PanelSequence;
use crate::snapshot::{self, LayoutSnapshot, SnapshotSource};
use crate::strategy::StrategyKind;
use crate::tree::LayoutTree;
use crate::viewport::ViewportState;
impl LayoutRuntime {
pub fn new(tree: LayoutTree) -> Self {
base(
tree,
ViewportState::default(),
StrategySource::None,
PanelSequence::default(),
)
}
pub fn from_strategy(strategy: StrategyKind, kinds: &[Arc<str>]) -> Result<Self, PaneError> {
let mut sequence = PanelSequence::default();
let mut viewport = ViewportState::default();
let tree = crate::strategy::build_initial(&strategy, kinds, &mut sequence, &mut viewport)?;
Ok(base(
tree,
viewport,
StrategySource::Standalone(strategy),
sequence,
))
}
pub fn from_tree_and_sequence(tree: LayoutTree, sequence: PanelSequence) -> Self {
let focus = sequence.get(0);
base(
tree,
ViewportState {
focus,
..ViewportState::default()
},
StrategySource::None,
sequence,
)
}
pub fn from_tree_and_strategy(
tree: LayoutTree,
strategy: StrategyKind,
kinds: &[Arc<str>],
) -> Self {
let mut sequence = PanelSequence::default();
crate::strategy::populate_sequence_by_kinds(&tree, kinds, &mut sequence);
let focus = sequence.get(0);
base(
tree,
ViewportState {
focus,
..ViewportState::default()
},
StrategySource::Standalone(strategy),
sequence,
)
}
pub(crate) fn from_adaptive(
kinds: &[Arc<str>],
breakpoints: Box<[BreakpointEntry]>,
active_idx: usize,
) -> Result<Self, PaneError> {
let strategy = &breakpoints[active_idx].strategy;
let mut sequence = PanelSequence::default();
let mut viewport = ViewportState::default();
let tree = crate::strategy::build_initial(strategy, kinds, &mut sequence, &mut viewport)?;
let mut rt = base(tree, viewport, StrategySource::Adaptive, sequence);
rt.breakpoints = Some(breakpoints);
rt.active_bp_idx = active_idx;
Ok(rt)
}
pub fn snapshot(&self) -> Result<LayoutSnapshot, PaneError> {
let bp_info = self
.breakpoints
.as_deref()
.map(|bps| (bps, self.active_bp_idx));
snapshot::capture(
&self.tree,
self.strategy(),
&self.sequence,
&self.viewport,
&self.overlays,
bp_info,
)
}
pub fn from_snapshot(snap: LayoutSnapshot) -> Result<Self, PaneError> {
let mut rt = match snap.source() {
SnapshotSource::Strategy { strategy, panels } => {
let sk = StrategyKind::from(strategy);
let kinds: Box<[Arc<str>]> = panels.iter().map(|s| Arc::from(&**s)).collect();
Self::from_strategy(sk, &kinds)?
}
SnapshotSource::Tree { root } => {
let tree = snapshot::snapshot_to_tree(root)?;
let mut seq = PanelSequence::default();
collect_panels_depth_first(&tree, &mut seq);
Self::from_tree_and_sequence(tree, seq)
}
SnapshotSource::Adaptive { breakpoints, .. } if breakpoints.is_empty() => {
return Err(PaneError::InvalidTree(TreeError::NoBreakpoints));
}
SnapshotSource::Adaptive {
breakpoints,
panels,
active_index,
} => {
let kinds: Box<[Arc<str>]> = panels.iter().map(|s| Arc::from(&**s)).collect();
let bp_entries: Box<[BreakpointEntry]> = breakpoints
.iter()
.map(|sb| BreakpointEntry {
min_width: sb.min_width,
strategy: StrategyKind::from(&sb.strategy),
})
.collect::<Vec<_>>()
.into();
let active = (*active_index).min(bp_entries.len().saturating_sub(1));
Self::from_adaptive(&kinds, bp_entries, active)?
}
};
let focus_pid = match snap.focused_key() {
Some(key) => rt.sequence.get(key.raw() as usize),
None => snap
.focused()
.and_then(|kind| rt.tree.panels_by_kind(kind).first().copied()),
};
if let Some(pid) = focus_pid {
let _ = rt.focus(pid);
}
let collapsed_pids: Box<[PanelId]> = match snap.collapsed_keys().is_empty() {
true => snap
.collapsed()
.iter()
.filter_map(|kind| rt.tree.panels_by_kind(kind).first().copied())
.collect(),
false => snap
.collapsed_keys()
.iter()
.filter_map(|&key| rt.sequence.get(key.raw() as usize))
.collect(),
};
for pid in collapsed_pids {
rt.toggle_collapsed(pid)?;
}
restore_overlays(&mut rt, snap.into_overlays())?;
Ok(rt)
}
}
impl From<LayoutTree> for LayoutRuntime {
fn from(tree: LayoutTree) -> Self {
Self::new(tree)
}
}
impl From<Layout> for LayoutRuntime {
fn from(layout: Layout) -> Self {
Self::new(LayoutTree::from(layout))
}
}
fn restore_overlays(
rt: &mut LayoutRuntime,
overlays: Vec<overlay::SnapshotOverlay>,
) -> Result<(), PaneError> {
for snap_overlay in overlays {
let kind: Arc<str> = Arc::from(snap_overlay.kind);
let id = rt.overlay_gen.next_id()?;
let def = OverlayDef {
id,
kind: Arc::clone(&kind),
anchor: snap_overlay.anchor,
width: snap_overlay.width,
height: snap_overlay.height,
visible: snap_overlay.visible,
};
let idx = rt.overlays.len();
rt.overlays.push(def);
rt.overlay_index.insert(kind, idx);
}
Ok(())
}
fn collect_panels_depth_first(tree: &LayoutTree, seq: &mut PanelSequence) {
let Some(root) = tree.root() else { return };
collect_panels_recursive(tree, root, seq);
}
fn collect_panels_recursive(tree: &LayoutTree, nid: NodeId, seq: &mut PanelSequence) {
let Some(node) = tree.node(nid) else { return };
match node {
Node::Panel { id, .. } => seq.push(*id),
_ => {
for &child in node.children() {
collect_panels_recursive(tree, child, seq);
}
}
}
}