diff --git a/editor/src/plugins/draw_polygon.rs b/editor/src/plugins/draw_polygon.rs index 5884945e32..8244cb57c4 100644 --- a/editor/src/plugins/draw_polygon.rs +++ b/editor/src/plugins/draw_polygon.rs @@ -25,7 +25,13 @@ impl DrawPolygonState { DrawPolygonState::Empty } - pub fn event(&mut self, input: &mut UserInput, canvas: &Canvas, map: &Map) -> bool { + pub fn event( + &mut self, + input: &mut UserInput, + canvas: &Canvas, + map: &Map, + osd: &mut TextOSD, + ) -> bool { let mut new_state: Option = None; match self { DrawPolygonState::Empty => { @@ -38,6 +44,9 @@ impl DrawPolygonState { } } DrawPolygonState::DrawingPoints(ref mut pts, ref mut current_idx, name) => { + osd.pad_if_nonempty(); + osd.add_line(format!("Currently editing {}", name)); + if input.key_pressed(Key::Tab, "list existing polygons") { let (names, polygons) = load_all_polygons(map.get_name()); if names.is_empty() { @@ -80,6 +89,9 @@ impl DrawPolygonState { } } DrawPolygonState::MovingPoint(ref mut pts, idx, name) => { + osd.pad_if_nonempty(); + osd.add_line(format!("Currently editing {}", name)); + pts[*idx] = canvas.get_cursor_in_map_space(); if let Some(Button::Keyboard(Key::LCtrl)) = input.use_event_directly().release_args() @@ -103,6 +115,9 @@ impl DrawPolygonState { ).expect("Saving polygon selection failed"); println!("Saved {}", path); new_state = Some(DrawPolygonState::Empty); + } else { + osd.pad_if_nonempty(); + tb.populate_osd(osd); } input.consume_event(); } @@ -131,21 +146,6 @@ impl DrawPolygonState { } } - pub fn populate_osd(&self, osd: &mut TextOSD) { - match self { - DrawPolygonState::NamingPolygon(tb, _) => { - osd.pad_if_nonempty(); - tb.populate_osd(osd); - } - DrawPolygonState::DrawingPoints(_, _, name) - | DrawPolygonState::MovingPoint(_, _, name) => { - osd.pad_if_nonempty(); - osd.add_line(format!("Currently editing {}", name)); - } - _ => {} - } - } - pub fn draw(&self, g: &mut GfxCtx, canvas: &Canvas) { // TODO add colorscheme entries let red = [1.0, 0.0, 0.0, 1.0]; diff --git a/editor/src/plugins/search.rs b/editor/src/plugins/search.rs index 746de0b2b3..3df578f7db 100644 --- a/editor/src/plugins/search.rs +++ b/editor/src/plugins/search.rs @@ -26,7 +26,7 @@ impl SearchState { None } - pub fn event(&mut self, input: &mut UserInput) -> bool { + pub fn event(&mut self, input: &mut UserInput, osd: &mut TextOSD) -> bool { let mut new_state: Option = None; match self { SearchState::Empty => { @@ -37,6 +37,9 @@ impl SearchState { SearchState::EnteringSearch(tb) => { if tb.event(input.use_event_directly()) { new_state = Some(SearchState::FilterOSM(tb.line.clone())); + } else { + osd.pad_if_nonempty(); + tb.populate_osd(osd); } input.consume_event(); } @@ -57,13 +60,6 @@ impl SearchState { _ => true, } } - - pub fn populate_osd(&self, osd: &mut TextOSD) { - if let SearchState::EnteringSearch(tb) = self { - osd.pad_if_nonempty(); - tb.populate_osd(osd); - } - } } impl Colorizer for SearchState { diff --git a/editor/src/plugins/sim_controls.rs b/editor/src/plugins/sim_controls.rs index 6070d6cdb9..836cb22a18 100644 --- a/editor/src/plugins/sim_controls.rs +++ b/editor/src/plugins/sim_controls.rs @@ -35,6 +35,7 @@ impl SimController { control_map: &ControlMap, sim: &mut Sim, selected: Option, + osd: &mut TextOSD, ) -> EventLoopMode { if input.unimportant_key_pressed(Key::S, "Seed the map with agents") { sim.small_spawn(map); @@ -106,19 +107,18 @@ impl SimController { } } } - if self.last_step.is_some() { - EventLoopMode::Animation - } else { - EventLoopMode::InputOnly - } - } - pub fn populate_osd(&self, sim: &Sim, osd: &mut TextOSD) { osd.pad_if_nonempty(); osd.add_line(sim.summary()); osd.add_line(format!( "Speed: {0} / desired {1:.2}x", self.sim_speed, self.desired_speed )); + + if self.last_step.is_some() { + EventLoopMode::Animation + } else { + EventLoopMode::InputOnly + } } } diff --git a/editor/src/plugins/warp.rs b/editor/src/plugins/warp.rs index 5a85c0e600..3c83af26d6 100644 --- a/editor/src/plugins/warp.rs +++ b/editor/src/plugins/warp.rs @@ -20,6 +20,7 @@ impl WarpState { sim: &Sim, canvas: &mut Canvas, selected: &mut Option, + osd: &mut TextOSD, ) -> bool { let mut new_state: Option = None; match self { @@ -33,6 +34,9 @@ impl WarpState { if tb.event(input.use_event_directly()) { warp(tb.line.clone(), map, sim, canvas, selected); new_state = Some(WarpState::Empty); + } else { + osd.pad_if_nonempty(); + tb.populate_osd(osd); } input.consume_event(); } @@ -45,13 +49,6 @@ impl WarpState { _ => true, } } - - pub fn populate_osd(&self, osd: &mut TextOSD) { - if let WarpState::EnteringSearch(tb) = self { - osd.pad_if_nonempty(); - tb.populate_osd(osd); - } - } } impl Colorizer for WarpState {} diff --git a/editor/src/plugins/wizard.rs b/editor/src/plugins/wizard.rs index 38d04f0cb1..aa0dbbc923 100644 --- a/editor/src/plugins/wizard.rs +++ b/editor/src/plugins/wizard.rs @@ -1,9 +1,9 @@ -use ezgui::{GfxCtx, Menu, MenuResult, TextBox, TextOSD, UserInput, Canvas}; +use ezgui::{Canvas, GfxCtx, Menu, MenuResult, TextBox, TextOSD, UserInput}; use map_model::Map; use piston::input::Key; +use plugins::Colorizer; use sim::Tick; use std::collections::VecDeque; -use plugins::Colorizer; #[derive(Debug)] struct SpawnOverTime { @@ -35,7 +35,7 @@ impl WizardSample { WizardSample::Inactive } - pub fn event(&mut self, input: &mut UserInput, map: &Map) -> bool { + pub fn event(&mut self, input: &mut UserInput, map: &Map, osd: &mut TextOSD) -> bool { let mut new_state: Option = None; match self { WizardSample::Inactive => { @@ -44,7 +44,7 @@ impl WizardSample { } } WizardSample::Active(ref mut wizard) => { - if let Some(spec) = workflow(wizard.wrap(input, map)) { + if let Some(spec) = workflow(wizard.wrap(input, map, osd)) { println!("Got answer: {:?}", spec); new_state = Some(WizardSample::Inactive); } else if wizard.aborted() { @@ -62,18 +62,6 @@ impl WizardSample { } } - pub fn populate_osd(&self, osd: &mut TextOSD) { - match self { - WizardSample::Active(wizard) => { - if let Some(ref tb) = wizard.tb { - osd.pad_if_nonempty(); - tb.populate_osd(osd); - } - } - _ => {} - } - } - pub fn draw(&self, g: &mut GfxCtx, canvas: &Canvas) { // TODO nothing yet, but do show neighborhood preview later } @@ -120,7 +108,12 @@ impl Wizard { } } - fn wrap<'a>(&'a mut self, input: &'a mut UserInput, map: &'a Map) -> WrappedWizard<'a> { + fn wrap<'a>( + &'a mut self, + input: &'a mut UserInput, + map: &'a Map, + osd: &'a mut TextOSD, + ) -> WrappedWizard<'a> { assert!(self.alive); let ready_usize = VecDeque::from(self.state_usize.clone()); @@ -128,6 +121,7 @@ impl Wizard { wizard: self, input, map, + osd, ready_usize, } } @@ -136,7 +130,12 @@ impl Wizard { !self.alive } - fn input_usize(&mut self, query: &str, input: &mut UserInput) -> Option { + fn input_usize( + &mut self, + query: &str, + input: &mut UserInput, + osd: &mut TextOSD, + ) -> Option { assert!(self.alive); // Otherwise, we try to use one event for two inputs potentially @@ -148,21 +147,23 @@ impl Wizard { self.tb = Some(TextBox::new()); } - if self.tb.as_mut().unwrap().event(input.use_event_directly()) { - input.consume_event(); + let done = self.tb.as_mut().unwrap().event(input.use_event_directly()); + input.consume_event(); + if done { let line = self.tb.as_ref().unwrap().line.clone(); + self.tb = None; if let Some(num) = line.parse::().ok() { - self.tb = None; self.state_usize.push(num); Some(num) } else { println!("Invalid number {} -- assuming you meant to abort", line); - self.tb = None; self.alive = false; None } } else { - input.consume_event(); + osd.pad_if_nonempty(); + osd.add_line(query.to_string()); + self.tb.as_ref().unwrap().populate_osd(osd); None } } @@ -173,6 +174,7 @@ struct WrappedWizard<'a> { wizard: &'a mut Wizard, input: &'a mut UserInput, map: &'a Map, + osd: &'a mut TextOSD, ready_usize: VecDeque, } @@ -182,6 +184,6 @@ impl<'a> WrappedWizard<'a> { if !self.ready_usize.is_empty() { return self.ready_usize.pop_front(); } - self.wizard.input_usize(query, self.input) + self.wizard.input_usize(query, self.input, self.osd) } } diff --git a/editor/src/ui.rs b/editor/src/ui.rs index 074441bbb5..44f6f93a84 100644 --- a/editor/src/ui.rs +++ b/editor/src/ui.rs @@ -21,7 +21,6 @@ use plugins::debug_objects::DebugObjectsState; use plugins::draw_polygon::DrawPolygonState; use plugins::floodfill::Floodfiller; use plugins::follow::FollowState; -use plugins::wizard::WizardSample; use plugins::geom_validation::Validator; use plugins::hider::Hider; use plugins::road_editor::RoadEditor; @@ -33,6 +32,7 @@ use plugins::stop_sign_editor::StopSignEditor; use plugins::traffic_signal_editor::TrafficSignalEditor; use plugins::turn_cycler::TurnCyclerState; use plugins::warp::WarpState; +use plugins::wizard::WizardSample; use plugins::Colorizer; use render::{DrawMap, RenderOptions}; use sim; @@ -48,19 +48,19 @@ const MIN_ZOOM_FOR_MOUSEOVER: f64 = 4.0; // Necessary so we can iterate over and run the plugins, which mutably borrow UI. pub struct UIWrapper { ui: UI, - plugins: Vec bool>>, + plugins: Vec bool>>, } impl GUI for UIWrapper { - fn event(&mut self, input: &mut UserInput) -> EventLoopMode { - self.ui.event(input, &self.plugins) + fn event(&mut self, input: UserInput, osd: &mut TextOSD) -> EventLoopMode { + self.ui.event(input, osd, &self.plugins) } - fn draw(&mut self, g: &mut GfxCtx, input: UserInput, window_size: Size) { + fn draw(&mut self, g: &mut GfxCtx, osd: TextOSD, window_size: Size) { // Since self is mut here, we can set window_size on the canvas, but then let the real // draw() be immutable. self.ui.canvas.start_drawing(g, window_size); - self.ui.draw(g, input); + self.ui.draw(g, osd); } } @@ -155,7 +155,7 @@ impl UIWrapper { UIWrapper { ui, plugins: vec![ - Box::new(|ui, input| { + Box::new(|ui, input, _osd| { let layer_changed = { let mut changed = false; for layer in ui.toggleable_layers().into_iter() { @@ -173,7 +173,7 @@ impl UIWrapper { false } }), - Box::new(|ui, input| { + Box::new(|ui, input, _osd| { ui.traffic_signal_editor.event( input, &ui.map, @@ -181,7 +181,7 @@ impl UIWrapper { ui.current_selection, ) }), - Box::new(|ui, input| { + Box::new(|ui, input, _osd| { ui.stop_sign_editor.event( input, &ui.map, @@ -189,7 +189,7 @@ impl UIWrapper { ui.current_selection, ) }), - Box::new(|ui, input| { + Box::new(|ui, input, _osd| { ui.road_editor.event( input, ui.current_selection, @@ -199,17 +199,18 @@ impl UIWrapper { &mut ui.sim, ) }), - Box::new(|ui, input| ui.search_state.event(input)), - Box::new(|ui, input| { + Box::new(|ui, input, osd| ui.search_state.event(input, osd)), + Box::new(|ui, input, osd| { ui.warp.event( input, &ui.map, &ui.sim, &mut ui.canvas, &mut ui.current_selection, + osd, ) }), - Box::new(|ui, input| { + Box::new(|ui, input, _osd| { ui.follow.event( input, &ui.map, @@ -218,12 +219,16 @@ impl UIWrapper { ui.current_selection, ) }), - Box::new(|ui, input| ui.show_route.event(input, &ui.sim, ui.current_selection)), - Box::new(|ui, input| ui.color_picker.event(input, &mut ui.canvas, &mut ui.cs)), - Box::new(|ui, input| ui.steepness_viz.event(input)), - Box::new(|ui, input| ui.osm_classifier.event(input)), - Box::new(|ui, input| ui.hider.event(input, &mut ui.current_selection)), - Box::new(|ui, input| { + Box::new(|ui, input, _osd| { + ui.show_route.event(input, &ui.sim, ui.current_selection) + }), + Box::new(|ui, input, _osd| { + ui.color_picker.event(input, &mut ui.canvas, &mut ui.cs) + }), + Box::new(|ui, input, _osd| ui.steepness_viz.event(input)), + Box::new(|ui, input, _osd| ui.osm_classifier.event(input)), + Box::new(|ui, input, _osd| ui.hider.event(input, &mut ui.current_selection)), + Box::new(|ui, input, _osd| { ui.debug_objects.event( ui.current_selection, input, @@ -232,14 +237,16 @@ impl UIWrapper { &ui.control_map, ) }), - Box::new(|ui, input| ui.floodfiller.event(&ui.map, input, ui.current_selection)), - Box::new(|ui, input| { + Box::new(|ui, input, _osd| { + ui.floodfiller.event(&ui.map, input, ui.current_selection) + }), + Box::new(|ui, input, _osd| { ui.geom_validator .event(input, &mut ui.canvas, &ui.map, &ui.draw_map) }), - Box::new(|ui, input| ui.turn_cycler.event(input, ui.current_selection)), - Box::new(|ui, input| ui.draw_polygon.event(input, &ui.canvas, &ui.map)), - Box::new(|ui, input| ui.wizard_sample.event(input, &ui.map)), + Box::new(|ui, input, _osd| ui.turn_cycler.event(input, ui.current_selection)), + Box::new(|ui, input, osd| ui.draw_polygon.event(input, &ui.canvas, &ui.map, osd)), + Box::new(|ui, input, osd| ui.wizard_sample.event(input, &ui.map, osd)), ], } } @@ -322,8 +329,9 @@ impl UI { fn event( &mut self, - input: &mut UserInput, - plugins: &Vec bool>>, + mut input: UserInput, + osd: &mut TextOSD, + plugins: &Vec bool>>, ) -> EventLoopMode { // First update the camera and handle zoom let old_zoom = self.canvas.cam_zoom; @@ -349,13 +357,13 @@ impl UI { // If there's an active plugin, just run it. if let Some(idx) = self.active_plugin { - if !plugins[idx](self, input) { + if !plugins[idx](self, &mut input, osd) { self.active_plugin = None; } } else { // Run each plugin, short-circuiting if the plugin claimed it was active. for (idx, plugin) in plugins.iter().enumerate() { - if plugin(self, input) { + if plugin(self, &mut input, osd) { self.active_plugin = Some(idx); break; } @@ -381,16 +389,19 @@ impl UI { } // Sim controller plugin is kind of always active? If nothing else ran, let it use keys. - self.sim_ctrl.event( - input, + let result = self.sim_ctrl.event( + &mut input, &self.map, &self.control_map, &mut self.sim, self.current_selection, - ) + osd, + ); + input.populate_osd(osd); + result } - fn draw(&self, g: &mut GfxCtx, input: UserInput) { + fn draw(&self, g: &mut GfxCtx, osd: TextOSD) { g.clear(self.cs.get(Colors::Background)); let (statics, dynamics) = self.draw_map.get_objects_onscreen( @@ -453,14 +464,6 @@ impl UI { self.draw_polygon.draw(g, &self.canvas); self.wizard_sample.draw(g, &self.canvas); - // TODO Only if active (except for the weird sim_ctrl)? - let mut osd = TextOSD::new(); - input.populate_osd(&mut osd); - self.sim_ctrl.populate_osd(&self.sim, &mut osd); - self.search_state.populate_osd(&mut osd); - self.warp.populate_osd(&mut osd); - self.draw_polygon.populate_osd(&mut osd); - self.wizard_sample.populate_osd(&mut osd); self.canvas.draw_osd_notification(g, osd); } diff --git a/ezgui/src/runner.rs b/ezgui/src/runner.rs index 4fc59d8f8f..2a30e5a956 100644 --- a/ezgui/src/runner.rs +++ b/ezgui/src/runner.rs @@ -4,13 +4,11 @@ use opengl_graphics::{Filter, GlGraphics, GlyphCache, OpenGL, TextureSettings}; use piston::event_loop::{EventLoop, EventSettings, Events}; use piston::input::RenderEvent; use piston::window::{Size, Window, WindowSettings}; -use GfxCtx; +use {GfxCtx, TextOSD}; pub trait GUI { - fn event(&mut self, input: &mut UserInput) -> EventLoopMode; - - // TODO just take OSD stuff, not all of the input - fn draw(&mut self, g: &mut GfxCtx, input: UserInput, window_size: Size); + fn event(&mut self, input: UserInput, osd: &mut TextOSD) -> EventLoopMode; + fn draw(&mut self, g: &mut GfxCtx, osd: TextOSD, window_size: Size); } #[derive(PartialEq)] @@ -41,8 +39,8 @@ pub fn run(mut gui: T, window_title: &str, initial_width: u32, initial_h let mut last_event_mode = EventLoopMode::InputOnly; while let Some(ev) = events.next(&mut window) { - let mut input = UserInput::new(ev.clone()); - let new_event_mode = gui.event(&mut input); + let mut osd = TextOSD::new(); + let new_event_mode = gui.event(UserInput::new(ev.clone()), &mut osd); // Don't constantly reset the events struct -- only when laziness changes. if new_event_mode != last_event_mode { events.set_lazy(new_event_mode == EventLoopMode::InputOnly); @@ -51,11 +49,7 @@ pub fn run(mut gui: T, window_title: &str, initial_width: u32, initial_h if let Some(args) = ev.render_args() { gl.draw(args.viewport(), |c, g| { - gui.draw( - &mut GfxCtx::new(&mut glyphs, g, c), - input, - window.draw_size(), - ); + gui.draw(&mut GfxCtx::new(&mut glyphs, g, c), osd, window.draw_size()); }); } } diff --git a/ezgui/src/text_box.rs b/ezgui/src/text_box.rs index f3545f95a4..02788c2061 100644 --- a/ezgui/src/text_box.rs +++ b/ezgui/src/text_box.rs @@ -32,6 +32,7 @@ impl TextBox { // TODO a way to abort out // Returns true if the user confirmed their entry. + // TODO return the entered string if done... pub fn event(&mut self, ev: &Event) -> bool { // Done? if let Some(Button::Keyboard(Key::Return)) = ev.press_args() { diff --git a/playground_gui/src/main.rs b/playground_gui/src/main.rs index c32c62a6e4..a125fff548 100644 --- a/playground_gui/src/main.rs +++ b/playground_gui/src/main.rs @@ -4,7 +4,7 @@ extern crate graphics; extern crate map_model; extern crate piston; -use ezgui::{Canvas, EventLoopMode, GfxCtx, UserInput, GUI}; +use ezgui::{Canvas, EventLoopMode, GfxCtx, TextOSD, UserInput, GUI}; use geom::{Circle, PolyLine, Polygon, Pt2D}; use graphics::types::Color; use map_model::LANE_THICKNESS; @@ -44,7 +44,7 @@ impl UI { } impl GUI for UI { - fn event(&mut self, input: &mut UserInput) -> EventLoopMode { + fn event(&mut self, mut input: UserInput, _osd: &mut TextOSD) -> EventLoopMode { if input.unimportant_key_pressed(Key::Escape, "quit") { process::exit(0); } @@ -71,7 +71,7 @@ impl GUI for UI { } // TODO Weird to mut self just to set window_size on the canvas - fn draw(&mut self, g: &mut GfxCtx, _input: UserInput, window_size: Size) { + fn draw(&mut self, g: &mut GfxCtx, _osd: TextOSD, window_size: Size) { g.clear(WHITE); self.canvas.start_drawing(g, window_size);