Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Nov 4, 2021
1 parent 760f07b commit fbe21bc
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 30 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ Best practices:
- `Foreground(Color)`: foreground color. The foreground will be used as foreground for the selected item, when focus is false, otherwise as background
- `HighlightedColor(Color)`: The provided color will be used to highlight the selected node. `Foreground` will be used if unset.
- `HighlightedStr(String)`: The provided string will be displayed on the left side of the selected entry in the tree
- `Rewind(Flag)`: If true, when going out of boundaries on tree, the index returns to the top or to the bottom based on position.
- `ScrollStep(Length)`: Defines the maximum amount of rows to scroll
- `TextProps(TextModifiers)`: set text modifiers
- `Title(Title)`: Set box title
Expand Down
35 changes: 27 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ impl TreeView {
self
}

pub fn scroll_step(mut self, step: usize) -> Self {
self.attr(Attribute::ScrollStep, AttrValue::Length(step));
self
}

pub fn with_tree(mut self, tree: Tree) -> Self {
self.tree = tree;
self
Expand Down Expand Up @@ -208,12 +213,6 @@ impl TreeView {

// -- private

fn rewindable(&self) -> bool {
self.props
.get_or(Attribute::Rewind, AttrValue::Flag(false))
.unwrap_flag()
}

/// ### changed
///
/// Returns whether selectd node has changed
Expand Down Expand Up @@ -347,22 +346,42 @@ impl MockComponent for TreeView {
match cmd {
Cmd::GoTo(Position::Begin) => {
let prev = self.states.selected().map(|x| x.to_string());
// TODO: impl
todo!();
self.changed(prev.as_deref())
}
Cmd::GoTo(Position::End) => {
let prev = self.states.selected().map(|x| x.to_string());
// TODO: impl
todo!();
self.changed(prev.as_deref())
}
Cmd::Move(Direction::Down) => {
let prev = self.states.selected().map(|x| x.to_string());
self.states.move_down(self.tree.root(), self.rewindable());
self.states.move_down(self.tree.root());
self.changed(prev.as_deref())
}
Cmd::Move(Direction::Up) => {
let prev = self.states.selected().map(|x| x.to_string());
self.states.move_up(self.tree.root(), self.rewindable());
self.states.move_up(self.tree.root());
self.changed(prev.as_deref())
}
Cmd::Scroll(Direction::Down) => {
let prev = self.states.selected().map(|x| x.to_string());
let step = self
.props
.get_or(Attribute::ScrollStep, AttrValue::Length(8))
.unwrap_length();
(0..step).for_each(|_| self.states.move_down(self.tree.root()));
self.changed(prev.as_deref())
}
Cmd::Scroll(Direction::Up) => {
let prev = self.states.selected().map(|x| x.to_string());
let step = self
.props
.get_or(Attribute::ScrollStep, AttrValue::Length(8))
.unwrap_length();
(0..step).for_each(|_| self.states.move_up(self.tree.root()));
self.changed(prev.as_deref())
}
Cmd::Submit => CmdResult::Submit(self.state()),
Expand Down
115 changes: 94 additions & 21 deletions src/tree_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,36 +128,57 @@ impl TreeState {
/// ### move_down
///
/// Move cursor down in current tree from current position. Rewind if required
pub fn move_down(&mut self, root: &Node, rewind: bool) {
// TODO: is open? then move to first child
// TODO: is leaf | close? then move to next sibling
todo!()
pub fn move_down(&mut self, root: &Node) {
if let Some(selected) = self.selected.take() {
// Get current node
if let Some(node) = root.query(&selected) {
// If node is open, then move to its first child
if !node.is_leaf() && self.is_open(node) {
// NOTE: unwrap is safe; checked by `is_leaf()`
self.selected = Some(node.children().first().unwrap().id().to_string());
} else {
// If has a "next sibling", let's get it
if let Some(sibling) = self.next_sibling(root, node) {
self.selected = Some(sibling.id().to_string());
} else {
// Then the next element becomes the next sibling of the parent
// this thing has to be performed recursively for all parents, until one is found (or root is reached)
let mut current = selected.clone();
loop {
if let Some(parent) = root.parent(&current) {
current = parent.id().to_string();
if let Some(sibling) = self.next_sibling(root, parent) {
self.selected = Some(sibling.id().to_string());
break;
}
} else {
// has no parent, keep selectd
self.selected = Some(selected);
break;
}
}
}
}
}
}
}

/// ### move_up
///
/// Move cursor up in current tree from current position. Rewind if required
pub fn move_up(&mut self, root: &Node, rewind: bool) {
pub fn move_up(&mut self, root: &Node) {
if let Some(selected) = self.selected.take() {
// Get parent
if let Some(parent) = root.parent(&selected) {
// Iter children; track previous node, which will become the new active element
// TODO: if rewind this is the last element
let mut prev_node = parent;
// TODO: make this function more functional
for child in parent.children() {
// If current node is found, break
if child.id() == &selected {
break;
} else {
// Else set child as previous node
prev_node = child;
}
}
// Finally set previous node as new selected node
self.selected = Some(prev_node.id().to_string());
// Selected becomes previous sibling; or if None, the parent
self.selected = Some(
self.previous_sibling(root, root.query(&selected).unwrap())
.unwrap_or(parent)
.id()
.to_string(),
);
} else {
// Keep selected
// Is root; then keep selected
self.selected = Some(selected);
}
}
Expand All @@ -178,4 +199,56 @@ impl TreeState {
fn close_children(&mut self, node: &Node) {
node.iter().for_each(|x| self.close_node(x));
}

/// ### previous_sibling
///
/// Returns the previous sibling of `node` in `tree`
fn previous_sibling<'a>(&mut self, root: &'a Node, node: &'a Node) -> Option<&'a Node> {
match root.parent(node.id()) {
None => None,
Some(parent) => {
let mut prev_node = None;
for child in parent.children() {
if child.id() == node.id() {
break;
}
prev_node = Some(child);
}
prev_node
}
}
}

/// ### next_sibling
///
/// Returs next sibling of `node` in `tree`
fn next_sibling<'a>(&mut self, root: &'a Node, node: &'a Node) -> Option<&'a Node> {
match root.parent(node.id()) {
None => None,
Some(parent) => {
let mut keep_next = false;
for child in parent.children() {
if keep_next {
// Return child
return Some(child);
} else if child.id() == node.id() {
// keep next element
keep_next = true;
}
}
// No next sibling
None
}
}
}
}

#[cfg(test)]
mod test {

use super::*;

use pretty_assertions::assert_eq;

// TODO: impl
}
1 change: 1 addition & 0 deletions src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ impl<'a> TreeWidget<'a> {
///
/// Calculate rows to skip before starting rendering the current tree
fn calc_rows_to_skip(node: &Node, state: &TreeState, height: u16) -> usize {
// TODO: impl
todo!()
}
}
Expand Down

0 comments on commit fbe21bc

Please sign in to comment.