Skip to content

Commit

Permalink
Keep working
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Nov 4, 2021
1 parent 6716972 commit 0c31966
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 46 deletions.
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,24 +134,24 @@ Best practices:

**Commands**:

| Cmd | Result | Behaviour |
|---------------------|------------|------------------------------------------------------|
| `Cmd::Submit` | `Submit` | Just returns submit event FIXME: format |
| `GoTo(Begin)` | `OnChange` | Move cursor to the top of the current tree node |
| `GoTo(End)` | `OnChange` | Move cursor to the bottom of the current tree node |
| `Move(Down)` | `OnChange` | Go to next element |
| `Move(Up)` | `OnChange` | Go to previous element |
| `Scroll(Down)` | `OnChange` | Move cursor down by defined max steps or end of node |
| `Scroll(Up)` | `OnChange` | Move cursor up by defined max steps or begin of node |
| `Toggle` | `OnChange` | Opens/closes highlighted node |
| Cmd | Result | Behaviour |
|---------------------|------------------|------------------------------------------------------|
| `GoTo(Begin)` | `Changed | None` | Move cursor to the top of the current tree node |
| `GoTo(End)` | `Changed | None` | Move cursor to the bottom of the current tree node |
| `Move(Down)` | `Changed | None` | Go to next element |
| `Move(Up)` | `Changed | None` | Go to previous element |
| `Scroll(Down)` | `Changed | None` | Move cursor down by defined max steps or end of node |
| `Scroll(Up)` | `Changed | None` | Move cursor up by defined max steps or begin of node |
| `Submit` | `Submit` | Just returns submit result with current state |
| `Toggle` | `None` | Opens/closes highlighted node |

**State**: the state returned is a `One(String)` containing the id of the selected node. If no node is selected `None` is returned.

**Properties**:

