rat_text/
text_input.rs

1//!
2//! Text input widget.
3//!
4//! * Can do the usual insert/delete/movement operations.
5//! * Text selection via keyboard and mouse.
6//! * Scrolls with the cursor.
7//! * Invalid flag.
8//!
9//! The visual cursor must be set separately after rendering.
10//! It is accessible as [TextInputState::screen_cursor()] after rendering.
11//!
12//! Event handling by calling the freestanding fn [handle_events].
13//! There's [handle_mouse_events] if you want to override the default key bindings but keep
14//! the mouse behaviour.
15//!
16use crate::_private::NonExhaustive;
17use crate::clipboard::{Clipboard, global_clipboard};
18use crate::core::core_op::*;
19use crate::core::{TextCore, TextString};
20use crate::event::{ReadOnly, TextOutcome};
21use crate::glyph2::{Glyph2, TextWrap2};
22use crate::text_store::TextStore;
23use crate::undo_buffer::{UndoBuffer, UndoEntry, UndoVec};
24use crate::{
25    HasScreenCursor, TextError, TextFocusGained, TextFocusLost, TextPosition, TextRange, TextStyle,
26    ipos_type, upos_type,
27};
28use crossterm::event::KeyModifiers;
29use rat_event::util::MouseFlags;
30use rat_event::{HandleEvent, MouseOnly, Regular, ct_event};
31use rat_focus::{FocusBuilder, FocusFlag, HasFocus};
32use rat_reloc::{RelocatableState, relocate_dark_offset};
33use ratatui::buffer::Buffer;
34use ratatui::layout::{Rect, Size};
35use ratatui::prelude::BlockExt;
36use ratatui::style::{Style, Stylize};
37use ratatui::widgets::{Block, StatefulWidget, Widget};
38use std::borrow::Cow;
39use std::cell::Cell;
40use std::cmp::min;
41use std::collections::HashMap;
42use std::ops::Range;
43use std::rc::Rc;
44
45/// Text input widget.
46///
47/// # Stateful
48/// This widget implements [`StatefulWidget`], you can use it with
49/// [`TextInputState`] to handle common actions.
50#[derive(Debug, Default, Clone)]
51pub struct TextInput<'a> {
52    style: Style,
53    block: Option<Block<'a>>,
54    focus_style: Option<Style>,
55    select_style: Option<Style>,
56    invalid_style: Option<Style>,
57
58    on_focus_gained: TextFocusGained,
59    on_focus_lost: TextFocusLost,
60    passwd: bool,
61
62    text_style: HashMap<usize, Style>,
63}
64
65/// State for TextInput.
66#[derive(Debug)]
67pub struct TextInputState {
68    /// The whole area with block.
69    /// __read only__ renewed with each render.
70    pub area: Rect,
71    /// Area inside a possible block.
72    /// __read only__ renewed with each render.
73    pub inner: Rect,
74    /// Rendered dimension. This may differ from (inner.width, inner.height)
75    /// if the text area has been relocated.
76    /// __read only__ renewed with each render.
77    pub rendered: Size,
78
79    /// Display offset.
80    /// __read+write__
81    pub offset: upos_type,
82    /// Dark offset due to clipping. Always set during rendering.
83    /// __read only__ ignore this value.
84    pub dark_offset: (u16, u16),
85    /// __read only__ use [scroll_cursor_to_visible](TextInputState::scroll_cursor_to_visible)
86    pub scroll_to_cursor: Rc<Cell<bool>>,
87
88    /// Editing core
89    pub value: TextCore<TextString>,
90    /// Display as invalid.
91    /// __read only__ use [set_invalid](TextInputState::set_invalid)
92    pub invalid: bool,
93    /// Display as password.
94    /// __read only__ use [passwd](TextInput::passwd)
95    pub passwd: bool,
96    /// The next user edit clears the text for doing any edit.
97    /// It will reset this flag. Other interactions may reset this flag too.
98    /// __read only__ use [set_overwrite](TextInputState::set_overwrite)
99    pub overwrite: Rc<Cell<bool>>,
100    /// Focus behaviour.
101    /// __read only__ use [on_focus_gained](TextInput::on_focus_gained)
102    pub on_focus_gained: Rc<Cell<TextFocusGained>>,
103    /// Focus behaviour.
104    /// __read only__ use [on_focus_lost](TextInput::on_focus_lost)
105    pub on_focus_lost: Rc<Cell<TextFocusLost>>,
106
107    /// Current focus state.
108    /// __read + write__ But don't write it.
109    pub focus: FocusFlag,
110
111    /// Mouse selection in progress.
112    /// __read+write__
113    pub mouse: MouseFlags,
114
115    /// Construct with `..Default::default()`
116    pub non_exhaustive: NonExhaustive,
117}
118
119impl<'a> TextInput<'a> {
120    /// New widget.
121    pub fn new() -> Self {
122        Self::default()
123    }
124
125    /// Set the combined style.
126    #[inline]
127    pub fn styles_opt(self, styles: Option<TextStyle>) -> Self {
128        if let Some(styles) = styles {
129            self.styles(styles)
130        } else {
131            self
132        }
133    }
134
135    /// Set the combined style.
136    #[inline]
137    pub fn styles(mut self, styles: TextStyle) -> Self {
138        self.style = styles.style;
139        if styles.block.is_some() {
140            self.block = styles.block;
141        }
142        if let Some(border_style) = styles.border_style {
143            self.block = self.block.map(|v| v.border_style(border_style));
144        }
145        if let Some(title_style) = styles.title_style {
146            self.block = self.block.map(|v| v.title_style(title_style));
147        }
148        self.block = self.block.map(|v| v.style(self.style));
149
150        if styles.focus.is_some() {
151            self.focus_style = styles.focus;
152        }
153        if styles.select.is_some() {
154            self.select_style = styles.select;
155        }
156        if styles.invalid.is_some() {
157            self.invalid_style = styles.invalid;
158        }
159        if let Some(of) = styles.on_focus_gained {
160            self.on_focus_gained = of;
161        }
162        if let Some(of) = styles.on_focus_lost {
163            self.on_focus_lost = of;
164        }
165        self
166    }
167
168    /// Base text style.
169    #[inline]
170    pub fn style(mut self, style: impl Into<Style>) -> Self {
171        let style = style.into();
172        self.style = style.clone();
173        self.block = self.block.map(|v| v.style(style));
174        self
175    }
176
177    /// Style when focused.
178    #[inline]
179    pub fn focus_style(mut self, style: impl Into<Style>) -> Self {
180        self.focus_style = Some(style.into());
181        self
182    }
183
184    /// Style for selection
185    #[inline]
186    pub fn select_style(mut self, style: impl Into<Style>) -> Self {
187        self.select_style = Some(style.into());
188        self
189    }
190
191    /// Style for the invalid indicator.
192    /// This is patched onto either base_style or focus_style
193    #[inline]
194    pub fn invalid_style(mut self, style: impl Into<Style>) -> Self {
195        self.invalid_style = Some(style.into());
196        self
197    }
198
199    /// Indexed text-style.
200    ///
201    /// Use [TextAreaState::add_style()] to refer a text range to
202    /// one of these styles.
203    pub fn text_style_idx(mut self, idx: usize, style: Style) -> Self {
204        self.text_style.insert(idx, style);
205        self
206    }
207
208    /// List of text-styles.
209    ///
210    /// Use [TextAreaState::add_style()] to refer a text range to
211    /// one of these styles.
212    pub fn text_style<T: IntoIterator<Item = Style>>(mut self, styles: T) -> Self {
213        for (i, s) in styles.into_iter().enumerate() {
214            self.text_style.insert(i, s);
215        }
216        self
217    }
218
219    /// Map of style_id -> text_style.
220    ///
221    /// Use [TextAreaState::add_style()] to refer a text range to
222    /// one of these styles.
223    pub fn text_style_map<T: Into<Style>>(mut self, styles: HashMap<usize, T>) -> Self {
224        for (i, s) in styles.into_iter() {
225            self.text_style.insert(i, s.into());
226        }
227        self
228    }
229
230    /// Block.
231    #[inline]
232    pub fn block(mut self, block: Block<'a>) -> Self {
233        self.block = Some(block);
234        self
235    }
236
237    /// Display as password field.
238    #[inline]
239    pub fn passwd(mut self) -> Self {
240        self.passwd = true;
241        self
242    }
243
244    /// Focus behaviour
245    #[inline]
246    pub fn on_focus_gained(mut self, of: TextFocusGained) -> Self {
247        self.on_focus_gained = of;
248        self
249    }
250
251    /// Focus behaviour
252    #[inline]
253    pub fn on_focus_lost(mut self, of: TextFocusLost) -> Self {
254        self.on_focus_lost = of;
255        self
256    }
257
258    /// Preferred width: 0
259    pub fn width(&self) -> u16 {
260        0
261    }
262
263    /// Preferred height: 1
264    pub fn height(&self) -> u16 {
265        1
266    }
267}
268
269impl<'a> StatefulWidget for &TextInput<'a> {
270    type State = TextInputState;
271
272    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
273        render_ref(self, area, buf, state);
274    }
275}
276
277impl StatefulWidget for TextInput<'_> {
278    type State = TextInputState;
279
280    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
281        render_ref(&self, area, buf, state);
282    }
283}
284
285fn render_ref(widget: &TextInput<'_>, area: Rect, buf: &mut Buffer, state: &mut TextInputState) {
286    state.area = area;
287    state.inner = widget.block.inner_if_some(area);
288    state.rendered = state.inner.as_size();
289    state.passwd = widget.passwd;
290    state.on_focus_gained.set(widget.on_focus_gained);
291    state.on_focus_lost.set(widget.on_focus_lost);
292
293    if state.scroll_to_cursor.get() {
294        let c = state.cursor();
295        let o = state.offset();
296
297        if state.rendered.width > 0 {
298            let mut no = if c < o {
299                c
300            } else if c >= o + state.rendered.width as upos_type {
301                c.saturating_sub(state.rendered.width as upos_type)
302            } else {
303                o
304            };
305            // correct by one at right margin. block cursors appear as part of the
306            // right border otherwise.
307            if c == no + state.rendered.width as upos_type {
308                no = no.saturating_add(1);
309            }
310            state.set_offset(no);
311        } else {
312            // no render area. don't do nothing.
313        }
314    }
315
316    let style = widget.style;
317    let focus_style = if let Some(focus_style) = widget.focus_style {
318        focus_style
319    } else {
320        style
321    };
322    let select_style = if let Some(select_style) = widget.select_style {
323        select_style
324    } else {
325        Style::default().black().on_yellow()
326    };
327    let invalid_style = if let Some(invalid_style) = widget.invalid_style {
328        invalid_style
329    } else {
330        Style::default().red()
331    };
332
333    let (style, select_style) = if state.focus.get() {
334        if state.invalid {
335            (
336                style.patch(focus_style).patch(invalid_style),
337                style
338                    .patch(focus_style)
339                    .patch(select_style)
340                    .patch(invalid_style),
341            )
342        } else {
343            (
344                style.patch(focus_style),
345                style.patch(focus_style).patch(select_style),
346            )
347        }
348    } else {
349        if state.invalid {
350            (
351                style.patch(invalid_style),
352                style.patch(select_style).patch(invalid_style),
353            )
354        } else {
355            (style, style.patch(select_style))
356        }
357    };
358
359    // set base style
360    if let Some(block) = &widget.block {
361        block.render(area, buf);
362    }
363    buf.set_style(state.inner, style);
364
365    if state.inner.width == 0 || state.inner.height == 0 {
366        // noop
367        return;
368    }
369
370    let ox = state.offset() as u16;
371    // this is just a guess at the display-width
372    let show_range = {
373        let start = min(ox as upos_type, state.len());
374        let end = min(start + state.inner.width as upos_type, state.len());
375        state.bytes_at_range(start..end)
376    };
377    let selection = state.selection();
378    let mut styles = Vec::new();
379
380    if widget.passwd {
381        // Render as passwd
382        for g in state.glyphs2() {
383            if g.screen_width() > 0 {
384                let mut style = style;
385                state
386                    .value
387                    .styles_at_page(g.text_bytes().start, show_range.clone(), &mut styles);
388                for style_nr in &styles {
389                    if let Some(s) = widget.text_style.get(style_nr) {
390                        style = style.patch(*s);
391                    }
392                }
393                // selection
394                if selection.contains(&g.pos().x) {
395                    style = style.patch(select_style);
396                };
397
398                // relative screen-pos of the glyph
399                let screen_pos = g.screen_pos();
400
401                // render glyph
402                if let Some(cell) =
403                    buf.cell_mut((state.inner.x + screen_pos.0, state.inner.y + screen_pos.1))
404                {
405                    cell.set_symbol("*");
406                    cell.set_style(style);
407                }
408                // clear the reset of the cells to avoid interferences.
409                for d in 1..g.screen_width() {
410                    if let Some(cell) = buf.cell_mut((
411                        state.inner.x + screen_pos.0 + d,
412                        state.inner.y + screen_pos.1,
413                    )) {
414                        cell.reset();
415                        cell.set_style(style);
416                    }
417                }
418            }
419        }
420    } else {
421        for g in state.glyphs2() {
422            if g.screen_width() > 0 {
423                let mut style = style;
424                state
425                    .value
426                    .styles_at_page(g.text_bytes().start, show_range.clone(), &mut styles);
427                for style_nr in &styles {
428                    if let Some(s) = widget.text_style.get(style_nr) {
429                        style = style.patch(*s);
430                    }
431                }
432                // selection
433                if selection.contains(&g.pos().x) {
434                    style = style.patch(select_style);
435                };
436
437                // relative screen-pos of the glyph
438                let screen_pos = g.screen_pos();
439
440                // render glyph
441                if let Some(cell) =
442                    buf.cell_mut((state.inner.x + screen_pos.0, state.inner.y + screen_pos.1))
443                {
444                    cell.set_symbol(g.glyph());
445                    cell.set_style(style);
446                }
447                // clear the reset of the cells to avoid interferences.
448                for d in 1..g.screen_width() {
449                    if let Some(cell) = buf.cell_mut((
450                        state.inner.x + screen_pos.0 + d,
451                        state.inner.y + screen_pos.1,
452                    )) {
453                        cell.reset();
454                        cell.set_style(style);
455                    }
456                }
457            }
458        }
459    }
460}
461
462impl Clone for TextInputState {
463    fn clone(&self) -> Self {
464        Self {
465            area: self.area,
466            inner: self.inner,
467            rendered: self.rendered,
468            offset: self.offset,
469            dark_offset: self.dark_offset,
470            scroll_to_cursor: Rc::new(Cell::new(self.scroll_to_cursor.get())),
471            value: self.value.clone(),
472            invalid: self.invalid,
473            passwd: self.passwd,
474            overwrite: Rc::new(Cell::new(self.overwrite.get())),
475            on_focus_gained: Rc::new(Cell::new(self.on_focus_gained.get())),
476            on_focus_lost: Rc::new(Cell::new(self.on_focus_lost.get())),
477            focus: self.focus_cb(self.focus.new_instance()),
478            mouse: Default::default(),
479            non_exhaustive: NonExhaustive,
480        }
481    }
482}
483
484impl Default for TextInputState {
485    fn default() -> Self {
486        let value = TextCore::new(Some(Box::new(UndoVec::new(99))), Some(global_clipboard()));
487
488        let mut z = Self {
489            area: Default::default(),
490            inner: Default::default(),
491            rendered: Default::default(),
492            offset: Default::default(),
493            dark_offset: Default::default(),
494            scroll_to_cursor: Default::default(),
495            value,
496            invalid: Default::default(),
497            passwd: Default::default(),
498            overwrite: Default::default(),
499            on_focus_gained: Default::default(),
500            on_focus_lost: Default::default(),
501            focus: Default::default(),
502            mouse: Default::default(),
503            non_exhaustive: NonExhaustive,
504        };
505        z.focus = z.focus_cb(FocusFlag::default());
506        z
507    }
508}
509
510impl TextInputState {
511    fn focus_cb(&self, flag: FocusFlag) -> FocusFlag {
512        let on_focus_lost = self.on_focus_lost.clone();
513        let cursor = self.value.shared_cursor();
514        let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
515        flag.on_lost(move || match on_focus_lost.get() {
516            TextFocusLost::None => {}
517            TextFocusLost::Position0 => {
518                scroll_cursor_to_visible.set(true);
519                let mut new_cursor = cursor.get();
520                new_cursor.cursor.x = 0;
521                new_cursor.anchor.x = 0;
522                cursor.set(new_cursor);
523            }
524        });
525        let on_focus_gained = self.on_focus_gained.clone();
526        let overwrite = self.overwrite.clone();
527        let cursor = self.value.shared_cursor();
528        let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
529        flag.on_gained(move || match on_focus_gained.get() {
530            TextFocusGained::None => {}
531            TextFocusGained::Overwrite => {
532                overwrite.set(true);
533            }
534            TextFocusGained::SelectAll => {
535                scroll_cursor_to_visible.set(true);
536                let mut new_cursor = cursor.get();
537                new_cursor.anchor = TextPosition::new(0, 0);
538                new_cursor.cursor = TextPosition::new(0, 1);
539                cursor.set(new_cursor);
540            }
541        });
542
543        flag
544    }
545}
546
547impl HasFocus for TextInputState {
548    fn build(&self, builder: &mut FocusBuilder) {
549        builder.leaf_widget(self);
550    }
551
552    fn focus(&self) -> FocusFlag {
553        self.focus.clone()
554    }
555
556    fn area(&self) -> Rect {
557        self.area
558    }
559}
560
561impl TextInputState {
562    pub fn new() -> Self {
563        Self::default()
564    }
565
566    pub fn named(name: &str) -> Self {
567        let mut z = Self::default();
568        z.focus = z.focus.with_name(name);
569        z
570    }
571
572    /// Renders the widget in invalid style.
573    #[inline]
574    pub fn set_invalid(&mut self, invalid: bool) {
575        self.invalid = invalid;
576    }
577
578    /// Renders the widget in invalid style.
579    #[inline]
580    pub fn invalid(&self) -> bool {
581        self.invalid
582    }
583
584    /// The next edit operation will overwrite the current content
585    /// instead of adding text. Any move operations will cancel
586    /// this overwrite.
587    #[inline]
588    pub fn set_overwrite(&mut self, overwrite: bool) {
589        self.overwrite.set(overwrite);
590    }
591
592    /// Will the next edit operation overwrite the content?
593    #[inline]
594    pub fn overwrite(&self) -> bool {
595        self.overwrite.get()
596    }
597
598    /// Show glyphs for control characters.
599    #[inline]
600    pub fn set_show_ctrl(&mut self, show_ctrl: bool) {
601        self.value.set_glyph_ctrl(show_ctrl);
602    }
603
604    /// Show glyphs for control characters.
605    pub fn show_ctrl(&self) -> bool {
606        self.value.glyph_ctrl()
607    }
608}
609
610impl TextInputState {
611    /// Clipboard used.
612    /// Default is to use the global_clipboard().
613    #[inline]
614    pub fn set_clipboard(&mut self, clip: Option<impl Clipboard + 'static>) {
615        match clip {
616            None => self.value.set_clipboard(None),
617            Some(v) => self.value.set_clipboard(Some(Box::new(v))),
618        }
619    }
620
621    /// Clipboard used.
622    /// Default is to use the global_clipboard().
623    #[inline]
624    pub fn clipboard(&self) -> Option<&dyn Clipboard> {
625        self.value.clipboard()
626    }
627
628    /// Copy to internal buffer
629    #[inline]
630    pub fn copy_to_clip(&mut self) -> bool {
631        let Some(clip) = self.value.clipboard() else {
632            return false;
633        };
634        if self.passwd {
635            return false;
636        }
637
638        _ = clip.set_string(self.selected_text().as_ref());
639        false
640    }
641
642    /// Cut to internal buffer
643    #[inline]
644    pub fn cut_to_clip(&mut self) -> bool {
645        let Some(clip) = self.value.clipboard() else {
646            return false;
647        };
648        if self.passwd {
649            return false;
650        }
651
652        match clip.set_string(self.selected_text().as_ref()) {
653            Ok(_) => self.delete_range(self.selection()),
654            Err(_) => false,
655        }
656    }
657
658    /// Paste from internal buffer.
659    #[inline]
660    pub fn paste_from_clip(&mut self) -> bool {
661        let Some(clip) = self.value.clipboard() else {
662            return false;
663        };
664
665        if let Ok(text) = clip.get_string() {
666            self.insert_str(text)
667        } else {
668            false
669        }
670    }
671}
672
673impl TextInputState {
674    /// Set undo buffer.
675    #[inline]
676    pub fn set_undo_buffer(&mut self, undo: Option<impl UndoBuffer + 'static>) {
677        match undo {
678            None => self.value.set_undo_buffer(None),
679            Some(v) => self.value.set_undo_buffer(Some(Box::new(v))),
680        }
681    }
682
683    /// Undo
684    #[inline]
685    pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
686        self.value.undo_buffer()
687    }
688
689    /// Undo
690    #[inline]
691    pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
692        self.value.undo_buffer_mut()
693    }
694
695    /// Get all recent replay recordings.
696    #[inline]
697    pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
698        self.value.recent_replay_log()
699    }
700
701    /// Apply the replay recording.
702    #[inline]
703    pub fn replay_log(&mut self, replay: &[UndoEntry]) {
704        self.value.replay_log(replay)
705    }
706
707    /// Undo operation
708    #[inline]
709    pub fn undo(&mut self) -> bool {
710        self.value.undo()
711    }
712
713    /// Redo operation
714    #[inline]
715    pub fn redo(&mut self) -> bool {
716        self.value.redo()
717    }
718}
719
720impl TextInputState {
721    /// Set and replace all styles.
722    ///
723    /// The ranges are byte-ranges into the text.
724    /// Each byte-range maps to an index into the styles set
725    /// with the widget.
726    ///
727    /// Any style-idx that don't have a match there are just
728    /// ignored. You can use this to store other range based information.
729    /// The ranges are corrected during edits, no need to recalculate
730    /// everything after each keystroke.
731    #[inline]
732    pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
733        self.value.set_styles(styles);
734    }
735
736    /// Add a style for a [TextRange].
737    ///
738    /// The style-idx refers to one of the styles set with the widget.
739    /// Missing styles are just ignored.
740    #[inline]
741    pub fn add_style(&mut self, range: Range<usize>, style: usize) {
742        self.value.add_style(range, style);
743    }
744
745    /// Add a style for char range.
746    /// The style-nr refers to one of the styles set with the widget.
747    #[inline]
748    pub fn add_range_style(
749        &mut self,
750        range: Range<upos_type>,
751        style: usize,
752    ) -> Result<(), TextError> {
753        let r = self
754            .value
755            .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))?;
756        self.value.add_style(r, style);
757        Ok(())
758    }
759
760    /// Remove the exact char-range and style.
761    #[inline]
762    pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
763        self.value.remove_style(range, style);
764    }
765
766    /// Remove the exact Range<upos_type> and style.
767    #[inline]
768    pub fn remove_range_style(
769        &mut self,
770        range: Range<upos_type>,
771        style: usize,
772    ) -> Result<(), TextError> {
773        let r = self
774            .value
775            .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))?;
776        self.value.remove_style(r, style);
777        Ok(())
778    }
779
780    /// Find all styles that touch the given range.
781    pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
782        self.value.styles_in(range, buf)
783    }
784
785    /// All styles active at the given position.
786    #[inline]
787    pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
788        self.value.styles_at(byte_pos, buf)
789    }
790
791    /// Check if the given style applies at the position and
792    /// return the complete range for the style.
793    #[inline]
794    pub fn styles_at_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
795        self.value.styles_at_match(byte_pos, style)
796    }
797
798    /// List of all styles.
799    #[inline]
800    pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
801        self.value.styles()
802    }
803}
804
805impl TextInputState {
806    /// Text-offset.
807    #[inline]
808    pub fn offset(&self) -> upos_type {
809        self.offset
810    }
811
812    /// Set the text-offset.
813    #[inline]
814    pub fn set_offset(&mut self, offset: upos_type) {
815        self.scroll_to_cursor.set(false);
816        self.offset = offset;
817    }
818
819    /// Cursor position.
820    #[inline]
821    pub fn cursor(&self) -> upos_type {
822        self.value.cursor().x
823    }
824
825    /// Selection anchor.
826    #[inline]
827    pub fn anchor(&self) -> upos_type {
828        self.value.anchor().x
829    }
830
831    /// Set the cursor position.
832    /// Scrolls the cursor to a visible position.
833    #[inline]
834    pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
835        self.scroll_cursor_to_visible();
836        self.value
837            .set_cursor(TextPosition::new(cursor, 0), extend_selection)
838    }
839
840    /// Selection.
841    #[inline]
842    pub fn has_selection(&self) -> bool {
843        self.value.has_selection()
844    }
845
846    /// Selection.
847    #[inline]
848    pub fn selection(&self) -> Range<upos_type> {
849        let mut v = self.value.selection();
850        if v.start == TextPosition::new(0, 1) {
851            v.start = TextPosition::new(self.line_width(), 0);
852        }
853        if v.end == TextPosition::new(0, 1) {
854            v.end = TextPosition::new(self.line_width(), 0);
855        }
856        v.start.x..v.end.x
857    }
858
859    /// Selection.
860    /// Scrolls the cursor to a visible position.
861    #[inline]
862    pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
863        self.scroll_cursor_to_visible();
864        self.value
865            .set_selection(TextPosition::new(anchor, 0), TextPosition::new(cursor, 0))
866    }
867
868    /// Selection.
869    /// Scrolls the cursor to a visible position.
870    #[inline]
871    pub fn select_all(&mut self) -> bool {
872        self.scroll_cursor_to_visible();
873        self.value.select_all()
874    }
875
876    /// Selection.
877    #[inline]
878    pub fn selected_text(&self) -> &str {
879        match self.str_slice(self.selection()) {
880            Cow::Borrowed(v) => v,
881            Cow::Owned(_) => {
882                unreachable!()
883            }
884        }
885    }
886}
887
888impl TextInputState {
889    /// Empty.
890    #[inline]
891    pub fn is_empty(&self) -> bool {
892        self.value.is_empty()
893    }
894
895    /// Text value.
896    #[inline]
897    pub fn value<T: for<'a> From<&'a str>>(&self) -> T {
898        self.value.text().as_str().into()
899    }
900
901    /// Text value.
902    #[inline]
903    pub fn text(&self) -> &str {
904        self.value.text().as_str()
905    }
906
907    /// Text slice as `Cow<str>`. Uses a byte range.
908    #[inline]
909    pub fn str_slice_byte(&self, range: Range<usize>) -> Cow<'_, str> {
910        self.value.str_slice_byte(range).expect("valid_range")
911    }
912
913    /// Text slice as `Cow<str>`. Uses a byte range.
914    #[inline]
915    pub fn try_str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
916        self.value.str_slice_byte(range)
917    }
918
919    /// Text slice as `Cow<str>`
920    #[inline]
921    pub fn str_slice(&self, range: Range<upos_type>) -> Cow<'_, str> {
922        self.value
923            .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
924            .expect("valid_range")
925    }
926
927    /// Text slice as `Cow<str>`
928    #[inline]
929    pub fn try_str_slice(&self, range: Range<upos_type>) -> Result<Cow<'_, str>, TextError> {
930        self.value
931            .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
932    }
933
934    /// Length as grapheme count.
935    #[inline]
936    pub fn len(&self) -> upos_type {
937        self.value.line_width(0).expect("valid_row")
938    }
939
940    /// Length in bytes.
941    #[inline]
942    pub fn len_bytes(&self) -> usize {
943        self.value.len_bytes()
944    }
945
946    /// Length as grapheme count.
947    #[inline]
948    pub fn line_width(&self) -> upos_type {
949        self.value.line_width(0).expect("valid_row")
950    }
951
952    /// Get a cursor over all the text with the current position set at pos.
953    #[inline]
954    pub fn text_graphemes(&self, pos: upos_type) -> <TextString as TextStore>::GraphemeIter<'_> {
955        self.value
956            .text_graphemes(TextPosition::new(pos, 0))
957            .expect("valid_pos")
958    }
959
960    /// Get a cursor over all the text with the current position set at pos.
961    #[inline]
962    pub fn try_text_graphemes(
963        &self,
964        pos: upos_type,
965    ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
966        self.value.text_graphemes(TextPosition::new(pos, 0))
967    }
968
969    /// Get a cursor over the text-range the current position set at pos.
970    #[inline]
971    pub fn graphemes(
972        &self,
973        range: Range<upos_type>,
974        pos: upos_type,
975    ) -> <TextString as TextStore>::GraphemeIter<'_> {
976        self.value
977            .graphemes(
978                TextRange::new((range.start, 0), (range.end, 0)),
979                TextPosition::new(pos, 0),
980            )
981            .expect("valid_args")
982    }
983
984    /// Get a cursor over the text-range the current position set at pos.
985    #[inline]
986    pub fn try_graphemes(
987        &self,
988        range: Range<upos_type>,
989        pos: upos_type,
990    ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
991        self.value.graphemes(
992            TextRange::new((range.start, 0), (range.end, 0)),
993            TextPosition::new(pos, 0),
994        )
995    }
996
997    /// Grapheme position to byte position.
998    /// This is the (start,end) position of the single grapheme after pos.
999    #[inline]
1000    pub fn byte_at(&self, pos: upos_type) -> Range<usize> {
1001        self.value
1002            .byte_at(TextPosition::new(pos, 0))
1003            .expect("valid_pos")
1004    }
1005
1006    /// Grapheme position to byte position.
1007    /// This is the (start,end) position of the single grapheme after pos.
1008    #[inline]
1009    pub fn try_byte_at(&self, pos: upos_type) -> Result<Range<usize>, TextError> {
1010        self.value.byte_at(TextPosition::new(pos, 0))
1011    }
1012
1013    /// Grapheme range to byte range.
1014    #[inline]
1015    pub fn bytes_at_range(&self, range: Range<upos_type>) -> Range<usize> {
1016        self.value
1017            .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1018            .expect("valid_range")
1019    }
1020
1021    /// Grapheme range to byte range.
1022    #[inline]
1023    pub fn try_bytes_at_range(&self, range: Range<upos_type>) -> Result<Range<usize>, TextError> {
1024        self.value
1025            .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1026    }
1027
1028    /// Byte position to grapheme position.
1029    /// Returns the position that contains the given byte index.
1030    #[inline]
1031    pub fn byte_pos(&self, byte: usize) -> upos_type {
1032        self.value.byte_pos(byte).map(|v| v.x).expect("valid_pos")
1033    }
1034
1035    /// Byte position to grapheme position.
1036    /// Returns the position that contains the given byte index.
1037    #[inline]
1038    pub fn try_byte_pos(&self, byte: usize) -> Result<upos_type, TextError> {
1039        self.value.byte_pos(byte).map(|v| v.x)
1040    }
1041
1042    /// Byte range to grapheme range.
1043    #[inline]
1044    pub fn byte_range(&self, bytes: Range<usize>) -> Range<upos_type> {
1045        self.value
1046            .byte_range(bytes)
1047            .map(|v| v.start.x..v.end.x)
1048            .expect("valid_range")
1049    }
1050
1051    /// Byte range to grapheme range.
1052    #[inline]
1053    pub fn try_byte_range(&self, bytes: Range<usize>) -> Result<Range<upos_type>, TextError> {
1054        self.value.byte_range(bytes).map(|v| v.start.x..v.end.x)
1055    }
1056}
1057
1058impl TextInputState {
1059    /// Reset to empty.
1060    #[inline]
1061    pub fn clear(&mut self) -> bool {
1062        if self.is_empty() {
1063            false
1064        } else {
1065            self.offset = 0;
1066            self.value.clear();
1067            true
1068        }
1069    }
1070
1071    /// Set text.
1072    ///
1073    /// Returns an error if the text contains line-breaks.
1074    #[inline]
1075    pub fn set_value<S: Into<String>>(&mut self, s: S) {
1076        self.offset = 0;
1077        self.value.set_text(TextString::new_string(s.into()));
1078    }
1079
1080    /// Set text.
1081    ///
1082    /// Returns an error if the text contains line-breaks.
1083    #[inline]
1084    pub fn set_text<S: Into<String>>(&mut self, s: S) {
1085        self.offset = 0;
1086        self.value.set_text(TextString::new_string(s.into()));
1087    }
1088
1089    /// Insert a char at the current position.
1090    #[inline]
1091    pub fn insert_char(&mut self, c: char) -> bool {
1092        if self.has_selection() {
1093            self.value
1094                .remove_str_range(self.value.selection())
1095                .expect("valid_selection");
1096        }
1097        if c == '\n' {
1098            return false;
1099        } else {
1100            self.value
1101                .insert_char(self.value.cursor(), c)
1102                .expect("valid_cursor");
1103        }
1104        self.scroll_cursor_to_visible();
1105        true
1106    }
1107
1108    /// Insert a str at the current position.
1109    #[inline]
1110    pub fn insert_str(&mut self, t: impl AsRef<str>) -> bool {
1111        let t = t.as_ref();
1112        if self.has_selection() {
1113            self.value
1114                .remove_str_range(self.value.selection())
1115                .expect("valid_selection");
1116        }
1117        self.value
1118            .insert_str(self.value.cursor(), t)
1119            .expect("valid_cursor");
1120        self.scroll_cursor_to_visible();
1121        true
1122    }
1123
1124    /// Deletes the given range.
1125    #[inline]
1126    pub fn delete_range(&mut self, range: Range<upos_type>) -> bool {
1127        self.try_delete_range(range).expect("valid_range")
1128    }
1129
1130    /// Deletes the given range.
1131    #[inline]
1132    pub fn try_delete_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
1133        if !range.is_empty() {
1134            self.value
1135                .remove_str_range(TextRange::new((range.start, 0), (range.end, 0)))?;
1136            self.scroll_cursor_to_visible();
1137            Ok(true)
1138        } else {
1139            Ok(false)
1140        }
1141    }
1142}
1143
1144impl TextInputState {
1145    /// Delete the char after the cursor.
1146    #[inline]
1147    pub fn delete_next_char(&mut self) -> bool {
1148        if self.has_selection() {
1149            self.delete_range(self.selection())
1150        } else {
1151            let pos = self.value.cursor();
1152            let r = remove_next_char(&mut self.value, pos).expect("valid_cursor");
1153            self.scroll_cursor_to_visible();
1154            r
1155        }
1156    }
1157
1158    /// Delete the char before the cursor.
1159    #[inline]
1160    pub fn delete_prev_char(&mut self) -> bool {
1161        if self.value.has_selection() {
1162            self.delete_range(self.selection())
1163        } else {
1164            let pos = self.value.cursor();
1165            let r = remove_prev_char(&mut self.value, pos).expect("valid_cursor");
1166            self.scroll_cursor_to_visible();
1167            r
1168        }
1169    }
1170
1171    /// Find the start of the next word. Word is everything that is not whitespace.
1172    pub fn next_word_start(&self, pos: upos_type) -> upos_type {
1173        self.try_next_word_start(pos).expect("valid_pos")
1174    }
1175
1176    /// Find the start of the next word. Word is everything that is not whitespace.
1177    pub fn try_next_word_start(&self, pos: upos_type) -> Result<upos_type, TextError> {
1178        next_word_start(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1179    }
1180
1181    /// Find the end of the next word.  Skips whitespace first, then goes on
1182    /// until it finds the next whitespace.
1183    pub fn next_word_end(&self, pos: upos_type) -> upos_type {
1184        self.try_next_word_end(pos).expect("valid_pos")
1185    }
1186
1187    /// Find the end of the next word.  Skips whitespace first, then goes on
1188    /// until it finds the next whitespace.
1189    pub fn try_next_word_end(&self, pos: upos_type) -> Result<upos_type, TextError> {
1190        next_word_end(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1191    }
1192
1193    /// Find prev word. Skips whitespace first.
1194    /// Attention: start/end are mirrored here compared to next_word_start/next_word_end,
1195    /// both return start<=end!
1196    pub fn prev_word_start(&self, pos: upos_type) -> upos_type {
1197        self.try_prev_word_start(pos).expect("valid_pos")
1198    }
1199
1200    /// Find prev word. Skips whitespace first.
1201    /// Attention: start/end are mirrored here compared to next_word_start/next_word_end,
1202    /// both return start<=end!
1203    pub fn try_prev_word_start(&self, pos: upos_type) -> Result<upos_type, TextError> {
1204        prev_word_start(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1205    }
1206
1207    /// Find the end of the previous word. Word is everything that is not whitespace.
1208    /// Attention: start/end are mirrored here compared to next_word_start/next_word_end,
1209    /// both return start<=end!
1210    pub fn prev_word_end(&self, pos: upos_type) -> upos_type {
1211        self.try_prev_word_end(pos).expect("valid_pos")
1212    }
1213
1214    /// Find the end of the previous word. Word is everything that is not whitespace.
1215    /// Attention: start/end are mirrored here compared to next_word_start/next_word_end,
1216    /// both return start<=end!
1217    pub fn try_prev_word_end(&self, pos: upos_type) -> Result<upos_type, TextError> {
1218        prev_word_end(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1219    }
1220
1221    /// Is the position at a word boundary?
1222    pub fn is_word_boundary(&self, pos: upos_type) -> bool {
1223        self.try_is_word_boundary(pos).expect("valid_pos")
1224    }
1225
1226    /// Is the position at a word boundary?
1227    pub fn try_is_word_boundary(&self, pos: upos_type) -> Result<bool, TextError> {
1228        is_word_boundary(&self.value, TextPosition::new(pos, 0))
1229    }
1230
1231    /// Find the start of the word at pos.
1232    pub fn word_start(&self, pos: upos_type) -> upos_type {
1233        self.try_word_start(pos).expect("valid_pos")
1234    }
1235
1236    /// Find the start of the word at pos.
1237    pub fn try_word_start(&self, pos: upos_type) -> Result<upos_type, TextError> {
1238        word_start(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1239    }
1240
1241    /// Find the end of the word at pos.
1242    pub fn word_end(&self, pos: upos_type) -> upos_type {
1243        self.try_word_end(pos).expect("valid_pos")
1244    }
1245
1246    /// Find the end of the word at pos.
1247    pub fn try_word_end(&self, pos: upos_type) -> Result<upos_type, TextError> {
1248        word_end(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1249    }
1250
1251    /// Deletes the next word.
1252    #[inline]
1253    pub fn delete_next_word(&mut self) -> bool {
1254        if self.has_selection() {
1255            self.delete_range(self.selection())
1256        } else {
1257            let cursor = self.cursor();
1258
1259            let start = self.next_word_start(cursor);
1260            if start != cursor {
1261                self.delete_range(cursor..start)
1262            } else {
1263                let end = self.next_word_end(cursor);
1264                self.delete_range(cursor..end)
1265            }
1266        }
1267    }
1268
1269    /// Deletes the given range.
1270    #[inline]
1271    pub fn delete_prev_word(&mut self) -> bool {
1272        if self.has_selection() {
1273            self.delete_range(self.selection())
1274        } else {
1275            let cursor = self.cursor();
1276
1277            let end = self.prev_word_end(cursor);
1278            if end != cursor {
1279                self.delete_range(end..cursor)
1280            } else {
1281                let start = self.prev_word_start(cursor);
1282                self.delete_range(start..cursor)
1283            }
1284        }
1285    }
1286
1287    /// Move to the next char.
1288    #[inline]
1289    pub fn move_right(&mut self, extend_selection: bool) -> bool {
1290        let c = min(self.cursor() + 1, self.len());
1291        self.set_cursor(c, extend_selection)
1292    }
1293
1294    /// Move to the previous char.
1295    #[inline]
1296    pub fn move_left(&mut self, extend_selection: bool) -> bool {
1297        let c = self.cursor().saturating_sub(1);
1298        self.set_cursor(c, extend_selection)
1299    }
1300
1301    /// Start of line
1302    #[inline]
1303    pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1304        self.set_cursor(0, extend_selection)
1305    }
1306
1307    /// End of line
1308    #[inline]
1309    pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
1310        self.set_cursor(self.len(), extend_selection)
1311    }
1312
1313    #[inline]
1314    pub fn move_to_next_word(&mut self, extend_selection: bool) -> bool {
1315        let cursor = self.cursor();
1316        let end = self.next_word_end(cursor);
1317        self.set_cursor(end, extend_selection)
1318    }
1319
1320    #[inline]
1321    pub fn move_to_prev_word(&mut self, extend_selection: bool) -> bool {
1322        let cursor = self.cursor();
1323        let start = self.prev_word_start(cursor);
1324        self.set_cursor(start, extend_selection)
1325    }
1326}
1327
1328impl HasScreenCursor for TextInputState {
1329    /// The current text cursor as an absolute screen position.
1330    #[inline]
1331    fn screen_cursor(&self) -> Option<(u16, u16)> {
1332        if self.is_focused() {
1333            if self.has_selection() {
1334                None
1335            } else {
1336                let cx = self.cursor();
1337                let ox = self.offset();
1338
1339                if cx < ox {
1340                    None
1341                } else if cx > ox + (self.inner.width + self.dark_offset.0) as upos_type {
1342                    None
1343                } else {
1344                    self.col_to_screen(cx)
1345                        .map(|sc| (self.inner.x + sc, self.inner.y))
1346                }
1347            }
1348        } else {
1349            None
1350        }
1351    }
1352}
1353
1354impl RelocatableState for TextInputState {
1355    fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
1356        self.area.relocate(shift, clip);
1357        self.inner.relocate(shift, clip);
1358        // clip offset for some corrections.
1359        self.dark_offset = relocate_dark_offset(self.inner, shift, clip);
1360    }
1361}
1362
1363impl TextInputState {
1364    fn glyphs2(&self) -> impl Iterator<Item = Glyph2<'_>> {
1365        let (text_wrap, left_margin, right_margin, word_margin) = (
1366            TextWrap2::Shift,
1367            self.offset() as upos_type,
1368            self.offset() as upos_type + self.rendered.width as upos_type,
1369            self.offset() as upos_type + self.rendered.width as upos_type,
1370        );
1371        self.value
1372            .glyphs2(
1373                self.rendered,
1374                0,
1375                0..1,
1376                0, /* no tabs */
1377                text_wrap,
1378                false,
1379                left_margin,
1380                right_margin,
1381                word_margin,
1382            )
1383            .expect("valid-row")
1384    }
1385
1386    /// Converts from a widget relative screen coordinate to a grapheme index.
1387    /// x is the relative screen position.
1388    pub fn screen_to_col(&self, scx: i16) -> upos_type {
1389        let ox = self.offset();
1390
1391        let scx = scx + self.dark_offset.0 as i16;
1392
1393        if scx < 0 {
1394            ox.saturating_sub((scx as ipos_type).unsigned_abs())
1395        } else if scx as u16 >= self.rendered.width {
1396            min(ox + scx as upos_type, self.len())
1397        } else {
1398            let scx = scx as u16;
1399
1400            let line = self.glyphs2();
1401
1402            let mut col = ox;
1403            for g in line {
1404                if g.contains_screen_x(scx) {
1405                    break;
1406                }
1407                col = g.pos().x + 1;
1408            }
1409            col
1410        }
1411    }
1412
1413    /// Converts a grapheme based position to a screen position
1414    /// relative to the widget area.
1415    pub fn col_to_screen(&self, pos: upos_type) -> Option<u16> {
1416        let ox = self.offset();
1417
1418        if pos < ox {
1419            return None;
1420        }
1421
1422        let line = self.glyphs2();
1423        let mut screen_x = 0;
1424        for g in line {
1425            if g.pos().x == pos {
1426                break;
1427            }
1428            screen_x = g.screen_pos().0 + g.screen_width();
1429        }
1430
1431        if screen_x >= self.dark_offset.0 {
1432            Some(screen_x - self.dark_offset.0)
1433        } else {
1434            None
1435        }
1436    }
1437
1438    /// Set the cursor position from a screen position relative to the origin
1439    /// of the widget. This value can be negative, which selects a currently
1440    /// not visible position and scrolls to it.
1441    #[inline]
1442    pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
1443        let scx = cursor;
1444
1445        let cx = self.screen_to_col(scx);
1446
1447        self.set_cursor(cx, extend_selection)
1448    }
1449
1450    /// Set the cursor position from screen coordinates,
1451    /// rounds the position to the next word start/end.
1452    ///
1453    /// The cursor positions are relative to the inner rect.
1454    /// They may be negative too, this allows setting the cursor
1455    /// to a position that is currently scrolled away.
1456    pub fn set_screen_cursor_words(&mut self, screen_cursor: i16, extend_selection: bool) -> bool {
1457        let anchor = self.anchor();
1458
1459        let cx = self.screen_to_col(screen_cursor);
1460        let cursor = cx;
1461
1462        let cursor = if cursor < anchor {
1463            self.word_start(cursor)
1464        } else {
1465            self.word_end(cursor)
1466        };
1467
1468        // extend anchor
1469        if !self.is_word_boundary(anchor) {
1470            if cursor < anchor {
1471                self.set_cursor(self.word_end(anchor), false);
1472            } else {
1473                self.set_cursor(self.word_start(anchor), false);
1474            }
1475        }
1476
1477        self.set_cursor(cursor, extend_selection)
1478    }
1479
1480    /// Scrolling
1481    pub fn scroll_left(&mut self, delta: upos_type) -> bool {
1482        self.set_offset(self.offset.saturating_sub(delta));
1483        true
1484    }
1485
1486    /// Scrolling
1487    pub fn scroll_right(&mut self, delta: upos_type) -> bool {
1488        self.set_offset(self.offset + delta);
1489        true
1490    }
1491
1492    /// Change the offset in a way that the cursor is visible.
1493    pub fn scroll_cursor_to_visible(&mut self) {
1494        self.scroll_to_cursor.set(true);
1495    }
1496}
1497
1498impl HandleEvent<crossterm::event::Event, Regular, TextOutcome> for TextInputState {
1499    fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> TextOutcome {
1500        // small helper ...
1501        fn tc(r: bool) -> TextOutcome {
1502            if r {
1503                TextOutcome::TextChanged
1504            } else {
1505                TextOutcome::Unchanged
1506            }
1507        }
1508        fn overwrite(state: &mut TextInputState) {
1509            if state.overwrite.get() {
1510                state.overwrite.set(false);
1511                state.clear();
1512            }
1513        }
1514        fn clear_overwrite(state: &mut TextInputState) {
1515            state.overwrite.set(false);
1516        }
1517
1518        // // focus behaviour
1519        // if self.lost_focus() {
1520        //     match self.on_focus_lost {
1521        //         TextFocusLost::None => {}
1522        //         TextFocusLost::Position0 => {
1523        //             self.move_to_line_start(false);
1524        //             // repaint is triggered by focus-change
1525        //         }
1526        //     }
1527        // }
1528        // if self.gained_focus() {
1529        //     match self.on_focus_gained {
1530        //         TextFocusGained::None => {}
1531        //         TextFocusGained::Overwrite => {
1532        //             self.overwrite = true;
1533        //         }
1534        //         TextFocusGained::SelectAll => {
1535        //             self.select_all();
1536        //             // repaint is triggered by focus-change
1537        //         }
1538        //     }
1539        // }
1540
1541        let mut r = if self.is_focused() {
1542            match event {
1543                ct_event!(key press c)
1544                | ct_event!(key press SHIFT-c)
1545                | ct_event!(key press CONTROL_ALT-c) => {
1546                    overwrite(self);
1547                    tc(self.insert_char(*c))
1548                }
1549                ct_event!(keycode press Backspace) | ct_event!(keycode press SHIFT-Backspace) => {
1550                    clear_overwrite(self);
1551                    tc(self.delete_prev_char())
1552                }
1553                ct_event!(keycode press Delete) | ct_event!(keycode press SHIFT-Delete) => {
1554                    clear_overwrite(self);
1555                    tc(self.delete_next_char())
1556                }
1557                ct_event!(keycode press CONTROL-Backspace)
1558                | ct_event!(keycode press ALT-Backspace) => {
1559                    clear_overwrite(self);
1560                    tc(self.delete_prev_word())
1561                }
1562                ct_event!(keycode press CONTROL-Delete) => {
1563                    clear_overwrite(self);
1564                    tc(self.delete_next_word())
1565                }
1566                ct_event!(key press CONTROL-'x') => {
1567                    clear_overwrite(self);
1568                    tc(self.cut_to_clip())
1569                }
1570                ct_event!(key press CONTROL-'v') => {
1571                    overwrite(self);
1572                    tc(self.paste_from_clip())
1573                }
1574                ct_event!(key press CONTROL-'d') => {
1575                    clear_overwrite(self);
1576                    tc(self.clear())
1577                }
1578                ct_event!(key press CONTROL-'z') => {
1579                    clear_overwrite(self);
1580                    tc(self.undo())
1581                }
1582                ct_event!(key press CONTROL_SHIFT-'Z') => {
1583                    clear_overwrite(self);
1584                    tc(self.redo())
1585                }
1586
1587                ct_event!(key release _)
1588                | ct_event!(key release SHIFT-_)
1589                | ct_event!(key release CONTROL_ALT-_)
1590                | ct_event!(keycode release Tab)
1591                | ct_event!(keycode release Backspace)
1592                | ct_event!(keycode release Delete)
1593                | ct_event!(keycode release CONTROL-Backspace)
1594                | ct_event!(keycode release ALT-Backspace)
1595                | ct_event!(keycode release CONTROL-Delete)
1596                | ct_event!(key release CONTROL-'x')
1597                | ct_event!(key release CONTROL-'v')
1598                | ct_event!(key release CONTROL-'d')
1599                | ct_event!(key release CONTROL-'y')
1600                | ct_event!(key release CONTROL-'z')
1601                | ct_event!(key release CONTROL_SHIFT-'Z') => TextOutcome::Unchanged,
1602
1603                _ => TextOutcome::Continue,
1604            }
1605        } else {
1606            TextOutcome::Continue
1607        };
1608        if r == TextOutcome::Continue {
1609            r = self.handle(event, ReadOnly);
1610        }
1611        r
1612    }
1613}
1614
1615impl HandleEvent<crossterm::event::Event, ReadOnly, TextOutcome> for TextInputState {
1616    fn handle(&mut self, event: &crossterm::event::Event, _keymap: ReadOnly) -> TextOutcome {
1617        fn clear_overwrite(state: &mut TextInputState) {
1618            state.overwrite.set(false);
1619        }
1620
1621        let mut r = if self.is_focused() {
1622            match event {
1623                ct_event!(keycode press Left) => {
1624                    clear_overwrite(self);
1625                    self.move_left(false).into()
1626                }
1627                ct_event!(keycode press Right) => {
1628                    clear_overwrite(self);
1629                    self.move_right(false).into()
1630                }
1631                ct_event!(keycode press CONTROL-Left) => {
1632                    clear_overwrite(self);
1633                    self.move_to_prev_word(false).into()
1634                }
1635                ct_event!(keycode press CONTROL-Right) => {
1636                    clear_overwrite(self);
1637                    self.move_to_next_word(false).into()
1638                }
1639                ct_event!(keycode press Home) => {
1640                    clear_overwrite(self);
1641                    self.move_to_line_start(false).into()
1642                }
1643                ct_event!(keycode press End) => {
1644                    clear_overwrite(self);
1645                    self.move_to_line_end(false).into()
1646                }
1647                ct_event!(keycode press SHIFT-Left) => {
1648                    clear_overwrite(self);
1649                    self.move_left(true).into()
1650                }
1651                ct_event!(keycode press SHIFT-Right) => {
1652                    clear_overwrite(self);
1653                    self.move_right(true).into()
1654                }
1655                ct_event!(keycode press CONTROL_SHIFT-Left) => {
1656                    clear_overwrite(self);
1657                    self.move_to_prev_word(true).into()
1658                }
1659                ct_event!(keycode press CONTROL_SHIFT-Right) => {
1660                    clear_overwrite(self);
1661                    self.move_to_next_word(true).into()
1662                }
1663                ct_event!(keycode press SHIFT-Home) => {
1664                    clear_overwrite(self);
1665                    self.move_to_line_start(true).into()
1666                }
1667                ct_event!(keycode press SHIFT-End) => {
1668                    clear_overwrite(self);
1669                    self.move_to_line_end(true).into()
1670                }
1671                ct_event!(keycode press ALT-Left) => {
1672                    clear_overwrite(self);
1673                    self.scroll_left(1).into()
1674                }
1675                ct_event!(keycode press ALT-Right) => {
1676                    clear_overwrite(self);
1677                    self.scroll_right(1).into()
1678                }
1679                ct_event!(key press CONTROL-'a') => {
1680                    clear_overwrite(self);
1681                    self.select_all().into()
1682                }
1683                ct_event!(key press CONTROL-'c') => {
1684                    clear_overwrite(self);
1685                    self.copy_to_clip().into()
1686                }
1687
1688                ct_event!(keycode release Left)
1689                | ct_event!(keycode release Right)
1690                | ct_event!(keycode release CONTROL-Left)
1691                | ct_event!(keycode release CONTROL-Right)
1692                | ct_event!(keycode release Home)
1693                | ct_event!(keycode release End)
1694                | ct_event!(keycode release SHIFT-Left)
1695                | ct_event!(keycode release SHIFT-Right)
1696                | ct_event!(keycode release CONTROL_SHIFT-Left)
1697                | ct_event!(keycode release CONTROL_SHIFT-Right)
1698                | ct_event!(keycode release SHIFT-Home)
1699                | ct_event!(keycode release SHIFT-End)
1700                | ct_event!(key release CONTROL-'a')
1701                | ct_event!(key release CONTROL-'c') => TextOutcome::Unchanged,
1702
1703                _ => TextOutcome::Continue,
1704            }
1705        } else {
1706            TextOutcome::Continue
1707        };
1708
1709        if r == TextOutcome::Continue {
1710            r = self.handle(event, MouseOnly);
1711        }
1712        r
1713    }
1714}
1715
1716impl HandleEvent<crossterm::event::Event, MouseOnly, TextOutcome> for TextInputState {
1717    fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> TextOutcome {
1718        fn clear_overwrite(state: &mut TextInputState) {
1719            state.overwrite.set(false);
1720        }
1721
1722        match event {
1723            ct_event!(mouse any for m) if self.mouse.drag(self.inner, m) => {
1724                let c = (m.column as i16) - (self.inner.x as i16);
1725                clear_overwrite(self);
1726                self.set_screen_cursor(c, true).into()
1727            }
1728            ct_event!(mouse any for m) if self.mouse.drag2(self.inner, m, KeyModifiers::ALT) => {
1729                let cx = m.column as i16 - self.inner.x as i16;
1730                clear_overwrite(self);
1731                self.set_screen_cursor_words(cx, true).into()
1732            }
1733            ct_event!(mouse any for m) if self.mouse.doubleclick(self.inner, m) => {
1734                let tx = self.screen_to_col(m.column as i16 - self.inner.x as i16);
1735                let start = self.word_start(tx);
1736                let end = self.word_end(tx);
1737                clear_overwrite(self);
1738                self.set_selection(start, end).into()
1739            }
1740            ct_event!(mouse down Left for column,row) => {
1741                if self.gained_focus() {
1742                    // don't react to the first click that's for
1743                    // focus. this one shouldn't demolish the selection.
1744                    TextOutcome::Unchanged
1745                } else if self.inner.contains((*column, *row).into()) {
1746                    let c = (column - self.inner.x) as i16;
1747                    clear_overwrite(self);
1748                    self.set_screen_cursor(c, false).into()
1749                } else {
1750                    TextOutcome::Continue
1751                }
1752            }
1753            ct_event!(mouse down CONTROL-Left for column,row) => {
1754                if self.inner.contains((*column, *row).into()) {
1755                    let cx = (column - self.inner.x) as i16;
1756                    clear_overwrite(self);
1757                    self.set_screen_cursor(cx, true).into()
1758                } else {
1759                    TextOutcome::Continue
1760                }
1761            }
1762            ct_event!(mouse down ALT-Left for column,row) => {
1763                if self.inner.contains((*column, *row).into()) {
1764                    let cx = (column - self.inner.x) as i16;
1765                    clear_overwrite(self);
1766                    self.set_screen_cursor_words(cx, true).into()
1767                } else {
1768                    TextOutcome::Continue
1769                }
1770            }
1771            _ => TextOutcome::Continue,
1772        }
1773    }
1774}
1775
1776/// Handle all events.
1777/// Text events are only processed if focus is true.
1778/// Mouse events are processed if they are in range.
1779pub fn handle_events(
1780    state: &mut TextInputState,
1781    focus: bool,
1782    event: &crossterm::event::Event,
1783) -> TextOutcome {
1784    state.focus.set(focus);
1785    state.handle(event, Regular)
1786}
1787
1788/// Handle only navigation events.
1789/// Text events are only processed if focus is true.
1790/// Mouse events are processed if they are in range.
1791pub fn handle_readonly_events(
1792    state: &mut TextInputState,
1793    focus: bool,
1794    event: &crossterm::event::Event,
1795) -> TextOutcome {
1796    state.focus.set(focus);
1797    state.handle(event, ReadOnly)
1798}
1799
1800/// Handle only mouse-events.
1801pub fn handle_mouse_events(
1802    state: &mut TextInputState,
1803    event: &crossterm::event::Event,
1804) -> TextOutcome {
1805    state.handle(event, MouseOnly)
1806}