use crate::prelude::*;
use crate::ui::canvas::{Canvas, CanvasArc};
use crate::ui::widget::Widgetable;
use crate::ui::widget::command_line::CommandLine;
use crate::ui::widget::root::RootContainer;
use crate::ui::widget::window::Window;
use crate::ui::widget::window::opt::{
WindowGlobalOptions, WindowGlobalOptionsBuilder, WindowOptions,
WindowOptionsBuilder,
};
use crate::{inode_enum_dispatcher, widget_enum_dispatcher};
pub use internal::*;
pub mod internal;
#[derive(Debug, Clone)]
pub enum TreeNode {
RootContainer(RootContainer),
Window(Window),
CommandLine(CommandLine),
}
inode_enum_dispatcher!(TreeNode, RootContainer, Window, CommandLine);
widget_enum_dispatcher!(TreeNode, RootContainer, Window, CommandLine);
#[derive(Debug, Clone)]
pub struct Tree {
base: Itree<TreeNode>,
command_line_id: Option<TreeNodeId>,
window_ids: BTreeSet<TreeNodeId>,
current_window_id: Option<TreeNodeId>,
global_options: WindowGlobalOptions,
global_local_options: WindowOptions,
}
arc_mutex_ptr!(Tree);
impl Tree {
pub fn new(canvas_size: U16Size) -> Self {
let shape = IRect::new(
(0, 0),
(canvas_size.width() as isize, canvas_size.height() as isize),
);
let root_container = RootContainer::new(shape);
let root_node = TreeNode::RootContainer(root_container);
Tree {
base: Itree::new(root_node),
command_line_id: None,
window_ids: BTreeSet::new(),
current_window_id: None,
global_options: WindowGlobalOptionsBuilder::default().build().unwrap(),
global_local_options: WindowOptionsBuilder::default().build().unwrap(),
}
}
pub fn len(&self) -> usize {
self.base.len()
}
pub fn is_empty(&self) -> bool {
self.base.is_empty()
}
pub fn root_id(&self) -> TreeNodeId {
self.base.root_id()
}
pub fn node_ids(&self) -> Vec<TreeNodeId> {
self.base.node_ids()
}
pub fn parent_id(&self, id: TreeNodeId) -> Option<TreeNodeId> {
self.base.parent_id(id)
}
pub fn children_ids(&self, id: TreeNodeId) -> Vec<TreeNodeId> {
self.base.children_ids(id)
}
pub fn node(&self, id: TreeNodeId) -> Option<&TreeNode> {
self.base.node(id)
}
pub fn node_mut(&mut self, id: TreeNodeId) -> Option<&mut TreeNode> {
self.base.node_mut(id)
}
pub fn command_line_id(&self) -> Option<TreeNodeId> {
self.command_line_id
}
pub fn current_window_id(&self) -> Option<TreeNodeId> {
self.current_window_id
}
pub fn set_current_window_id(
&mut self,
window_id: Option<TreeNodeId>,
) -> Option<TreeNodeId> {
if cfg!(debug_assertions) {
match window_id {
Some(window_id) => {
debug_assert!(self.node_mut(window_id).is_some());
debug_assert!(matches!(
self.node_mut(window_id).unwrap(),
TreeNode::Window(_)
));
}
None => { }
}
}
let old = self.current_window_id;
self.current_window_id = window_id;
old
}
pub fn window_ids(&self) -> &BTreeSet<TreeNodeId> {
&self.window_ids
}
}
impl Tree {
pub fn window(&self, window_id: TreeNodeId) -> Option<&Window> {
match self.node(window_id) {
Some(window_node) => {
debug_assert!(matches!(window_node, TreeNode::Window(_)));
match window_node {
TreeNode::Window(w) => {
debug_assert_eq!(w.id(), window_id);
Some(w)
}
_ => unreachable!(), }
}
None => None,
}
}
pub fn window_mut(&mut self, window_id: TreeNodeId) -> Option<&mut Window> {
match self.node_mut(window_id) {
Some(window_node) => {
debug_assert!(matches!(window_node, TreeNode::Window(_)));
match window_node {
TreeNode::Window(w) => {
debug_assert_eq!(w.id(), window_id);
Some(w)
}
_ => unreachable!(), }
}
None => None,
}
}
pub fn current_window(&self) -> Option<&Window> {
match self.current_window_id {
Some(current_window_id) => self.window(current_window_id),
None => None,
}
}
pub fn current_window_mut(&mut self) -> Option<&mut Window> {
match self.current_window_id {
Some(current_window_id) => self.window_mut(current_window_id),
None => None,
}
}
pub fn command_line(&self) -> Option<&CommandLine> {
match self.command_line_id {
Some(cmdline_id) => {
debug_assert!(self.node(cmdline_id).is_some());
let cmdline_node = self.node(cmdline_id).unwrap();
debug_assert!(matches!(cmdline_node, TreeNode::CommandLine(_)));
match cmdline_node {
TreeNode::CommandLine(w) => {
debug_assert_eq!(w.id(), cmdline_id);
Some(w)
}
_ => unreachable!(),
}
}
None => None,
}
}
pub fn command_line_mut(&mut self) -> Option<&mut CommandLine> {
match self.command_line_id {
Some(cmdline_id) => {
debug_assert!(self.node_mut(cmdline_id).is_some());
let cmdline_node = self.node_mut(cmdline_id).unwrap();
debug_assert!(matches!(cmdline_node, TreeNode::CommandLine(_)));
match cmdline_node {
TreeNode::CommandLine(w) => {
debug_assert_eq!(w.id(), cmdline_id);
Some(w)
}
_ => unreachable!(),
}
}
None => None,
}
}
}
impl Tree {
fn insert_guard(&mut self, node: &TreeNode) {
match node {
TreeNode::CommandLine(command_line) => {
self.command_line_id = Some(command_line.id());
}
TreeNode::Window(window) => {
self.window_ids.insert(window.id());
}
_ => { }
}
}
pub fn insert(
&mut self,
parent_id: TreeNodeId,
child_node: TreeNode,
) -> Option<TreeNode> {
self.insert_guard(&child_node);
self.base.insert(parent_id, child_node)
}
pub fn bounded_insert(
&mut self,
parent_id: TreeNodeId,
child_node: TreeNode,
) -> Option<TreeNode> {
self.insert_guard(&child_node);
self.base.bounded_insert(parent_id, child_node)
}
fn remove_guard(&mut self, id: TreeNodeId) {
if self.command_line_id == Some(id) {
self.command_line_id = None;
}
self.window_ids.remove(&id);
if self.current_window_id == Some(id) {
if let Some(last_window_id) = self.window_ids.last() {
self.current_window_id = Some(*last_window_id);
}
}
}
pub fn remove(&mut self, id: TreeNodeId) -> Option<TreeNode> {
self.remove_guard(id);
self.base.remove(id)
}
}
impl Tree {
pub fn bounded_move_by(
&mut self,
id: TreeNodeId,
x: isize,
y: isize,
) -> Option<IRect> {
self.base.bounded_move_by(id, x, y)
}
pub fn bounded_move_to(
&mut self,
id: TreeNodeId,
x: isize,
y: isize,
) -> Option<IRect> {
self.base.bounded_move_to(id, x, y)
}
}
impl Tree {
pub fn global_options(&self) -> &WindowGlobalOptions {
&self.global_options
}
pub fn global_options_mut(&mut self) -> &mut WindowGlobalOptions {
&mut self.global_options
}
pub fn set_global_options(&mut self, options: &WindowGlobalOptions) {
self.global_options = *options;
}
pub fn global_local_options(&self) -> &WindowOptions {
&self.global_local_options
}
pub fn global_local_options_mut(&mut self) -> &mut WindowOptions {
&mut self.global_local_options
}
pub fn set_global_local_options(&mut self, options: &WindowOptions) {
self.global_local_options = *options;
}
}
impl Tree {
pub fn draw(&self, canvas: CanvasArc) {
let mut canvas = lock!(canvas);
for node in self.base.iter() {
if !node.visible() {
continue;
}
node.draw(&mut canvas);
}
}
}