widgetry/widgets/
containers.rs

1use crate::{EventCtx, GfxCtx, Outcome, ScreenDims, ScreenPt, Widget, WidgetImpl, WidgetOutput};
2
3pub struct Nothing {}
4
5impl WidgetImpl for Nothing {
6    fn get_dims(&self) -> ScreenDims {
7        unreachable!()
8    }
9
10    fn set_pos(&mut self, _top_left: ScreenPt) {
11        unreachable!()
12    }
13
14    fn event(&mut self, _: &mut EventCtx, _: &mut WidgetOutput) {
15        unreachable!()
16    }
17    fn draw(&self, _g: &mut GfxCtx) {
18        unreachable!()
19    }
20}
21
22pub struct Container {
23    // false means column
24    pub is_row: bool,
25    pub members: Vec<Widget>,
26}
27
28impl Container {
29    pub fn new(is_row: bool, mut members: Vec<Widget>) -> Container {
30        members.retain(|w| !w.widget.is::<Nothing>());
31        Container { is_row, members }
32    }
33}
34
35impl WidgetImpl for Container {
36    fn get_dims(&self) -> ScreenDims {
37        // TODO This impl isn't correct, but it works for the one use case of
38        // get_width_for_forcing.
39        let mut width: f64 = 0.0;
40        for x in &self.members {
41            width = width.max(x.get_width_for_forcing());
42        }
43        ScreenDims::new(width, 0.0)
44    }
45    fn set_pos(&mut self, _top_left: ScreenPt) {
46        unreachable!()
47    }
48
49    fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
50        for w in &mut self.members {
51            if let Some(id) = ctx.focus_owned_by.as_ref() {
52                // Container is the only place that needs to actually enforce focus. If a Panel
53                // consists of only one top-level widget, then there's nothing else to conflict
54                // with focus. And in the common case, we have a tree of Containers, with
55                // non-Container leaves.
56                if w.id.as_ref() != Some(id) && !w.widget.is::<Container>() {
57                    continue;
58                }
59            }
60            w.widget.event(ctx, output);
61            // If the widget produced an outcome, short-circuit.
62            if !matches!(output.outcome, Outcome::Nothing) {
63                return;
64            }
65        }
66    }
67
68    fn draw(&self, g: &mut GfxCtx) {
69        for w in &self.members {
70            w.draw(g);
71        }
72    }
73}