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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::{
text, Btn, Button, EventCtx, GeomBatch, GfxCtx, Line, Outcome, ScreenDims, ScreenPt,
ScreenRectangle, Text, Widget, WidgetImpl, WidgetOutput,
};
use geom::{Polygon, Pt2D};
const TEXT_WIDTH: f64 = 2.0 * text::MAX_CHAR_WIDTH;
pub struct Spinner {
low: isize,
high: isize,
pub current: isize,
up: Button,
down: Button,
top_left: ScreenPt,
dims: ScreenDims,
}
impl Spinner {
pub fn new(ctx: &EventCtx, (low, high): (isize, isize), current: isize) -> Widget {
let up = Btn::text_fg("↑")
.build(ctx, "increase value", None)
.take_btn();
let down = Btn::text_fg("↓")
.build(ctx, "decrease value", None)
.take_btn();
let dims = ScreenDims::new(
TEXT_WIDTH + up.get_dims().width,
up.get_dims().height + down.get_dims().height,
);
Widget::new(Box::new(Spinner {
low,
high,
current,
up,
down,
top_left: ScreenPt::new(0.0, 0.0),
dims,
}))
}
}
impl WidgetImpl for Spinner {
fn get_dims(&self) -> ScreenDims {
self.dims
}
fn set_pos(&mut self, top_left: ScreenPt) {
self.top_left = top_left;
self.up
.set_pos(ScreenPt::new(top_left.x + TEXT_WIDTH, top_left.y));
self.down.set_pos(ScreenPt::new(
top_left.x + TEXT_WIDTH,
top_left.y + self.up.get_dims().height,
));
}
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
self.up.event(ctx, output);
if let Outcome::Clicked(_) = output.outcome {
output.outcome = Outcome::Changed;
if self.current != self.high {
self.current += 1;
}
ctx.no_op_event(true, |ctx| self.up.event(ctx, output));
return;
}
self.down.event(ctx, output);
if let Outcome::Clicked(_) = output.outcome {
output.outcome = Outcome::Changed;
if self.current != self.low {
self.current -= 1;
}
ctx.no_op_event(true, |ctx| self.down.event(ctx, output));
return;
}
if let Some(pt) = ctx.canvas.get_cursor_in_screen_space() {
if ScreenRectangle::top_left(self.top_left, self.dims).contains(pt) {
if let Some((_, dy)) = ctx.input.get_mouse_scroll() {
if dy > 0.0 && self.current != self.high {
self.current += 1;
output.outcome = Outcome::Changed;
}
if dy < 0.0 && self.current != self.low {
self.current -= 1;
output.outcome = Outcome::Changed;
}
}
}
}
}
fn draw(&self, g: &mut GfxCtx) {
let mut batch = GeomBatch::from(vec![(
text::BG_COLOR,
Polygon::rounded_rectangle(self.dims.width, self.dims.height, Some(5.0)),
)]);
batch.append(
Text::from(Line(self.current.to_string()))
.render_to_batch(g.prerender)
.centered_on(Pt2D::new(TEXT_WIDTH / 2.0, self.dims.height / 2.0)),
);
let draw = g.upload(batch);
g.redraw_at(self.top_left, &draw);
self.up.draw(g);
self.down.draw(g);
}
}