1#![allow(clippy::reversed_empty_ranges)]
2
3use crate::{
4 core::{algebra::Vector2, math::Rect, pool::Handle},
5 message::UiMessage,
6 widget::{Widget, WidgetBuilder},
7 BuildContext, Control, Orientation, UiNode, UserInterface,
8};
9use std::{
10 any::{Any, TypeId},
11 cell::RefCell,
12 ops::{Deref, DerefMut, Range},
13};
14
15#[derive(Clone)]
16pub struct WrapPanel {
17 widget: Widget,
18 orientation: Orientation,
19 lines: RefCell<Vec<Line>>,
20}
21
22crate::define_widget_deref!(WrapPanel);
23
24impl WrapPanel {
25 pub fn new(widget: Widget) -> Self {
26 Self {
27 widget,
28 orientation: Orientation::Vertical,
29 lines: Default::default(),
30 }
31 }
32
33 pub fn set_orientation(&mut self, orientation: Orientation) {
34 if self.orientation != orientation {
35 self.orientation = orientation;
36 self.widget.invalidate_layout();
37 }
38 }
39
40 pub fn orientation(&self) -> Orientation {
41 self.orientation
42 }
43}
44
45#[derive(Clone)]
46struct Line {
47 children: Range<usize>,
48 bounds: Rect<f32>,
49}
50
51impl Default for Line {
52 fn default() -> Self {
53 Self {
54 children: 0..0,
55 bounds: Default::default(),
56 }
57 }
58}
59
60impl Control for WrapPanel {
61 fn query_component(&self, type_id: TypeId) -> Option<&dyn Any> {
62 if type_id == TypeId::of::<Self>() {
63 Some(self)
64 } else {
65 None
66 }
67 }
68
69 fn measure_override(&self, ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
70 let mut measured_size: Vector2<f32> = Vector2::default();
71 let mut line_size = Vector2::default();
72 for child_handle in self.widget.children() {
73 let child = ui.node(*child_handle);
74 ui.measure_node(*child_handle, available_size);
75 let desired = child.desired_size();
76 match self.orientation {
77 Orientation::Vertical => {
78 if line_size.y + desired.y > available_size.y {
79 measured_size.y = measured_size.y.max(line_size.y);
81 measured_size.x += line_size.x;
82 line_size = Vector2::default();
83 }
84 line_size.x = line_size.x.max(desired.x);
85 line_size.y += desired.y;
86 }
87 Orientation::Horizontal => {
88 if line_size.x + desired.x > available_size.x {
89 measured_size.x = measured_size.x.max(line_size.x);
91 measured_size.y += line_size.y;
92 line_size = Vector2::default();
93 }
94 line_size.x += desired.x;
95 line_size.y = line_size.y.max(desired.y);
96 }
97 }
98 }
99
100 match self.orientation {
102 Orientation::Vertical => {
103 measured_size.y = measured_size.y.max(line_size.y);
104 measured_size.x += line_size.x;
105 }
106 Orientation::Horizontal => {
107 measured_size.x = measured_size.x.max(line_size.x);
108 measured_size.y += line_size.y;
109 }
110 }
111
112 measured_size
113 }
114
115 fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
116 let mut lines = self.lines.borrow_mut();
118 lines.clear();
119 let mut line = Line::default();
120 for child_handle in self.widget.children() {
121 let child = ui.node(*child_handle);
122 let desired = child.desired_size();
123 match self.orientation {
124 Orientation::Vertical => {
125 if line.bounds.h() + desired.y > final_size.y {
126 lines.push(line.clone());
128 line.bounds.position.x += line.bounds.w();
130 line.bounds.position.y = 0.0;
131 line.bounds.size.x = desired.x;
132 line.bounds.size.y = desired.y;
133 line.children.start = line.children.end;
135 line.children.end = line.children.start + 1;
136 } else {
137 line.bounds.size.y += desired.y;
138 line.bounds.size.x = line.bounds.w().max(desired.x);
139 line.children.end += 1;
140 }
141 }
142 Orientation::Horizontal => {
143 if line.bounds.w() + desired.x > final_size.x {
144 lines.push(line.clone());
146 line.bounds.position.x = 0.0;
148 line.bounds.position.y += line.bounds.h();
149 line.bounds.size.x = desired.x;
150 line.bounds.size.y = desired.y;
151 line.children.start = line.children.end;
153 line.children.end = line.children.start + 1;
154 } else {
155 line.bounds.size.x += desired.x;
156 line.bounds.size.y = line.bounds.h().max(desired.y);
157 line.children.end += 1;
158 }
159 }
160 }
161 }
162
163 lines.push(line);
165
166 let mut full_size = Vector2::default();
168 for line in lines.iter() {
169 let mut cursor = line.bounds.position;
170 for child_index in line.children.clone() {
171 let child_handle = self.children()[child_index];
172 let child = ui.node(child_handle);
173 let desired = child.desired_size();
174 match self.orientation {
175 Orientation::Vertical => {
176 let child_bounds =
177 Rect::new(line.bounds.x(), cursor.y, line.bounds.w(), desired.y);
178 ui.arrange_node(child_handle, &child_bounds);
179 cursor.y += desired.y;
180 }
181 Orientation::Horizontal => {
182 let child_bounds =
183 Rect::new(cursor.x, line.bounds.y(), desired.x, line.bounds.h());
184 ui.arrange_node(child_handle, &child_bounds);
185 cursor.x += desired.x;
186 }
187 }
188 }
189 match self.orientation {
190 Orientation::Vertical => {
191 full_size.x += line.bounds.w();
192 full_size.y = final_size.y.max(line.bounds.h());
193 }
194 Orientation::Horizontal => {
195 full_size.x = final_size.x.max(line.bounds.w());
196 full_size.y += line.bounds.h();
197 }
198 }
199 }
200
201 full_size
202 }
203
204 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
205 self.widget.handle_routed_message(ui, message);
206 }
207}
208
209pub struct WrapPanelBuilder {
210 widget_builder: WidgetBuilder,
211 orientation: Option<Orientation>,
212}
213
214impl WrapPanelBuilder {
215 pub fn new(widget_builder: WidgetBuilder) -> Self {
216 Self {
217 widget_builder,
218 orientation: None,
219 }
220 }
221
222 pub fn with_orientation(mut self, orientation: Orientation) -> Self {
223 self.orientation = Some(orientation);
224 self
225 }
226
227 pub fn build_node(self) -> UiNode {
228 let stack_panel = WrapPanel {
229 widget: self.widget_builder.build(),
230 orientation: self.orientation.unwrap_or(Orientation::Vertical),
231 lines: Default::default(),
232 };
233
234 UiNode::new(stack_panel)
235 }
236
237 pub fn build(self, ui: &mut BuildContext) -> Handle<UiNode> {
238 ui.add_node(self.build_node())
239 }
240}