From 8f244438c1dc8d58e4003a7f19895459753c096d Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Fri, 6 Jul 2018 10:02:01 -0700 Subject: [PATCH] plumbing window_size with canvas --- docs/lanes.md | 14 +++++++++++ editor/src/experimental.rs | 16 ++++++------ editor/src/gui.rs | 4 +-- editor/src/main.rs | 16 ++++++++---- editor/src/plugins/color_picker.rs | 13 +++++----- editor/src/plugins/geom_validation.rs | 11 ++------- editor/src/plugins/warp.rs | 14 +++-------- editor/src/ui.rs | 35 ++++++++++++--------------- ezgui/src/canvas.rs | 23 +++++++++++------- ezgui/src/lib.rs | 2 -- 10 files changed, 75 insertions(+), 73 deletions(-) diff --git a/docs/lanes.md b/docs/lanes.md index 36d8070c8c..f796c3b1fd 100644 --- a/docs/lanes.md +++ b/docs/lanes.md @@ -168,3 +168,17 @@ Traffic signals? - drawing turn icons as red/yellow/green is pretty clear... - could draw an unaligned signal box with 3 circles in the middle of the intersection, but what does it represent? maybe just an initial indicator of what's going on; not full detail. - similarly, draw a single stop sign in the middle of other intersections? :P + + + + +GUI refactoring thoughts: +- GfxCtx members should be private. make methods for drawing rectangles and such + - should be useful short term. dunno how this will look later with gfx-rs, but dedupes code in the meantime. +- should GfxCtx own Canvas or vice versa? + - Canvas has persistent state, GfxCtx is ephemeral every draw cycle + - dont want to draw outside of render, but may want to readjust camera + - compromise is maybe storing the last known window size in canvas, so we dont have to keep plumbing it between frames anyway. + + +should GfxCtx own canvas? diff --git a/editor/src/experimental.rs b/editor/src/experimental.rs index 9dfe8800e8..ae14cb629d 100644 --- a/editor/src/experimental.rs +++ b/editor/src/experimental.rs @@ -26,9 +26,9 @@ pub struct UI { } impl UI { - pub fn new() -> UI { + pub fn new(window_size: Size) -> UI { UI { - canvas: Canvas::new(), + canvas: Canvas::new(window_size), p3_offset: (200.0, 150.0), show_labels: true, } @@ -36,11 +36,7 @@ impl UI { } impl gui::GUI for UI { - fn event( - mut self, - input: &mut UserInput, - _window_size: &Size, - ) -> (UI, animation::EventLoopMode) { + fn event(mut self, input: &mut UserInput) -> (UI, animation::EventLoopMode) { if input.unimportant_key_pressed(Key::Escape, "Press escape to quit") { process::exit(0); } @@ -66,9 +62,11 @@ impl gui::GUI for UI { (self, animation::EventLoopMode::InputOnly) } - fn draw(&self, g: &mut GfxCtx, _input: UserInput) { + // 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) { graphics::clear(WHITE, g.gfx); - g.ctx = self.canvas.get_transformed_context(&g.orig_ctx); + g.ctx = self.canvas + .get_transformed_context(&g.orig_ctx, window_size); let mut labels: Vec<(Pt2D, String)> = Vec::new(); diff --git a/editor/src/gui.rs b/editor/src/gui.rs index 766316d157..b73868c598 100644 --- a/editor/src/gui.rs +++ b/editor/src/gui.rs @@ -5,10 +5,10 @@ use piston::window::Size; use std; pub trait GUI { - fn event(self, input: &mut UserInput, window_size: &Size) -> (Self, animation::EventLoopMode) + fn event(self, input: &mut UserInput) -> (Self, animation::EventLoopMode) where Self: std::marker::Sized; // TODO just take OSD stuff, not all of the input - fn draw(&self, g: &mut GfxCtx, input: UserInput); + fn draw(&mut self, g: &mut GfxCtx, input: UserInput, window_size: Size); } diff --git a/editor/src/main.rs b/editor/src/main.rs index 72872c944c..a0bf4cbbdc 100644 --- a/editor/src/main.rs +++ b/editor/src/main.rs @@ -80,16 +80,22 @@ fn main() { texture_settings, ).expect("Could not load font"); - let size = &window.draw_size(); + let window_size = window.draw_size(); if flags.experimental_gui { - run(events, window, gl, glyphs, experimental::UI::new()); + run( + events, + window, + gl, + glyphs, + experimental::UI::new(window_size), + ); } else { run( events, window, gl, glyphs, - ui::UI::new(&flags.abst_input, size, flags.rng_seed), + ui::UI::new(&flags.abst_input, window_size, flags.rng_seed), ); } } @@ -105,7 +111,7 @@ fn run( while let Some(ev) = events.next(&mut window) { let mut input = UserInput::new(ev.clone()); - let (new_gui, new_event_mode) = gui.event(&mut input, &window.draw_size()); + let (new_gui, new_event_mode) = gui.event(&mut input); gui = new_gui; // Don't constantly reset the events struct -- only when laziness changes. if new_event_mode != last_event_mode { @@ -121,9 +127,9 @@ fn run( gfx: g, orig_ctx: c, ctx: c, - window_size: window.draw_size(), }, input, + window.draw_size(), ); }); } diff --git a/editor/src/plugins/color_picker.rs b/editor/src/plugins/color_picker.rs index af88723244..db62e737c3 100644 --- a/editor/src/plugins/color_picker.rs +++ b/editor/src/plugins/color_picker.rs @@ -7,7 +7,6 @@ use ezgui::input::UserInput; use ezgui::menu; use graphics; use piston::input::{Key, MouseCursorEvent}; -use piston::window::Size; use std::str::FromStr; use std::string::ToString; use strum::IntoEnumIterator; @@ -33,7 +32,7 @@ impl ColorPicker { pub fn handle_event( self, input: &mut UserInput, - window_size: &Size, + canvas: &Canvas, cs: &mut ColorScheme, ) -> ColorPicker { match self { @@ -78,7 +77,7 @@ impl ColorPicker { if let Some(pos) = input.use_event_directly().mouse_cursor_args() { // TODO argh too much casting - let (start_x, start_y) = get_screen_offset(window_size); + let (start_x, start_y) = get_screen_offset(canvas); let x = (pos[0] - (start_x as f64)) / (TILE_DIMS as f64) / 255.0; let y = (pos[1] - (start_y as f64)) / (TILE_DIMS as f64) / 255.0; if x >= 0.0 && x <= 1.0 && y >= 0.0 && y <= 1.0 { @@ -102,7 +101,7 @@ impl ColorPicker { canvas.draw_mouse_tooltip(g, &menu.lines_to_display()); } ColorPicker::PickingColor(_, _) => { - let (start_x, start_y) = get_screen_offset(&g.window_size); + let (start_x, start_y) = get_screen_offset(canvas); for x in 0..WIDTH { for y in 0..HEIGHT { @@ -126,11 +125,11 @@ impl ColorPicker { } } -fn get_screen_offset(window_size: &Size) -> (u32, u32) { +fn get_screen_offset(canvas: &Canvas) -> (u32, u32) { let total_width = TILE_DIMS * WIDTH; let total_height = TILE_DIMS * HEIGHT; - let start_x = (window_size.width - total_width) / 2; - let start_y = (window_size.height - total_height) / 2; + let start_x = (canvas.window_size.width - total_width) / 2; + let start_y = (canvas.window_size.height - total_height) / 2; (start_x, start_y) } diff --git a/editor/src/plugins/geom_validation.rs b/editor/src/plugins/geom_validation.rs index 718e42107d..c5c312729d 100644 --- a/editor/src/plugins/geom_validation.rs +++ b/editor/src/plugins/geom_validation.rs @@ -7,7 +7,6 @@ use geom::Pt2D; use graphics::math::Vec2d; use map_model::{geometry, BuildingID, IntersectionID, Map, ParcelID, RoadID}; use piston::input::Key; -use piston::window::Size; use render; #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] @@ -86,13 +85,7 @@ impl Validator { } } - pub fn event( - &mut self, - input: &mut UserInput, - canvas: &mut Canvas, - window_size: &Size, - map: &Map, - ) -> bool { + pub fn event(&mut self, input: &mut UserInput, canvas: &mut Canvas, map: &Map) -> bool { // Initialize or advance? if !self.current_problem.is_some() || input.key_pressed(Key::N, "Press N to see the next problem") @@ -102,7 +95,7 @@ impl Validator { if let Some((id1, id2)) = self.current_problem { println!("{:?} and {:?} intersect", id1, id2); let pt = get_pt(map, id1); - canvas.center_on_map_pt(pt.x(), pt.y(), window_size); + canvas.center_on_map_pt(pt.x(), pt.y()); // TODO also modify selection state to highlight stuff? return false; } else { diff --git a/editor/src/plugins/warp.rs b/editor/src/plugins/warp.rs index e50e19eaa6..d32024c707 100644 --- a/editor/src/plugins/warp.rs +++ b/editor/src/plugins/warp.rs @@ -3,7 +3,6 @@ use ezgui::input::UserInput; use ezgui::text_box::TextBox; use map_model::{geometry, BuildingID, IntersectionID, Map, ParcelID, RoadID}; use piston::input::Key; -use piston::window::Size; use plugins::selection::SelectionState; use std::usize; @@ -18,7 +17,6 @@ impl WarpState { input: &mut UserInput, map: &Map, canvas: &mut Canvas, - window_size: &Size, selection_state: &mut SelectionState, ) -> WarpState { match self { @@ -35,7 +33,7 @@ impl WarpState { WarpState::EnteringSearch(mut tb) => { if tb.event(input.use_event_directly()) { input.consume_event(); - warp(tb.line, map, canvas, window_size, selection_state); + warp(tb.line, map, canvas, selection_state); WarpState::Empty } else { input.consume_event(); @@ -54,13 +52,7 @@ impl WarpState { } } -fn warp( - line: String, - map: &Map, - canvas: &mut Canvas, - window_size: &Size, - selection_state: &mut SelectionState, -) { +fn warp(line: String, map: &Map, canvas: &mut Canvas, selection_state: &mut SelectionState) { let pt = match usize::from_str_radix(&line[1..line.len()], 10) { Ok(idx) => match line.chars().next().unwrap() { 'r' => { @@ -92,5 +84,5 @@ fn warp( return; } }; - canvas.center_on_map_pt(pt.x(), pt.y(), window_size); + canvas.center_on_map_pt(pt.x(), pt.y()); } diff --git a/editor/src/ui.rs b/editor/src/ui.rs index bfcbf57e6c..5aab9a9ab9 100644 --- a/editor/src/ui.rs +++ b/editor/src/ui.rs @@ -73,7 +73,7 @@ pub struct UI { } impl UI { - pub fn new(abst_path: &str, window_size: &Size, rng_seed: Option) -> UI { + pub fn new(abst_path: &str, window_size: Size, rng_seed: Option) -> UI { println!("Opening {}", abst_path); let map = map_model::Map::new(abst_path).expect("Couldn't load map"); let (draw_map, center_pt) = render::DrawMap::new(&map); @@ -119,7 +119,7 @@ impl UI { color_picker: ColorPicker::new(), geom_validator: None, - canvas: Canvas::new(), + canvas: Canvas::new(window_size), cs: ColorScheme::load("color_scheme").unwrap(), }; @@ -134,8 +134,7 @@ impl UI { } Err(_) => { println!("Couldn't load editor_state, just centering initial view"); - ui.canvas - .center_on_map_pt(center_pt.x(), center_pt.y(), window_size); + ui.canvas.center_on_map_pt(center_pt.x(), center_pt.y()); } } @@ -155,10 +154,10 @@ impl UI { self.debug_mode.handle_zoom(old_zoom, new_zoom); } - fn mouseover_something(&self, window_size: &Size) -> Option { + fn mouseover_something(&self) -> Option { let (x, y) = self.canvas.get_cursor_in_map_space(); - let screen_bbox = self.canvas.get_screen_bbox(window_size); + let screen_bbox = self.canvas.get_screen_bbox(); let roads_onscreen = if self.show_roads.is_enabled() { self.draw_map.get_roads_onscreen(screen_bbox, &self.hider) @@ -329,11 +328,7 @@ impl UI { } impl gui::GUI for UI { - fn event( - mut self, - input: &mut UserInput, - window_size: &Size, - ) -> (UI, animation::EventLoopMode) { + fn event(mut self, input: &mut UserInput) -> (UI, animation::EventLoopMode) { let mut event_loop_mode = animation::EventLoopMode::InputOnly; let mut edit_mode = false; @@ -368,8 +363,9 @@ impl gui::GUI for UI { // TODO disabling temporarily since it conflicts with warp. need to solve the // one-plugin-at-a-time problem. if !edit_mode && false { - self.color_picker = self.color_picker - .handle_event(input, window_size, &mut self.cs); + self.color_picker = + self.color_picker + .handle_event(input, &mut self.canvas, &mut self.cs); } self.current_search_state = self.current_search_state.event(input); @@ -377,7 +373,6 @@ impl gui::GUI for UI { input, &self.map, &mut self.canvas, - window_size, &mut self.current_selection_state, ); @@ -422,7 +417,7 @@ impl gui::GUI for UI { if !self.canvas.is_dragging() && input.use_event_directly().mouse_cursor_args().is_some() && new_zoom >= MIN_ZOOM_FOR_MOUSEOVER { - let item = self.mouseover_something(window_size); + let item = self.mouseover_something(); self.current_selection_state = self.current_selection_state.handle_mouseover(item); } self.hider.event(input, &mut self.current_selection_state); @@ -479,7 +474,7 @@ impl gui::GUI for UI { } if let Some(mut v) = self.geom_validator { - if v.event(input, &mut self.canvas, window_size, &self.map) { + if v.event(input, &mut self.canvas, &self.map) { self.geom_validator = None; } else { self.geom_validator = Some(v); @@ -512,12 +507,14 @@ impl gui::GUI for UI { (self, event_loop_mode) } - fn draw(&self, g: &mut GfxCtx, input: UserInput) { + // 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) { graphics::clear(self.cs.get(Colors::Background), g.gfx); - g.ctx = self.canvas.get_transformed_context(&g.orig_ctx); + g.ctx = self.canvas + .get_transformed_context(&g.orig_ctx, window_size); - let screen_bbox = self.canvas.get_screen_bbox(&g.window_size); + let screen_bbox = self.canvas.get_screen_bbox(); if self.show_parcels.is_enabled() { for p in &self.draw_map.get_parcels_onscreen(screen_bbox) { diff --git a/ezgui/src/canvas.rs b/ezgui/src/canvas.rs index caa0ed962e..d0f601c6df 100644 --- a/ezgui/src/canvas.rs +++ b/ezgui/src/canvas.rs @@ -20,10 +20,12 @@ pub struct Canvas { cursor_y: f64, left_mouse_drag_from: Option<[f64; 2]>, + + pub window_size: Size, } impl Canvas { - pub fn new() -> Canvas { + pub fn new(window_size: Size) -> Canvas { Canvas { cam_x: 0.0, cam_y: 0.0, @@ -33,6 +35,7 @@ impl Canvas { cursor_y: 0.0, left_mouse_drag_from: None, + window_size, } } @@ -73,7 +76,9 @@ impl Canvas { } } - pub fn get_transformed_context(&self, ctx: &Context) -> Context { + // TODO rename + pub fn get_transformed_context(&mut self, ctx: &Context, window_size: Size) -> Context { + self.window_size = window_size; ctx.trans(-self.cam_x, -self.cam_y).zoom(self.cam_zoom) } @@ -90,7 +95,7 @@ impl Canvas { return; } let (_, height) = text::dims(g, lines); - let y1 = f64::from(g.window_size.height) - height; + let y1 = f64::from(self.window_size.height) - height; text::draw_text_bubble(g, lines, 0.0, y1); } @@ -124,9 +129,9 @@ impl Canvas { (y + self.cam_y) / self.cam_zoom } - pub fn center_on_map_pt(&mut self, x: f64, y: f64, window_size: &Size) { - self.cam_x = (x * self.cam_zoom) - (f64::from(window_size.width) / 2.0); - self.cam_y = (y * self.cam_zoom) - (f64::from(window_size.height) / 2.0); + pub fn center_on_map_pt(&mut self, x: f64, y: f64) { + self.cam_x = (x * self.cam_zoom) - (f64::from(self.window_size.width) / 2.0); + self.cam_y = (y * self.cam_zoom) - (f64::from(self.window_size.height) / 2.0); } fn map_to_screen_x(&self, x: f64) -> f64 { @@ -137,15 +142,15 @@ impl Canvas { } // little weird to return an aabb_quadtree type here. need standard geometry types - pub fn get_screen_bbox(&self, window_size: &Size) -> Rect { + pub fn get_screen_bbox(&self) -> Rect { Rect { top_left: Point { x: self.screen_to_map_x(0.0) as f32, y: self.screen_to_map_y(0.0) as f32, }, bottom_right: Point { - x: self.screen_to_map_x(f64::from(window_size.width)) as f32, - y: self.screen_to_map_y(f64::from(window_size.height)) as f32, + x: self.screen_to_map_x(f64::from(self.window_size.width)) as f32, + y: self.screen_to_map_y(f64::from(self.window_size.height)) as f32, }, } } diff --git a/ezgui/src/lib.rs b/ezgui/src/lib.rs index 165473c5e1..6c4508a582 100644 --- a/ezgui/src/lib.rs +++ b/ezgui/src/lib.rs @@ -15,7 +15,6 @@ use graphics::Context; use graphics::character::CharacterCache; use opengl_graphics::{GlGraphics, Texture}; use piston::input::Key; -use piston::window::Size; //struct GfxCtx<'a, G: 'a + Graphics, C: 'a + CharacterCache> { pub struct GfxCtx<'a> { @@ -23,7 +22,6 @@ pub struct GfxCtx<'a> { pub orig_ctx: Context, pub ctx: Context, pub gfx: &'a mut GlGraphics, - pub window_size: Size, } pub struct ToggleableLayer {