use std::sync::Arc;
use crate::builder::LayoutBuilder;
use crate::error::PaneError;
use crate::layout::Layout;
use crate::panel::{fixed, grow};
use crate::preset::{collect_kinds, validate_active, validate_f32_param, validate_kinds};
pub struct Scrollable {
kinds: Arc<[Arc<str>]>,
active: usize,
gap: f32,
}
impl Scrollable {
pub(crate) fn new(kinds: impl IntoIterator<Item = impl Into<Arc<str>>>) -> Self {
Self {
kinds: collect_kinds(kinds),
active: 0,
gap: 0.0,
}
}
crate::macros::builder_setters!(
active(index: usize);
gap(gap: f32)
);
pub fn build(&self) -> Result<Layout, PaneError> {
validate_kinds(&self.kinds)?;
validate_active(self.active, self.kinds.len())?;
validate_f32_param("gap", self.gap)?;
match self.kinds.len() {
1 => super::build_single(Arc::clone(&self.kinds[0])),
_ => self.build_scroll(),
}
}
fn build_scroll(&self) -> Result<Layout, PaneError> {
let mut b = LayoutBuilder::new();
let window_start = window_start_from_focus(self.active, self.kinds.len(), 2);
let gap_px = self.gap;
let kinds = &self.kinds;
b.row_gap(gap_px, |r| add_scroll_panels(r, kinds, window_start))?;
b.build()
}
}
fn window_start_from_focus(focus: usize, len: usize, panel_count: usize) -> usize {
let start = (focus + 1).saturating_sub(panel_count);
start.min(len.saturating_sub(panel_count))
}
fn add_scroll_panels(ctx: &mut crate::ContainerCtx, kinds: &[Arc<str>], window: usize) {
for (i, kind) in kinds.iter().enumerate() {
let visible = i == window || i == window + 1;
let constraint = match visible {
true => grow(1.0),
false => fixed(0.0),
};
ctx.panel_with(Arc::clone(kind), constraint);
}
}
super::impl_preset!(
Scrollable,
runtime(kinds, |this| crate::strategy::StrategyKind::Window {
panel_count: 2,
gap: this.gap,
})
);