makepad_widget/
textinput.rs1use makepad_render::*;
2use crate::texteditor::*;
3use crate::textbuffer::*;
4use crate::plaineditor::*;
5use crate::widgetstyle::*;
6#[derive(Clone)]
7pub struct TextInput {
8 pub text_editor: TextEditor,
9 pub text_buffer: TextBuffer,
10 pub empty_message: String,
11}
12
13pub struct TextInputOptions {
14 pub multiline: bool,
15 pub read_only: bool,
16 pub empty_message: String
17}
18
19impl TextInput {
20
21 pub fn proto(cx: &mut Cx, opt: TextInputOptions) -> Self {
22 Self {
23 text_editor: TextEditor {
24 read_only: opt.read_only,
25 multiline: opt.multiline,
26 draw_line_numbers: false,
27 draw_cursor_row: false,
28 highlight_area_on: false,
29 line_number_width: 0.,
30 top_padding: 0.,
31 mark_unmatched_parens: false,
32 view_layout: Layout {
33 walk: Walk {width: Width::Compute, height: Height::Compute, margin: Margin {t: 4., l: 0., r: 0., b: 0.}},
34 padding: Padding::all(7.),
35 ..Layout::default()
36 },
37 folding_depth: 3,
38 ..TextEditor::proto(cx)
39 },
40 empty_message: opt.empty_message,
41 text_buffer: TextBuffer::from_utf8(""),
42 }
43 }
44
45 pub fn style_text_input() -> StyleId {uid!()}
46
47 pub fn style(cx: &mut Cx, _opt: &StyleOptions) {
48 cx.begin_style(Self::style_text_input());
49 TextEditor::color_bg().set(cx, Theme::color_bg_normal().get(cx));
50 TextEditor::gutter_width().set(cx, 0.);
51 TextEditor::padding_top().set(cx, 0.);
52 TextEditor::shader_bg().set(cx, Quad::def_quad_shader().compose(shader_ast!({
53 fn pixel() -> vec4 {
54 df_viewport(pos * vec2(w, h));
55 df_box(0., 0., w, h, 2.5);
56 return df_fill(color);
57 }
58 })));
59 cx.end_style();
60 }
61
62 pub fn handle_text_input(&mut self, cx: &mut Cx, event: &mut Event) -> TextEditorEvent {
63 let text_buffer = &mut self.text_buffer;
64 let ce = self.text_editor.handle_text_editor(cx, event, text_buffer);
65 ce
66 }
67
68 pub fn set_value(&mut self, cx: &mut Cx, text: &str) {
69 let text_buffer = &mut self.text_buffer;
70 text_buffer.load_from_utf8(text);
71 self.text_editor.view.redraw_view_area(cx);
72 }
73
74 pub fn get_value(&self) -> String {
75 self.text_buffer.get_as_string()
76 }
77
78 pub fn draw_text_input_static(&mut self, cx: &mut Cx, text: &str) {
79 let text_buffer = &mut self.text_buffer;
80 text_buffer.load_from_utf8(text);
81 self.draw_text_input(cx);
82 }
83
84 pub fn draw_text_input(&mut self, cx: &mut Cx) {
85 cx.begin_style(Self::style_text_input());
86 let text_buffer = &mut self.text_buffer;
87 if text_buffer.needs_token_chunks() && text_buffer.lines.len() >0 {
88
89 let mut state = TokenizerState::new(&text_buffer.lines);
90 let mut tokenizer = PlainTokenizer::new();
91 let mut pair_stack = Vec::new();
92 loop {
93 let offset = text_buffer.flat_text.len();
94 let token_type = tokenizer.next_token(&mut state, &mut text_buffer.flat_text, &text_buffer.token_chunks);
95 TokenChunk::push_with_pairing(&mut text_buffer.token_chunks, &mut pair_stack, state.next, offset, text_buffer.flat_text.len(), token_type);
96 if token_type == TokenType::Eof {
97 break
98 }
99 }
100 }
101
102 if self.text_editor.begin_text_editor(cx, text_buffer).is_err() {return cx.end_style();}
103
104 if text_buffer.is_empty() {
105 let pos = cx.get_turtle_pos();
106 self.text_editor.text.color = color("#666");
107 self.text_editor.text.draw_text(cx, &self.empty_message);
108 cx.set_turtle_pos(pos);
109 }
110
111 for (index, token_chunk) in text_buffer.token_chunks.iter_mut().enumerate() {
112 self.text_editor.draw_chunk(cx, index, &text_buffer.flat_text, token_chunk, &text_buffer.messages.cursors);
113 }
114
115 self.text_editor.end_text_editor(cx, text_buffer);
116 cx.end_style();
117 }
118}