1use bevy::prelude::*;
16#[cfg(not(target_arch = "wasm32"))]
17use bevy::sprite_render::{Wireframe2dConfig, Wireframe2dPlugin};
18use bevy::{
19 feathers::{controls::FeathersCheckbox, theme::UiTheme, FeathersPlugins},
20 ui_widgets::{checkbox_self_update, ValueChange},
21};
22use checkbox::feathers_option_checkbox;
23use scene::{bottom_left_scene, top_left_scene};
24
25#[path = "../helpers/checkbox.rs"]
26mod checkbox;
27
28#[path = "../helpers/theme.rs"]
29mod theme;
30
31#[path = "../helpers/scene.rs"]
32mod scene;
33
34#[derive(Resource, Default)]
36struct AppStatus {
37 rotation: bool,
38}
39
40#[derive(Clone, Copy, Component, Debug, Default, PartialEq)]
41enum CheckboxInput {
42 #[default]
43 Rotation,
44 Wireframe,
45}
46
47fn main() {
48 let mut app = App::new();
49 app.add_plugins((
50 DefaultPlugins,
51 FeathersPlugins,
52 #[cfg(not(target_arch = "wasm32"))]
53 Wireframe2dPlugin::default(),
54 ))
55 .init_resource::<AppStatus>()
56 .add_systems(Startup, setup);
57 app.insert_resource(UiTheme(theme::basic_example_theme(Color::WHITE)));
58 app.add_observer(handle_value_change_checkbox);
59 app.add_systems(Update, rotate.run_if(rotate_checkbox_checked));
60 app.add_observer(checkbox_self_update);
61 app.run();
62}
63
64const X_EXTENT: f32 = 1000.;
65const Y_EXTENT: f32 = 150.;
66const THICKNESS: f32 = 5.0;
67
68fn setup(
69 mut commands: Commands,
70 mut meshes: ResMut<Assets<Mesh>>,
71 mut materials: ResMut<Assets<ColorMaterial>>,
72) {
73 commands.spawn(Camera2d);
74
75 let shapes = [
76 meshes.add(Circle::new(50.0)),
77 meshes.add(CircularSector::new(50.0, 1.0)),
78 meshes.add(CircularSegment::new(50.0, 1.25)),
79 meshes.add(Ellipse::new(25.0, 50.0)),
80 meshes.add(Annulus::new(25.0, 50.0)),
81 meshes.add(Capsule2d::new(25.0, 50.0)),
82 meshes.add(Rhombus::new(75.0, 100.0)),
83 meshes.add(Rectangle::new(50.0, 100.0)),
84 meshes.add(RegularPolygon::new(50.0, 6)),
85 meshes.add(Triangle2d::new(
86 Vec2::Y * 50.0,
87 Vec2::new(-50.0, -50.0),
88 Vec2::new(50.0, -50.0),
89 )),
90 meshes.add(Segment2d::new(
91 Vec2::new(-50.0, 50.0),
92 Vec2::new(50.0, -50.0),
93 )),
94 meshes.add(Polyline2d::new(vec![
95 Vec2::new(-50.0, 50.0),
96 Vec2::new(0.0, -50.0),
97 Vec2::new(50.0, 50.0),
98 ])),
99 ];
100 let num_shapes = shapes.len();
101
102 for (i, shape) in shapes.into_iter().enumerate() {
103 let color = Color::hsl(360. * i as f32 / num_shapes as f32, 0.95, 0.7);
105
106 commands.spawn((
107 Mesh2d(shape),
108 MeshMaterial2d(materials.add(color)),
109 Transform::from_xyz(
110 -X_EXTENT / 2. + i as f32 / (num_shapes - 1) as f32 * X_EXTENT,
112 Y_EXTENT / 2.,
113 0.0,
114 ),
115 ));
116 }
117
118 let rings = [
119 meshes.add(Circle::new(50.0).to_ring(THICKNESS)),
120 meshes.add(Ring::new(
122 CircularSector::new(50.0, 1.0),
123 CircularSector::new(45.0, 1.0),
124 )),
125 meshes.add(CircularSegment::new(50.0, 1.25).to_ring(THICKNESS)),
126 meshes.add({
127 let outer = Ellipse::new(25.0, 50.0);
129 let mut inner = outer;
130 inner.half_size -= Vec2::splat(THICKNESS);
131 Ring::new(outer, inner)
132 }),
133 meshes.add(Ring::new(Circle::new(50.0), Circle::new(25.0))),
135 meshes.add(Capsule2d::new(25.0, 50.0).to_ring(THICKNESS)),
136 meshes.add(Rhombus::new(75.0, 100.0).to_ring(THICKNESS)),
137 meshes.add(Rectangle::new(50.0, 100.0).to_ring(THICKNESS)),
138 meshes.add(RegularPolygon::new(50.0, 6).to_ring(THICKNESS)),
139 meshes.add(
140 Triangle2d::new(
141 Vec2::Y * 50.0,
142 Vec2::new(-50.0, -50.0),
143 Vec2::new(50.0, -50.0),
144 )
145 .to_ring(THICKNESS),
146 ),
147 ];
148 let num_rings = rings.len() + 2;
150
151 for (i, shape) in rings.into_iter().enumerate() {
152 let color = Color::hsl(360. * i as f32 / num_rings as f32, 0.95, 0.7);
154
155 commands.spawn((
156 Mesh2d(shape),
157 MeshMaterial2d(materials.add(color)),
158 Transform::from_xyz(
159 -X_EXTENT / 2. + i as f32 / (num_rings - 1) as f32 * X_EXTENT,
161 -Y_EXTENT / 2.,
162 0.0,
163 ),
164 ));
165 }
166 spawn_buttons(&mut commands);
167}
168
169fn spawn_buttons(commands: &mut Commands) {
171 if !cfg!(target_arch = "wasm32") {
172 commands.spawn_scene(bsn! {
173 @bottom_left_scene()
174 Children [
175 @feathers_option_checkbox("ROTATE", Some(CheckboxInput::Rotation))
176 --
177 @feathers_option_checkbox("WIREFRAME", Some(CheckboxInput::Wireframe))
178 ]
179 });
180 } else {
181 commands.spawn_scene(bsn! {
182 @top_left_scene() Children [
184 @feathers_option_checkbox("ROTATE", Some(CheckboxInput::Rotation))
185 ]
186 });
187 }
188}
189
190fn handle_value_change_checkbox(
191 event: On<ValueChange<bool>>,
192 #[cfg(not(target_arch = "wasm32"))] mut wireframe_config: ResMut<Wireframe2dConfig>,
193 mut app_status: ResMut<AppStatus>,
194 checkbox_input_q: Query<&CheckboxInput, With<FeathersCheckbox>>,
195) {
196 if let Ok(checkbox_input) = checkbox_input_q.get(event.source) {
197 match checkbox_input {
198 CheckboxInput::Rotation => {
199 app_status.rotation = event.value;
200 }
201 #[cfg(target_arch = "wasm32")]
202 CheckboxInput::Wireframe => {}
203 #[cfg(not(target_arch = "wasm32"))]
204 CheckboxInput::Wireframe => {
205 wireframe_config.global = event.value;
206 }
207 }
208 }
209}
210
211fn rotate_checkbox_checked(app_status: Res<AppStatus>) -> bool {
212 app_status.rotation
213}
214
215fn rotate(mut query: Query<&mut Transform, With<Mesh2d>>, time: Res<Time>) {
216 for mut transform in &mut query {
217 transform.rotate_z(time.delta_secs() / 2.0);
218 }
219}