Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-app/src/splitpane.rs

//! **`SplitPane` — host two Facets with a draggable divider.** A composition
//! container (the Fas 2 layout extra): mount two components side-by-side (or
//! stacked) with a resizable split, so a route can show a master+detail / compare
//! view. Itself a [`Facet`]; `state_json` folds in both children.

use facett_core::{Facet, FacetCaps};

/// A resizable two-pane split hosting two [`Facet`]s.
pub struct SplitPane {
    title: String,
    first: Box<dyn Facet>,
    second: Box<dyn Facet>,
    /// `true` = top/bottom, `false` = left/right (default).
    vertical: bool,
    /// Initial fraction of the first pane (0..1).
    ratio: f32,
}

impl SplitPane {
    pub fn new(title: impl Into<String>, first: Box<dyn Facet>, second: Box<dyn Facet>) -> Self {
        Self { title: title.into(), first, second, vertical: false, ratio: 0.5 }
    }
    /// Stack the panes vertically (top/bottom) instead of side-by-side.
    pub fn vertical(mut self, on: bool) -> Self {
        self.vertical = on;
        self
    }
    /// Initial fraction of the first pane (clamped to `0.1..=0.9`).
    pub fn ratio(mut self, ratio: f32) -> Self {
        self.ratio = ratio.clamp(0.1, 0.9);
        self
    }
}

impl Facet for SplitPane {
    fn title(&self) -> &str {
        &self.title
    }

    fn ui(&mut self, ui: &mut egui::Ui) {
        let id = ui.id().with("splitpane");
        let (first, second) = (&mut self.first, &mut self.second);
        if self.vertical {
            let h = ui.available_height() * self.ratio;
            egui::Panel::top(id).resizable(true).default_size(h).show(ui, |ui| first.ui(ui));
            second.ui(ui);
        } else {
            let w = ui.available_width() * self.ratio;
            egui::Panel::left(id).resizable(true).default_size(w).show(ui, |ui| first.ui(ui));
            second.ui(ui);
        }
    }

    fn state_json(&self) -> serde_json::Value {
        serde_json::json!({
            "title": self.title,
            "vertical": self.vertical,
            "ratio": self.ratio,
            "first": { "title": self.first.title(), "state": self.first.state_json() },
            "second": { "title": self.second.title(), "state": self.second.state_json() },
        })
    }

    fn caps(&self) -> FacetCaps {
        FacetCaps::NONE.themeable().resizable()
    }
}