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
use super::*;

#[derive(Default)]
pub struct LineEdit {
	offset: Vec2,
	size: Vec2,
	scale: f32,
	caret: usize,
	pub text: CachedStr,
}
impl LineEdit {
	pub fn draw<'s>(&'s mut self, r: &mut RenderLock<'s>, t: &'s Theme, pos: Vec2, size: Vec2) {
		const CUR_PAD: f32 = 0.01;

		if self.text.changed() || self.size != size {
			let (offset, scale) = util::fit_text(&self.text, t, size);

			self.offset = offset;
			self.size = size;
			self.scale = scale;
		}

		r.draw(Rect { pos, size, color: t.bg });

		let id = LUID(self);
		let Self { offset, scale, caret, text, .. } = self;

		if r.focused(id) {
			let x = util::caret_x(text, t, *scale, *caret, CUR_PAD);
			r.draw(Rect {
				pos: offset.sum(pos).sum((x, 0.)),
				size: (CUR_PAD, *scale),
				color: t.highlight,
			});
		}

		r.draw(Text {
			pos: offset.sum(pos),
			color: t.text,
			scale: *scale,
			text,
			font: &t.font,
		});
		r.logic(
			(pos, pos.sum(size)),
			move |e, focused, mouse_pos| {
				let mut _text = StaticPtr!(text);
				let clamp = |c, o| util::move_caret(&[(text as &str)], (c, 0), (o, 0), true).0;
				let click = || util::caret_to_cursor(&[(text as &str)], (0., 0.), t, *scale, (pos.x() + offset.x(), 0.), mouse_pos).0;
				let idx = |o| {
					let (pos, o) = ilVec2((*caret, o));
					(text as &str).len_at_char(usize((pos + o).max(0)))
				};
				let text = _text.get_mut();

				match e {
					OfferFocus => return Accept,
					MouseButton { state, .. } if state.pressed() => *caret = click(),
					Keyboard { key, state } if focused && state.pressed() => match key {
						Key::Enter | Key::Escape if focused => return CancelFocus,
						Key::Right => *caret = clamp(*caret, if state.ctrl() { 10 } else { 1 }),
						Key::Left => *caret = clamp(*caret, -if state.ctrl() { 10 } else { 1 }),
						Key::Delete if idx(-1) < text.len() => {
							let i = idx(-1);
							text.str().remove(i);
						}
						Key::Backspace if idx(-1) > 0 => {
							let i = idx(-2);
							*caret = clamp(*caret, -1);
							text.str().remove(i);
						}
						_ => (),
					},
					Char { ch } if focused => {
						let i = idx(-1);
						text.str().insert(i, *ch);
						*caret = clamp(*caret, 1);
					}
					_ => (),
				}
				if focused {
					Accept
				} else {
					Reject
				}
			},
			id,
		);
	}
}