|
|
@ -29,6 +29,16 @@ pub enum Content {
|
|
|
|
Container(Box<Container>),
|
|
|
|
Container(Box<Container>),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub enum Resize {
|
|
|
|
|
|
|
|
Shrink,
|
|
|
|
|
|
|
|
Grow,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub enum Dimension {
|
|
|
|
|
|
|
|
Width,
|
|
|
|
|
|
|
|
Height,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Node {
|
|
|
|
impl Node {
|
|
|
|
pub fn container(layout: Layout) -> Self {
|
|
|
|
pub fn container(layout: Layout) -> Self {
|
|
|
|
Self {
|
|
|
|
Self {
|
|
|
@ -65,6 +75,14 @@ pub struct Container {
|
|
|
|
layout: Layout,
|
|
|
|
layout: Layout,
|
|
|
|
children: Vec<ViewId>,
|
|
|
|
children: Vec<ViewId>,
|
|
|
|
area: Rect,
|
|
|
|
area: Rect,
|
|
|
|
|
|
|
|
node_bounds: Vec<ContainerBounds>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
|
|
|
pub struct ContainerBounds {
|
|
|
|
|
|
|
|
width: usize,
|
|
|
|
|
|
|
|
height: usize,
|
|
|
|
|
|
|
|
expand: bool,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Container {
|
|
|
|
impl Container {
|
|
|
@ -73,8 +91,80 @@ impl Container {
|
|
|
|
layout,
|
|
|
|
layout,
|
|
|
|
children: Vec::new(),
|
|
|
|
children: Vec::new(),
|
|
|
|
area: Rect::default(),
|
|
|
|
area: Rect::default(),
|
|
|
|
|
|
|
|
node_bounds: Vec::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_child_by_view_id(&mut self, node: ViewId) -> Option<&mut ContainerBounds> {
|
|
|
|
|
|
|
|
self.children
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.position(|child| child == &node)
|
|
|
|
|
|
|
|
.and_then(|index| self.node_bounds.get_mut(index))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn push_child(&mut self, node: ViewId) -> &mut Self {
|
|
|
|
|
|
|
|
self.children.push(node);
|
|
|
|
|
|
|
|
self.add_child_bounds();
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn insert_child(&mut self, index: usize, node: ViewId) -> &mut Self {
|
|
|
|
|
|
|
|
self.children.insert(index, node);
|
|
|
|
|
|
|
|
self.insert_child_bounds(index);
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn remove_child(&mut self, index: usize) -> &mut Self {
|
|
|
|
|
|
|
|
self.children.remove(index);
|
|
|
|
|
|
|
|
self.remove_child_bounds(index);
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn add_child_bounds(&mut self) -> &mut Self {
|
|
|
|
|
|
|
|
self.node_bounds.push(ContainerBounds {
|
|
|
|
|
|
|
|
width: 10,
|
|
|
|
|
|
|
|
height: 10,
|
|
|
|
|
|
|
|
expand: false,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn insert_child_bounds(&mut self, index: usize) -> &mut Self {
|
|
|
|
|
|
|
|
self.node_bounds.insert(
|
|
|
|
|
|
|
|
index,
|
|
|
|
|
|
|
|
ContainerBounds {
|
|
|
|
|
|
|
|
width: 10,
|
|
|
|
|
|
|
|
height: 10,
|
|
|
|
|
|
|
|
expand: false,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn remove_child_bounds(&mut self, index: usize) -> &mut Self {
|
|
|
|
|
|
|
|
self.node_bounds.remove(index);
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn calculate_slots_width(&self) -> usize {
|
|
|
|
|
|
|
|
self.node_bounds
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.map(|bounds| match bounds.expand {
|
|
|
|
|
|
|
|
true => 40,
|
|
|
|
|
|
|
|
false => bounds.width,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.sum()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn calculate_slots_height(&self) -> usize {
|
|
|
|
|
|
|
|
self.node_bounds
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.map(|bounds| match bounds.expand {
|
|
|
|
|
|
|
|
true => 40,
|
|
|
|
|
|
|
|
false => bounds.height,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.sum()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Default for Container {
|
|
|
|
impl Default for Container {
|
|
|
@ -131,7 +221,7 @@ impl Tree {
|
|
|
|
pos + 1
|
|
|
|
pos + 1
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
container.children.insert(pos, node);
|
|
|
|
container.insert_child(pos, node);
|
|
|
|
// focus the new node
|
|
|
|
// focus the new node
|
|
|
|
self.focus = node;
|
|
|
|
self.focus = node;
|
|
|
|
|
|
|
|
|
|
|
@ -168,7 +258,7 @@ impl Tree {
|
|
|
|
.unwrap();
|
|
|
|
.unwrap();
|
|
|
|
pos + 1
|
|
|
|
pos + 1
|
|
|
|
};
|
|
|
|
};
|
|
|
|
container.children.insert(pos, node);
|
|
|
|
container.insert_child(pos, node);
|
|
|
|
self.nodes[node].parent = parent;
|
|
|
|
self.nodes[node].parent = parent;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
let mut split = Node::container(layout);
|
|
|
|
let mut split = Node::container(layout);
|
|
|
@ -182,8 +272,8 @@ impl Tree {
|
|
|
|
} => container,
|
|
|
|
} => container,
|
|
|
|
_ => unreachable!(),
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
container.children.push(focus);
|
|
|
|
container.push_child(focus);
|
|
|
|
container.children.push(node);
|
|
|
|
container.push_child(node);
|
|
|
|
self.nodes[focus].parent = split;
|
|
|
|
self.nodes[focus].parent = split;
|
|
|
|
self.nodes[node].parent = split;
|
|
|
|
self.nodes[node].parent = split;
|
|
|
|
|
|
|
|
|
|
|
@ -232,7 +322,7 @@ impl Tree {
|
|
|
|
} = &mut self.nodes[parent_id]
|
|
|
|
} = &mut self.nodes[parent_id]
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if let Some(pos) = container.children.iter().position(|&child| child == index) {
|
|
|
|
if let Some(pos) = container.children.iter().position(|&child| child == index) {
|
|
|
|
container.children.remove(pos);
|
|
|
|
container.remove_child(pos);
|
|
|
|
// TODO: if container now only has one child, remove it and place child in parent
|
|
|
|
// TODO: if container now only has one child, remove it and place child in parent
|
|
|
|
if container.children.is_empty() && parent_id != self.root {
|
|
|
|
if container.children.is_empty() && parent_id != self.root {
|
|
|
|
// if container now empty, remove it
|
|
|
|
// if container now empty, remove it
|
|
|
@ -359,12 +449,17 @@ impl Tree {
|
|
|
|
match container.layout {
|
|
|
|
match container.layout {
|
|
|
|
Layout::Horizontal => {
|
|
|
|
Layout::Horizontal => {
|
|
|
|
let len = container.children.len();
|
|
|
|
let len = container.children.len();
|
|
|
|
|
|
|
|
let slots = container.calculate_slots_height();
|
|
|
|
let height = area.height / len as u16;
|
|
|
|
let slot_height = area.height as f32 / slots as f32;
|
|
|
|
|
|
|
|
|
|
|
|
let mut child_y = area.y;
|
|
|
|
let mut child_y = area.y;
|
|
|
|
|
|
|
|
|
|
|
|
for (i, child) in container.children.iter().enumerate() {
|
|
|
|
for (i, child) in container.children.iter().enumerate() {
|
|
|
|
|
|
|
|
let bounds = container.node_bounds[i];
|
|
|
|
|
|
|
|
let height = match bounds.expand {
|
|
|
|
|
|
|
|
true => (40.0 * slot_height) as u16,
|
|
|
|
|
|
|
|
false => (slot_height * bounds.height as f32).floor() as u16,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let mut area = Rect::new(
|
|
|
|
let mut area = Rect::new(
|
|
|
|
container.area.x,
|
|
|
|
container.area.x,
|
|
|
|
child_y,
|
|
|
|
child_y,
|
|
|
@ -373,7 +468,7 @@ impl Tree {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
child_y += height;
|
|
|
|
child_y += height;
|
|
|
|
|
|
|
|
|
|
|
|
// last child takes the remaining width because we can get uneven
|
|
|
|
// last child takes the remaining height because we can get uneven
|
|
|
|
// space from rounding
|
|
|
|
// space from rounding
|
|
|
|
if i == len - 1 {
|
|
|
|
if i == len - 1 {
|
|
|
|
area.height = container.area.y + container.area.height - area.y;
|
|
|
|
area.height = container.area.y + container.area.height - area.y;
|
|
|
@ -384,15 +479,20 @@ impl Tree {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Layout::Vertical => {
|
|
|
|
Layout::Vertical => {
|
|
|
|
let len = container.children.len();
|
|
|
|
let len = container.children.len();
|
|
|
|
|
|
|
|
let slots = container.calculate_slots_width();
|
|
|
|
let width = area.width / len as u16;
|
|
|
|
let slot_width: f32 = area.width as f32 / slots as f32;
|
|
|
|
|
|
|
|
let mut child_x = area.x;
|
|
|
|
|
|
|
|
|
|
|
|
let inner_gap = 1u16;
|
|
|
|
let inner_gap = 1u16;
|
|
|
|
// let total_gap = inner_gap * (len as u16 - 1);
|
|
|
|
// let total_gap = inner_gap * (len as u16 - 1);
|
|
|
|
|
|
|
|
|
|
|
|
let mut child_x = area.x;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i, child) in container.children.iter().enumerate() {
|
|
|
|
for (i, child) in container.children.iter().enumerate() {
|
|
|
|
|
|
|
|
let bounds = container.node_bounds[i];
|
|
|
|
|
|
|
|
let width = match bounds.expand {
|
|
|
|
|
|
|
|
true => (40.0 * slot_width) as u16,
|
|
|
|
|
|
|
|
false => (slot_width * bounds.width as f32).floor() as u16,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let mut area = Rect::new(
|
|
|
|
let mut area = Rect::new(
|
|
|
|
child_x,
|
|
|
|
child_x,
|
|
|
|
container.area.y,
|
|
|
|
container.area.y,
|
|
|
@ -571,6 +671,83 @@ impl Tree {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_active_node_bounds_mut(
|
|
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
|
|
expect_layout: Layout,
|
|
|
|
|
|
|
|
) -> Option<&mut ContainerBounds> {
|
|
|
|
|
|
|
|
let mut focus = self.focus;
|
|
|
|
|
|
|
|
let mut parent = self.nodes[focus].parent;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Parent expected to be container
|
|
|
|
|
|
|
|
if let Some(focused_layout) = match &self.nodes[parent].content {
|
|
|
|
|
|
|
|
Content::View(_) => unreachable!(),
|
|
|
|
|
|
|
|
Content::Container(node) => Some(node.layout),
|
|
|
|
|
|
|
|
} {
|
|
|
|
|
|
|
|
// if we want to make a width change and we have a `Horizontal` layout focused,
|
|
|
|
|
|
|
|
// alter the parent `Vertical` layout instead and vice versa
|
|
|
|
|
|
|
|
if focused_layout != expect_layout {
|
|
|
|
|
|
|
|
focus = parent;
|
|
|
|
|
|
|
|
parent = self.nodes[parent].parent;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Content::Container(node) = &mut self.nodes[parent].content {
|
|
|
|
|
|
|
|
return node.as_mut().get_child_by_view_id(focus);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn resize_buffer(&mut self, resize_type: Resize, dimension: Dimension) {
|
|
|
|
|
|
|
|
match dimension {
|
|
|
|
|
|
|
|
Dimension::Width => {
|
|
|
|
|
|
|
|
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Vertical) {
|
|
|
|
|
|
|
|
match resize_type {
|
|
|
|
|
|
|
|
Resize::Shrink => {
|
|
|
|
|
|
|
|
if bounds.width > 1 {
|
|
|
|
|
|
|
|
bounds.width -= 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Resize::Grow => {
|
|
|
|
|
|
|
|
if bounds.width < 20 {
|
|
|
|
|
|
|
|
bounds.width += 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
self.recalculate();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Dimension::Height => {
|
|
|
|
|
|
|
|
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Horizontal) {
|
|
|
|
|
|
|
|
match resize_type {
|
|
|
|
|
|
|
|
Resize::Shrink => {
|
|
|
|
|
|
|
|
if bounds.height > 1 {
|
|
|
|
|
|
|
|
bounds.height -= 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Resize::Grow => {
|
|
|
|
|
|
|
|
if bounds.height < 20 {
|
|
|
|
|
|
|
|
bounds.height += 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
self.recalculate();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn toggle_focus_window(&mut self) {
|
|
|
|
|
|
|
|
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Horizontal) {
|
|
|
|
|
|
|
|
bounds.expand = !bounds.expand;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Vertical) {
|
|
|
|
|
|
|
|
bounds.expand = !bounds.expand;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.recalculate();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn swap_split_in_direction(&mut self, direction: Direction) -> Option<()> {
|
|
|
|
pub fn swap_split_in_direction(&mut self, direction: Direction) -> Option<()> {
|
|
|
|
let focus = self.focus;
|
|
|
|
let focus = self.focus;
|
|
|
|
let target = self.find_split_in_direction(focus, direction)?;
|
|
|
|
let target = self.find_split_in_direction(focus, direction)?;
|
|
|
|