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