bevy_ui_builders/scroll_view/
builder.rs1use bevy::prelude::*;
4use super::types::*;
5
6pub struct ScrollViewBuilder {
8 width: Val,
9 height: Val,
10 max_width: Val,
11 max_height: Val,
12 padding: UiRect,
13 margin: UiRect,
14 gap: Val,
15 direction: ScrollDirection,
16 config: ScrollConfig,
17 background_color: Color,
18}
19
20impl ScrollViewBuilder {
21 pub fn new() -> Self {
23 Self {
24 width: Val::Percent(100.0),
25 height: Val::Auto,
26 max_width: Val::Percent(100.0),
27 max_height: Val::Vh(90.0), padding: UiRect::all(Val::Vw(2.0)), margin: UiRect::ZERO,
30 gap: Val::Vh(2.0), direction: ScrollDirection::Vertical,
32 config: ScrollConfig::default(),
33 background_color: Color::NONE,
34 }
35 }
36
37 pub fn width(mut self, width: Val) -> Self {
39 self.width = width;
40 self
41 }
42
43 pub fn height(mut self, height: Val) -> Self {
45 self.height = height;
46 self
47 }
48
49 pub fn max_width(mut self, max_width: Val) -> Self {
51 self.max_width = max_width;
52 self
53 }
54
55 pub fn max_height(mut self, max_height: Val) -> Self {
57 self.max_height = max_height;
58 self
59 }
60
61 pub fn padding_vh(mut self, vh: f32) -> Self {
63 self.padding = UiRect::all(Val::Vh(vh));
64 self
65 }
66
67 pub fn padding_vw(mut self, vw: f32) -> Self {
69 self.padding = UiRect::all(Val::Vw(vw));
70 self
71 }
72
73 pub fn padding(mut self, padding: UiRect) -> Self {
75 self.padding = padding;
76 self
77 }
78
79 pub fn margin(mut self, margin: UiRect) -> Self {
81 self.margin = margin;
82 self
83 }
84
85 pub fn gap(mut self, gap: Val) -> Self {
87 self.gap = gap;
88 self
89 }
90
91 pub fn direction(mut self, direction: ScrollDirection) -> Self {
93 self.direction = direction;
94 self
95 }
96
97 pub fn auto_scroll(mut self, enabled: bool) -> Self {
99 self.config.auto_scroll_to_focus = enabled;
100 self
101 }
102
103 pub fn show_indicators(mut self, show: bool) -> Self {
105 self.config.show_indicators = show;
106 self
107 }
108
109 pub fn background_color(mut self, color: Color) -> Self {
111 self.background_color = color;
112 self
113 }
114
115 pub fn build(self, parent: &mut ChildSpawnerCommands) -> Entity {
117 let overflow = match self.direction {
118 ScrollDirection::Vertical => Overflow::scroll_y(),
119 ScrollDirection::Horizontal => Overflow::scroll_x(),
120 ScrollDirection::Both => Overflow::scroll(),
121 };
122
123 let (flex_direction, row_gap, column_gap) = match self.direction {
124 ScrollDirection::Vertical => (FlexDirection::Column, self.gap, Val::ZERO),
125 ScrollDirection::Horizontal => (FlexDirection::Row, Val::ZERO, self.gap),
126 ScrollDirection::Both => (FlexDirection::Column, self.gap, self.gap),
127 };
128
129 let show_indicators = self.config.show_indicators;
130 let container = parent.spawn((
131 Node {
132 width: self.width,
133 height: self.height,
134 max_width: self.max_width,
135 max_height: self.max_height,
136 padding: self.padding,
137 margin: self.margin,
138 flex_direction,
139 row_gap,
140 column_gap,
141 align_items: AlignItems::Stretch,
142 overflow,
143 ..default()
144 },
145 BackgroundColor(self.background_color),
146 ScrollView,
147 ScrollState::default(),
148 self.config,
149 )).id();
150
151 if show_indicators && self.direction != ScrollDirection::Horizontal {
153 parent.spawn((
154 Node {
155 position_type: PositionType::Absolute,
156 right: Val::Px(4.0),
157 top: Val::Px(4.0),
158 bottom: Val::Px(4.0),
159 width: Val::Px(8.0),
160 ..default()
161 },
162 BackgroundColor(Color::srgba(1.0, 1.0, 1.0, 0.1)),
163 ScrollBarTrack,
164 )).with_children(|track| {
165 track.spawn((
166 Node {
167 width: Val::Percent(100.0),
168 height: Val::Percent(20.0), ..default()
170 },
171 BackgroundColor(Color::srgba(1.0, 1.0, 1.0, 0.3)),
172 ScrollBarThumb { scroll_container: container },
173 Visibility::Hidden, ));
175 });
176 }
177
178 container
179 }
180
181 pub fn build_with_children<F>(self, parent: &mut ChildSpawnerCommands, children_fn: F) -> Entity
183 where
184 F: FnOnce(&mut ChildSpawnerCommands),
185 {
186 let overflow = match self.direction {
187 ScrollDirection::Vertical => Overflow::scroll_y(),
188 ScrollDirection::Horizontal => Overflow::scroll_x(),
189 ScrollDirection::Both => Overflow::scroll(),
190 };
191
192 let (flex_direction, row_gap, column_gap) = match self.direction {
193 ScrollDirection::Vertical => (FlexDirection::Column, self.gap, Val::ZERO),
194 ScrollDirection::Horizontal => (FlexDirection::Row, Val::ZERO, self.gap),
195 ScrollDirection::Both => (FlexDirection::Column, self.gap, self.gap),
196 };
197
198 let show_indicators = self.config.show_indicators;
199 let container = parent
200 .spawn((
201 Node {
202 width: self.width,
203 height: self.height,
204 max_width: self.max_width,
205 max_height: self.max_height,
206 padding: self.padding,
207 margin: self.margin,
208 flex_direction,
209 row_gap,
210 column_gap,
211 align_items: AlignItems::Stretch,
212 overflow,
213 ..default()
214 },
215 BackgroundColor(self.background_color),
216 ScrollView,
217 ScrollState::default(),
218 self.config,
219 ))
220 .with_children(children_fn)
221 .id();
222
223 if show_indicators && self.direction != ScrollDirection::Horizontal {
225 parent.spawn((
226 Node {
227 position_type: PositionType::Absolute,
228 right: Val::Px(4.0),
229 top: Val::Px(4.0),
230 bottom: Val::Px(4.0),
231 width: Val::Px(8.0),
232 ..default()
233 },
234 BackgroundColor(Color::srgba(1.0, 1.0, 1.0, 0.1)),
235 ScrollBarTrack,
236 )).with_children(|track| {
237 track.spawn((
238 Node {
239 width: Val::Percent(100.0),
240 height: Val::Percent(20.0), ..default()
242 },
243 BackgroundColor(Color::srgba(1.0, 1.0, 1.0, 0.3)),
244 ScrollBarThumb { scroll_container: container },
245 Visibility::Hidden, ));
247 });
248 }
249
250 container
251 }
252}
253
254impl Default for ScrollViewBuilder {
255 fn default() -> Self {
256 Self::new()
257 }
258}
259
260pub fn scroll_view() -> ScrollViewBuilder {
262 ScrollViewBuilder::new()
263}