Use bevy schedule for all UI

This commit is contained in:
Alex Mikhalev 2023-05-02 21:28:37 -07:00
parent d744525903
commit 25c03beb2d

View File

@ -5,7 +5,7 @@ use bevy_ecs::{
system::{Commands, IntoSystem, Query, ReadOnlySystem, Res, ResMut, System}, system::{Commands, IntoSystem, Query, ReadOnlySystem, Res, ResMut, System},
}; };
use eframe::{ use eframe::{
egui::{self, CursorIcon, Painter, Response, Sense, Ui}, egui::{self, CursorIcon, Painter, Response, Sense},
emath::{Pos2, Rect, RectTransform, Vec2}, emath::{Pos2, Rect, RectTransform, Vec2},
epaint::{Color32, Hsva, Stroke}, epaint::{Color32, Hsva, Stroke},
}; };
@ -21,7 +21,8 @@ fn main() {
"sketchrs", "sketchrs",
options, options,
Box::new(|_cc| Box::new(MyApp::default())), Box::new(|_cc| Box::new(MyApp::default())),
).unwrap(); )
.unwrap();
} }
#[derive(Clone, Copy, PartialEq, Resource)] #[derive(Clone, Copy, PartialEq, Resource)]
@ -390,12 +391,6 @@ fn paint_points(
}); });
} }
struct MyApp {
world: World,
show_entities_stage: Schedule,
show_sidebar_stage: Schedule,
}
fn init(mut commands: Commands) { fn init(mut commands: Commands) {
let p1 = geometry::insert_point_at(&mut commands, (10., 30.)); let p1 = geometry::insert_point_at(&mut commands, (10., 30.));
let p2 = geometry::insert_point_at(&mut commands, (-20., 15.)); let p2 = geometry::insert_point_at(&mut commands, (-20., 15.));
@ -403,22 +398,23 @@ fn init(mut commands: Commands) {
commands.spawn(Line::new(p1, p2)); commands.spawn(Line::new(p1, p2));
} }
impl Default for MyApp { #[derive(Resource)]
fn default() -> Self { struct ContextRes(egui::Context);
let mut world = World::default();
world.init_resource::<Tool>(); impl Deref for ContextRes {
type Target = egui::Context;
let mut init_stage = Schedule::new(); fn deref(&self) -> &Self::Target {
init_stage.add_system(init); &self.0
init_stage.run(&mut world);
Self {
world,
show_entities_stage: Self::create_show_entities_stage(),
show_sidebar_stage: Self::create_show_sidebar_stage(),
} }
} }
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
#[system_set(base)]
pub enum ShowEntitiesStage {
Input,
Tools,
Paint,
} }
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
@ -429,8 +425,40 @@ pub enum ScheduleSet {
Paint, Paint,
} }
impl MyApp { fn prepare(ctx: Res<ContextRes>) {
fn create_show_entities_stage() -> Schedule { ctx.request_repaint();
ctx.set_visuals(egui::Visuals::dark());
}
fn toolbar<'a>(
ctx: Res<ContextRes>,
selected: Query<Entity, With<Selected>>,
mut commands: Commands,
mut tool: ResMut<Tool>,
) {
egui::TopBottomPanel::top("top_panel").show(&**ctx, |ui| {
// ui.heading("sketchrs");
let mut selected_tool = *tool;
ui.horizontal(|ui| {
ui.radio_value(&mut selected_tool, Tool::Select, "Select");
ui.radio_value(&mut selected_tool, Tool::Move, "Move");
ui.radio_value(&mut selected_tool, Tool::AddPoint, "Add Point");
ui.radio_value(&mut selected_tool, Tool::AddLine, "Add Line");
});
if selected_tool != *tool {
*tool = selected_tool;
for selected in selected.iter() {
commands.entity(selected).remove::<Selected>();
}
}
});
}
struct ShowEntitiesSchedule(Schedule);
impl Default for ShowEntitiesSchedule {
fn default() -> Self {
let mut schedule = Schedule::new(); let mut schedule = Schedule::new();
schedule schedule
.configure_sets((ScheduleSet::Input, ScheduleSet::Tools, ScheduleSet::Paint).chain()); .configure_sets((ScheduleSet::Input, ScheduleSet::Tools, ScheduleSet::Paint).chain());
@ -442,6 +470,7 @@ impl MyApp {
move_tool.run_if(is_tool_active(Tool::Move)), move_tool.run_if(is_tool_active(Tool::Move)),
add_point_tool.run_if(is_tool_active(Tool::AddPoint)), add_point_tool.run_if(is_tool_active(Tool::AddPoint)),
add_line_tool.run_if(is_tool_active(Tool::AddLine)), add_line_tool.run_if(is_tool_active(Tool::AddLine)),
add_relation_tool.run_if(is_tool_active(Tool::AddRelation)),
) )
.distributive_run_if(is_hovered) .distributive_run_if(is_hovered)
.in_base_set(ScheduleSet::Tools), .in_base_set(ScheduleSet::Tools),
@ -449,61 +478,52 @@ impl MyApp {
schedule.add_systems( schedule.add_systems(
(paint_lines, paint_points.after(paint_lines)).in_base_set(ScheduleSet::Paint), (paint_lines, paint_points.after(paint_lines)).in_base_set(ScheduleSet::Paint),
); );
schedule Self(schedule)
}
} }
fn create_show_sidebar_stage() -> Schedule { fn central_panel(mut world: &mut World, mut schedule: Local<ShowEntitiesSchedule>) {
let mut schedule = Schedule::new(); let ctx = world.get_resource::<ContextRes>().unwrap().0.clone();
schedule egui::CentralPanel::default()
} .frame(egui::Frame::none())
.show(&ctx, |ui| {
fn show_toolbar(&mut self, ui: &mut Ui) { let sense = match *world.resource::<Tool>() {
ui.heading("sketchrs");
ui.horizontal(|ui| {
ui.label("Tool: ");
let tool = &mut *self.world.resource_mut::<Tool>();
ui.selectable_value(tool, Tool::Select, "Select");
ui.selectable_value(tool, Tool::Move, "Move");
ui.selectable_value(tool, Tool::AddPoint, "+ Point");
ui.selectable_value(tool, Tool::AddLine, "+ Line");
ui.selectable_value(tool, Tool::AddRelation, "+ Relation");
});
}
fn show_entities(&mut self, ui: &mut Ui) {
let sense = match *self.world.resource::<Tool>() {
Tool::Move => Sense::drag(), Tool::Move => Sense::drag(),
Tool::Select | Tool::AddPoint | Tool::AddLine | Tool::AddRelation => Sense::click(), Tool::Select | Tool::AddPoint | Tool::AddLine | Tool::AddRelation => Sense::click(),
}; };
let (response, painter) = ui.allocate_painter(ui.available_size(), sense); let (response, painter) = ui.allocate_painter(ui.available_size(), sense);
let to_screen = ToScreen(RectTransform::from_to( let to_screen = RectTransform::from_to(
Rect::from_center_size(Pos2::ZERO, response.rect.size() / 2.0), Rect::from_center_size(Pos2::ZERO, response.rect.size() / 2.0),
response.rect, response.rect,
)); );
self.world.insert_resource(to_screen); world.insert_resource(ToScreen(to_screen));
self.world.insert_resource(ResponseRes(response)); world.insert_resource(ResponseRes(response));
self.world.insert_resource(PainterRes(painter)); world.insert_resource(PainterRes(painter));
self.show_entities_stage.run(&mut self.world); schedule.0.run(&mut world);
self.world.remove_resource::<PainterRes>(); world.remove_resource::<PainterRes>();
self.world.remove_resource::<ResponseRes>(); world.remove_resource::<ResponseRes>();
self.world.remove_resource::<ToScreen>(); world.remove_resource::<ToScreen>();
});
} }
fn show_side_panel(&mut self, ui: &mut Ui) { fn side_panel(
let tool = *self.world.resource::<Tool>(); ctx: Res<ContextRes>,
selected: Query<(Entity, Option<&Point>, Option<&Line>), With<Selected>>,
tool: Res<Tool>,
) {
egui::SidePanel::right("side_panel")
.resizable(true)
.default_width(150.0)
.width_range(80.0..=200.0)
.show(&**ctx, |ui| {
let tool = *tool;
ui.vertical(|ui| match tool { ui.vertical(|ui| match tool {
Tool::Select => { Tool::Select => {
let mut selected = self
.world
.query_filtered::<(Entity, Option<&Point>, Option<&Line>), With<Selected>>();
let mut count = 0; let mut count = 0;
selected.for_each(&self.world, |(id, point, line)| { selected.for_each(|(id, point, line)| {
count += 1; count += 1;
if point.is_some() { if point.is_some() {
ui.label(format!("Selected point {}", id.index())); ui.label(format!("Selected point {}", id.index()));
@ -516,10 +536,7 @@ impl MyApp {
} }
} }
Tool::AddRelation => { Tool::AddRelation => {
let mut selected = self if let Some(first) = selected.iter().next() {
.world
.query_filtered::<(Entity, Option<&Point>, Option<&Line>), With<Selected>>();
if let Some(first) = selected.iter(&self.world).next() {
} else { } else {
ui.label("Select an entity to add a relation"); ui.label("Select an entity to add a relation");
} }
@ -528,32 +545,53 @@ impl MyApp {
ui.label(":)"); ui.label(":)");
} }
}); });
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
ctx.request_repaint();
ctx.set_visuals(egui::Visuals::dark());
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| self.show_toolbar(ui));
egui::CentralPanel::default()
.frame(egui::Frame::none())
.show(ctx, |ui| {
self.show_entities(ui);
}); });
}
egui::SidePanel::right("right_panel") fn bottom_panel(ctx: Res<ContextRes>) {
.resizable(true) egui::TopBottomPanel::bottom("bottom_panel").show(&ctx, |ui| {
.default_width(150.0)
.width_range(80.0..=200.0)
.show(ctx, |ui| self.show_side_panel(ui));
egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("Status:"); ui.label("Status:");
}); });
}); });
} }
struct MyApp {
world: World,
update_schedule: Schedule,
}
impl Default for MyApp {
fn default() -> Self {
Self::new()
}
}
impl MyApp {
fn new() -> Self {
let mut world = World::default();
world.init_resource::<Tool>();
let mut init_sched = Schedule::new();
init_sched.add_system(init);
init_sched.run(&mut world);
let mut update = Schedule::default();
update.add_systems((prepare, toolbar, side_panel, bottom_panel, central_panel).chain());
Self {
world,
update_schedule: update,
}
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
self.world.insert_resource(ContextRes(ctx.clone()));
self.update_schedule.run(&mut self.world);
self.world.remove_resource::<ContextRes>();
}
} }