widgetry/geom/
geom_batch_stack.rs
1use crate::GeomBatch;
2
3#[derive(Clone, Copy, Debug, PartialEq)]
4pub enum Axis {
5 Horizontal,
6 Vertical,
7}
8
9#[derive(Clone, Copy, Debug, PartialEq)]
10pub enum Alignment {
11 Center,
12 Top,
13 Left,
14 }
16
17#[derive(Debug, Clone)]
23pub struct GeomBatchStack {
24 batches: Vec<GeomBatch>,
25 axis: Axis,
26 alignment: Alignment,
27 spacing: f64,
28}
29
30impl Default for GeomBatchStack {
31 fn default() -> Self {
32 GeomBatchStack {
33 batches: vec![],
34 axis: Axis::Horizontal,
35 alignment: Alignment::Center,
36 spacing: 0.0,
37 }
38 }
39}
40
41impl GeomBatchStack {
42 pub fn horizontal(batches: Vec<GeomBatch>) -> Self {
43 Self::from_axis(batches, Axis::Horizontal)
44 }
45
46 pub fn vertical(batches: Vec<GeomBatch>) -> Self {
47 Self::from_axis(batches, Axis::Vertical)
48 }
49
50 pub fn from_axis(batches: Vec<GeomBatch>, axis: Axis) -> Self {
51 GeomBatchStack {
52 batches,
53 axis,
54 ..Default::default()
55 }
56 }
57
58 pub fn get(&self, index: usize) -> Option<&GeomBatch> {
59 self.batches.get(index)
60 }
61
62 pub fn get_mut(&mut self, index: usize) -> Option<&mut GeomBatch> {
63 self.batches.get_mut(index)
64 }
65
66 pub fn push(&mut self, geom_batch: GeomBatch) {
67 self.batches.push(geom_batch);
68 }
69
70 pub fn append(&mut self, geom_batches: &mut Vec<GeomBatch>) {
71 self.batches.append(geom_batches);
72 }
73
74 pub fn set_axis(&mut self, new_value: Axis) {
75 self.axis = new_value;
76 }
77
78 pub fn set_alignment(&mut self, new_value: Alignment) {
79 self.alignment = new_value;
80 }
81
82 pub fn set_spacing(&mut self, spacing: impl Into<f64>) -> &mut Self {
83 self.spacing = spacing.into();
84 self
85 }
86
87 pub fn batch(self) -> GeomBatch {
88 if self.batches.is_empty() {
89 return GeomBatch::new();
90 }
91
92 let max_bound_for_axis = self
93 .batches
94 .iter()
95 .map(GeomBatch::get_bounds)
96 .max_by(|b1, b2| match self.axis {
97 Axis::Vertical => b1.width().partial_cmp(&b2.width()).unwrap(),
98 Axis::Horizontal => b1.height().partial_cmp(&b2.height()).unwrap(),
99 })
100 .unwrap();
101
102 let mut stack_batch = GeomBatch::new();
103 let mut stack_offset = 0.0;
104 for mut batch in self.batches {
105 let bounds = batch.get_bounds();
106 let alignment_inset = match (self.alignment, self.axis) {
107 (Alignment::Center, Axis::Vertical) => {
108 (max_bound_for_axis.width() - bounds.width()) / 2.0
109 }
110 (Alignment::Center, Axis::Horizontal) => {
111 (max_bound_for_axis.height() - bounds.height()) / 2.0
112 }
113 (Alignment::Top, Axis::Vertical) => {
114 panic!("cannot top-align items in a vertical stack")
115 }
116 (Alignment::Top, Axis::Horizontal) => 0.0,
117 (Alignment::Left, Axis::Horizontal) => {
118 panic!("cannot left-align items in a horizontal stack")
119 }
120 (Alignment::Left, Axis::Vertical) => 0.0,
121 };
122
123 let (dx, dy) = match self.axis {
124 Axis::Vertical => (alignment_inset, stack_offset),
125 Axis::Horizontal => (stack_offset, alignment_inset),
126 };
127 batch = batch.translate(dx, dy);
128 stack_batch.append(batch);
129
130 stack_offset += self.spacing;
131 match self.axis {
132 Axis::Vertical => stack_offset += bounds.height(),
133 Axis::Horizontal => stack_offset += bounds.width(),
134 }
135 }
136 stack_batch
137 }
138}