- `Background(Color)`: background color. The background color will be used as background for unselected entry, but will be used as foreground for the selected entry when focus is true
- `Borders(Borders)`: set borders properties for component
- `Custom($TREE_DEPTH, Length)`: Sets the max tree depth
- `Custom($TREE_IDENT_SIZE, Size)`: Set space to render for each each depth level
- `Custom($TREE_INITIAL_NODE, String)`: Select initial node in the tree. This option has priority over `keep_state`
- `Custom($TREE_PRESERVE_STATE, Flag)`: If true, the selected entry will be kept after an update of the tree (obviously if the entry still exists in the tree).
- `FocusStyle(Style)`: inactive style
Expand All @@ -160,6 +160,7 @@ Best practices:
- `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

### Updating the tree
Expand Down
156 changes: 148 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,24 @@ mod widget;
use tree_state::TreeState;
use widget::TreeWidget;
// deps
use orange_trees::{Node as OrangeNode, Tree as OrangeTree};
pub use orange_trees::{Node as OrangeNode, Tree as OrangeTree};
use tuirealm::command::{Cmd, CmdResult, Direction, Position};
use tuirealm::props::{
Alignment, AttrValue, Attribute, Borders, Color, InputType, Props, Style, TextModifiers,
Alignment, AttrValue, Attribute, Borders, Color, Props, Style, TextModifiers,
};
use tuirealm::tui::layout::Rect;
use tuirealm::{Frame, MockComponent, State, StateValue};

// -- type override
pub(crate) type Node = OrangeNode<String, String>;
pub(crate) type Tree = OrangeTree<String, String>;
pub type Node = OrangeNode<String, String>;
pub type Tree = OrangeTree<String, String>;

// -- props

pub const TREE_INDENT_SIZE: &str = "indent-size";
pub const TREE_INITIAL_NODE: &str = "initial-mode";
pub const TREE_PRESERVE_STATE: &str = "preserve-state";

// -- component

/// ## TreeView
Expand All @@ -94,7 +98,7 @@ pub struct TreeView {
states: TreeState,
/// The actual Tree data structure. You can access this from your Component to operate on it
/// for example after a certain events.
pub tree: Tree,
tree: Tree,
}

impl Default for TreeView {
Expand Down Expand Up @@ -130,6 +134,11 @@ impl TreeView {
self
}

pub fn modifiers(mut self, m: TextModifiers) -> Self {
self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
self
}

pub fn title<S: AsRef<str>>(mut self, t: S, a: Alignment) -> Self {
self.attr(
Attribute::Title,
Expand All @@ -138,12 +147,143 @@ impl TreeView {
self
}

// TODO: custom properties
pub fn initial_node<S: AsRef<str>>(mut self, node: S) -> Self {
self.attr(
Attribute::Custom(TREE_INITIAL_NODE),
AttrValue::String(node.as_ref().to_string()),
);
self
}

pub fn preserve_state(mut self, preserve: bool) -> Self {
self.attr(
Attribute::Custom(TREE_PRESERVE_STATE),
AttrValue::Flag(preserve),
);
self
}

// TODO: indent_spaces
pub fn indent_size(mut self, sz: u16) -> Self {
self.attr(Attribute::Custom(TREE_INDENT_SIZE), AttrValue::Size(sz));
self
}

pub fn tree(mut self, tree: Tree) -> Self {
pub fn with_tree(mut self, tree: Tree) -> Self {
self.tree = tree;
self
}

// -- tree methods

/// ### tree
///
/// Get a reference to tree
pub fn tree(&self) -> &Tree {
&self.tree
}

/// ### tree_mut
///
/// Get mutable reference to tree
pub fn tree_mut(&mut self) -> &mut Tree {
&mut self.tree
}

/// ### set_tree
///
/// Set new tree in component
pub fn set_tree(&mut self, tree: Tree) {
self.tree = tree;
// TODO: update states, etc...
}

// -- private

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

/// ### changed
///
/// Returns whether selectd node has changed
fn changed(&self, prev: Option<&str>) -> CmdResult {
match self.states.selected() {
None => CmdResult::None,
id if id != prev => CmdResult::Changed(self.state()),
_ => CmdResult::None,
}
}
}

// -- mock

impl MockComponent for TreeView {
fn view(&mut self, frame: &mut Frame, area: Rect) {
todo!()
}

fn query(&self, attr: Attribute) -> Option<AttrValue> {
self.props.get(attr)
}

fn attr(&mut self, attr: Attribute, value: AttrValue) {
// Initial node
if matches!(attr, Attribute::Custom(TREE_INITIAL_NODE)) {
// Select node if exists
if let Some(node) = self.tree.root().query(&value.unwrap_string()) {
self.states.select(node);
}
} else {
self.props.set(attr, value);
}
}

fn state(&self) -> State {
match self.states.selected() {
None => State::None,
Some(id) => State::One(StateValue::String(id.to_string())),
}
}

fn perform(&mut self, cmd: Cmd) -> CmdResult {
match cmd {
Cmd::GoTo(Position::Begin) => {
let prev = self.states.selected().map(|x| x.to_string());
todo!();
self.changed(prev.as_deref())
}
Cmd::GoTo(Position::End) => {
let prev = self.states.selected().map(|x| x.to_string());
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.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.changed(prev.as_deref())
}
Cmd::Submit => CmdResult::Submit(self.state()),
Cmd::Toggle => {
// Open/close selected node
if let Some(selected) = self.states.selected() {
if let Some(node) = self.tree.root().query(&selected.to_string()) {
if self.states.is_closed(node) {
self.states.open_node(node);
} else {
self.states.close_node(node);
}
}
}
CmdResult::None
}
_ => CmdResult::None,
}
}
}
53 changes: 39 additions & 14 deletions src/tree_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,52 +54,84 @@ impl TreeState {
self.open.contains(node.id())
}

/// ### is_closed
///
/// Returns whether `node` is closed
pub fn is_closed(&self, node: &Node) -> bool {
!self.is_open(node)
}

/// ### selected
///
/// Get current selected item
pub fn selected(&self) -> Option<&str> {
self.selected.map(|x| x.as_str())
self.selected.as_ref().map(|x| x.as_str())
}

/// ### is_selected
///
/// Returns whether provided node is currently selected
pub fn is_selected(&self, node: &Node) -> bool {
self.selected.map(|x| &x == node.id()).unwrap_or(false)
self.selected
.as_ref()
.map(|x| x == node.id())
.unwrap_or(false)
}

/// ### tree_changed
///
/// The tree has changed, so this method must check whether to keep states or not
pub fn tree_changed(&mut self, root: &Node) {
todo!()
// Check whether selected is still valid
self.selected = match self.selected.take() {
None => None,
Some(selected) => {
if root.query(&selected).is_some() {
Some(selected)
} else {
None
}
}
};
// Check whether open nodes still exist
self.open.retain(|x| root.query(x).is_some());
}

/// ### open_node
///
/// Open `node`
/// Open `node`. Node can be open only if it is closed and it is NOT a leaf
pub fn open_node(&mut self, node: &Node) {
todo!()
if !node.is_leaf() && self.is_closed(node) {
self.open.push(node.id().to_string());
}
}

/// ### close_node
///
/// Close `node`
pub fn close_node(&mut self, node: &Node) {
todo!()
if self.is_open(node) {
// Remove from open nodes
self.open.retain(|x| x != node.id());
// Remove children for node
self.close_children(node);
}
}

/// ### 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!()
}

/// ### move_up
///
/// Move cursor up in current tree from current position. Rewind if required
pub fn move_up(&mut self, root: &Node, rewind: bool) {
// TODO: move to sibling before
todo!()
}

Expand All @@ -112,17 +144,10 @@ impl TreeState {

// -- private

/// ### open_children
///
/// Open all node children recursively
fn open_children(&mut self, node: &Node) {
todo!()
}

/// ### close_children
///
/// Close all node children recursively
fn close_children(&mut self, node: &Node) {
todo!()
node.iter().for_each(|x| self.close_node(x));
}
}
Loading

0 comments on commit 0c31966

Please sign in to comment.