egui_probe/
text.rs

1use std::{any::TypeId, ops::Range};
2
3use crate::{EguiProbe, Style, option::option_probe_with};
4
5impl EguiProbe for String {
6    #[inline(always)]
7    fn probe(&mut self, ui: &mut egui::Ui, _: &Style) -> egui::Response {
8        ui.add(egui::TextEdit::singleline(self))
9    }
10}
11
12impl EguiProbe for &str {
13    #[inline(always)]
14    fn probe(&mut self, ui: &mut egui::Ui, _: &Style) -> egui::Response {
15        ui.add(egui::TextEdit::singleline(self))
16    }
17}
18
19struct CharBuffer {
20    ch: char,
21    buf: [u8; 4],
22}
23
24impl CharBuffer {
25    const fn new(ch: char) -> Self {
26        let mut buf = [0; 4];
27        let _ = ch.encode_utf8(&mut buf);
28        CharBuffer { ch, buf }
29    }
30}
31
32impl Default for CharBuffer {
33    fn default() -> Self {
34        Self::new('\0')
35    }
36}
37
38impl egui::text_edit::TextBuffer for CharBuffer {
39    fn is_mutable(&self) -> bool {
40        true
41    }
42
43    fn as_str(&self) -> &str {
44        // SAFETY: prefix of buf is valid UTF-8
45        unsafe { std::str::from_utf8_unchecked(&self.buf[..self.ch.len_utf8()]) }
46    }
47
48    fn insert_text(&mut self, text: &str, char_index: usize) -> usize {
49        if char_index > 1 {
50            return 0;
51        }
52        match text.chars().next() {
53            None => 0,
54            Some(c) => {
55                self.ch = c;
56                let _ = c.encode_utf8(&mut self.buf);
57                1
58            }
59        }
60    }
61
62    fn delete_char_range(&mut self, _char_range: Range<usize>) {}
63
64    fn type_id(&self) -> TypeId {
65        TypeId::of::<Self>()
66    }
67}
68
69impl EguiProbe for char {
70    #[inline(always)]
71    fn probe(&mut self, ui: &mut egui::Ui, _: &Style) -> egui::Response {
72        let mut buf = CharBuffer::new(*self);
73        let r = ui.add(egui::TextEdit::singleline(&mut buf));
74        if r.changed() {
75            *self = buf.ch;
76        }
77        r
78    }
79}
80
81/// Wrapper for string-like types to show multiline text field.
82pub struct EguiProbeMultiline<'a, T> {
83    pub string: &'a mut T,
84}
85
86impl EguiProbe for EguiProbeMultiline<'_, String> {
87    #[inline(always)]
88    fn probe(&mut self, ui: &mut egui::Ui, _: &Style) -> egui::Response {
89        ui.add(egui::TextEdit::multiline(self.string))
90    }
91}
92
93impl EguiProbe for EguiProbeMultiline<'_, &str> {
94    #[inline(always)]
95    fn probe(&mut self, ui: &mut egui::Ui, _: &Style) -> egui::Response {
96        ui.add(egui::TextEdit::multiline(self.string))
97    }
98}
99
100impl EguiProbe for EguiProbeMultiline<'_, Option<String>> {
101    #[inline(always)]
102    fn probe(&mut self, ui: &mut egui::Ui, style: &Style) -> egui::Response {
103        option_probe_with(self.string, ui, style, String::new, |string, ui, _| {
104            ui.add(egui::TextEdit::multiline(string))
105        })
106    }
107}
108
109impl EguiProbe for EguiProbeMultiline<'_, Option<&str>> {
110    #[inline(always)]
111    fn probe(&mut self, ui: &mut egui::Ui, style: &Style) -> egui::Response {
112        option_probe_with(
113            self.string,
114            ui,
115            style,
116            || "",
117            |string, ui, _| ui.add(egui::TextEdit::multiline(string)),
118        )
119    }
120}