widgetry/tools/
prompt_input.rs

1use crate::{
2    DrawBaselayer, EventCtx, GfxCtx, Key, Line, Outcome, Panel, State, TextBox, Transition, Widget,
3};
4
5/// Prompt for arbitrary text input, then feed the answer to a callback.
6pub struct PromptInput<A> {
7    panel: Panel,
8    cb: Option<Box<dyn FnOnce(String, &mut EventCtx, &mut A) -> Transition<A>>>,
9}
10
11impl<A: 'static> PromptInput<A> {
12    pub fn new_state(
13        ctx: &mut EventCtx,
14        query: &str,
15        initial: String,
16        cb: Box<dyn FnOnce(String, &mut EventCtx, &mut A) -> Transition<A>>,
17    ) -> Box<dyn State<A>> {
18        Box::new(PromptInput {
19            panel: Panel::new_builder(Widget::col(vec![
20                Widget::row(vec![
21                    Line(query).small_heading().into_widget(ctx),
22                    ctx.style().btn_close_widget(ctx),
23                ]),
24                TextBox::default_widget(ctx, "input", initial),
25                ctx.style()
26                    .btn_outline
27                    .text("confirm")
28                    .hotkey(Key::Enter)
29                    .build_def(ctx),
30            ]))
31            .build(ctx),
32            cb: Some(cb),
33        })
34    }
35}
36
37impl<A: 'static> State<A> for PromptInput<A> {
38    fn event(&mut self, ctx: &mut EventCtx, app: &mut A) -> Transition<A> {
39        match self.panel.event(ctx) {
40            Outcome::Clicked(x) => match x.as_ref() {
41                "close" => Transition::Pop,
42                "confirm" => {
43                    let data = self.panel.text_box("input");
44                    (self.cb.take().unwrap())(data, ctx, app)
45                }
46                _ => unreachable!(),
47            },
48            _ => {
49                if ctx.normal_left_click() && ctx.canvas.get_cursor_in_screen_space().is_none() {
50                    return Transition::Pop;
51                }
52                Transition::Keep
53            }
54        }
55    }
56
57    fn draw_baselayer(&self) -> DrawBaselayer {
58        DrawBaselayer::PreviousState
59    }
60
61    fn draw(&self, g: &mut GfxCtx, _: &A) {
62        super::grey_out_map(g);
63        self.panel.draw(g);
64    }
65}