Skip to main content

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