Enforce minimum pane size by counting splits in each axis
This commit is contained in:
parent
2a43921c56
commit
1445e068e0
2 changed files with 141 additions and 31 deletions
|
|
@ -17,17 +17,18 @@ impl Axis {
|
|||
rectangle: &Rectangle,
|
||||
ratio: f32,
|
||||
spacing: f32,
|
||||
min_size: f32,
|
||||
min_size_a: f32,
|
||||
min_size_b: f32,
|
||||
) -> (Rectangle, Rectangle, f32) {
|
||||
match self {
|
||||
Axis::Horizontal => {
|
||||
let height_top = (rectangle.height * ratio - spacing / 2.0)
|
||||
.round()
|
||||
.max(min_size)
|
||||
.min(rectangle.height - min_size);
|
||||
.max(min_size_a)
|
||||
.min(rectangle.height - min_size_b - spacing);
|
||||
|
||||
let height_bottom =
|
||||
(rectangle.height - height_top - spacing).max(min_size);
|
||||
(rectangle.height - height_top - spacing).max(min_size_b);
|
||||
|
||||
let ratio = (height_top + spacing / 2.0) / rectangle.height;
|
||||
|
||||
|
|
@ -47,11 +48,11 @@ impl Axis {
|
|||
Axis::Vertical => {
|
||||
let width_left = (rectangle.width * ratio - spacing / 2.0)
|
||||
.round()
|
||||
.max(min_size)
|
||||
.min(rectangle.width - min_size);
|
||||
.max(min_size_a)
|
||||
.min(rectangle.width - min_size_b - spacing);
|
||||
|
||||
let width_right =
|
||||
(rectangle.width - width_left - spacing).max(min_size);
|
||||
(rectangle.width - width_left - spacing).max(min_size_b);
|
||||
|
||||
let ratio = (width_left + spacing / 2.0) / rectangle.width;
|
||||
|
||||
|
|
@ -202,7 +203,8 @@ mod tests {
|
|||
width: 10.0,
|
||||
height: overall_height,
|
||||
};
|
||||
let (top, bottom, _ratio) = a.split(&r, 0.5, spacing, 0.0);
|
||||
let (top, bottom, _ratio) =
|
||||
a.split(&r, 0.5, spacing, 0.0, 0.0);
|
||||
assert_eq!(
|
||||
top,
|
||||
Rectangle {
|
||||
|
|
@ -233,7 +235,8 @@ mod tests {
|
|||
width: overall_width,
|
||||
height: 10.0,
|
||||
};
|
||||
let (left, right, _ratio) = a.split(&r, 0.5, spacing, 0.0);
|
||||
let (left, right, _ratio) =
|
||||
a.split(&r, 0.5, spacing, 0.0, 0.0);
|
||||
assert_eq!(
|
||||
left,
|
||||
Rectangle {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,33 @@ pub enum Node {
|
|||
Pane(Pane),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Count {
|
||||
Split {
|
||||
horizontal: usize,
|
||||
vertical: usize,
|
||||
a: Box<Count>,
|
||||
b: Box<Count>,
|
||||
},
|
||||
Pane,
|
||||
}
|
||||
|
||||
impl Count {
|
||||
fn horizontal(&self) -> usize {
|
||||
match self {
|
||||
Count::Split { horizontal, .. } => *horizontal,
|
||||
Count::Pane => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn vertical(&self) -> usize {
|
||||
match self {
|
||||
Count::Split { vertical, .. } => *vertical,
|
||||
Count::Pane => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node {
|
||||
/// Returns an iterator over each [`Split`] in this [`Node`].
|
||||
pub fn splits(&self) -> impl Iterator<Item = &Split> {
|
||||
|
|
@ -48,6 +75,28 @@ impl Node {
|
|||
})
|
||||
}
|
||||
|
||||
fn count(&self) -> Count {
|
||||
match self {
|
||||
Node::Split { a, b, axis, .. } => {
|
||||
let a = a.count();
|
||||
let b = b.count();
|
||||
|
||||
let (horizontal, vertical) = match axis {
|
||||
Axis::Horizontal => (1, 0),
|
||||
Axis::Vertical => (0, 1),
|
||||
};
|
||||
|
||||
Count::Split {
|
||||
horizontal: a.horizontal() + b.horizontal() + horizontal,
|
||||
vertical: a.vertical() + b.vertical() + vertical,
|
||||
a: Box::new(a),
|
||||
b: Box::new(b),
|
||||
}
|
||||
}
|
||||
Node::Pane(_) => Count::Pane,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the rectangular region for each [`Pane`] in the [`Node`] given
|
||||
/// the spacing between panes and the total available space.
|
||||
pub fn pane_regions(
|
||||
|
|
@ -57,6 +106,7 @@ impl Node {
|
|||
bounds: Size,
|
||||
) -> BTreeMap<Pane, Rectangle> {
|
||||
let mut regions = BTreeMap::new();
|
||||
let count = self.count();
|
||||
|
||||
self.compute_regions(
|
||||
spacing,
|
||||
|
|
@ -67,6 +117,7 @@ impl Node {
|
|||
width: bounds.width,
|
||||
height: bounds.height,
|
||||
},
|
||||
&count,
|
||||
&mut regions,
|
||||
);
|
||||
|
||||
|
|
@ -83,6 +134,7 @@ impl Node {
|
|||
bounds: Size,
|
||||
) -> BTreeMap<Split, (Axis, Rectangle, f32)> {
|
||||
let mut splits = BTreeMap::new();
|
||||
let count = self.count();
|
||||
|
||||
self.compute_splits(
|
||||
spacing,
|
||||
|
|
@ -93,6 +145,7 @@ impl Node {
|
|||
width: bounds.width,
|
||||
height: bounds.height,
|
||||
},
|
||||
&count,
|
||||
&mut splits,
|
||||
);
|
||||
|
||||
|
|
@ -198,21 +251,50 @@ impl Node {
|
|||
spacing: f32,
|
||||
min_size: f32,
|
||||
current: &Rectangle,
|
||||
count: &Count,
|
||||
regions: &mut BTreeMap<Pane, Rectangle>,
|
||||
) {
|
||||
match self {
|
||||
Node::Split {
|
||||
axis, ratio, a, b, ..
|
||||
} => {
|
||||
let (region_a, region_b, _ratio) =
|
||||
axis.split(current, *ratio, spacing, min_size);
|
||||
match (self, count) {
|
||||
(
|
||||
Node::Split {
|
||||
axis, ratio, a, b, ..
|
||||
},
|
||||
Count::Split {
|
||||
a: count_a,
|
||||
b: count_b,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
let (a_factor, b_factor) = match axis {
|
||||
Axis::Horizontal => {
|
||||
(count_a.horizontal(), count_b.horizontal())
|
||||
}
|
||||
Axis::Vertical => (count_a.vertical(), count_b.vertical()),
|
||||
};
|
||||
|
||||
a.compute_regions(spacing, min_size, ®ion_a, regions);
|
||||
b.compute_regions(spacing, min_size, ®ion_b, regions);
|
||||
let (region_a, region_b, _ratio) = axis.split(
|
||||
current,
|
||||
*ratio,
|
||||
spacing,
|
||||
min_size * (a_factor + 1) as f32
|
||||
+ spacing * a_factor as f32,
|
||||
min_size * (b_factor + 1) as f32
|
||||
+ spacing * b_factor as f32,
|
||||
);
|
||||
|
||||
a.compute_regions(
|
||||
spacing, min_size, ®ion_a, count_a, regions,
|
||||
);
|
||||
b.compute_regions(
|
||||
spacing, min_size, ®ion_b, count_b, regions,
|
||||
);
|
||||
}
|
||||
Node::Pane(pane) => {
|
||||
(Node::Pane(pane), Count::Pane) => {
|
||||
let _ = regions.insert(*pane, *current);
|
||||
}
|
||||
_ => {
|
||||
unreachable!("Node configuration and count do not match")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,25 +303,50 @@ impl Node {
|
|||
spacing: f32,
|
||||
min_size: f32,
|
||||
current: &Rectangle,
|
||||
count: &Count,
|
||||
splits: &mut BTreeMap<Split, (Axis, Rectangle, f32)>,
|
||||
) {
|
||||
match self {
|
||||
Node::Split {
|
||||
axis,
|
||||
ratio,
|
||||
a,
|
||||
b,
|
||||
id,
|
||||
} => {
|
||||
let (region_a, region_b, ratio) =
|
||||
axis.split(current, *ratio, spacing, min_size);
|
||||
match (self, count) {
|
||||
(
|
||||
Node::Split {
|
||||
axis,
|
||||
ratio,
|
||||
a,
|
||||
b,
|
||||
id,
|
||||
},
|
||||
Count::Split {
|
||||
a: count_a,
|
||||
b: count_b,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
let (a_factor, b_factor) = match axis {
|
||||
Axis::Horizontal => {
|
||||
(count_a.horizontal(), count_b.horizontal())
|
||||
}
|
||||
Axis::Vertical => (count_a.vertical(), count_b.vertical()),
|
||||
};
|
||||
|
||||
let (region_a, region_b, ratio) = axis.split(
|
||||
current,
|
||||
*ratio,
|
||||
spacing,
|
||||
min_size * (a_factor + 1) as f32
|
||||
+ spacing * a_factor as f32,
|
||||
min_size * (b_factor + 1) as f32
|
||||
+ spacing * b_factor as f32,
|
||||
);
|
||||
|
||||
let _ = splits.insert(*id, (*axis, *current, ratio));
|
||||
|
||||
a.compute_splits(spacing, min_size, ®ion_a, splits);
|
||||
b.compute_splits(spacing, min_size, ®ion_b, splits);
|
||||
a.compute_splits(spacing, min_size, ®ion_a, count_a, splits);
|
||||
b.compute_splits(spacing, min_size, ®ion_b, count_b, splits);
|
||||
}
|
||||
(Node::Pane(_), Count::Pane) => {}
|
||||
_ => {
|
||||
unreachable!("Node configuration and split count do not match")
|
||||
}
|
||||
Node::Pane(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue