1use 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#[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#[derive(Debug)]
69pub struct TextInputState {
70 pub area: Rect,
73 pub inner: Rect,
76 pub rendered: Size,
80
81 pub offset: upos_type,
84 pub dark_offset: (u16, u16),
87 pub scroll_to_cursor: Rc<Cell<bool>>,
89
90 pub value: TextCore<TextString>,
92 pub invalid: bool,
95 pub passwd: bool,
98 pub overwrite: Rc<Cell<bool>>,
102 pub on_focus_gained: Rc<Cell<TextFocusGained>>,
105 pub on_focus_lost: Rc<Cell<TextFocusLost>>,
108
109 pub focus: FocusFlag,
112
113 pub mouse: MouseFlags,
116
117 pub non_exhaustive: NonExhaustive,
119}
120
121impl<'a> TextInput<'a> {
122 pub fn new() -> Self {
124 Self::default()
125 }
126
127 #[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 #[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 #[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 #[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 #[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 #[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 #[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 pub fn text_style_idx(mut self, idx: usize, style: Style) -> Self {
217 self.text_style.insert(idx, style);
218 self
219 }
220
221 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 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 #[inline]
245 pub fn block(mut self, block: Block<'a>) -> Self {
246 self.block = Some(block);
247 self
248 }
249
250 #[inline]
252 pub fn passwd(mut self) -> Self {
253 self.passwd = true;
254 self
255 }
256
257 #[inline]
259 pub fn on_focus_gained(mut self, of: TextFocusGained) -> Self {
260 self.on_focus_gained = of;
261 self
262 }
263
264 #[inline]
266 pub fn on_focus_lost(mut self, of: TextFocusLost) -> Self {
267 self.on_focus_lost = of;
268 self
269 }
270
271 pub fn width(&self) -> u16 {
273 0
274 }
275
276 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 if c == no + state.rendered.width as upos_type {
321 no = no.saturating_add(1);
322 }
323 state.set_offset(no);
324 } else {
325 }
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 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 return;
390 }
391
392 let ox = state.offset() as u16;
393 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 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 if selection.contains(&g.pos().x) {
424 style = style.patch(select_style);
425 };
426
427 screen_pos = g.screen_pos();
429
430 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 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 if selection.contains(&g.pos().x) {
468 style = style.patch(select_style);
469 };
470
471 screen_pos = g.screen_pos();
473
474 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 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 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 #[inline]
628 pub fn set_invalid(&mut self, invalid: bool) {
629 self.invalid = invalid;
630 }
631
632 #[inline]
634 pub fn invalid(&self) -> bool {
635 self.invalid
636 }
637
638 #[inline]
642 pub fn set_overwrite(&mut self, overwrite: bool) {
643 self.overwrite.set(overwrite);
644 }
645
646 #[inline]
648 pub fn overwrite(&self) -> bool {
649 self.overwrite.get()
650 }
651
652 #[inline]
654 pub fn set_show_ctrl(&mut self, show_ctrl: bool) {
655 self.value.set_glyph_ctrl(show_ctrl);
656 }
657
658 pub fn show_ctrl(&self) -> bool {
660 self.value.glyph_ctrl()
661 }
662}
663
664impl TextInputState {
665 #[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 #[inline]
678 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
679 self.value.clipboard()
680 }
681
682 #[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 #[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 #[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 #[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 #[inline]
739 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
740 self.value.undo_buffer()
741 }
742
743 #[inline]
745 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
746 self.value.undo_buffer_mut()
747 }
748
749 #[inline]
751 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
752 self.value.recent_replay_log()
753 }
754
755 #[inline]
757 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
758 self.value.replay_log(replay)
759 }
760
761 #[inline]
763 pub fn undo(&mut self) -> bool {
764 self.value.undo()
765 }
766
767 #[inline]
769 pub fn redo(&mut self) -> bool {
770 self.value.redo()
771 }
772}
773
774impl TextInputState {
775 #[inline]
786 pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
787 self.value.set_styles(styles);
788 }
789
790 #[inline]
795 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
796 self.value.add_style(range, style);
797 }
798
799 #[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 #[inline]
816 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
817 self.value.remove_style(range, style);
818 }
819
820 #[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 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
836 self.value.styles_in(range, buf)
837 }
838
839 #[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 #[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 #[inline]
854 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
855 self.value.styles()
856 }
857}
858
859impl TextInputState {
860 #[inline]
862 pub fn offset(&self) -> upos_type {
863 self.offset
864 }
865
866 #[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 #[inline]
875 pub fn cursor(&self) -> upos_type {
876 self.value.cursor().x
877 }
878
879 #[inline]
881 pub fn anchor(&self) -> upos_type {
882 self.value.anchor().x
883 }
884
885 #[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 #[inline]
896 pub fn has_selection(&self) -> bool {
897 self.value.has_selection()
898 }
899
900 #[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 #[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 #[inline]
925 pub fn select_all(&mut self) -> bool {
926 self.scroll_cursor_to_visible();
927 self.value.select_all()
928 }
929
930 #[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 #[inline]
945 pub fn is_empty(&self) -> bool {
946 self.value.is_empty()
947 }
948
949 #[inline]
951 pub fn value<T: for<'a> From<&'a str>>(&self) -> T {
952 self.value.text().as_str().into()
953 }
954
955 #[inline]
957 pub fn text(&self) -> &str {
958 self.value.text().as_str()
959 }
960
961 #[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 #[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 #[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 #[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 #[inline]
990 pub fn len(&self) -> upos_type {
991 self.value.line_width(0).expect("valid_row")
992 }
993
994 #[inline]
996 pub fn len_bytes(&self) -> usize {
997 self.value.len_bytes()
998 }
999
1000 #[inline]
1002 pub fn line_width(&self) -> upos_type {
1003 self.value.line_width(0).expect("valid_row")
1004 }
1005
1006 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 pub fn next_word_start(&self, pos: upos_type) -> upos_type {
1227 self.try_next_word_start(pos).expect("valid_pos")
1228 }
1229
1230 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 pub fn next_word_end(&self, pos: upos_type) -> upos_type {
1238 self.try_next_word_end(pos).expect("valid_pos")
1239 }
1240
1241 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 pub fn prev_word_start(&self, pos: upos_type) -> upos_type {
1251 self.try_prev_word_start(pos).expect("valid_pos")
1252 }
1253
1254 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 pub fn prev_word_end(&self, pos: upos_type) -> upos_type {
1265 self.try_prev_word_end(pos).expect("valid_pos")
1266 }
1267
1268 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 pub fn is_word_boundary(&self, pos: upos_type) -> bool {
1277 self.try_is_word_boundary(pos).expect("valid_pos")
1278 }
1279
1280 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 pub fn word_start(&self, pos: upos_type) -> upos_type {
1287 self.try_word_start(pos).expect("valid_pos")
1288 }
1289
1290 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 pub fn word_end(&self, pos: upos_type) -> upos_type {
1297 self.try_word_end(pos).expect("valid_pos")
1298 }
1299
1300 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 #[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 #[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 #[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 #[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 #[inline]
1357 pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1358 self.set_cursor(0, extend_selection)
1359 }
1360
1361 #[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 #[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 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, text_wrap,
1432 false,
1433 left_margin,
1434 right_margin,
1435 word_margin,
1436 )
1437 .expect("valid-row")
1438 }
1439
1440 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 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 #[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 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 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 pub fn scroll_left(&mut self, delta: upos_type) -> bool {
1536 self.set_offset(self.offset.saturating_sub(delta));
1537 true
1538 }
1539
1540 pub fn scroll_right(&mut self, delta: upos_type) -> bool {
1542 self.set_offset(self.offset + delta);
1543 true
1544 }
1545
1546 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 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 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
1807pub fn handle_events(state: &mut TextInputState, focus: bool, event: &Event) -> TextOutcome {
1811 state.focus.set(focus);
1812 state.handle(event, Regular)
1813}
1814
1815pub 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
1827pub fn handle_mouse_events(state: &mut TextInputState, event: &Event) -> TextOutcome {
1829 state.handle(event, MouseOnly)
1830}