mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 17:34:58 +03:00
make popup menus use scrolling
This commit is contained in:
parent
c9b8438bd5
commit
3bd4a7220d
@ -1,14 +1,18 @@
|
||||
use crate::layout::Widget;
|
||||
use crate::widgets::PopupMenu;
|
||||
use crate::{
|
||||
Button, Color, DrawBoth, EventCtx, Filler, GeomBatch, GfxCtx, Histogram, HorizontalAlignment,
|
||||
JustDraw, Plot, ScreenDims, ScreenPt, ScreenRectangle, Slider, Text, VerticalAlignment,
|
||||
};
|
||||
use abstutil::Cloneable;
|
||||
use geom::{Distance, Duration, Polygon};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use stretch::geometry::{Rect, Size};
|
||||
use stretch::node::{Node, Stretch};
|
||||
use stretch::style::{AlignItems, Dimension, FlexDirection, FlexWrap, JustifyContent, Style};
|
||||
|
||||
type Menu = PopupMenu<Box<dyn Cloneable>>;
|
||||
|
||||
pub struct ManagedWidget {
|
||||
widget: WidgetType,
|
||||
style: LayoutStyle,
|
||||
@ -20,6 +24,7 @@ enum WidgetType {
|
||||
Draw(JustDraw),
|
||||
Btn(Button),
|
||||
Slider(String),
|
||||
Menu(String),
|
||||
Filler(String),
|
||||
// TODO Sadness. Can't have some kind of wildcard generic here?
|
||||
DurationPlot(Plot<Duration>),
|
||||
@ -166,6 +171,10 @@ impl ManagedWidget {
|
||||
ManagedWidget::new(WidgetType::Slider(label.to_string()))
|
||||
}
|
||||
|
||||
pub fn menu(label: &str) -> ManagedWidget {
|
||||
ManagedWidget::new(WidgetType::Menu(label.to_string()))
|
||||
}
|
||||
|
||||
pub fn filler(label: &str) -> ManagedWidget {
|
||||
ManagedWidget::new(WidgetType::Filler(label.to_string()))
|
||||
}
|
||||
@ -197,6 +206,7 @@ impl ManagedWidget {
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
sliders: &mut HashMap<String, Slider>,
|
||||
menus: &mut HashMap<String, Menu>,
|
||||
) -> Option<Outcome> {
|
||||
match self.widget {
|
||||
WidgetType::Draw(_) => {}
|
||||
@ -209,13 +219,16 @@ impl ManagedWidget {
|
||||
WidgetType::Slider(ref name) => {
|
||||
sliders.get_mut(name).unwrap().event(ctx);
|
||||
}
|
||||
WidgetType::Menu(ref name) => {
|
||||
menus.get_mut(name).unwrap().event(ctx);
|
||||
}
|
||||
WidgetType::Filler(_)
|
||||
| WidgetType::DurationPlot(_)
|
||||
| WidgetType::UsizePlot(_)
|
||||
| WidgetType::Histogram(_) => {}
|
||||
WidgetType::Row(ref mut widgets) | WidgetType::Column(ref mut widgets) => {
|
||||
for w in widgets {
|
||||
if let Some(o) = w.event(ctx, sliders) {
|
||||
if let Some(o) = w.event(ctx, sliders, menus) {
|
||||
return Some(o);
|
||||
}
|
||||
}
|
||||
@ -224,7 +237,12 @@ impl ManagedWidget {
|
||||
None
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, sliders: &HashMap<String, Slider>) {
|
||||
fn draw(
|
||||
&self,
|
||||
g: &mut GfxCtx,
|
||||
sliders: &HashMap<String, Slider>,
|
||||
menus: &HashMap<String, Menu>,
|
||||
) {
|
||||
if let Some(ref bg) = self.bg {
|
||||
bg.redraw(ScreenPt::new(self.rect.x1, self.rect.y1), g);
|
||||
}
|
||||
@ -233,13 +251,14 @@ impl ManagedWidget {
|
||||
WidgetType::Draw(ref j) => j.draw(g),
|
||||
WidgetType::Btn(ref btn) => btn.draw(g),
|
||||
WidgetType::Slider(ref name) => sliders[name].draw(g),
|
||||
WidgetType::Menu(ref name) => menus[name].draw(g),
|
||||
WidgetType::Filler(_) => {}
|
||||
WidgetType::DurationPlot(ref plot) => plot.draw(g),
|
||||
WidgetType::UsizePlot(ref plot) => plot.draw(g),
|
||||
WidgetType::Histogram(ref hgram) => hgram.draw(g),
|
||||
WidgetType::Row(ref widgets) | WidgetType::Column(ref widgets) => {
|
||||
for w in widgets {
|
||||
w.draw(g, sliders);
|
||||
w.draw(g, sliders, menus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -250,6 +269,7 @@ impl ManagedWidget {
|
||||
&self,
|
||||
parent: Node,
|
||||
sliders: &HashMap<String, Slider>,
|
||||
menus: &HashMap<String, Menu>,
|
||||
fillers: &HashMap<String, Filler>,
|
||||
stretch: &mut Stretch,
|
||||
nodes: &mut Vec<Node>,
|
||||
@ -259,6 +279,7 @@ impl ManagedWidget {
|
||||
WidgetType::Draw(ref widget) => widget,
|
||||
WidgetType::Btn(ref widget) => widget,
|
||||
WidgetType::Slider(ref name) => &sliders[name],
|
||||
WidgetType::Menu(ref name) => &menus[name],
|
||||
WidgetType::Filler(ref name) => &fillers[name],
|
||||
WidgetType::DurationPlot(ref widget) => widget,
|
||||
WidgetType::UsizePlot(ref widget) => widget,
|
||||
@ -272,7 +293,7 @@ impl ManagedWidget {
|
||||
let row = stretch.new_node(style, Vec::new()).unwrap();
|
||||
nodes.push(row);
|
||||
for widget in widgets {
|
||||
widget.get_flexbox(row, sliders, fillers, stretch, nodes);
|
||||
widget.get_flexbox(row, sliders, menus, fillers, stretch, nodes);
|
||||
}
|
||||
stretch.add_child(parent, row).unwrap();
|
||||
return;
|
||||
@ -286,7 +307,7 @@ impl ManagedWidget {
|
||||
let col = stretch.new_node(style, Vec::new()).unwrap();
|
||||
nodes.push(col);
|
||||
for widget in widgets {
|
||||
widget.get_flexbox(col, sliders, fillers, stretch, nodes);
|
||||
widget.get_flexbox(col, sliders, menus, fillers, stretch, nodes);
|
||||
}
|
||||
stretch.add_child(parent, col).unwrap();
|
||||
return;
|
||||
@ -309,6 +330,7 @@ impl ManagedWidget {
|
||||
fn apply_flexbox(
|
||||
&mut self,
|
||||
sliders: &mut HashMap<String, Slider>,
|
||||
menus: &mut HashMap<String, Menu>,
|
||||
fillers: &mut HashMap<String, Filler>,
|
||||
stretch: &Stretch,
|
||||
nodes: &mut Vec<Node>,
|
||||
@ -358,6 +380,9 @@ impl ManagedWidget {
|
||||
WidgetType::Slider(ref name) => {
|
||||
sliders.get_mut(name).unwrap().set_pos(top_left);
|
||||
}
|
||||
WidgetType::Menu(ref name) => {
|
||||
menus.get_mut(name).unwrap().set_pos(top_left);
|
||||
}
|
||||
WidgetType::Filler(ref name) => {
|
||||
fillers.get_mut(name).unwrap().set_pos(top_left);
|
||||
}
|
||||
@ -375,6 +400,7 @@ impl ManagedWidget {
|
||||
for widget in widgets {
|
||||
widget.apply_flexbox(
|
||||
sliders,
|
||||
menus,
|
||||
fillers,
|
||||
stretch,
|
||||
nodes,
|
||||
@ -389,6 +415,7 @@ impl ManagedWidget {
|
||||
for widget in widgets {
|
||||
widget.apply_flexbox(
|
||||
sliders,
|
||||
menus,
|
||||
fillers,
|
||||
stretch,
|
||||
nodes,
|
||||
@ -406,6 +433,7 @@ impl ManagedWidget {
|
||||
match self.widget {
|
||||
WidgetType::Draw(_)
|
||||
| WidgetType::Slider(_)
|
||||
| WidgetType::Menu(_)
|
||||
| WidgetType::Filler(_)
|
||||
| WidgetType::DurationPlot(_)
|
||||
| WidgetType::UsizePlot(_) => {}
|
||||
@ -433,6 +461,7 @@ pub struct Composite {
|
||||
pos: CompositePosition,
|
||||
|
||||
sliders: HashMap<String, Slider>,
|
||||
menus: HashMap<String, Menu>,
|
||||
fillers: HashMap<String, Filler>,
|
||||
|
||||
// TODO This doesn't clip. There's no way to express that the scrollable thing should occupy a
|
||||
@ -453,6 +482,8 @@ enum CompositePosition {
|
||||
|
||||
const SCROLL_SPEED: f64 = 5.0;
|
||||
|
||||
// TODO These APIs aren't composable. Need a builer pattern or ideally, to scrape all the special
|
||||
// objects from the tree.
|
||||
impl Composite {
|
||||
fn new(top_level: ManagedWidget, pos: CompositePosition) -> Composite {
|
||||
Composite {
|
||||
@ -460,6 +491,7 @@ impl Composite {
|
||||
pos,
|
||||
|
||||
sliders: HashMap::new(),
|
||||
menus: HashMap::new(),
|
||||
fillers: HashMap::new(),
|
||||
|
||||
scrollable: false,
|
||||
@ -516,7 +548,11 @@ impl Composite {
|
||||
c
|
||||
}
|
||||
|
||||
pub fn scrollable(ctx: &EventCtx, top_level: ManagedWidget) -> Composite {
|
||||
pub fn scrollable(
|
||||
ctx: &EventCtx,
|
||||
top_level: ManagedWidget,
|
||||
menus: Vec<(&str, Menu)>,
|
||||
) -> Composite {
|
||||
let mut c = Composite::new(
|
||||
top_level,
|
||||
CompositePosition::Aligned(HorizontalAlignment::Left, VerticalAlignment::Top),
|
||||
@ -528,6 +564,9 @@ impl Composite {
|
||||
Slider::vertical(ctx, ctx.canvas.window_height - 100.0),
|
||||
);
|
||||
c.top_level = ManagedWidget::row(vec![c.top_level, ManagedWidget::slider("scrollbar")]);
|
||||
for (name, menu) in menus {
|
||||
c.menus.insert(name.to_string(), menu);
|
||||
}
|
||||
c.recompute_layout(ctx);
|
||||
c
|
||||
}
|
||||
@ -556,8 +595,14 @@ impl Composite {
|
||||
.unwrap();
|
||||
|
||||
let mut nodes = vec![];
|
||||
self.top_level
|
||||
.get_flexbox(root, &self.sliders, &self.fillers, &mut stretch, &mut nodes);
|
||||
self.top_level.get_flexbox(
|
||||
root,
|
||||
&self.sliders,
|
||||
&self.menus,
|
||||
&self.fillers,
|
||||
&mut stretch,
|
||||
&mut nodes,
|
||||
);
|
||||
nodes.reverse();
|
||||
|
||||
stretch.compute_layout(root, Size::undefined()).unwrap();
|
||||
@ -576,6 +621,7 @@ impl Composite {
|
||||
let offset = self.scroll_y_offset(ctx);
|
||||
self.top_level.apply_flexbox(
|
||||
&mut self.sliders,
|
||||
&mut self.menus,
|
||||
&mut self.fillers,
|
||||
&stretch,
|
||||
&mut nodes,
|
||||
@ -628,7 +674,9 @@ impl Composite {
|
||||
}
|
||||
|
||||
let before = self.scroll_y_offset(ctx);
|
||||
let result = self.top_level.event(ctx, &mut self.sliders);
|
||||
let result = self
|
||||
.top_level
|
||||
.event(ctx, &mut self.sliders, &mut self.menus);
|
||||
if self.scroll_y_offset(ctx) != before {
|
||||
self.recompute_layout(ctx);
|
||||
}
|
||||
@ -637,7 +685,7 @@ impl Composite {
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
g.canvas.mark_covered_area(self.top_level.rect.clone());
|
||||
self.top_level.draw(g, &self.sliders);
|
||||
self.top_level.draw(g, &self.sliders, &self.menus);
|
||||
}
|
||||
|
||||
pub fn get_all_click_actions(&self) -> HashSet<String> {
|
||||
@ -666,6 +714,10 @@ impl Composite {
|
||||
self.sliders.remove(name).unwrap()
|
||||
}
|
||||
|
||||
pub fn menu(&self, name: &str) -> &Menu {
|
||||
&self.menus[name]
|
||||
}
|
||||
|
||||
pub fn filler_rect(&self, name: &str) -> ScreenRectangle {
|
||||
let f = &self.fillers[name];
|
||||
ScreenRectangle::top_left(f.top_left, f.dims)
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::layout::Widget;
|
||||
use crate::{
|
||||
hotkey, layout, text, Choice, EventCtx, GfxCtx, InputResult, Key, Line, ScreenDims, ScreenPt,
|
||||
hotkey, text, Choice, EventCtx, GfxCtx, InputResult, Key, Line, ScreenDims, ScreenPt,
|
||||
ScreenRectangle, Text,
|
||||
};
|
||||
|
||||
@ -8,29 +8,22 @@ use crate::{
|
||||
// complex.
|
||||
|
||||
pub struct PopupMenu<T: Clone> {
|
||||
prompt: Text,
|
||||
choices: Vec<Choice<T>>,
|
||||
current_idx: usize,
|
||||
standalone_layout: Option<layout::ContainerOrientation>,
|
||||
click_to_cancel: bool,
|
||||
|
||||
pub(crate) state: InputResult<T>,
|
||||
|
||||
top_left: ScreenPt,
|
||||
dims: ScreenDims,
|
||||
}
|
||||
|
||||
impl<T: Clone> PopupMenu<T> {
|
||||
pub fn new(
|
||||
prompt: Text,
|
||||
choices: Vec<Choice<T>>,
|
||||
ctx: &EventCtx,
|
||||
click_to_cancel: bool,
|
||||
) -> PopupMenu<T> {
|
||||
pub fn new(choices: Vec<Choice<T>>, ctx: &EventCtx) -> PopupMenu<T> {
|
||||
let mut m = PopupMenu {
|
||||
prompt,
|
||||
choices,
|
||||
current_idx: 0,
|
||||
standalone_layout: Some(layout::ContainerOrientation::Centered),
|
||||
click_to_cancel,
|
||||
|
||||
state: InputResult::StillActive,
|
||||
|
||||
top_left: ScreenPt::new(0.0, 0.0),
|
||||
dims: ScreenDims::new(0.0, 0.0),
|
||||
@ -39,17 +32,16 @@ impl<T: Clone> PopupMenu<T> {
|
||||
m
|
||||
}
|
||||
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) -> InputResult<T> {
|
||||
if let Some(o) = self.standalone_layout {
|
||||
layout::stack_vertically(o, ctx, vec![self]);
|
||||
self.recalculate_dims(ctx);
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) {
|
||||
match self.state {
|
||||
InputResult::StillActive => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// Handle the mouse
|
||||
if ctx.redo_mouseover() {
|
||||
let cursor = ctx.canvas.get_cursor_in_screen_space();
|
||||
let mut top_left = self.top_left;
|
||||
top_left.y += ctx.text_dims(&self.prompt).height;
|
||||
for idx in 0..self.choices.len() {
|
||||
let rect = ScreenRectangle {
|
||||
x1: top_left.x,
|
||||
@ -69,7 +61,6 @@ impl<T: Clone> PopupMenu<T> {
|
||||
if ctx.normal_left_click() {
|
||||
// Did we actually click the entry?
|
||||
let mut top_left = self.top_left;
|
||||
top_left.y += ctx.text_dims(&self.prompt).height;
|
||||
top_left.y += ctx.default_line_height() * (self.current_idx as f64);
|
||||
let rect = ScreenRectangle {
|
||||
x1: top_left.x,
|
||||
@ -79,10 +70,9 @@ impl<T: Clone> PopupMenu<T> {
|
||||
};
|
||||
if rect.contains(ctx.canvas.get_cursor_in_screen_space()) {
|
||||
if choice.active {
|
||||
return InputResult::Done(choice.label.clone(), choice.data.clone());
|
||||
self.state = InputResult::Done(choice.label.clone(), choice.data.clone());
|
||||
return;
|
||||
}
|
||||
} else if self.click_to_cancel {
|
||||
return InputResult::Canceled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,7 +84,8 @@ impl<T: Clone> PopupMenu<T> {
|
||||
}
|
||||
if let Some(hotkey) = choice.hotkey {
|
||||
if ctx.input.new_was_pressed(hotkey) {
|
||||
return InputResult::Done(choice.label.clone(), choice.data.clone());
|
||||
self.state = InputResult::Done(choice.label.clone(), choice.data.clone());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,9 +94,10 @@ impl<T: Clone> PopupMenu<T> {
|
||||
if ctx.input.new_was_pressed(hotkey(Key::Enter).unwrap()) {
|
||||
let choice = &self.choices[self.current_idx];
|
||||
if choice.active {
|
||||
return InputResult::Done(choice.label.clone(), choice.data.clone());
|
||||
self.state = InputResult::Done(choice.label.clone(), choice.data.clone());
|
||||
return;
|
||||
} else {
|
||||
return InputResult::StillActive;
|
||||
return;
|
||||
}
|
||||
} else if ctx.input.new_was_pressed(hotkey(Key::UpArrow).unwrap()) {
|
||||
if self.current_idx > 0 {
|
||||
@ -116,10 +108,9 @@ impl<T: Clone> PopupMenu<T> {
|
||||
self.current_idx += 1;
|
||||
}
|
||||
} else if ctx.input.new_was_pressed(hotkey(Key::Escape).unwrap()) {
|
||||
return InputResult::Canceled;
|
||||
self.state = InputResult::Canceled;
|
||||
return;
|
||||
}
|
||||
|
||||
InputResult::StillActive
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
@ -135,7 +126,7 @@ impl<T: Clone> PopupMenu<T> {
|
||||
}
|
||||
|
||||
fn calculate_txt(&self) -> Text {
|
||||
let mut txt = self.prompt.clone();
|
||||
let mut txt = Text::new();
|
||||
|
||||
for (idx, choice) in self.choices.iter().enumerate() {
|
||||
if choice.active {
|
||||
|
@ -1,7 +1,10 @@
|
||||
use crate::widgets::log_scroller::LogScroller;
|
||||
use crate::widgets::text_box::TextBox;
|
||||
use crate::widgets::PopupMenu;
|
||||
use crate::{layout, EventCtx, GfxCtx, InputResult, Key, MultiKey, SliderWithTextBox, Text};
|
||||
use crate::{
|
||||
layout, Color, Composite, EventCtx, GfxCtx, InputResult, Key, ManagedWidget, MultiKey,
|
||||
SliderWithTextBox, Text,
|
||||
};
|
||||
use abstutil::Cloneable;
|
||||
use geom::Time;
|
||||
use std::collections::VecDeque;
|
||||
@ -9,7 +12,7 @@ use std::collections::VecDeque;
|
||||
pub struct Wizard {
|
||||
alive: bool,
|
||||
tb: Option<TextBox>,
|
||||
menu: Option<PopupMenu<Box<dyn Cloneable>>>,
|
||||
menu_comp: Option<Composite>,
|
||||
log_scroller: Option<LogScroller>,
|
||||
slider: Option<SliderWithTextBox>,
|
||||
|
||||
@ -22,7 +25,7 @@ impl Wizard {
|
||||
Wizard {
|
||||
alive: true,
|
||||
tb: None,
|
||||
menu: None,
|
||||
menu_comp: None,
|
||||
log_scroller: None,
|
||||
slider: None,
|
||||
confirmed_state: Vec::new(),
|
||||
@ -30,8 +33,8 @@ impl Wizard {
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
if let Some(ref menu) = self.menu {
|
||||
menu.draw(g);
|
||||
if let Some(ref comp) = self.menu_comp {
|
||||
comp.draw(g);
|
||||
}
|
||||
if let Some(ref tb) = self.tb {
|
||||
tb.draw(g);
|
||||
@ -61,8 +64,12 @@ impl Wizard {
|
||||
|
||||
// The caller can ask for any type at any time
|
||||
pub fn current_menu_choice<R: 'static + Cloneable>(&self) -> Option<&R> {
|
||||
if let Some(ref menu) = self.menu {
|
||||
let item: &R = menu.current_choice().as_any().downcast_ref::<R>()?;
|
||||
if let Some(ref comp) = self.menu_comp {
|
||||
let item: &R = comp
|
||||
.menu("menu")
|
||||
.current_choice()
|
||||
.as_any()
|
||||
.downcast_ref::<R>()?;
|
||||
return Some(item);
|
||||
}
|
||||
None
|
||||
@ -242,7 +249,7 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
|
||||
}
|
||||
|
||||
// If the menu was empty, wait for the user to acknowledge the text-box before aborting the
|
||||
// wizard.
|
||||
// wizard
|
||||
if self.wizard.log_scroller.is_some() {
|
||||
if self
|
||||
.wizard
|
||||
@ -257,7 +264,7 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.wizard.menu.is_none() {
|
||||
if self.wizard.menu_comp.is_none() {
|
||||
let choices: Vec<Choice<R>> = choices_generator();
|
||||
if choices.is_empty() {
|
||||
self.wizard.log_scroller = Some(LogScroller::new(
|
||||
@ -266,19 +273,28 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
|
||||
));
|
||||
return None;
|
||||
}
|
||||
self.wizard.menu = Some(PopupMenu::new(
|
||||
Text::prompt(query),
|
||||
choices
|
||||
.into_iter()
|
||||
.map(|c| Choice {
|
||||
label: c.label,
|
||||
data: c.data.clone_box(),
|
||||
hotkey: c.hotkey,
|
||||
active: c.active,
|
||||
})
|
||||
.collect(),
|
||||
self.wizard.menu_comp = Some(Composite::scrollable(
|
||||
self.ctx,
|
||||
false,
|
||||
ManagedWidget::col(vec![
|
||||
ManagedWidget::draw_text(self.ctx, Text::prompt(query)),
|
||||
ManagedWidget::menu("menu"),
|
||||
])
|
||||
.bg(Color::grey(0.4)),
|
||||
vec![(
|
||||
"menu",
|
||||
PopupMenu::new(
|
||||
choices
|
||||
.into_iter()
|
||||
.map(|c| Choice {
|
||||
label: c.label,
|
||||
data: c.data.clone_box(),
|
||||
hotkey: c.hotkey,
|
||||
active: c.active,
|
||||
})
|
||||
.collect(),
|
||||
self.ctx,
|
||||
),
|
||||
)],
|
||||
));
|
||||
}
|
||||
|
||||
@ -289,22 +305,26 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
|
||||
return None;
|
||||
}
|
||||
|
||||
match self.wizard.menu.as_mut().unwrap().event(self.ctx) {
|
||||
self.wizard.menu_comp.as_mut().unwrap().event(self.ctx);
|
||||
|
||||
let (result, destroy) = match self.wizard.menu_comp.as_ref().unwrap().menu("menu").state {
|
||||
InputResult::Canceled => {
|
||||
self.wizard.menu = None;
|
||||
self.wizard.alive = false;
|
||||
None
|
||||
(None, true)
|
||||
}
|
||||
InputResult::StillActive => None,
|
||||
InputResult::Done(choice, item) => {
|
||||
self.wizard.menu = None;
|
||||
InputResult::StillActive => (None, false),
|
||||
InputResult::Done(ref choice, ref item) => {
|
||||
self.wizard
|
||||
.confirmed_state
|
||||
.push(Box::new((choice.to_string(), item.clone())));
|
||||
let downcasted_item: &R = item.as_any().downcast_ref::<R>().unwrap();
|
||||
Some((choice, downcasted_item.clone()))
|
||||
(Some((choice.to_string(), downcasted_item.clone())), true)
|
||||
}
|
||||
};
|
||||
if destroy {
|
||||
self.wizard.menu_comp = None;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn choose_string<S: Into<String>, F: Fn() -> Vec<S>>(
|
||||
@ -363,7 +383,7 @@ impl<'a, 'b> WrappedWizard<'a, 'b> {
|
||||
// If the control flow through a wizard block needs to change, might need to call this.
|
||||
pub fn reset(&mut self) {
|
||||
assert!(self.wizard.tb.is_none());
|
||||
assert!(self.wizard.menu.is_none());
|
||||
assert!(self.wizard.menu_comp.is_none());
|
||||
assert!(self.wizard.log_scroller.is_none());
|
||||
assert!(self.wizard.slider.is_none());
|
||||
self.wizard.confirmed_state.clear();
|
||||
|
@ -78,7 +78,11 @@ impl InfoPanel {
|
||||
}
|
||||
|
||||
InfoPanel {
|
||||
composite: Composite::scrollable(ctx, ManagedWidget::col(col).bg(Color::grey(0.3))),
|
||||
composite: Composite::scrollable(
|
||||
ctx,
|
||||
ManagedWidget::col(col).bg(Color::grey(0.3)),
|
||||
Vec::new(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,5 +293,9 @@ fn make_diagram(i: IntersectionID, selected: usize, ui: &UI, ctx: &EventCtx) ->
|
||||
);
|
||||
}
|
||||
|
||||
Composite::scrollable(ctx, ManagedWidget::col(col).bg(Color::hex("#545454")))
|
||||
Composite::scrollable(
|
||||
ctx,
|
||||
ManagedWidget::col(col).bg(Color::hex("#545454")),
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ pub fn make(ctx: &EventCtx, ui: &UI, tab: Tab) -> Box<dyn State> {
|
||||
.padding(10),
|
||||
content,
|
||||
]),
|
||||
Vec::new(),
|
||||
))
|
||||
.cb("BACK", Box::new(|_, _| Some(Transition::Pop)));
|
||||
for (t, label) in tab_data {
|
||||
|
Loading…
Reference in New Issue
Block a user