widgetry/widgets/
just_draw.rs1use geom::Polygon;
2
3use crate::{
4 ClickOutcome, Drawable, EventCtx, GeomBatch, GfxCtx, Outcome, ScreenDims, ScreenPt,
5 ScreenRectangle, Text, Widget, WidgetImpl, WidgetOutput,
6};
7
8pub struct JustDraw {
10 pub draw: Drawable,
11
12 pub top_left: ScreenPt,
13 pub dims: ScreenDims,
14}
15
16impl JustDraw {
17 pub(crate) fn wrap(ctx: &EventCtx, batch: GeomBatch) -> Widget {
18 Widget::new(Box::new(JustDraw {
19 dims: batch.get_dims(),
20 draw: ctx.upload(batch),
21 top_left: ScreenPt::new(0.0, 0.0),
22 }))
23 }
24}
25
26impl WidgetImpl for JustDraw {
27 fn get_dims(&self) -> ScreenDims {
28 self.dims
29 }
30
31 fn set_pos(&mut self, top_left: ScreenPt) {
32 self.top_left = top_left;
33 }
34
35 fn event(&mut self, _: &mut EventCtx, _: &mut WidgetOutput) {}
36
37 fn draw(&self, g: &mut GfxCtx) {
38 g.redraw_at(self.top_left, &self.draw);
39 }
40}
41
42pub struct DrawWithTooltips {
43 draw: Drawable,
44 tooltips: Vec<(Polygon, Text, Option<ClickOutcome>)>,
45 hover: Box<dyn Fn(&Polygon) -> GeomBatch>,
46 hovering_on_idx: Option<usize>,
47
48 top_left: ScreenPt,
49 dims: ScreenDims,
50}
51
52impl DrawWithTooltips {
53 pub fn new_widget(
61 ctx: &EventCtx,
62 batch: GeomBatch,
63 tooltips: Vec<(Polygon, Text, Option<ClickOutcome>)>,
64 hover: Box<dyn Fn(&Polygon) -> GeomBatch>,
65 ) -> Widget {
66 Widget::new(Box::new(DrawWithTooltips {
67 dims: batch.get_dims(),
68 top_left: ScreenPt::new(0.0, 0.0),
69 hover,
70 hovering_on_idx: None,
71 draw: ctx.upload(batch),
72 tooltips,
73 }))
74 }
75}
76
77impl WidgetImpl for DrawWithTooltips {
78 fn get_dims(&self) -> ScreenDims {
79 self.dims
80 }
81
82 fn set_pos(&mut self, top_left: ScreenPt) {
83 self.top_left = top_left;
84 }
85
86 fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
87 if ctx.redo_mouseover() {
88 self.hovering_on_idx = None;
89 if let Some(cursor) = ctx.canvas.get_cursor_in_screen_space() {
90 if !ScreenRectangle::top_left(self.top_left, self.dims).contains(cursor) {
91 return;
92 }
93 let translated =
94 ScreenPt::new(cursor.x - self.top_left.x, cursor.y - self.top_left.y).to_pt();
95 for (idx, (hitbox, _, _)) in self.tooltips.iter().enumerate() {
96 if hitbox.contains_pt(translated) {
97 self.hovering_on_idx = Some(idx);
98 break;
99 }
100 }
101 }
102 }
103
104 if let Some(idx) = self.hovering_on_idx {
105 if ctx.normal_left_click() {
106 if let Some(ref label) = self.tooltips[idx].2 {
107 output.outcome = match label {
108 ClickOutcome::Label(label) => Outcome::Clicked(label.clone()),
109 ClickOutcome::Custom(data) => Outcome::ClickCustom(data.clone()),
110 }
111 }
112 }
113 }
114 }
115
116 fn draw(&self, g: &mut GfxCtx) {
117 g.redraw_at(self.top_left, &self.draw);
118 if let Some(idx) = self.hovering_on_idx {
119 let (hitbox, txt, _) = &self.tooltips[idx];
120 let extra = g.upload((self.hover)(hitbox));
121 g.redraw_at(self.top_left, &extra);
122 g.draw_mouse_tooltip(txt.clone());
123 }
124 }
125}
126
127pub struct DeferDraw {
130 pub batch: GeomBatch,
131
132 pub top_left: ScreenPt,
133 dims: ScreenDims,
134}
135
136impl DeferDraw {
137 pub fn new_widget(batch: GeomBatch) -> Widget {
138 Widget::new(Box::new(DeferDraw {
139 dims: batch.get_dims(),
140 batch,
141 top_left: ScreenPt::new(0.0, 0.0),
142 }))
143 }
144}
145
146impl WidgetImpl for DeferDraw {
147 fn get_dims(&self) -> ScreenDims {
148 self.dims
149 }
150
151 fn set_pos(&mut self, top_left: ScreenPt) {
152 self.top_left = top_left;
153 }
154
155 fn event(&mut self, _: &mut EventCtx, _: &mut WidgetOutput) {
156 unreachable!()
157 }
158
159 fn draw(&self, _: &mut GfxCtx) {
160 unreachable!()
161 }
162}