-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathexpand.rs
More file actions
117 lines (95 loc) · 3.47 KB
/
expand.rs
File metadata and controls
117 lines (95 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::ops::ControlFlow;
use anathema_geometry::Size;
use anathema_widgets::LayoutForEach;
use anathema_widgets::error::Result;
use anathema_widgets::layout::{Constraints, LayoutCtx};
use super::Axis;
const DEFAULT_FACTOR: u16 = 1;
/// Distributes the total size over a list of weights
///
/// It uses the [Huntington-Hill method](https://en.wikipedia.org/wiki/Huntington%E2%80%93Hill_method)
///
/// Panics when called with more weights than the total number of available size.
/// Allocates a minimum of one to each weight.
fn distribute_size(weights: &[u16], mut total: u16) -> Vec<u16> {
let mut indexed = weights
.iter()
.copied()
.enumerate()
.map(|(i, w)| (i, w, 0u16))
.collect::<Vec<_>>();
fn pop(n: &mut u16) -> bool {
if let Some(nn) = n.checked_sub(1) {
*n = nn;
true
} else {
false
}
}
while pop(&mut total) {
indexed.sort_by_cached_key(|&(_, w, r)| (((w as f64) / ((r * (r + 1)) as f64).sqrt()) * -10000.) as isize);
indexed[0].2 += 1;
}
indexed.sort_by_key(|&(i, ..)| i);
indexed.into_iter().map(|(_, _, r)| r).collect()
}
pub fn layout_all_expansions<'bp>(
nodes: &mut LayoutForEach<'_, 'bp>,
constraints: Constraints,
axis: Axis,
ctx: &mut LayoutCtx<'_, 'bp>,
) -> Result<Size> {
let mut factors = vec![];
_ = nodes.each(ctx, |ctx, node, _children| {
if node.ident == "expand" {
let attributes = ctx.attribute_storage.get(node.id());
let factor = attributes.get_as::<u16>("factor").unwrap_or(DEFAULT_FACTOR);
factors.push(factor);
}
Ok(ControlFlow::Continue(()))
})?;
let mut size = Size::ZERO;
if factors.is_empty() {
return Ok(size);
}
// Distribute the available space
let sizes = match axis {
Axis::Horizontal => distribute_size(&factors, constraints.max_width()),
Axis::Vertical => distribute_size(&factors, constraints.max_height()),
};
let mut index = 0;
_ = nodes.each(ctx, |ctx, node, children| {
if node.ident != "expand" {
return Ok(ControlFlow::Continue(()));
}
let sub_size = sizes[index];
index += 1;
let constraints = match axis {
Axis::Horizontal => {
let mut constraints = Constraints::new(sub_size, constraints.max_height());
// Ensure that the rounding doesn't push the constraint outside of the max width
constraints.min_width = constraints.min_width.min(constraints.max_width());
constraints
}
Axis::Vertical => {
let mut constraints = Constraints::new(constraints.max_width(), sub_size);
// Ensure that the rounding doesn't push the constraint outside of the max height
constraints.min_height = constraints.min_height.min(constraints.max_height());
constraints
}
};
let widget_size = Size::from(node.layout(children, constraints, ctx)?);
match axis {
Axis::Horizontal => {
size.width += widget_size.width;
size.height = size.height.max(widget_size.height);
}
Axis::Vertical => {
size.width = size.width.max(widget_size.width);
size.height += widget_size.height;
}
}
Ok(ControlFlow::Continue(()))
})?;
Ok(size)
}