grafix_toolbox/gui/elements/
lineedit.rs1use super::{util::caret as ca, *};
2
3#[derive(Default, Debug)]
4pub struct LineEdit {
5 offset: Vec2,
6 size: Vec2,
7 scale: f32,
8 caret: isize,
9 pub editing: bool,
10 pub text: CachedStr,
11}
12impl LineEdit {
13 pub fn edited(&self, r: &RenderLock) -> vec2<bool> {
14 let editing = r.focused(ref_UUID(self));
15 let r @ (_edit_started, _edited) = (!self.editing && editing, !editing && self.editing);
16 r
17 }
18 pub fn draw<'s: 'l, 'l>(&'s mut self, r: &mut RenderLock<'l>, t: &'l Theme, layout @ Surf { pos, size }: Surf, filter: Option<&'l HashSet<char>>) -> Option<&'l str> {
19 let CUR_PAD = 0.01;
20 let (id, s, font) = (ref_UUID(self), self, &t.font);
21
22 if s.text.changed() || s.size != size {
23 ((s.offset, s.scale), s.size) = (u::fit_line(&s.text, font, t.font_size, size), size);
24 }
25 let Self {
26 offset, scale, ref mut caret, ref mut editing, ref mut text, ..
27 } = *s;
28
29 r.draw(Rect { pos, size, color: t.bg });
30
31 let (te @ Surf { pos, .. }, focused) = (layout.xy(offset), r.focused(id));
32 if focused {
33 let x = ca::adv(text, font, scale, (*caret, 0), CUR_PAD);
34 let Surf { pos, size } = te.x(x).size((CUR_PAD, scale));
35 r.draw(Rect { pos, size, color: t.highlight });
36 }
37
38 r.draw(Text { pos, color: t.text, scale, text, font });
39
40 let (text, edited) = (Cell::from_mut(text), !focused && *editing);
41 *editing = focused;
42 r.logic(
43 layout,
44 move |e, focused, mouse_pos| {
45 let clamp = |o| ca::set(text.bind(), (*caret + o, 0), (0, 0)).0;
46 let click = |p: Vec2| ca::at_pos(text.bind(), font, scale, 0, p.sub(pos)).0;
47 let idx = |o| ca::idx(text.bind(), (*caret, 0), (o, 0));
48 match *e {
49 OfferFocus => (),
50 MouseButton { m, .. } if m.pressed() => *caret = click(mouse_pos),
51 Keyboard { key, m } if focused && m.pressed() => match key {
52 Key::Right => *caret = u::if_ctrl(m, 10, 1).pipe(clamp),
53 Key::Left => *caret = u::if_ctrl(m, -10, -1).pipe(clamp),
54 Key::Delete if idx(0) < text.bind().len() => {
55 let i = idx(0);
56 text.mutate(|t| t.str().remove(i));
57 }
58 Key::Backspace if idx(0) > 0 => {
59 let i = idx(-1);
60 *caret = clamp(-1);
61 text.mutate(|t| t.str().remove(i));
62 }
63 Key::Return | Key::Escape => return DropFocus,
64 _ => return Pass,
65 },
66 Char { ch } if focused => {
67 let filter = filter.map(|f| f.get(&ch).is_some()).unwrap_or(true);
68 if filter {
69 let i = idx(0);
70 text.mutate(|t| t.str().insert(i, ch));
71 *caret += 1;
72 }
73 }
74 _ => return Pass,
75 }
76 Accept
77 },
78 id,
79 );
80 None.or_val(!edited, || Some(unsafe { &**text.as_ptr() }))
81 }
82}
83
84impl<'s: 'l, 'l> Lock::LineEdit<'s, 'l, '_> {
85 pub fn draw(self, g: impl Into<Surf>) -> Option<&'l str> {
86 let Self { s, r, t } = self;
87 s.draw(r, t, g.into(), None)
88 }
89}