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 named(name: &str) -> Self {
614 let mut z = Self::default();
615 z.focus = z.focus.with_name(name);
616 z
617 }
618
619 #[inline]
621 pub fn set_invalid(&mut self, invalid: bool) {
622 self.invalid = invalid;
623 }
624
625 #[inline]
627 pub fn invalid(&self) -> bool {
628 self.invalid
629 }
630
631 #[inline]
635 pub fn set_overwrite(&mut self, overwrite: bool) {
636 self.overwrite.set(overwrite);
637 }
638
639 #[inline]
641 pub fn overwrite(&self) -> bool {
642 self.overwrite.get()
643 }
644
645 #[inline]
647 pub fn set_show_ctrl(&mut self, show_ctrl: bool) {
648 self.value.set_glyph_ctrl(show_ctrl);
649 }
650
651 pub fn show_ctrl(&self) -> bool {
653 self.value.glyph_ctrl()
654 }
655}
656
657impl TextInputState {
658 #[inline]
661 pub fn set_clipboard(&mut self, clip: Option<impl Clipboard + 'static>) {
662 match clip {
663 None => self.value.set_clipboard(None),
664 Some(v) => self.value.set_clipboard(Some(Box::new(v))),
665 }
666 }
667
668 #[inline]
671 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
672 self.value.clipboard()
673 }
674
675 #[inline]
677 pub fn copy_to_clip(&mut self) -> bool {
678 let Some(clip) = self.value.clipboard() else {
679 return false;
680 };
681 if self.passwd {
682 return false;
683 }
684
685 _ = clip.set_string(self.selected_text().as_ref());
686 false
687 }
688
689 #[inline]
691 pub fn cut_to_clip(&mut self) -> bool {
692 let Some(clip) = self.value.clipboard() else {
693 return false;
694 };
695 if self.passwd {
696 return false;
697 }
698
699 match clip.set_string(self.selected_text().as_ref()) {
700 Ok(_) => self.delete_range(self.selection()),
701 Err(_) => false,
702 }
703 }
704
705 #[inline]
707 pub fn paste_from_clip(&mut self) -> bool {
708 let Some(clip) = self.value.clipboard() else {
709 return false;
710 };
711
712 if let Ok(text) = clip.get_string() {
713 self.insert_str(text)
714 } else {
715 false
716 }
717 }
718}
719
720impl TextInputState {
721 #[inline]
723 pub fn set_undo_buffer(&mut self, undo: Option<impl UndoBuffer + 'static>) {
724 match undo {
725 None => self.value.set_undo_buffer(None),
726 Some(v) => self.value.set_undo_buffer(Some(Box::new(v))),
727 }
728 }
729
730 #[inline]
732 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
733 self.value.undo_buffer()
734 }
735
736 #[inline]
738 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
739 self.value.undo_buffer_mut()
740 }
741
742 #[inline]
744 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
745 self.value.recent_replay_log()
746 }
747
748 #[inline]
750 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
751 self.value.replay_log(replay)
752 }
753
754 #[inline]
756 pub fn undo(&mut self) -> bool {
757 self.value.undo()
758 }
759
760 #[inline]
762 pub fn redo(&mut self) -> bool {
763 self.value.redo()
764 }
765}
766
767impl TextInputState {
768 #[inline]
779 pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
780 self.value.set_styles(styles);
781 }
782
783 #[inline]
788 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
789 self.value.add_style(range, style);
790 }
791
792 #[inline]
795 pub fn add_range_style(
796 &mut self,
797 range: Range<upos_type>,
798 style: usize,
799 ) -> Result<(), TextError> {
800 let r = self
801 .value
802 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))?;
803 self.value.add_style(r, style);
804 Ok(())
805 }
806
807 #[inline]
809 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
810 self.value.remove_style(range, style);
811 }
812
813 #[inline]
815 pub fn remove_range_style(
816 &mut self,
817 range: Range<upos_type>,
818 style: usize,
819 ) -> Result<(), TextError> {
820 let r = self
821 .value
822 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))?;
823 self.value.remove_style(r, style);
824 Ok(())
825 }
826
827 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
829 self.value.styles_in(range, buf)
830 }
831
832 #[inline]
834 pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
835 self.value.styles_at(byte_pos, buf)
836 }
837
838 #[inline]
841 pub fn styles_at_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
842 self.value.styles_at_match(byte_pos, style)
843 }
844
845 #[inline]
847 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
848 self.value.styles()
849 }
850}
851
852impl TextInputState {
853 #[inline]
855 pub fn offset(&self) -> upos_type {
856 self.offset
857 }
858
859 #[inline]
861 pub fn set_offset(&mut self, offset: upos_type) {
862 self.scroll_to_cursor.set(false);
863 self.offset = offset;
864 }
865
866 #[inline]
868 pub fn cursor(&self) -> upos_type {
869 self.value.cursor().x
870 }
871
872 #[inline]
874 pub fn anchor(&self) -> upos_type {
875 self.value.anchor().x
876 }
877
878 #[inline]
881 pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
882 self.scroll_cursor_to_visible();
883 self.value
884 .set_cursor(TextPosition::new(cursor, 0), extend_selection)
885 }
886
887 #[inline]
889 pub fn has_selection(&self) -> bool {
890 self.value.has_selection()
891 }
892
893 #[inline]
895 pub fn selection(&self) -> Range<upos_type> {
896 let mut v = self.value.selection();
897 if v.start == TextPosition::new(0, 1) {
898 v.start = TextPosition::new(self.line_width(), 0);
899 }
900 if v.end == TextPosition::new(0, 1) {
901 v.end = TextPosition::new(self.line_width(), 0);
902 }
903 v.start.x..v.end.x
904 }
905
906 #[inline]
909 pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
910 self.scroll_cursor_to_visible();
911 self.value
912 .set_selection(TextPosition::new(anchor, 0), TextPosition::new(cursor, 0))
913 }
914
915 #[inline]
918 pub fn select_all(&mut self) -> bool {
919 self.scroll_cursor_to_visible();
920 self.value.select_all()
921 }
922
923 #[inline]
925 pub fn selected_text(&self) -> &str {
926 match self.str_slice(self.selection()) {
927 Cow::Borrowed(v) => v,
928 Cow::Owned(_) => {
929 unreachable!()
930 }
931 }
932 }
933}
934
935impl TextInputState {
936 #[inline]
938 pub fn is_empty(&self) -> bool {
939 self.value.is_empty()
940 }
941
942 #[inline]
944 pub fn value<T: for<'a> From<&'a str>>(&self) -> T {
945 self.value.text().as_str().into()
946 }
947
948 #[inline]
950 pub fn text(&self) -> &str {
951 self.value.text().as_str()
952 }
953
954 #[inline]
956 pub fn str_slice_byte(&self, range: Range<usize>) -> Cow<'_, str> {
957 self.value.str_slice_byte(range).expect("valid_range")
958 }
959
960 #[inline]
962 pub fn try_str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
963 self.value.str_slice_byte(range)
964 }
965
966 #[inline]
968 pub fn str_slice(&self, range: Range<upos_type>) -> Cow<'_, str> {
969 self.value
970 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
971 .expect("valid_range")
972 }
973
974 #[inline]
976 pub fn try_str_slice(&self, range: Range<upos_type>) -> Result<Cow<'_, str>, TextError> {
977 self.value
978 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
979 }
980
981 #[inline]
983 pub fn len(&self) -> upos_type {
984 self.value.line_width(0).expect("valid_row")
985 }
986
987 #[inline]
989 pub fn len_bytes(&self) -> usize {
990 self.value.len_bytes()
991 }
992
993 #[inline]
995 pub fn line_width(&self) -> upos_type {
996 self.value.line_width(0).expect("valid_row")
997 }
998
999 #[inline]
1001 pub fn text_graphemes(&self, pos: upos_type) -> <TextString as TextStore>::GraphemeIter<'_> {
1002 self.value
1003 .text_graphemes(TextPosition::new(pos, 0))
1004 .expect("valid_pos")
1005 }
1006
1007 #[inline]
1009 pub fn try_text_graphemes(
1010 &self,
1011 pos: upos_type,
1012 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1013 self.value.text_graphemes(TextPosition::new(pos, 0))
1014 }
1015
1016 #[inline]
1018 pub fn graphemes(
1019 &self,
1020 range: Range<upos_type>,
1021 pos: upos_type,
1022 ) -> <TextString as TextStore>::GraphemeIter<'_> {
1023 self.value
1024 .graphemes(
1025 TextRange::new((range.start, 0), (range.end, 0)),
1026 TextPosition::new(pos, 0),
1027 )
1028 .expect("valid_args")
1029 }
1030
1031 #[inline]
1033 pub fn try_graphemes(
1034 &self,
1035 range: Range<upos_type>,
1036 pos: upos_type,
1037 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1038 self.value.graphemes(
1039 TextRange::new((range.start, 0), (range.end, 0)),
1040 TextPosition::new(pos, 0),
1041 )
1042 }
1043
1044 #[inline]
1047 pub fn byte_at(&self, pos: upos_type) -> Range<usize> {
1048 self.value
1049 .byte_at(TextPosition::new(pos, 0))
1050 .expect("valid_pos")
1051 }
1052
1053 #[inline]
1056 pub fn try_byte_at(&self, pos: upos_type) -> Result<Range<usize>, TextError> {
1057 self.value.byte_at(TextPosition::new(pos, 0))
1058 }
1059
1060 #[inline]
1062 pub fn bytes_at_range(&self, range: Range<upos_type>) -> Range<usize> {
1063 self.value
1064 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1065 .expect("valid_range")
1066 }
1067
1068 #[inline]
1070 pub fn try_bytes_at_range(&self, range: Range<upos_type>) -> Result<Range<usize>, TextError> {
1071 self.value
1072 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1073 }
1074
1075 #[inline]
1078 pub fn byte_pos(&self, byte: usize) -> upos_type {
1079 self.value.byte_pos(byte).map(|v| v.x).expect("valid_pos")
1080 }
1081
1082 #[inline]
1085 pub fn try_byte_pos(&self, byte: usize) -> Result<upos_type, TextError> {
1086 self.value.byte_pos(byte).map(|v| v.x)
1087 }
1088
1089 #[inline]
1091 pub fn byte_range(&self, bytes: Range<usize>) -> Range<upos_type> {
1092 self.value
1093 .byte_range(bytes)
1094 .map(|v| v.start.x..v.end.x)
1095 .expect("valid_range")
1096 }
1097
1098 #[inline]
1100 pub fn try_byte_range(&self, bytes: Range<usize>) -> Result<Range<upos_type>, TextError> {
1101 self.value.byte_range(bytes).map(|v| v.start.x..v.end.x)
1102 }
1103}
1104
1105impl TextInputState {
1106 #[inline]
1108 pub fn clear(&mut self) -> bool {
1109 if self.is_empty() {
1110 false
1111 } else {
1112 self.offset = 0;
1113 self.value.clear();
1114 true
1115 }
1116 }
1117
1118 #[inline]
1122 pub fn set_value<S: Into<String>>(&mut self, s: S) {
1123 self.offset = 0;
1124 self.value.set_text(TextString::new_string(s.into()));
1125 }
1126
1127 #[inline]
1131 pub fn set_text<S: Into<String>>(&mut self, s: S) {
1132 self.offset = 0;
1133 self.value.set_text(TextString::new_string(s.into()));
1134 }
1135
1136 #[inline]
1138 pub fn insert_char(&mut self, c: char) -> bool {
1139 if self.has_selection() {
1140 self.value
1141 .remove_str_range(self.value.selection())
1142 .expect("valid_selection");
1143 }
1144 if c == '\n' {
1145 return false;
1146 } else {
1147 self.value
1148 .insert_char(self.value.cursor(), c)
1149 .expect("valid_cursor");
1150 }
1151 self.scroll_cursor_to_visible();
1152 true
1153 }
1154
1155 #[inline]
1157 pub fn insert_str(&mut self, t: impl AsRef<str>) -> bool {
1158 let t = t.as_ref();
1159 if self.has_selection() {
1160 self.value
1161 .remove_str_range(self.value.selection())
1162 .expect("valid_selection");
1163 }
1164 self.value
1165 .insert_str(self.value.cursor(), t)
1166 .expect("valid_cursor");
1167 self.scroll_cursor_to_visible();
1168 true
1169 }
1170
1171 #[inline]
1173 pub fn delete_range(&mut self, range: Range<upos_type>) -> bool {
1174 self.try_delete_range(range).expect("valid_range")
1175 }
1176
1177 #[inline]
1179 pub fn try_delete_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
1180 if !range.is_empty() {
1181 self.value
1182 .remove_str_range(TextRange::new((range.start, 0), (range.end, 0)))?;
1183 self.scroll_cursor_to_visible();
1184 Ok(true)
1185 } else {
1186 Ok(false)
1187 }
1188 }
1189}
1190
1191impl TextInputState {
1192 #[inline]
1194 pub fn delete_next_char(&mut self) -> bool {
1195 if self.has_selection() {
1196 self.delete_range(self.selection())
1197 } else {
1198 let pos = self.value.cursor();
1199 let r = remove_next_char(&mut self.value, pos).expect("valid_cursor");
1200 self.scroll_cursor_to_visible();
1201 r
1202 }
1203 }
1204
1205 #[inline]
1207 pub fn delete_prev_char(&mut self) -> bool {
1208 if self.value.has_selection() {
1209 self.delete_range(self.selection())
1210 } else {
1211 let pos = self.value.cursor();
1212 let r = remove_prev_char(&mut self.value, pos).expect("valid_cursor");
1213 self.scroll_cursor_to_visible();
1214 r
1215 }
1216 }
1217
1218 pub fn next_word_start(&self, pos: upos_type) -> upos_type {
1220 self.try_next_word_start(pos).expect("valid_pos")
1221 }
1222
1223 pub fn try_next_word_start(&self, pos: upos_type) -> Result<upos_type, TextError> {
1225 next_word_start(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1226 }
1227
1228 pub fn next_word_end(&self, pos: upos_type) -> upos_type {
1231 self.try_next_word_end(pos).expect("valid_pos")
1232 }
1233
1234 pub fn try_next_word_end(&self, pos: upos_type) -> Result<upos_type, TextError> {
1237 next_word_end(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1238 }
1239
1240 pub fn prev_word_start(&self, pos: upos_type) -> upos_type {
1244 self.try_prev_word_start(pos).expect("valid_pos")
1245 }
1246
1247 pub fn try_prev_word_start(&self, pos: upos_type) -> Result<upos_type, TextError> {
1251 prev_word_start(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1252 }
1253
1254 pub fn prev_word_end(&self, pos: upos_type) -> upos_type {
1258 self.try_prev_word_end(pos).expect("valid_pos")
1259 }
1260
1261 pub fn try_prev_word_end(&self, pos: upos_type) -> Result<upos_type, TextError> {
1265 prev_word_end(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1266 }
1267
1268 pub fn is_word_boundary(&self, pos: upos_type) -> bool {
1270 self.try_is_word_boundary(pos).expect("valid_pos")
1271 }
1272
1273 pub fn try_is_word_boundary(&self, pos: upos_type) -> Result<bool, TextError> {
1275 is_word_boundary(&self.value, TextPosition::new(pos, 0))
1276 }
1277
1278 pub fn word_start(&self, pos: upos_type) -> upos_type {
1280 self.try_word_start(pos).expect("valid_pos")
1281 }
1282
1283 pub fn try_word_start(&self, pos: upos_type) -> Result<upos_type, TextError> {
1285 word_start(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1286 }
1287
1288 pub fn word_end(&self, pos: upos_type) -> upos_type {
1290 self.try_word_end(pos).expect("valid_pos")
1291 }
1292
1293 pub fn try_word_end(&self, pos: upos_type) -> Result<upos_type, TextError> {
1295 word_end(&self.value, TextPosition::new(pos, 0)).map(|v| v.x)
1296 }
1297
1298 #[inline]
1300 pub fn delete_next_word(&mut self) -> bool {
1301 if self.has_selection() {
1302 self.delete_range(self.selection())
1303 } else {
1304 let cursor = self.cursor();
1305
1306 let start = self.next_word_start(cursor);
1307 if start != cursor {
1308 self.delete_range(cursor..start)
1309 } else {
1310 let end = self.next_word_end(cursor);
1311 self.delete_range(cursor..end)
1312 }
1313 }
1314 }
1315
1316 #[inline]
1318 pub fn delete_prev_word(&mut self) -> bool {
1319 if self.has_selection() {
1320 self.delete_range(self.selection())
1321 } else {
1322 let cursor = self.cursor();
1323
1324 let end = self.prev_word_end(cursor);
1325 if end != cursor {
1326 self.delete_range(end..cursor)
1327 } else {
1328 let start = self.prev_word_start(cursor);
1329 self.delete_range(start..cursor)
1330 }
1331 }
1332 }
1333
1334 #[inline]
1336 pub fn move_right(&mut self, extend_selection: bool) -> bool {
1337 let c = min(self.cursor() + 1, self.len());
1338 self.set_cursor(c, extend_selection)
1339 }
1340
1341 #[inline]
1343 pub fn move_left(&mut self, extend_selection: bool) -> bool {
1344 let c = self.cursor().saturating_sub(1);
1345 self.set_cursor(c, extend_selection)
1346 }
1347
1348 #[inline]
1350 pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1351 self.set_cursor(0, extend_selection)
1352 }
1353
1354 #[inline]
1356 pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
1357 self.set_cursor(self.len(), extend_selection)
1358 }
1359
1360 #[inline]
1361 pub fn move_to_next_word(&mut self, extend_selection: bool) -> bool {
1362 let cursor = self.cursor();
1363 let end = self.next_word_end(cursor);
1364 self.set_cursor(end, extend_selection)
1365 }
1366
1367 #[inline]
1368 pub fn move_to_prev_word(&mut self, extend_selection: bool) -> bool {
1369 let cursor = self.cursor();
1370 let start = self.prev_word_start(cursor);
1371 self.set_cursor(start, extend_selection)
1372 }
1373}
1374
1375impl HasScreenCursor for TextInputState {
1376 #[inline]
1378 fn screen_cursor(&self) -> Option<(u16, u16)> {
1379 if self.is_focused() {
1380 if self.has_selection() {
1381 None
1382 } else {
1383 let cx = self.cursor();
1384 let ox = self.offset();
1385
1386 if cx < ox {
1387 None
1388 } else if cx > ox + (self.inner.width + self.dark_offset.0) as upos_type {
1389 None
1390 } else {
1391 self.col_to_screen(cx)
1392 .map(|sc| (self.inner.x + sc, self.inner.y))
1393 }
1394 }
1395 } else {
1396 None
1397 }
1398 }
1399}
1400
1401impl RelocatableState for TextInputState {
1402 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
1403 self.area.relocate(shift, clip);
1404 self.inner.relocate(shift, clip);
1405 self.dark_offset = relocate_dark_offset(self.inner, shift, clip);
1407 }
1408}
1409
1410impl TextInputState {
1411 fn glyphs2(&self) -> impl Iterator<Item = Glyph2<'_>> {
1412 let (text_wrap, left_margin, right_margin, word_margin) = (
1413 TextWrap2::Shift,
1414 self.offset() as upos_type,
1415 self.offset() as upos_type + self.rendered.width as upos_type,
1416 self.offset() as upos_type + self.rendered.width as upos_type,
1417 );
1418 self.value
1419 .glyphs2(
1420 self.rendered,
1421 0,
1422 0..1,
1423 0, text_wrap,
1425 false,
1426 left_margin,
1427 right_margin,
1428 word_margin,
1429 )
1430 .expect("valid-row")
1431 }
1432
1433 pub fn screen_to_col(&self, scx: i16) -> upos_type {
1436 let ox = self.offset();
1437
1438 let scx = scx + self.dark_offset.0 as i16;
1439
1440 if scx < 0 {
1441 ox.saturating_sub((scx as ipos_type).unsigned_abs())
1442 } else if scx as u16 >= self.rendered.width {
1443 min(ox + scx as upos_type, self.len())
1444 } else {
1445 let scx = scx as u16;
1446
1447 let line = self.glyphs2();
1448
1449 let mut col = ox;
1450 for g in line {
1451 if g.contains_screen_x(scx) {
1452 break;
1453 }
1454 col = g.pos().x + 1;
1455 }
1456 col
1457 }
1458 }
1459
1460 pub fn col_to_screen(&self, pos: upos_type) -> Option<u16> {
1463 let ox = self.offset();
1464
1465 if pos < ox {
1466 return None;
1467 }
1468
1469 let line = self.glyphs2();
1470 let mut screen_x = 0;
1471 for g in line {
1472 if g.pos().x == pos {
1473 break;
1474 }
1475 screen_x = g.screen_pos().0 + g.screen_width();
1476 }
1477
1478 if screen_x >= self.dark_offset.0 {
1479 Some(screen_x - self.dark_offset.0)
1480 } else {
1481 None
1482 }
1483 }
1484
1485 #[inline]
1489 pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
1490 let scx = cursor;
1491
1492 let cx = self.screen_to_col(scx);
1493
1494 self.set_cursor(cx, extend_selection)
1495 }
1496
1497 pub fn set_screen_cursor_words(&mut self, screen_cursor: i16, extend_selection: bool) -> bool {
1504 let anchor = self.anchor();
1505
1506 let cx = self.screen_to_col(screen_cursor);
1507 let cursor = cx;
1508
1509 let cursor = if cursor < anchor {
1510 self.word_start(cursor)
1511 } else {
1512 self.word_end(cursor)
1513 };
1514
1515 if !self.is_word_boundary(anchor) {
1517 if cursor < anchor {
1518 self.set_cursor(self.word_end(anchor), false);
1519 } else {
1520 self.set_cursor(self.word_start(anchor), false);
1521 }
1522 }
1523
1524 self.set_cursor(cursor, extend_selection)
1525 }
1526
1527 pub fn scroll_left(&mut self, delta: upos_type) -> bool {
1529 self.set_offset(self.offset.saturating_sub(delta));
1530 true
1531 }
1532
1533 pub fn scroll_right(&mut self, delta: upos_type) -> bool {
1535 self.set_offset(self.offset + delta);
1536 true
1537 }
1538
1539 pub fn scroll_cursor_to_visible(&mut self) {
1541 self.scroll_to_cursor.set(true);
1542 }
1543}
1544
1545impl HandleEvent<Event, Regular, TextOutcome> for TextInputState {
1546 fn handle(&mut self, event: &Event, _keymap: Regular) -> TextOutcome {
1547 fn tc(r: bool) -> TextOutcome {
1549 if r {
1550 TextOutcome::TextChanged
1551 } else {
1552 TextOutcome::Unchanged
1553 }
1554 }
1555 fn overwrite(state: &mut TextInputState) {
1556 if state.overwrite.get() {
1557 state.overwrite.set(false);
1558 state.clear();
1559 }
1560 }
1561 fn clear_overwrite(state: &mut TextInputState) {
1562 state.overwrite.set(false);
1563 }
1564
1565 let mut r = if self.is_focused() {
1566 match event {
1567 ct_event!(key press c)
1568 | ct_event!(key press SHIFT-c)
1569 | ct_event!(key press CONTROL_ALT-c) => {
1570 overwrite(self);
1571 tc(self.insert_char(*c))
1572 }
1573 ct_event!(keycode press Backspace) | ct_event!(keycode press SHIFT-Backspace) => {
1574 clear_overwrite(self);
1575 tc(self.delete_prev_char())
1576 }
1577 ct_event!(keycode press Delete) | ct_event!(keycode press SHIFT-Delete) => {
1578 clear_overwrite(self);
1579 tc(self.delete_next_char())
1580 }
1581 ct_event!(keycode press CONTROL-Backspace)
1582 | ct_event!(keycode press ALT-Backspace) => {
1583 clear_overwrite(self);
1584 tc(self.delete_prev_word())
1585 }
1586 ct_event!(keycode press CONTROL-Delete) => {
1587 clear_overwrite(self);
1588 tc(self.delete_next_word())
1589 }
1590 ct_event!(key press CONTROL-'x') => {
1591 clear_overwrite(self);
1592 tc(self.cut_to_clip())
1593 }
1594 ct_event!(key press CONTROL-'v') => {
1595 overwrite(self);
1596 tc(self.paste_from_clip())
1597 }
1598 ct_event!(key press CONTROL-'d') => {
1599 clear_overwrite(self);
1600 tc(self.clear())
1601 }
1602 ct_event!(key press CONTROL-'z') => {
1603 clear_overwrite(self);
1604 tc(self.undo())
1605 }
1606 ct_event!(key press CONTROL_SHIFT-'Z') => {
1607 clear_overwrite(self);
1608 tc(self.redo())
1609 }
1610
1611 ct_event!(key release _)
1612 | ct_event!(key release SHIFT-_)
1613 | ct_event!(key release CONTROL_ALT-_)
1614 | ct_event!(keycode release Tab)
1615 | ct_event!(keycode release Backspace)
1616 | ct_event!(keycode release Delete)
1617 | ct_event!(keycode release CONTROL-Backspace)
1618 | ct_event!(keycode release ALT-Backspace)
1619 | ct_event!(keycode release CONTROL-Delete)
1620 | ct_event!(key release CONTROL-'x')
1621 | ct_event!(key release CONTROL-'v')
1622 | ct_event!(key release CONTROL-'d')
1623 | ct_event!(key release CONTROL-'y')
1624 | ct_event!(key release CONTROL-'z')
1625 | ct_event!(key release CONTROL_SHIFT-'Z') => TextOutcome::Unchanged,
1626
1627 _ => TextOutcome::Continue,
1628 }
1629 } else {
1630 TextOutcome::Continue
1631 };
1632 if r == TextOutcome::Continue {
1633 r = self.handle(event, ReadOnly);
1634 }
1635 r
1636 }
1637}
1638
1639impl HandleEvent<Event, ReadOnly, TextOutcome> for TextInputState {
1640 fn handle(&mut self, event: &Event, _keymap: ReadOnly) -> TextOutcome {
1641 fn clear_overwrite(state: &mut TextInputState) {
1642 state.overwrite.set(false);
1643 }
1644
1645 let mut r = if self.is_focused() {
1646 match event {
1647 ct_event!(keycode press Left) => {
1648 clear_overwrite(self);
1649 self.move_left(false).into()
1650 }
1651 ct_event!(keycode press Right) => {
1652 clear_overwrite(self);
1653 self.move_right(false).into()
1654 }
1655 ct_event!(keycode press CONTROL-Left) => {
1656 clear_overwrite(self);
1657 self.move_to_prev_word(false).into()
1658 }
1659 ct_event!(keycode press CONTROL-Right) => {
1660 clear_overwrite(self);
1661 self.move_to_next_word(false).into()
1662 }
1663 ct_event!(keycode press Home) => {
1664 clear_overwrite(self);
1665 self.move_to_line_start(false).into()
1666 }
1667 ct_event!(keycode press End) => {
1668 clear_overwrite(self);
1669 self.move_to_line_end(false).into()
1670 }
1671 ct_event!(keycode press SHIFT-Left) => {
1672 clear_overwrite(self);
1673 self.move_left(true).into()
1674 }
1675 ct_event!(keycode press SHIFT-Right) => {
1676 clear_overwrite(self);
1677 self.move_right(true).into()
1678 }
1679 ct_event!(keycode press CONTROL_SHIFT-Left) => {
1680 clear_overwrite(self);
1681 self.move_to_prev_word(true).into()
1682 }
1683 ct_event!(keycode press CONTROL_SHIFT-Right) => {
1684 clear_overwrite(self);
1685 self.move_to_next_word(true).into()
1686 }
1687 ct_event!(keycode press SHIFT-Home) => {
1688 clear_overwrite(self);
1689 self.move_to_line_start(true).into()
1690 }
1691 ct_event!(keycode press SHIFT-End) => {
1692 clear_overwrite(self);
1693 self.move_to_line_end(true).into()
1694 }
1695 ct_event!(keycode press ALT-Left) => {
1696 clear_overwrite(self);
1697 self.scroll_left(1).into()
1698 }
1699 ct_event!(keycode press ALT-Right) => {
1700 clear_overwrite(self);
1701 self.scroll_right(1).into()
1702 }
1703 ct_event!(key press CONTROL-'a') => {
1704 clear_overwrite(self);
1705 self.select_all().into()
1706 }
1707 ct_event!(key press CONTROL-'c') => {
1708 clear_overwrite(self);
1709 self.copy_to_clip().into()
1710 }
1711
1712 ct_event!(keycode release Left)
1713 | ct_event!(keycode release Right)
1714 | ct_event!(keycode release CONTROL-Left)
1715 | ct_event!(keycode release CONTROL-Right)
1716 | ct_event!(keycode release Home)
1717 | ct_event!(keycode release End)
1718 | ct_event!(keycode release SHIFT-Left)
1719 | ct_event!(keycode release SHIFT-Right)
1720 | ct_event!(keycode release CONTROL_SHIFT-Left)
1721 | ct_event!(keycode release CONTROL_SHIFT-Right)
1722 | ct_event!(keycode release SHIFT-Home)
1723 | ct_event!(keycode release SHIFT-End)
1724 | ct_event!(key release CONTROL-'a')
1725 | ct_event!(key release CONTROL-'c') => TextOutcome::Unchanged,
1726
1727 _ => TextOutcome::Continue,
1728 }
1729 } else {
1730 TextOutcome::Continue
1731 };
1732
1733 if r == TextOutcome::Continue {
1734 r = self.handle(event, MouseOnly);
1735 }
1736 r
1737 }
1738}
1739
1740impl HandleEvent<Event, MouseOnly, TextOutcome> for TextInputState {
1741 fn handle(&mut self, event: &Event, _keymap: MouseOnly) -> TextOutcome {
1742 fn clear_overwrite(state: &mut TextInputState) {
1743 state.overwrite.set(false);
1744 }
1745
1746 match event {
1747 ct_event!(mouse any for m) if self.mouse.drag(self.inner, m) => {
1748 let c = (m.column as i16) - (self.inner.x as i16);
1749 clear_overwrite(self);
1750 self.set_screen_cursor(c, true).into()
1751 }
1752 ct_event!(mouse any for m) if self.mouse.drag2(self.inner, m, KeyModifiers::ALT) => {
1753 let cx = m.column as i16 - self.inner.x as i16;
1754 clear_overwrite(self);
1755 self.set_screen_cursor_words(cx, true).into()
1756 }
1757 ct_event!(mouse any for m) if self.mouse.doubleclick(self.inner, m) => {
1758 let tx = self.screen_to_col(m.column as i16 - self.inner.x as i16);
1759 let start = self.word_start(tx);
1760 let end = self.word_end(tx);
1761 clear_overwrite(self);
1762 self.set_selection(start, end).into()
1763 }
1764 ct_event!(mouse down Left for column,row) => {
1765 if self.gained_focus() {
1766 TextOutcome::Unchanged
1769 } else if self.inner.contains((*column, *row).into()) {
1770 let c = (column - self.inner.x) as i16;
1771 clear_overwrite(self);
1772 self.set_screen_cursor(c, false).into()
1773 } else {
1774 TextOutcome::Continue
1775 }
1776 }
1777 ct_event!(mouse down CONTROL-Left for column,row) => {
1778 if self.inner.contains((*column, *row).into()) {
1779 let cx = (column - self.inner.x) as i16;
1780 clear_overwrite(self);
1781 self.set_screen_cursor(cx, true).into()
1782 } else {
1783 TextOutcome::Continue
1784 }
1785 }
1786 ct_event!(mouse down ALT-Left for column,row) => {
1787 if self.inner.contains((*column, *row).into()) {
1788 let cx = (column - self.inner.x) as i16;
1789 clear_overwrite(self);
1790 self.set_screen_cursor_words(cx, true).into()
1791 } else {
1792 TextOutcome::Continue
1793 }
1794 }
1795 _ => TextOutcome::Continue,
1796 }
1797 }
1798}
1799
1800pub fn handle_events(state: &mut TextInputState, focus: bool, event: &Event) -> TextOutcome {
1804 state.focus.set(focus);
1805 state.handle(event, Regular)
1806}
1807
1808pub fn handle_readonly_events(
1812 state: &mut TextInputState,
1813 focus: bool,
1814 event: &Event,
1815) -> TextOutcome {
1816 state.focus.set(focus);
1817 state.handle(event, ReadOnly)
1818}
1819
1820pub fn handle_mouse_events(state: &mut TextInputState, event: &Event) -> TextOutcome {
1822 state.handle(event, MouseOnly)
1823}