consistently having one(ish) plugin do stuff at a time

This commit is contained in:
Dustin Carlino 2018-07-06 11:23:53 -07:00
parent e2aabeb0e9
commit 18132e3c8b
13 changed files with 238 additions and 218 deletions

View File

@ -179,3 +179,15 @@ GUI refactoring thoughts:
- 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.
One UI plugin at a time:
- What can plugins do?
- (rarely) contribute OSD lines (in some order)
- (rarely) do custom drawing (in some order)
- event handling
- mutate themselves or consume+return?
- indicate if the plugin was active and did stuff?
- just quit after handling each plugin? and do panning / some selection stuff earlier
- alright, atfer the current cleanup with short-circuiting... express as a more abstract monadish thing? or since there are side effects sometimes and inconsistent arguments and such, maybe not?
- consistently mutate a plugin or return a copy

View File

@ -1,16 +0,0 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
#[derive(PartialEq)]
pub enum EventLoopMode {
Animation,
InputOnly,
}
impl EventLoopMode {
pub fn merge(self, other: EventLoopMode) -> EventLoopMode {
match self {
EventLoopMode::Animation => EventLoopMode::Animation,
_ => other,
}
}
}

View File

@ -1,4 +1,3 @@
use animation;
use ezgui::GfxCtx;
use ezgui::canvas::Canvas;
use ezgui::input::UserInput;
@ -36,7 +35,7 @@ impl UI {
}
impl gui::GUI for UI {
fn event(mut self, input: &mut UserInput) -> (UI, animation::EventLoopMode) {
fn event(mut self, input: &mut UserInput) -> (UI, gui::EventLoopMode) {
if input.unimportant_key_pressed(Key::Escape, "Press escape to quit") {
process::exit(0);
}
@ -59,7 +58,7 @@ impl gui::GUI for UI {
self.canvas.handle_event(input.use_event_directly());
(self, animation::EventLoopMode::InputOnly)
(self, gui::EventLoopMode::InputOnly)
}
// TODO Weird to mut self just to set window_size on the canvas

View File

@ -1,14 +1,19 @@
use animation;
use ezgui::GfxCtx;
use ezgui::input::UserInput;
use piston::window::Size;
use std;
pub trait GUI {
fn event(self, input: &mut UserInput) -> (Self, animation::EventLoopMode)
fn event(self, input: &mut UserInput) -> (Self, EventLoopMode)
where
Self: std::marker::Sized;
// TODO just take OSD stuff, not all of the input
fn draw(&mut self, g: &mut GfxCtx, input: UserInput, window_size: Size);
}
#[derive(PartialEq)]
pub enum EventLoopMode {
Animation,
InputOnly,
}

View File

@ -34,7 +34,6 @@ use piston::input::RenderEvent;
use piston::window::{Window, WindowSettings};
use structopt::StructOpt;
mod animation;
mod colors;
mod experimental;
mod gui;
@ -107,7 +106,7 @@ fn run<T: gui::GUI>(
mut glyphs: GlyphCache,
mut gui: T,
) {
let mut last_event_mode = animation::EventLoopMode::InputOnly;
let mut last_event_mode = gui::EventLoopMode::InputOnly;
while let Some(ev) = events.next(&mut window) {
let mut input = UserInput::new(ev.clone());
@ -115,7 +114,7 @@ fn run<T: gui::GUI>(
gui = new_gui;
// Don't constantly reset the events struct -- only when laziness changes.
if new_event_mode != last_event_mode {
events.set_lazy(new_event_mode == animation::EventLoopMode::InputOnly);
events.set_lazy(new_event_mode == gui::EventLoopMode::InputOnly);
last_event_mode = new_event_mode;
}

View File

@ -16,7 +16,7 @@ impl OsmClassifier {
OsmClassifier { active: false }
}
pub fn handle_event(&mut self, input: &mut UserInput) {
pub fn handle_event(&mut self, input: &mut UserInput) -> bool {
let msg = if self.active {
"Press 6 to stop showing OSM classes"
} else {
@ -24,6 +24,9 @@ impl OsmClassifier {
};
if input.unimportant_key_pressed(Key::D6, msg) {
self.active = !self.active;
true
} else {
false
}
}

View File

@ -29,29 +29,33 @@ impl ColorPicker {
ColorPicker::Inactive
}
// True if plugin was active
pub fn handle_event(
self,
input: &mut UserInput,
canvas: &Canvas,
cs: &mut ColorScheme,
) -> ColorPicker {
) -> (ColorPicker, bool) {
match self {
ColorPicker::Inactive => {
if input.unimportant_key_pressed(Key::D8, "Press 8 to configure colors") {
return ColorPicker::Choosing(menu::Menu::new(
Colors::iter().map(|c| c.to_string()).collect(),
));
return (
ColorPicker::Choosing(menu::Menu::new(
Colors::iter().map(|c| c.to_string()).collect(),
)),
true,
);
}
ColorPicker::Inactive
(ColorPicker::Inactive, false)
}
ColorPicker::Choosing(mut menu) => {
// TODO arrow keys scroll canvas too
match menu.event(input.use_event_directly()) {
menu::Result::Canceled => ColorPicker::Inactive,
menu::Result::StillActive => ColorPicker::Choosing(menu),
menu::Result::Canceled => (ColorPicker::Inactive, true),
menu::Result::StillActive => (ColorPicker::Choosing(menu), true),
menu::Result::Done(choice) => {
let c = Colors::from_str(&choice).unwrap();
ColorPicker::PickingColor(c, cs.get(c))
(ColorPicker::PickingColor(c, cs.get(c)), true)
}
}
}
@ -64,7 +68,7 @@ impl ColorPicker {
),
) {
cs.set(c, orig_color);
return ColorPicker::Inactive;
return (ColorPicker::Inactive, true);
}
if input.key_pressed(
@ -72,7 +76,7 @@ impl ColorPicker {
&format!("Press enter to finalize new color for {:?}", c),
) {
println!("Setting color for {:?}", c);
return ColorPicker::Inactive;
return (ColorPicker::Inactive, true);
}
if let Some(pos) = input.use_event_directly().mouse_cursor_args() {
@ -82,11 +86,11 @@ impl ColorPicker {
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 {
cs.set(c, get_color(x as f32, y as f32));
return ColorPicker::PickingColor(c, orig_color);
return (ColorPicker::PickingColor(c, orig_color), true);
}
}
ColorPicker::PickingColor(c, orig_color)
(ColorPicker::PickingColor(c, orig_color), true)
}
}
}
@ -109,8 +113,8 @@ impl ColorPicker {
g.draw_rectangle(
color,
[
(x * TILE_DIMS + start_x) as f64,
(y * TILE_DIMS + start_y) as f64,
canvas.screen_to_map_x((x * TILE_DIMS + start_x) as f64),
canvas.screen_to_map_y((y * TILE_DIMS + start_y) as f64),
TILE_DIMS as f64,
TILE_DIMS as f64,
],

View File

@ -34,22 +34,23 @@ impl SearchState {
}
// TODO Does this pattern where we consume self and return it work out nicer?
pub fn event(self, input: &mut UserInput) -> SearchState {
// True if active
pub fn event(self, input: &mut UserInput) -> (SearchState, bool) {
match self {
SearchState::Empty => {
if input.unimportant_key_pressed(Key::Slash, "Press / to start searching") {
SearchState::EnteringSearch(TextBox::new())
(SearchState::EnteringSearch(TextBox::new()), true)
} else {
self
(self, false)
}
}
SearchState::EnteringSearch(mut tb) => {
if tb.event(input.use_event_directly()) {
input.consume_event();
SearchState::FilterOSM(tb.line)
(SearchState::FilterOSM(tb.line), true)
} else {
input.consume_event();
SearchState::EnteringSearch(tb)
(SearchState::EnteringSearch(tb), true)
}
}
SearchState::FilterOSM(filter) => {
@ -57,9 +58,9 @@ impl SearchState {
Key::Return,
&format!("Press enter to clear the current search for {}", filter),
) {
SearchState::Empty
(SearchState::Empty, true)
} else {
SearchState::FilterOSM(filter)
(SearchState::FilterOSM(filter), true)
}
}
}

View File

@ -1,6 +1,5 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use animation;
use colors::{ColorScheme, Colors};
use control::ControlMap;
use ezgui::GfxCtx;
@ -26,6 +25,7 @@ pub enum ID {
//Parcel(ParcelID),
}
#[derive(Clone)]
pub enum SelectionState {
Empty,
SelectedIntersection(IntersectionID),
@ -57,28 +57,15 @@ impl SelectionState {
}
// TODO consume self
pub fn event(
&self,
input: &mut UserInput,
map: &Map,
sim: &mut Sim,
) -> (SelectionState, animation::EventLoopMode) {
pub fn event(&self, input: &mut UserInput, map: &Map) -> (SelectionState, bool) {
// TODO simplify the way this is written
match *self {
SelectionState::Empty => (SelectionState::Empty, animation::EventLoopMode::InputOnly),
SelectionState::SelectedIntersection(id) => (
SelectionState::SelectedIntersection(id),
animation::EventLoopMode::InputOnly,
),
SelectionState::SelectedRoad(id, current_turn_index) => {
if input.key_pressed(
Key::LCtrl,
&format!("Hold Ctrl to show road {:?}'s tooltip", id),
) {
(
SelectionState::TooltipRoad(id),
animation::EventLoopMode::InputOnly,
)
(SelectionState::TooltipRoad(id), true)
} else if input
.key_pressed(Key::Tab, "Press Tab to cycle through this road's turns")
{
@ -86,58 +73,24 @@ impl SelectionState {
Some(i) => i + 1,
None => 0,
};
(
SelectionState::SelectedRoad(id, Some(idx)),
animation::EventLoopMode::InputOnly,
)
(SelectionState::SelectedRoad(id, Some(idx)), true)
} else if input.key_pressed(Key::D, "press D to debug") {
map.get_r(id).dump_debug();
(
SelectionState::SelectedRoad(id, current_turn_index),
animation::EventLoopMode::InputOnly,
)
(SelectionState::SelectedRoad(id, current_turn_index), true)
} else {
(
SelectionState::SelectedRoad(id, current_turn_index),
animation::EventLoopMode::InputOnly,
)
(self.clone(), false)
}
}
SelectionState::TooltipRoad(id) => {
if let Some(Button::Keyboard(Key::LCtrl)) =
input.use_event_directly().release_args()
{
(
SelectionState::SelectedRoad(id, None),
animation::EventLoopMode::InputOnly,
)
(SelectionState::SelectedRoad(id, None), true)
} else {
(
SelectionState::TooltipRoad(id),
animation::EventLoopMode::InputOnly,
)
(self.clone(), false)
}
}
SelectionState::SelectedBuilding(id) => (
SelectionState::SelectedBuilding(id),
animation::EventLoopMode::InputOnly,
),
SelectionState::SelectedTurn(id) => (
SelectionState::SelectedTurn(id),
animation::EventLoopMode::InputOnly,
),
SelectionState::SelectedCar(id) => {
// TODO not sure if we should debug like this (pushing the bit down to all the
// layers representing an entity) or by using some scary global mutable singleton
if input.unimportant_key_pressed(Key::D, "press D to debug") {
sim.toggle_debug(id);
}
(
SelectionState::SelectedCar(id),
animation::EventLoopMode::InputOnly,
)
}
_ => (self.clone(), false),
}
}
@ -248,10 +201,11 @@ impl Hider {
}
}
pub fn event(&mut self, input: &mut UserInput, state: &mut SelectionState) {
pub fn event(&mut self, input: &mut UserInput, state: &mut SelectionState) -> bool {
if input.unimportant_key_pressed(Key::K, "Press k to unhide everything") {
println!("Unhiding {} things", self.items.len());
self.items.clear();
return true;
}
let item = match state {
@ -265,8 +219,10 @@ impl Hider {
self.items.insert(id);
println!("Hiding {:?}", id);
*state = SelectionState::Empty;
return true;
}
}
false
}
pub fn show_r(&self, id: RoadID) -> bool {

View File

@ -33,7 +33,7 @@ impl SteepnessVisualizer {
s
}
pub fn handle_event(&mut self, input: &mut UserInput) {
pub fn handle_event(&mut self, input: &mut UserInput) -> bool {
let msg = if self.active {
"Press 5 to stop showing steepness"
} else {
@ -41,6 +41,9 @@ impl SteepnessVisualizer {
};
if input.unimportant_key_pressed(Key::D5, msg) {
self.active = !self.active;
true
} else {
false
}
}

View File

@ -12,32 +12,33 @@ pub enum WarpState {
}
impl WarpState {
// True if active
pub fn event(
self,
input: &mut UserInput,
map: &Map,
canvas: &mut Canvas,
selection_state: &mut SelectionState,
) -> WarpState {
) -> (WarpState, bool) {
match self {
WarpState::Empty => {
if input.unimportant_key_pressed(
Key::J,
"Press J to start searching for something to warp to",
) {
WarpState::EnteringSearch(TextBox::new())
(WarpState::EnteringSearch(TextBox::new()), true)
} else {
self
(self, false)
}
}
WarpState::EnteringSearch(mut tb) => {
if tb.event(input.use_event_directly()) {
input.consume_event();
warp(tb.line, map, canvas, selection_state);
WarpState::Empty
(WarpState::Empty, true)
} else {
input.consume_event();
WarpState::EnteringSearch(tb)
(WarpState::EnteringSearch(tb), true)
}
}
}

View File

@ -3,7 +3,6 @@
// TODO this should just be a way to handle interactions between plugins
use abstutil;
use animation;
use colors::{ColorScheme, Colors};
use control::ControlMap;
use control::{ModifiedStopSign, ModifiedTrafficSignal};
@ -52,7 +51,10 @@ pub struct UI {
show_icons: ToggleableLayer,
debug_mode: ToggleableLayer,
// This is a particularly special plugin, since it's always kind of active and other things
// read/write it.
current_selection_state: SelectionState,
hider: Hider,
current_search_state: SearchState,
warp: WarpState,
@ -327,12 +329,25 @@ impl UI {
}
impl gui::GUI for UI {
fn event(mut self, input: &mut UserInput) -> (UI, animation::EventLoopMode) {
let mut event_loop_mode = animation::EventLoopMode::InputOnly;
let mut edit_mode = false;
fn event(mut self, input: &mut UserInput) -> (UI, gui::EventLoopMode) {
// First update the camera and handle zoom
let old_zoom = self.canvas.cam_zoom;
self.canvas.handle_event(input.use_event_directly());
let new_zoom = self.canvas.cam_zoom;
self.zoom_for_toggleable_layers(old_zoom, new_zoom);
// Always handle mouseover
if old_zoom >= MIN_ZOOM_FOR_MOUSEOVER && new_zoom < MIN_ZOOM_FOR_MOUSEOVER {
self.current_selection_state = SelectionState::Empty;
}
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();
self.current_selection_state = self.current_selection_state.handle_mouseover(item);
}
if let Some(mut e) = self.traffic_signal_editor {
edit_mode = true;
if e.event(
input,
&self.map,
@ -343,10 +358,10 @@ impl gui::GUI for UI {
} else {
self.traffic_signal_editor = Some(e);
}
return (self, gui::EventLoopMode::InputOnly);
}
if let Some(mut e) = self.stop_sign_editor {
edit_mode = true;
if e.event(
input,
&self.map,
@ -357,111 +372,86 @@ impl gui::GUI for UI {
} else {
self.stop_sign_editor = Some(e);
}
return (self, gui::EventLoopMode::InputOnly);
}
// 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 =
{
let (new_color_picker, active) =
self.color_picker
.handle_event(input, &mut self.canvas, &mut self.cs);
}
self.current_search_state = self.current_search_state.event(input);
self.warp = self.warp.event(
input,
&self.map,
&mut self.canvas,
&mut self.current_selection_state,
);
if !edit_mode && self.sim_ctrl.event(input, &self.map, &self.control_map) {
event_loop_mode = event_loop_mode.merge(animation::EventLoopMode::Animation);
}
let old_zoom = self.canvas.cam_zoom;
self.canvas.handle_event(input.use_event_directly());
let new_zoom = self.canvas.cam_zoom;
self.zoom_for_toggleable_layers(old_zoom, new_zoom);
if !edit_mode {
if self.show_roads.handle_event(input) {
if let SelectionState::SelectedRoad(_, _) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
if let SelectionState::TooltipRoad(_) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
self.color_picker = new_color_picker;
if active {
return (self, gui::EventLoopMode::InputOnly);
}
if self.show_buildings.handle_event(input) {
if let SelectionState::SelectedBuilding(_) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
}
if self.show_intersections.handle_event(input) {
if let SelectionState::SelectedIntersection(_) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
}
self.show_parcels.handle_event(input);
self.show_icons.handle_event(input);
self.steepness_viz.handle_event(input);
self.osm_classifier.handle_event(input);
self.debug_mode.handle_event(input);
}
if old_zoom >= MIN_ZOOM_FOR_MOUSEOVER && new_zoom < MIN_ZOOM_FOR_MOUSEOVER {
self.current_selection_state = SelectionState::Empty;
}
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();
self.current_selection_state = self.current_selection_state.handle_mouseover(item);
let (new_search, active) = self.current_search_state.event(input);
self.current_search_state = new_search;
if active {
return (self, gui::EventLoopMode::InputOnly);
}
}
self.hider.event(input, &mut self.current_selection_state);
// TODO can't get this destructuring expressed right
let (new_selection_state, new_event_loop_mode) =
self.current_selection_state
.event(input, &self.map, &mut self.sim_ctrl.sim);
event_loop_mode = event_loop_mode.merge(new_event_loop_mode);
self.current_selection_state = new_selection_state;
match self.current_selection_state {
SelectionState::SelectedRoad(id, _) => {
if self.floodfiller.is_none() {
if input.key_pressed(Key::F, "Press F to start floodfilling from this road") {
self.floodfiller = Some(Floodfiller::new(id));
}
}
if self.map.get_r(id).lane_type == map_model::LaneType::Driving {
if input.key_pressed(Key::A, "Press A to add a car starting from this road") {
if !self.sim_ctrl.sim.spawn_one_on_road(id) {
println!("No room, sorry");
}
}
}
{
let (new_warp, active) = self.warp.event(
input,
&self.map,
&mut self.canvas,
&mut self.current_selection_state,
);
self.warp = new_warp;
if active {
return (self, gui::EventLoopMode::InputOnly);
}
SelectionState::SelectedIntersection(id) => {
if self.traffic_signal_editor.is_none()
&& self.control_map.traffic_signals.contains_key(&id)
{
if input.key_pressed(
Key::E,
&format!("Press E to edit traffic signal for {:?}", id),
) {
self.traffic_signal_editor = Some(TrafficSignalEditor::new(id));
}
}
if self.stop_sign_editor.is_none() && self.control_map.stop_signs.contains_key(&id)
{
if input.key_pressed(Key::E, &format!("Press E to edit stop sign for {:?}", id))
{
self.stop_sign_editor = Some(StopSignEditor::new(id));
}
}
}
if self.show_roads.handle_event(input) {
if let SelectionState::SelectedRoad(_, _) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
_ => {}
if let SelectionState::TooltipRoad(_) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
return (self, gui::EventLoopMode::InputOnly);
}
if self.show_buildings.handle_event(input) {
if let SelectionState::SelectedBuilding(_) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
return (self, gui::EventLoopMode::InputOnly);
}
if self.show_intersections.handle_event(input) {
if let SelectionState::SelectedIntersection(_) = self.current_selection_state {
self.current_selection_state = SelectionState::Empty;
}
return (self, gui::EventLoopMode::InputOnly);
}
if self.show_parcels.handle_event(input) {
return (self, gui::EventLoopMode::InputOnly);
}
if self.show_icons.handle_event(input) {
return (self, gui::EventLoopMode::InputOnly);
}
if self.debug_mode.handle_event(input) {
return (self, gui::EventLoopMode::InputOnly);
}
if self.steepness_viz.handle_event(input) {
return (self, gui::EventLoopMode::InputOnly);
}
if self.osm_classifier.handle_event(input) {
return (self, gui::EventLoopMode::InputOnly);
}
if self.hider.event(input, &mut self.current_selection_state) {
return (self, gui::EventLoopMode::InputOnly);
}
if let Some(mut f) = self.floodfiller {
@ -470,6 +460,7 @@ impl gui::GUI for UI {
} else {
self.floodfiller = Some(f);
}
return (self, gui::EventLoopMode::InputOnly);
}
if let Some(mut v) = self.geom_validator {
@ -478,14 +469,70 @@ impl gui::GUI for UI {
} else {
self.geom_validator = Some(v);
}
return (self, gui::EventLoopMode::InputOnly);
}
if input.unimportant_key_pressed(Key::I, "Validate map geometry") {
self.geom_validator = Some(Validator::new(&self.draw_map));
return (self, gui::EventLoopMode::InputOnly);
}
if input.unimportant_key_pressed(Key::S, "Spawn 1000 cars in random places") {
self.sim_ctrl.sim.spawn_many_on_empty_roads(&self.map, 1000);
return (self, gui::EventLoopMode::InputOnly);
}
if input.unimportant_key_pressed(Key::I, "Validate map geometry") {
self.geom_validator = Some(Validator::new(&self.draw_map));
match self.current_selection_state {
SelectionState::SelectedCar(id) => {
// TODO not sure if we should debug like this (pushing the bit down to all the
// layers representing an entity) or by using some scary global mutable singleton
if input.unimportant_key_pressed(Key::D, "press D to debug") {
self.sim_ctrl.sim.toggle_debug(id);
return (self, gui::EventLoopMode::InputOnly);
}
}
SelectionState::SelectedRoad(id, _) => {
if input.key_pressed(Key::F, "Press F to start floodfilling from this road") {
self.floodfiller = Some(Floodfiller::new(id));
return (self, gui::EventLoopMode::InputOnly);
}
if self.map.get_r(id).lane_type == map_model::LaneType::Driving {
if input.key_pressed(Key::A, "Press A to add a car starting from this road") {
if !self.sim_ctrl.sim.spawn_one_on_road(id) {
println!("No room, sorry");
}
return (self, gui::EventLoopMode::InputOnly);
}
}
}
SelectionState::SelectedIntersection(id) => {
if self.control_map.traffic_signals.contains_key(&id) {
if input.key_pressed(
Key::E,
&format!("Press E to edit traffic signal for {:?}", id),
) {
self.traffic_signal_editor = Some(TrafficSignalEditor::new(id));
return (self, gui::EventLoopMode::InputOnly);
}
}
if self.control_map.stop_signs.contains_key(&id) {
if input.key_pressed(Key::E, &format!("Press E to edit stop sign for {:?}", id))
{
self.stop_sign_editor = Some(StopSignEditor::new(id));
return (self, gui::EventLoopMode::InputOnly);
}
}
}
_ => {}
}
// Do this one lastish, since it conflicts with lots of other stuff
{
let (new_selection, active) = self.current_selection_state.event(input, &self.map);
self.current_selection_state = new_selection;
if active {
return (self, gui::EventLoopMode::InputOnly);
}
}
if input.unimportant_key_pressed(Key::Escape, "Press escape to quit") {
@ -503,7 +550,12 @@ impl gui::GUI for UI {
process::exit(0);
}
(self, event_loop_mode)
// Sim controller plugin is kind of always active? If nothing else ran, let it use keys.
if self.sim_ctrl.event(input, &self.map, &self.control_map) {
(self, gui::EventLoopMode::Animation)
} else {
(self, gui::EventLoopMode::InputOnly)
}
}
// TODO Weird to mut self just to set window_size on the canvas

View File

@ -3,13 +3,13 @@
use GfxCtx;
use aabb_quadtree::geom::{Point, Rect};
use graphics::Transformed;
use piston::input::{Button, Event, Key, MouseButton, MouseCursorEvent, MouseScrollEvent,
PressEvent, ReleaseEvent};
use piston::input::{Button, Event, MouseButton, MouseCursorEvent, MouseScrollEvent, PressEvent,
ReleaseEvent};
use piston::window::Size;
use text;
const ZOOM_SPEED: f64 = 0.05;
const PAN_SPEED: f64 = 10.0;
//const PAN_SPEED: f64 = 10.0;
pub struct Canvas {
pub cam_x: f64,
@ -60,7 +60,8 @@ impl Canvas {
if let Some(Button::Mouse(MouseButton::Left)) = ev.release_args() {
self.left_mouse_drag_from = None;
}
if let Some(Button::Keyboard(key)) = ev.press_args() {
// These aren't used much now, and they conflict with other plugins
/*if let Some(Button::Keyboard(key)) = ev.press_args() {
match key {
Key::Up => self.cam_y -= PAN_SPEED,
Key::Down => self.cam_y += PAN_SPEED,
@ -70,7 +71,7 @@ impl Canvas {
Key::W => self.zoom_towards_mouse(ZOOM_SPEED),
_ => {}
}
}
}*/
if let Some(scroll) = ev.mouse_scroll_args() {
self.zoom_towards_mouse(scroll[1] * ZOOM_SPEED);
}
@ -123,10 +124,10 @@ impl Canvas {
)
}
fn screen_to_map_x(&self, x: f64) -> f64 {
pub fn screen_to_map_x(&self, x: f64) -> f64 {
(x + self.cam_x) / self.cam_zoom
}
fn screen_to_map_y(&self, y: f64) -> f64 {
pub fn screen_to_map_y(&self, y: f64) -> f64 {
(y + self.cam_y) / self.cam_zoom
}