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
125
use crate::{
text, EventCtx, GeomBatch, GfxCtx, Key, Line, Outcome, ScreenDims, ScreenPt, ScreenRectangle,
Text, WidgetImpl, WidgetOutput,
};
use geom::Polygon;
pub struct TextBox {
line: String,
cursor_x: usize,
has_focus: bool,
hovering: bool,
autofocus: bool,
top_left: ScreenPt,
dims: ScreenDims,
}
impl TextBox {
pub fn new(ctx: &EventCtx, max_chars: usize, prefilled: String, autofocus: bool) -> TextBox {
TextBox {
cursor_x: prefilled.len(),
line: prefilled,
has_focus: false,
hovering: false,
autofocus,
top_left: ScreenPt::new(0.0, 0.0),
dims: ScreenDims::new(
(max_chars as f64) * text::MAX_CHAR_WIDTH,
ctx.default_line_height(),
),
}
}
fn calculate_text(&self) -> Text {
let mut txt = Text::from(Line(&self.line[0..self.cursor_x]));
if self.cursor_x < self.line.len() {
txt.append_all(vec![
Line("|").fg(text::SELECTED_COLOR),
Line(&self.line[self.cursor_x..=self.cursor_x]),
Line(&self.line[self.cursor_x + 1..]),
]);
} else {
txt.append(Line("|").fg(text::SELECTED_COLOR));
}
txt
}
pub fn get_line(&self) -> String {
self.line.clone()
}
}
impl WidgetImpl for TextBox {
fn get_dims(&self) -> ScreenDims {
self.dims
}
fn set_pos(&mut self, top_left: ScreenPt) {
self.top_left = top_left;
}
fn event(&mut self, ctx: &mut EventCtx, output: &mut WidgetOutput) {
if ctx.redo_mouseover() {
if let Some(pt) = ctx.canvas.get_cursor_in_screen_space() {
self.hovering = ScreenRectangle::top_left(self.top_left, self.dims).contains(pt);
} else {
self.hovering = false;
}
}
if ctx.normal_left_click() {
ctx.input.unconsume_event();
self.has_focus = self.hovering;
}
if !self.has_focus && !self.autofocus {
return;
}
if let Some(key) = ctx.input.any_pressed() {
match key {
Key::LeftArrow => {
if self.cursor_x > 0 {
self.cursor_x -= 1;
}
}
Key::RightArrow => {
self.cursor_x = (self.cursor_x + 1).min(self.line.len());
}
Key::Backspace => {
if self.cursor_x > 0 {
output.outcome = Outcome::Changed;
self.line.remove(self.cursor_x - 1);
self.cursor_x -= 1;
}
}
_ => {
if let Some(c) = key.to_char(ctx.canvas.lshift_held) {
output.outcome = Outcome::Changed;
self.line.insert(self.cursor_x, c);
self.cursor_x += 1;
} else {
ctx.input.unconsume_event();
}
}
};
}
}
fn draw(&self, g: &mut GfxCtx) {
let mut batch = GeomBatch::from(vec![(
text::BG_COLOR,
Polygon::rectangle(self.dims.width, self.dims.height),
)]);
batch.append(self.calculate_text().render_to_batch(g.prerender));
let draw = g.upload(batch);
g.redraw_at(self.top_left, &draw);
}
}