1use bevy::input::common_conditions::input_just_pressed;
2use bevy::prelude::*;
3use bevy::utils::HashSet;
4use bevy_egui::egui::Window;
5use bevy_egui::{EguiContexts, EguiPlugin};
6use bevy_mod_picking::picking_core::PickingPluginsSettings;
7use bevy_mod_picking::selection::SelectionPluginSettings;
8use egui_dock::egui;
9
10use crate::components::{Beta, Dart, DartId, Edge, EdgeId, Face, FaceId, Vertex, VertexId, Volume};
11use crate::resources::{
12 DartHeadMul, DartRenderColor, DartShrink, DartWidth, EdgeRenderColor, EdgeWidth,
13 FaceRenderColor, FaceShrink, VertexRenderColor, VertexWidth, VolumeRenderColor, VolumeShrink,
14};
15
16pub struct GuiPlugin;
20
21impl Plugin for GuiPlugin {
22 fn build(&self, app: &mut App) {
23 app.add_plugins(EguiPlugin)
24 .insert_resource(UiState::default())
25 .insert_resource(WindowVisible(false))
26 .add_systems(
27 Update,
28 toggle_window_system.run_if(input_just_pressed(KeyCode::Tab)),
29 )
30 .add_systems(Update, ui_system);
31 }
32}
33
34#[derive(Resource)]
38pub struct WindowVisible(pub bool);
39
40fn toggle_window_system(mut window_visible: ResMut<WindowVisible>) {
41 window_visible.0 = !window_visible.0;
42}
43
44#[allow(clippy::too_many_arguments)]
45fn ui_system(
46 mut contexts: EguiContexts,
47 window_visible: Res<WindowVisible>,
48 drc: ResMut<DartRenderColor>,
49 ds: ResMut<DartShrink>,
50 dw: ResMut<DartWidth>,
51 dhm: ResMut<DartHeadMul>,
52 verc: ResMut<VertexRenderColor>,
53 v_width: ResMut<VertexWidth>,
54 edrc: ResMut<EdgeRenderColor>,
55 edw: ResMut<EdgeWidth>,
56 farc: ResMut<FaceRenderColor>,
57 fas: ResMut<FaceShrink>,
58 vorc: ResMut<VolumeRenderColor>,
59 vos: ResMut<VolumeShrink>,
60) {
61 if window_visible.0 {
62 Window::new("Rendering Options")
63 .collapsible(false)
64 .show(contexts.ctx_mut(), |ui| {
65 draw_options(
66 ui, drc, ds, dw, dhm, verc, v_width, edrc, edw, farc, fas, vorc, vos,
67 );
68 });
69 }
70}
71
72#[derive(Resource)]
75pub struct UiState {
76 pub(crate) selected_entities: HashSet<Entity>,
77}
78
79impl Default for UiState {
80 fn default() -> Self {
81 Self {
82 selected_entities: HashSet::new(),
83 }
84 }
85}
86
87#[allow(clippy::too_many_arguments)]
91pub fn draw_options(
92 ui: &mut egui::Ui,
93 mut drc: ResMut<DartRenderColor>,
94 mut ds: ResMut<DartShrink>,
95 mut dw: ResMut<DartWidth>,
96 mut dhm: ResMut<DartHeadMul>,
97 mut verc: ResMut<VertexRenderColor>,
98 mut v_width: ResMut<VertexWidth>,
99 mut edrc: ResMut<EdgeRenderColor>,
100 mut edw: ResMut<EdgeWidth>,
101 mut farc: ResMut<FaceRenderColor>,
102 mut fas: ResMut<FaceShrink>,
103 mut vorc: ResMut<VolumeRenderColor>,
104 mut vos: ResMut<VolumeShrink>,
105) {
106 ui.label(egui::RichText::new("Map Rendering").size(15.));
107 ui.separator(); egui::Grid::new("map_opt_grid")
110 .num_columns(6)
111 .show(ui, |ui| {
112 ui.label(egui::RichText::new("Object"));
114 ui.label(egui::RichText::new("Render"));
115 ui.label(egui::RichText::new("Color"));
116 ui.label(egui::RichText::new("Shrink"));
117 ui.label(egui::RichText::new("Width"));
118 ui.label(egui::RichText::new("Head Factor"));
119 ui.end_row();
120 ui.label("Darts");
122 ui.checkbox(&mut drc.0, "");
123 ui.add_enabled_ui(drc.0, |ui| draw_color_picker(ui, &mut drc.1));
124 ui.add(egui::DragValue::new(&mut ds.0).speed(0.01));
125 ui.add(egui::DragValue::new(&mut dw.0).speed(0.01));
126 ui.add(egui::DragValue::new(&mut dhm.0).speed(0.01));
127 ui.end_row();
128
129 ui.label("Vertices");
131 ui.checkbox(&mut verc.0, "");
132 ui.add_enabled_ui(verc.0, |ui| draw_color_picker(ui, &mut verc.1));
133 ui.label("");
134 ui.add(egui::DragValue::new(&mut v_width.0).speed(0.01));
135 ui.end_row();
136
137 ui.label("Edges");
139 ui.checkbox(&mut edrc.0, "");
140 ui.add_enabled_ui(edrc.0, |ui| draw_color_picker(ui, &mut edrc.1));
141 ui.label("");
142 ui.add(egui::DragValue::new(&mut edw.0).speed(0.01));
143 ui.end_row();
144
145 ui.label("Faces");
147 ui.checkbox(&mut farc.0, "");
148 ui.add_enabled_ui(farc.0, |ui| draw_color_picker(ui, &mut farc.1));
149 ui.add(egui::DragValue::new(&mut fas.0).speed(0.01));
150 ui.end_row();
151
152 ui.label("Volumes");
154 ui.checkbox(&mut vorc.0, "");
155 ui.add_enabled_ui(vorc.0, |ui| draw_color_picker(ui, &mut vorc.1));
156 ui.label("");
157 ui.add(egui::DragValue::new(&mut vos.0).speed(0.01));
158 ui.end_row();
159 });
160}
161
162fn draw_color_picker(ui: &mut egui::Ui, color: &mut egui::Color32) {
163 let mut egui_color =
165 egui::Color32::from_rgba_premultiplied(color.r(), color.g(), color.b(), color.a());
166 let color_picker = egui::color_picker::color_edit_button_srgba(
168 ui,
169 &mut egui_color,
170 egui::color_picker::Alpha::Opaque,
171 );
172 if color_picker.changed() {
174 *color = egui::Color32::from_rgba_premultiplied(
175 egui_color.r(),
176 egui_color.g(),
177 egui_color.b(),
178 egui_color.a(),
179 );
180 }
181}
182
183#[allow(unused)]
186fn draw_picking_options(ui: &mut egui::Ui, world: &mut World) {
187 ui.label(egui::RichText::new("Picking").size(15.));
188 ui.separator(); egui::Grid::new("pick_opt_grid")
191 .num_columns(2)
192 .show(ui, |ui| {
193 ui.label("Enable");
194 {
195 let mut picking_params = world.resource_mut::<PickingPluginsSettings>();
196 ui.checkbox(&mut picking_params.is_enabled, "");
197 }
198 ui.end_row();
199 ui.label("Click nothing deselect all");
200 {
201 let mut picking_params = world.resource_mut::<SelectionPluginSettings>();
202 ui.checkbox(&mut picking_params.click_nothing_deselect_all, "");
203 }
204 });
205}
206
207pub fn draw_inspected_data(
209 ui: &mut egui::Ui,
210 world: &mut World,
211 selected_entities: &HashSet<Entity>,
212) {
213 ui.label(egui::RichText::new("Selected Components").size(15.));
214
215 if selected_entities.is_empty() {
216 ui.separator();
217 }
218
219 for entity in selected_entities {
220 ui.separator();
221 if world.get::<Dart>(*entity).is_some() {
222 let Some(id) = world.get::<DartId>(*entity) else {
223 unreachable!()
224 };
225 ui.label(format!("Dart #{}", id.0));
226 let Some(vid) = world.get::<VertexId>(*entity) else {
227 unreachable!();
228 };
229 let Some(eid) = world.get::<EdgeId>(*entity) else {
230 unreachable!();
231 };
232 let Some(fid) = world.get::<FaceId>(*entity) else {
233 unreachable!();
234 };
235 egui::Grid::new(format!("dart #{}", id.0)) .num_columns(4)
237 .show(ui, |ui| {
238 ui.label("i-cells");
239 ui.label("Vertex");
240 ui.label("Edge");
241 ui.label("Face");
242 ui.end_row();
243 ui.label("IDs");
244 ui.label(format!("{}", vid.0));
245 ui.label(format!("{}", eid.0));
246 ui.label(format!("{}", fid.0));
247 });
248 } else if world.get::<Beta>(*entity).is_some() {
249 ui.label("Beta");
250 } else if world.get::<Vertex>(*entity).is_some() {
251 let Some(id) = world.get::<VertexId>(*entity) else {
252 unreachable!()
253 };
254 ui.label(format!("Vertex #{}", id.0));
255 } else if world.get::<Edge>(*entity).is_some() {
256 let Some(id) = world.get::<EdgeId>(*entity) else {
257 unreachable!()
258 };
259 ui.label(format!("Edge #{}", id.0));
260 } else if world.get::<Face>(*entity).is_some() {
261 ui.label("Face");
262 } else if world.get::<Volume>(*entity).is_some() {
263 ui.label("Volume");
264 }
265 }
266}