1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use anyhow::Result;
use serde::{Deserialize, Serialize};
use abstio::MapName;
use abstutil::Timer;
use map_gui::tools::{ChooseSomething, PromptInput};
use widgetry::tools::PopupMsg;
use widgetry::{Choice, EventCtx, State, Transition};
use crate::{App, BrowseNeighborhoods, ModalFilters, Partitioning};
#[derive(Serialize, Deserialize)]
pub struct Proposal {
pub map: MapName,
pub name: String,
pub abst_version: String,
pub partitioning: Partitioning,
pub modal_filters: ModalFilters,
}
impl Proposal {
pub fn save_ui(ctx: &mut EventCtx) -> Box<dyn State<App>> {
PromptInput::new_state(
ctx,
"Name this proposal",
String::new(),
Box::new(|name, _, app| {
Self::save(app, name);
Transition::Pop
}),
)
}
fn save(app: &App, name: String) {
let path = abstio::path_ltn_proposals(app.map.get_name(), &name);
let proposal = Proposal {
map: app.map.get_name().clone(),
name,
abst_version: map_gui::tools::version().to_string(),
partitioning: app.session.partitioning.clone(),
modal_filters: app.session.modal_filters.clone(),
};
abstio::write_binary(path, &proposal);
}
pub fn load_picker_ui(ctx: &mut EventCtx, app: &App) -> Box<dyn State<App>> {
ChooseSomething::new_state(
ctx,
"Load which proposal?",
Choice::strings(abstio::list_all_objects(abstio::path_all_ltn_proposals(
app.map.get_name(),
))),
Box::new(|name, ctx, app| {
Transition::Replace(match Self::load(ctx, app, &name) {
Some(err_state) => err_state,
None => BrowseNeighborhoods::new_state(ctx, app),
})
}),
)
}
pub fn load(ctx: &mut EventCtx, app: &mut App, name: &str) -> Option<Box<dyn State<App>>> {
ctx.loading_screen(
"load existing proposal",
|ctx, mut timer| match Self::inner_load(ctx, app, name, &mut timer) {
Ok(()) => None,
Err(err) => Some(PopupMsg::new_state(
ctx,
"Error",
vec![format!("Couldn't load proposal {}", name), err.to_string()],
)),
},
)
}
fn inner_load(ctx: &mut EventCtx, app: &mut App, name: &str, timer: &mut Timer) -> Result<()> {
let proposal: Proposal =
abstio::maybe_read_binary(abstio::path_ltn_proposals(app.map.get_name(), name), timer)?;
app.session.partitioning = proposal.partitioning;
app.session.modal_filters = proposal.modal_filters;
app.session.draw_all_filters = app.session.modal_filters.draw(ctx, &app.map);
Ok(())
}
}