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
use makepad_render::*;
use crate::texteditor::*;
use crate::textbuffer::*;
use crate::plaineditor::*;
use crate::widgetstyle::*;
#[derive(Clone)]
pub struct TextInput {
    pub text_editor: TextEditor,
    pub text_buffer: TextBuffer,
    pub empty_message: String,
}

pub struct TextInputOptions {
    pub multiline: bool,
    pub read_only: bool,
    pub empty_message: String
}

impl TextInput {
    
    pub fn proto(cx: &mut Cx, opt: TextInputOptions) -> Self {
        Self {
            text_editor: TextEditor {
                read_only: opt.read_only,
                multiline: opt.multiline,
                draw_line_numbers: false,
                draw_cursor_row: false,
                highlight_area_on: false,
                line_number_width: 0.,
                top_padding: 0.,
                mark_unmatched_parens: false,
                view_layout: Layout {
                    walk: Walk {width: Width::Compute, height: Height::Compute, margin: Margin {t: 4., l: 0., r: 0., b: 0.}},
                    padding: Padding::all(7.),
                    ..Layout::default()
                },
                folding_depth: 3,
                ..TextEditor::proto(cx)
            },
            empty_message: opt.empty_message,
            text_buffer: TextBuffer::from_utf8(""),
        }
    }
    
    pub fn style_text_input() -> StyleId {uid!()}
    
    pub fn style(cx: &mut Cx, _opt: &StyleOptions) {
        cx.begin_style(Self::style_text_input());
        TextEditor::color_bg().set(cx, Theme::color_bg_normal().get(cx));
        TextEditor::gutter_width().set(cx, 0.);
        TextEditor::padding_top().set(cx, 0.);
        TextEditor::shader_bg().set(cx, Quad::def_quad_shader().compose(shader_ast!({
            fn pixel() -> vec4 {
                df_viewport(pos * vec2(w, h));
                df_box(0., 0., w, h, 2.5);
                return df_fill(color);
            }
        })));
        cx.end_style();
    }
    
    pub fn handle_text_input(&mut self, cx: &mut Cx, event: &mut Event) -> TextEditorEvent {
        let text_buffer = &mut self.text_buffer;
        let ce = self.text_editor.handle_text_editor(cx, event, text_buffer);
        ce
    }
    
    pub fn set_value(&mut self, cx: &mut Cx, text: &str) {
        let text_buffer = &mut self.text_buffer;
        text_buffer.load_from_utf8(text);
        self.text_editor.view.redraw_view_area(cx);
    }
    
    pub fn get_value(&self) -> String {
        self.text_buffer.get_as_string()
    }
    
    pub fn draw_text_input_static(&mut self, cx: &mut Cx, text: &str) {
        let text_buffer = &mut self.text_buffer;
        text_buffer.load_from_utf8(text);
        self.draw_text_input(cx);
    }
    
    pub fn draw_text_input(&mut self, cx: &mut Cx) {
        cx.begin_style(Self::style_text_input());
        let text_buffer = &mut self.text_buffer;
        if text_buffer.needs_token_chunks() && text_buffer.lines.len() >0 {
            
            let mut state = TokenizerState::new(&text_buffer.lines);
            let mut tokenizer = PlainTokenizer::new();
            let mut pair_stack = Vec::new();
            loop {
                let offset = text_buffer.flat_text.len();
                let token_type = tokenizer.next_token(&mut state, &mut text_buffer.flat_text, &text_buffer.token_chunks);
                TokenChunk::push_with_pairing(&mut text_buffer.token_chunks, &mut pair_stack, state.next, offset, text_buffer.flat_text.len(), token_type);
                if token_type == TokenType::Eof {
                    break
                }
            }
        }
        
        if self.text_editor.begin_text_editor(cx, text_buffer).is_err() {return cx.end_style();}
        
        if text_buffer.is_empty() {
            let pos = cx.get_turtle_pos();
            self.text_editor.text.color = color("#666");
            self.text_editor.text.draw_text(cx, &self.empty_message);
            cx.set_turtle_pos(pos);
        }
        
        for (index, token_chunk) in text_buffer.token_chunks.iter_mut().enumerate() {
            self.text_editor.draw_chunk(cx, index, &text_buffer.flat_text, token_chunk, &text_buffer.messages.cursors);
        }
        
        self.text_editor.end_text_editor(cx, text_buffer);
        cx.end_style();
    }
}