plumbing window_size with canvas

This commit is contained in:
Dustin Carlino 2018-07-06 10:02:01 -07:00
parent 10dfceb4ec
commit 8f244438c1
10 changed files with 75 additions and 73 deletions

View File

@ -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?

View File

@ -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();

View File

@ -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);
}

View File

@ -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<T: gui::GUI>(
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<T: gui::GUI>(
gfx: g,
orig_ctx: c,
ctx: c,
window_size: window.draw_size(),
},
input,
window.draw_size(),
);
});
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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());
}

View File

@ -73,7 +73,7 @@ pub struct UI {
}
impl UI {
pub fn new(abst_path: &str, window_size: &Size, rng_seed: Option<u8>) -> UI {
pub fn new(abst_path: &str, window_size: Size, rng_seed: Option<u8>) -> 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<ID> {
fn mouseover_something(&self) -> Option<ID> {
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) {

View File

@ -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,
},
}
}

View File

@ -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<Texture = G::Texture>> {
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 {