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