1 use crate::app::App; 2 use crate::colors::ColorSchemeChoice; 3 use crate::game::{State, Transition}; 4 use geom::Duration; 5 use widgetry::{ 6 hotkey, Btn, Checkbox, Choice, EventCtx, GfxCtx, Key, Line, Outcome, Panel, Spinner, TextExt, 7 Widget, 8 }; 9 10 // TODO SimOptions stuff too 11 #[derive(Clone)] 12 pub struct Options { 13 pub dev: bool, 14 pub debug_all_agents: bool, 15 16 pub label_roads: bool, 17 pub traffic_signal_style: TrafficSignalStyle, 18 pub color_scheme: ColorSchemeChoice, 19 pub min_zoom_for_detail: f64, 20 pub large_unzoomed_agents: bool, 21 22 pub time_increment: Duration, 23 pub resume_after_edit: bool, 24 pub dont_draw_time_warp: bool, 25 pub time_warp_halt_limit: Duration, 26 27 pub language: Option<String>, 28 } 29 30 impl Options { default() -> Options31 pub fn default() -> Options { 32 Options { 33 dev: false, 34 debug_all_agents: false, 35 36 label_roads: true, 37 traffic_signal_style: TrafficSignalStyle::BAP, 38 color_scheme: ColorSchemeChoice::Standard, 39 min_zoom_for_detail: 4.0, 40 large_unzoomed_agents: false, 41 42 time_increment: Duration::minutes(10), 43 resume_after_edit: true, 44 dont_draw_time_warp: false, 45 time_warp_halt_limit: Duration::minutes(5), 46 47 language: None, 48 } 49 } 50 } 51 52 #[derive(Clone, PartialEq, Debug)] 53 pub enum TrafficSignalStyle { 54 BAP, 55 GroupArrows, 56 Sidewalks, 57 Icons, 58 IndividualTurnArrows, 59 } 60 61 pub struct OptionsPanel { 62 panel: Panel, 63 } 64 65 impl OptionsPanel { new(ctx: &mut EventCtx, app: &App) -> Box<dyn State>66 pub fn new(ctx: &mut EventCtx, app: &App) -> Box<dyn State> { 67 Box::new(OptionsPanel { 68 panel: Panel::new(Widget::col(vec![ 69 Widget::custom_row(vec![ 70 Line("Settings").small_heading().draw(ctx), 71 Btn::plaintext("X") 72 .build(ctx, "close", hotkey(Key::Escape)) 73 .align_right(), 74 ]), 75 "Camera controls".draw_text(ctx), 76 Widget::col(vec![ 77 Checkbox::checkbox( 78 ctx, 79 "Invert direction of vertical scrolling", 80 None, 81 ctx.canvas.invert_scroll, 82 ), 83 Checkbox::checkbox( 84 ctx, 85 "Pan map when cursor is at edge of screen", 86 None, 87 ctx.canvas.edge_auto_panning, 88 ) 89 .named("autopan"), 90 Checkbox::checkbox( 91 ctx, 92 "Use touchpad to pan and hold Control to zoom", 93 None, 94 ctx.canvas.touchpad_to_move, 95 ), 96 Checkbox::checkbox( 97 ctx, 98 "Use arrow keys to pan and Q/W to zoom", 99 None, 100 ctx.canvas.keys_to_pan, 101 ), 102 Widget::row(vec![ 103 "Scroll speed for menus".draw_text(ctx).centered_vert(), 104 Spinner::new(ctx, (1, 50), ctx.canvas.gui_scroll_speed as isize) 105 .named("gui_scroll_speed"), 106 ]), 107 ]) 108 .bg(app.cs.section_bg) 109 .padding(8), 110 "Appearance".draw_text(ctx), 111 Widget::col(vec![ 112 Checkbox::checkbox(ctx, "Draw road names", None, app.opts.label_roads), 113 Widget::row(vec![ 114 "Traffic signal rendering:".draw_text(ctx), 115 Widget::dropdown( 116 ctx, 117 "Traffic signal rendering", 118 app.opts.traffic_signal_style.clone(), 119 vec![ 120 Choice::new( 121 "Brian's variation of arrows showing the protected and \ 122 permitted movements", 123 TrafficSignalStyle::BAP, 124 ), 125 Choice::new( 126 "arrows showing the protected and permitted movements", 127 TrafficSignalStyle::GroupArrows, 128 ), 129 Choice::new( 130 "arrows showing the protected and permitted movements, with \ 131 sidewalks", 132 TrafficSignalStyle::Sidewalks, 133 ), 134 Choice::new( 135 "icons for movements (like the editor UI)", 136 TrafficSignalStyle::Icons, 137 ), 138 Choice::new( 139 "arrows showing individual turns (to debug)", 140 TrafficSignalStyle::IndividualTurnArrows, 141 ), 142 ], 143 ), 144 ]), 145 Widget::row(vec![ 146 "Color scheme:".draw_text(ctx), 147 Widget::dropdown( 148 ctx, 149 "Color scheme", 150 app.opts.color_scheme, 151 ColorSchemeChoice::choices(), 152 ), 153 ]), 154 Widget::row(vec![ 155 "Camera zoom to switch to unzoomed view".draw_text(ctx), 156 Widget::dropdown( 157 ctx, 158 "min zoom", 159 app.opts.min_zoom_for_detail, 160 vec![ 161 Choice::new("1.0", 1.0), 162 Choice::new("2.0", 2.0), 163 Choice::new("3.0", 3.0), 164 Choice::new("4.0", 4.0), 165 Choice::new("5.0", 5.0), 166 Choice::new("6.0", 6.0), 167 ], 168 ), 169 ]), 170 Checkbox::checkbox( 171 ctx, 172 "Draw enlarged unzoomed agents", 173 None, 174 app.opts.large_unzoomed_agents, 175 ), 176 Widget::row(vec![ 177 "Language".draw_text(ctx), 178 Widget::dropdown(ctx, "language", app.opts.language.clone(), { 179 let mut choices = Vec::new(); 180 choices.push(Choice::new("Map native language", None)); 181 for lang in app.primary.map.get_languages() { 182 choices.push(Choice::new(lang, Some(lang.to_string()))); 183 } 184 choices 185 }), 186 ]), 187 ]) 188 .bg(app.cs.section_bg) 189 .padding(8), 190 "Debug".draw_text(ctx), 191 Widget::col(vec![ 192 Checkbox::checkbox(ctx, "Enable developer mode", None, app.opts.dev), 193 Checkbox::checkbox( 194 ctx, 195 "Draw all agents to debug geometry (Slow!)", 196 None, 197 app.opts.debug_all_agents, 198 ), 199 ]) 200 .bg(app.cs.section_bg) 201 .padding(8), 202 Btn::text_bg2("Apply") 203 .build_def(ctx, hotkey(Key::Enter)) 204 .centered_horiz(), 205 ])) 206 .build(ctx), 207 }) 208 } 209 } 210 211 impl State for OptionsPanel { event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition212 fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { 213 match self.panel.event(ctx) { 214 Outcome::Clicked(x) => match x.as_ref() { 215 "close" => { 216 return Transition::Pop; 217 } 218 "Apply" => { 219 app.opts.dev = self.panel.is_checked("Enable developer mode"); 220 app.opts.debug_all_agents = self 221 .panel 222 .is_checked("Draw all agents to debug geometry (Slow!)"); 223 224 ctx.canvas.invert_scroll = self 225 .panel 226 .is_checked("Invert direction of vertical scrolling"); 227 ctx.canvas.touchpad_to_move = self 228 .panel 229 .is_checked("Use touchpad to pan and hold Control to zoom"); 230 ctx.canvas.keys_to_pan = self 231 .panel 232 .is_checked("Use arrow keys to pan and Q/W to zoom"); 233 ctx.canvas.edge_auto_panning = self.panel.is_checked("autopan"); 234 ctx.canvas.gui_scroll_speed = self.panel.spinner("gui_scroll_speed") as usize; 235 236 app.opts.label_roads = self.panel.is_checked("Draw road names"); 237 let style = self.panel.dropdown_value("Traffic signal rendering"); 238 if app.opts.traffic_signal_style != style { 239 app.opts.traffic_signal_style = style; 240 println!("Rerendering traffic signals..."); 241 for i in &mut app.primary.draw_map.intersections { 242 *i.draw_traffic_signal.borrow_mut() = None; 243 } 244 } 245 246 let scheme = self.panel.dropdown_value("Color scheme"); 247 if app.opts.color_scheme != scheme { 248 app.opts.color_scheme = scheme; 249 app.switch_map(ctx, app.primary.current_flags.sim_flags.load.clone()); 250 } 251 252 app.opts.min_zoom_for_detail = self.panel.dropdown_value("min zoom"); 253 app.opts.large_unzoomed_agents = 254 self.panel.is_checked("Draw enlarged unzoomed agents"); 255 256 let language = self.panel.dropdown_value("language"); 257 if language != app.opts.language { 258 app.opts.language = language; 259 for r in &mut app.primary.draw_map.roads { 260 r.clear_rendering(); 261 } 262 } 263 264 return Transition::Pop; 265 } 266 _ => unreachable!(), 267 }, 268 _ => {} 269 } 270 271 Transition::Keep 272 } 273 draw(&self, g: &mut GfxCtx, app: &App)274 fn draw(&self, g: &mut GfxCtx, app: &App) { 275 State::grey_out_map(g, app); 276 self.panel.draw(g); 277 } 278 } 279