1use bevy::{color::palettes::tailwind, prelude::*};
5
6const MIN_RESIZE_VAL: f32 = 1.0;
7const IMAGE_GROUP_BOX_MIN_WIDTH: f32 = 50.0;
8const IMAGE_GROUP_BOX_MAX_WIDTH: f32 = 100.0;
9const IMAGE_GROUP_BOX_MIN_HEIGHT: f32 = 10.0;
10const IMAGE_GROUP_BOX_MAX_HEIGHT: f32 = 50.0;
11const IMAGE_GROUP_BOX_INIT_WIDTH: f32 =
12 (IMAGE_GROUP_BOX_MIN_WIDTH + IMAGE_GROUP_BOX_MAX_WIDTH) / 2.;
13const IMAGE_GROUP_BOX_INIT_HEIGHT: f32 =
14 (IMAGE_GROUP_BOX_MIN_HEIGHT + IMAGE_GROUP_BOX_MAX_HEIGHT) / 2.;
15const TEXT_PREFIX: &str = "Compare NodeImageMode(Auto, Stretch) press `Up`/`Down` to resize height, press `Left`/`Right` to resize width\n";
16
17fn main() {
18 App::new()
19 .add_plugins(DefaultPlugins)
20 .insert_resource(GlobalUiDebugOptions {
22 enabled: true,
23 ..default()
24 })
25 .add_systems(Startup, setup)
26 .add_systems(Update, update)
27 .add_observer(on_trigger_image_group)
28 .run();
29}
30
31#[derive(Debug, Component)]
32struct ImageGroup;
33
34#[derive(Debug, Event)]
35enum ImageGroupResize {
36 HeightGrow,
37 HeightShrink,
38 WidthGrow,
39 WidthShrink,
40}
41
42#[derive(Debug, Component)]
44struct TextData {
45 height: f32,
46 width: f32,
47}
48
49#[derive(Debug)]
50enum Direction {
51 Height,
52 Width,
53}
54
55#[derive(Debug, EntityEvent)]
56struct TextUpdate {
57 entity: Entity,
58 direction: Direction,
59 change: f32,
60}
61
62fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
63 let image_handle = asset_server.load("branding/icon.png");
64 let full_text = format!(
65 "{}height : {}%, width : {}%",
66 TEXT_PREFIX, IMAGE_GROUP_BOX_INIT_HEIGHT, IMAGE_GROUP_BOX_INIT_WIDTH,
67 );
68
69 commands.spawn(Camera2d);
70
71 let container = commands
72 .spawn((
73 Node {
74 display: Display::Grid,
75 width: percent(100),
76 height: percent(100),
77 grid_template_rows: vec![GridTrack::min_content(), GridTrack::flex(1.0)],
78 ..default()
79 },
80 BackgroundColor(Color::WHITE),
81 ))
82 .id();
83
84 commands
86 .spawn((
87 TextData {
88 height: IMAGE_GROUP_BOX_INIT_HEIGHT,
89 width: IMAGE_GROUP_BOX_INIT_WIDTH,
90 },
91 Text::new(full_text),
92 TextColor::BLACK,
93 Node {
94 grid_row: GridPlacement::span(1),
95 padding: px(6).all(),
96 ..default()
97 },
98 UiDebugOptions {
99 enabled: false,
100 ..default()
101 },
102 ChildOf(container),
103 ))
104 .observe(update_text);
105
106 commands
107 .spawn((
108 Node {
109 display: Display::Flex,
110 grid_row: GridPlacement::span(1),
111 flex_direction: FlexDirection::Column,
112 justify_content: JustifyContent::SpaceAround,
113 padding: px(10.).all(),
114 ..default()
115 },
116 BackgroundColor(Color::BLACK),
117 ChildOf(container),
118 ))
119 .with_children(|builder| {
120 builder
122 .spawn((
123 ImageGroup,
124 Node {
125 display: Display::Flex,
126 justify_content: JustifyContent::Start,
127 width: percent(IMAGE_GROUP_BOX_INIT_WIDTH),
128 height: percent(IMAGE_GROUP_BOX_INIT_HEIGHT),
129 ..default()
130 },
131 BackgroundColor(Color::from(tailwind::BLUE_100)),
132 ))
133 .with_children(|parent| {
134 for _ in 0..4 {
135 parent.spawn((
137 Node::default(),
138 ImageNode {
139 image: image_handle.clone(),
140 image_mode: NodeImageMode::Auto,
141 ..default()
142 },
143 ));
144 }
145 });
146 builder
148 .spawn((
149 ImageGroup,
150 Node {
151 display: Display::Flex,
152 justify_content: JustifyContent::Start,
153 width: percent(IMAGE_GROUP_BOX_INIT_WIDTH),
154 height: percent(IMAGE_GROUP_BOX_INIT_HEIGHT),
155 ..default()
156 },
157 BackgroundColor(Color::from(tailwind::BLUE_100)),
158 ))
159 .with_children(|parent| {
160 for width in [10., 20., 30., 40.] {
161 parent.spawn((
162 Node {
163 height: percent(100),
164 width: percent(width),
165 ..default()
166 },
167 ImageNode {
168 image: image_handle.clone(),
169 image_mode: NodeImageMode::Stretch,
170 ..default()
171 },
172 ));
173 }
174 });
175 });
176}
177
178fn update(
180 keycode: Res<ButtonInput<KeyCode>>,
181 mut commands: Commands,
182 query: Query<Entity, With<TextData>>,
183) {
184 let entity = query.single().unwrap();
185 if keycode.pressed(KeyCode::ArrowUp) {
186 commands.trigger(ImageGroupResize::HeightGrow);
187 commands.trigger(TextUpdate {
188 entity,
189 direction: Direction::Height,
190 change: MIN_RESIZE_VAL,
191 });
192 }
193 if keycode.pressed(KeyCode::ArrowDown) {
194 commands.trigger(ImageGroupResize::HeightShrink);
195 commands.trigger(TextUpdate {
196 entity,
197 direction: Direction::Height,
198 change: -MIN_RESIZE_VAL,
199 });
200 }
201 if keycode.pressed(KeyCode::ArrowLeft) {
202 commands.trigger(ImageGroupResize::WidthShrink);
203 commands.trigger(TextUpdate {
204 entity,
205 direction: Direction::Width,
206 change: -MIN_RESIZE_VAL,
207 });
208 }
209 if keycode.pressed(KeyCode::ArrowRight) {
210 commands.trigger(ImageGroupResize::WidthGrow);
211 commands.trigger(TextUpdate {
212 entity,
213 direction: Direction::Width,
214 change: MIN_RESIZE_VAL,
215 });
216 }
217}
218
219fn update_text(
220 event: On<TextUpdate>,
221 mut textmeta: Single<&mut TextData>,
222 mut text: Single<&mut Text>,
223) {
224 let mut new_text = Text::new(TEXT_PREFIX);
225 match event.direction {
226 Direction::Height => {
227 textmeta.height = (textmeta.height + event.change)
228 .clamp(IMAGE_GROUP_BOX_MIN_HEIGHT, IMAGE_GROUP_BOX_MAX_HEIGHT);
229 new_text.push_str(&format!(
230 "height : {}%, width : {}%",
231 textmeta.height, textmeta.width
232 ));
233 }
234 Direction::Width => {
235 textmeta.width = (textmeta.width + event.change)
236 .clamp(IMAGE_GROUP_BOX_MIN_WIDTH, IMAGE_GROUP_BOX_MAX_WIDTH);
237 new_text.push_str(&format!(
238 "height : {}%, width : {}%",
239 textmeta.height, textmeta.width
240 ));
241 }
242 }
243 text.0 = new_text.0;
244}
245
246fn on_trigger_image_group(event: On<ImageGroupResize>, query: Query<&mut Node, With<ImageGroup>>) {
247 for mut node in query {
248 match event.event() {
249 ImageGroupResize::HeightGrow => {
250 if let Val::Percent(val) = &mut node.height {
251 *val = (*val + MIN_RESIZE_VAL).min(IMAGE_GROUP_BOX_MAX_HEIGHT);
252 }
253 }
254 ImageGroupResize::HeightShrink => {
255 if let Val::Percent(val) = &mut node.height {
256 *val = (*val - MIN_RESIZE_VAL).max(IMAGE_GROUP_BOX_MIN_HEIGHT);
257 }
258 }
259 ImageGroupResize::WidthGrow => {
260 if let Val::Percent(val) = &mut node.width {
261 *val = (*val + MIN_RESIZE_VAL).min(IMAGE_GROUP_BOX_MAX_WIDTH);
262 }
263 }
264 ImageGroupResize::WidthShrink => {
265 if let Val::Percent(val) = &mut node.width {
266 *val = (*val - MIN_RESIZE_VAL).max(IMAGE_GROUP_BOX_MIN_WIDTH);
267 }
268 }
269 }
270 }
271}