cursive-tree 0.0.9

Tree view for the Cursive TUI library
Documentation
use super::{super::backend::*, depth::*, iterator::*, kind::*, list::*, node::*, path::*};

use {
    cursive::{style::*, utils::span::*, *},
    std::cmp::*,
};

//
// TreeModel
//

/// Tree model.
pub struct TreeModel<BackendT>
where
    BackendT: TreeBackend,
{
    /// Roots.
    pub roots: NodeList<BackendT>,

    /// Context.
    pub context: BackendT::Context,
}

impl<BackendT> TreeModel<BackendT>
where
    BackendT: TreeBackend,
{
    /// Constructor.
    pub fn new(context: BackendT::Context) -> Self {
        Self { roots: Default::default(), context }
    }

    /// Whether we have no nodes.
    pub fn is_empty(&self) -> bool {
        self.roots.0.is_empty()
    }

    /// Iterate nodes in visual order from top to bottom.
    ///
    /// When only_expanded is true will skip the children of collapsed branches.
    pub fn iter(&self, only_expanded: bool) -> NodeIterator<'_, BackendT> {
        self.roots.iter(only_expanded)
    }

    /// Get node at path.
    pub fn at_path(&self, path: NodePath) -> Option<&Node<BackendT>> {
        self.roots.at_path(path)
    }

    /// Get node at path.
    pub fn at_path_mut(&mut self, path: NodePath) -> Option<&mut Node<BackendT>> {
        self.roots.at_path_mut(path)
    }

    /// Get node at row.
    pub fn at_row(&self, row: usize) -> Option<&Node<BackendT>> {
        let mut iterator = self.iter(true);
        let mut current_row: usize = 0;
        while let Some(node) = iterator.next() {
            let next_row = current_row + node.label_size.y;
            if (row >= current_row) && (row < next_row) {
                return Some(node);
            }
            current_row = next_row;
        }
        None
    }

    /// Find path to node.
    pub fn path(&self, node: &Node<BackendT>) -> Option<NodePath> {
        let mut path = Default::default();
        if self.roots.fill_path(&mut path, node) { Some(path) } else { None }
    }

    /// Full extents for drawing.
    pub fn extents(&self) -> Vec2 {
        let mut extents = Vec2::default();
        let mut iterator = self.iter(true);
        while let Some(node) = iterator.next() {
            extents.x = max(extents.x, node.depth * 2 + 2 + node.label_size.x);
            extents.y += node.label_size.y;
        }
        extents
    }

    /// Add a root node.
    pub fn add_root<IdT, LabelT>(&mut self, kind: NodeKind, id: IdT, label: LabelT)
    where
        IdT: Into<BackendT::ID>,
        LabelT: Into<SpannedString<Style>>,
    {
        self.roots.add(0, kind, id, label);
    }

    /// Insert a root node.
    pub fn insert_root<IdT, LabelT>(&mut self, index: usize, kind: NodeKind, id: IdT, label: LabelT)
    where
        IdT: Into<BackendT::ID>,
        LabelT: Into<SpannedString<Style>>,
    {
        self.roots.insert(index, 0, kind, id, label);
    }

    /// Expand branch nodes.
    ///
    /// If depth is [None] will expand the entire tree.
    ///
    /// If depth is 0 will do nothing.
    ///
    /// Note that this *will* populate expanded nodes from the backend.
    pub fn expand(&mut self, depth: Option<usize>) -> Result<(), BackendT::Error>
    where
        BackendT::Context: Clone,
    {
        self.roots.expand(depth, self.context.clone())
    }

    /// Collapse branch nodes.
    ///
    /// If depth is [None] will collapse the entire tree.
    ///
    /// If depth is 0 will do nothing.
    pub fn collapse(&mut self, depth: Option<usize>) {
        self.roots.collapse(depth);
    }

    /// Fetch roots and possibly their children from backend.
    ///
    /// If depth is [None] will populate the entire tree.
    ///
    /// If depth is 1 will only populate the roots.
    ///
    /// If depth is 0 will do nothing.
    ///
    /// Note that populating a branch node will *not* automatically expand it.
    pub fn populate(&mut self, mut depth: Option<usize>) -> Result<(), BackendT::Error>
    where
        BackendT::Context: Clone,
    {
        if depth.is_zero() {
            return Ok(());
        }

        self.roots = BackendT::roots(self.context.clone())?;

        depth.decrease();
        if !depth.is_zero() {
            for node in &mut self.roots {
                node.populate(depth, self.context.clone())?;
            }
        }

        Ok(())
    }

    /// Remove all nodes.
    pub fn clear(&mut self) {
        self.roots.0.clear();
    }
}