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 bidi: bool,
64
65 text_style: HashMap<usize, Style>,
66}
67
68#[derive(Debug)]
70pub struct TextInputState {
71 pub area: Rect,
74 pub inner: Rect,
77 pub rendered: Size,
81
82 pub offset: upos_type,
85 pub dark_offset: (u16, u16),
88 pub scroll_to_cursor: Rc<Cell<bool>>,
90
91 pub value: TextCore<TextString>,
93 pub invalid: bool,
96 pub passwd: bool,
99 pub overwrite: Rc<Cell<bool>>,
103 pub on_focus_gained: Rc<Cell<TextFocusGained>>,
106 pub on_focus_lost: Rc<Cell<TextFocusLost>>,
109
110 pub focus: FocusFlag,
113
114 pub mouse: MouseFlags,
117
118 pub non_exhaustive: NonExhaustive,
120}
121
122impl<'a> TextInput<'a> {
123 pub fn new() -> Self {
125 Self::default()
126 }
127
128 #[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 #[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 #[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 #[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 #[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 #[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 #[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 pub fn text_style_idx(mut self, idx: usize, style: Style) -> Self {
218 self.text_style.insert(idx, style);
219 self
220 }
221
222 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 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 #[inline]
246 pub fn block(mut self, block: Block<'a>) -> Self {
247 self.block = Some(block);
248 self
249 }
250
251 #[inline]
256 pub fn bidi(mut self) -> Self {
257 self.bidi = true;
258 self
259 }
260
261 #[inline]
263 pub fn passwd(mut self) -> Self {
264 self.passwd = true;
265 self
266 }
267
268 #[inline]
270 pub fn on_focus_gained(mut self, of: TextFocusGained) -> Self {
271 self.on_focus_gained = of;
272 self
273 }
274
275 #[inline]
277 pub fn on_focus_lost(mut self, of: TextFocusLost) -> Self {
278 self.on_focus_lost = of;
279 self
280 }
281
282 pub fn width(&self) -> u16 {
284 0
285 }
286
287 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 if c == no + state.rendered.width as upos_type {
332 no = no.saturating_add(1);
333 }
334 state.set_offset(no);
335 } else {
336 }
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 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 return;
401 }
402
403 let ox = state.offset() as u16;
404 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 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 if selection.contains(&g.pos().x) {
435 style = style.patch(select_style);
436 };
437
438 screen_pos = g.screen_pos();
440
441 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 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 if selection.contains(&g.pos().x) {
482 style = style.patch(select_style);
483 };
484
485 screen_pos = g.screen_pos();
487
488 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 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 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_cb(self.focus.new_instance()),
554 mouse: Default::default(),
555 non_exhaustive: NonExhaustive,
556 }
557 }
558}
559
560impl Default for TextInputState {
561 fn default() -> Self {
562 let value = TextCore::new(Some(Box::new(UndoVec::new(99))), Some(global_clipboard()));
563
564 let mut z = Self {
565 area: Default::default(),
566 inner: Default::default(),
567 rendered: Default::default(),
568 offset: Default::default(),
569 dark_offset: Default::default(),
570 scroll_to_cursor: Default::default(),
571 value,
572 invalid: Default::default(),
573 passwd: Default::default(),
574 overwrite: Default::default(),
575 on_focus_gained: Default::default(),
576 on_focus_lost: Default::default(),
577 focus: Default::default(),
578 mouse: Default::default(),
579 non_exhaustive: NonExhaustive,
580 };
581 z.focus = z.focus_cb(FocusFlag::default());
582 z
583 }
584}
585
586impl TextInputState {
587 fn focus_cb(&self, flag: FocusFlag) -> FocusFlag {
588 let on_focus_lost = self.on_focus_lost.clone();
589 let cursor = self.value.shared_cursor();
590 let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
591 flag.on_lost(move || match on_focus_lost.get() {
592 TextFocusLost::None => {}
593 TextFocusLost::Position0 => {
594 scroll_cursor_to_visible.set(true);
595 let mut new_cursor = cursor.get();
596 new_cursor.cursor.x = 0;
597 new_cursor.anchor.x = 0;
598 cursor.set(new_cursor);
599 }
600 });
601 let on_focus_gained = self.on_focus_gained.clone();
602 let overwrite = self.overwrite.clone();
603 let cursor = self.value.shared_cursor();
604 let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
605 flag.on_gained(move || match on_focus_gained.get() {
606 TextFocusGained::None => {}
607 TextFocusGained::Overwrite => {
608 overwrite.set(true);
609 }
610 TextFocusGained::SelectAll => {
611 scroll_cursor_to_visible.set(true);
612 let mut new_cursor = cursor.get();
613 new_cursor.anchor = TextPosition::new(0, 0);
614 new_cursor.cursor = TextPosition::new(0, 1);
615 cursor.set(new_cursor);
616 }
617 });
618
619 flag
620 }
621}
622
623impl HasFocus for TextInputState {
624 fn build(&self, builder: &mut FocusBuilder) {
625 builder.leaf_widget(self);
626 }
627
628 fn focus(&self) -> FocusFlag {
629 self.focus.clone()
630 }
631
632 fn area(&self) -> Rect {
633 self.area
634 }
635}
636
637impl TextInputState {
638 pub fn new() -> Self {
639 Self::default()
640 }
641
642 pub fn new_focused() -> Self {
644 let s = Self::default();
645 s.focus.set(true);
646 s
647 }
648
649 pub fn named(name: &str) -> Self {
650 let mut z = Self::default();
651 z.focus = z.focus.with_name(name);
652 z
653 }
654
655 #[inline]
657 pub fn set_invalid(&mut self, invalid: bool) {
658 self.invalid = invalid;
659 }
660
661 #[inline]
663 pub fn invalid(&self) -> bool {
664 self.invalid
665 }
666
667 #[inline]
671 pub fn set_overwrite(&mut self, overwrite: bool) {
672 self.overwrite.set(overwrite);
673 }
674
675 #[inline]
677 pub fn overwrite(&self) -> bool {
678 self.overwrite.get()
679 }
680
681 #[inline]
683 pub fn set_show_ctrl(&mut self, show_ctrl: bool) {
684 self.value.set_glyph_ctrl(show_ctrl);
685 }
686
687 pub fn show_ctrl(&self) -> bool {
689 self.value.glyph_ctrl()
690 }
691}
692
693impl TextInputState {
694 #[inline]
697 pub fn set_clipboard(&mut self, clip: Option<impl Clipboard + 'static>) {
698 match clip {
699 None => self.value.set_clipboard(None),
700 Some(v) => self.value.set_clipboard(Some(Box::new(v))),
701 }
702 }
703
704 #[inline]
707 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
708 self.value.clipboard()
709 }
710
711 #[inline]
713 pub fn copy_to_clip(&mut self) -> bool {
714 let Some(clip) = self.value.clipboard() else {
715 return false;
716 };
717 if self.passwd {
718 return false;
719 }
720
721 _ = clip.set_string(self.selected_text().as_ref());
722 false
723 }
724
725 #[inline]
727 pub fn cut_to_clip(&mut self) -> bool {
728 let Some(clip) = self.value.clipboard() else {
729 return false;
730 };
731 if self.passwd {
732 return false;
733 }
734
735 match clip.set_string(self.selected_text().as_ref()) {
736 Ok(_) => self.delete_range(self.selection()),
737 Err(_) => false,
738 }
739 }
740
741 #[inline]
743 pub fn paste_from_clip(&mut self) -> bool {
744 let Some(clip) = self.value.clipboard() else {
745 return false;
746 };
747
748 if let Ok(text) = clip.get_string() {
749 self.insert_str(text)
750 } else {
751 false
752 }
753 }
754}
755
756impl TextInputState {
757 #[inline]
759 pub fn set_undo_buffer(&mut self, undo: Option<impl UndoBuffer + 'static>) {
760 match undo {
761 None => self.value.set_undo_buffer(None),
762 Some(v) => self.value.set_undo_buffer(Some(Box::new(v))),
763 }
764 }
765
766 #[inline]
768 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
769 self.value.undo_buffer()
770 }
771
772 #[inline]
774 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
775 self.value.undo_buffer_mut()
776 }
777
778 #[inline]
780 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
781 self.value.recent_replay_log()
782 }
783
784 #[inline]
786 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
787 self.value.replay_log(replay)
788 }
789
790 #[inline]
792 pub fn undo(&mut self) -> bool {
793 self.value.undo()
794 }
795
796 #[inline]
798 pub fn redo(&mut self) -> bool {
799 self.value.redo()
800 }
801}
802
803impl TextInputState {
804 #[inline]
815 pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
816 self.value.set_styles(styles);
817 }
818
819 #[inline]
824 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
825 self.value.add_style(range, style);
826 }
827
828 #[inline]
831 pub fn add_range_style(
832 &mut self,
833 range: Range<upos_type>,
834 style: usize,
835 ) -> Result<(), TextError> {
836 let r = self
837 .value
838 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))?;
839 self.value.add_style(r, style);
840 Ok(())
841 }
842
843 #[inline]
845 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
846 self.value.remove_style(range, style);
847 }
848
849 #[inline]
851 pub fn remove_range_style(
852 &mut self,
853 range: Range<upos_type>,
854 style: usize,
855 ) -> Result<(), TextError> {
856 let r = self
857 .value
858 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))?;
859 self.value.remove_style(r, style);
860 Ok(())
861 }
862
863 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
865 self.value.styles_in(range, buf)
866 }
867
868 #[inline]
870 pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
871 self.value.styles_at(byte_pos, buf)
872 }
873
874 #[inline]
877 pub fn styles_at_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
878 self.value.styles_at_match(byte_pos, style)
879 }
880
881 #[inline]
883 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
884 self.value.styles()
885 }
886}
887
888impl TextInputState {
889 #[inline]
891 pub fn offset(&self) -> upos_type {
892 self.offset
893 }
894
895 #[inline]
897 pub fn set_offset(&mut self, offset: upos_type) {
898 self.scroll_to_cursor.set(false);
899 self.offset = offset;
900 }
901
902 #[inline]
904 pub fn cursor(&self) -> upos_type {
905 self.value.cursor().x
906 }
907
908 #[inline]
910 pub fn anchor(&self) -> upos_type {
911 self.value.anchor().x
912 }
913
914 #[inline]
917 pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
918 self.scroll_cursor_to_visible();
919 self.value
920 .set_cursor(TextPosition::new(cursor, 0), extend_selection)
921 }
922
923 #[inline]
925 pub fn has_selection(&self) -> bool {
926 self.value.has_selection()
927 }
928
929 #[inline]
931 pub fn selection(&self) -> Range<upos_type> {
932 let mut v = self.value.selection();
933 if v.start == TextPosition::new(0, 1) {
934 v.start = TextPosition::new(self.line_width(), 0);
935 }
936 if v.end == TextPosition::new(0, 1) {
937 v.end = TextPosition::new(self.line_width(), 0);
938 }
939 v.start.x..v.end.x
940 }
941
942 #[inline]
945 pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
946 self.scroll_cursor_to_visible();
947 self.value
948 .set_selection(TextPosition::new(anchor, 0), TextPosition::new(cursor, 0))
949 }
950
951 #[inline]
954 pub fn select_all(&mut self) -> bool {
955 self.scroll_cursor_to_visible();
956 self.value.select_all()
957 }
958
959 #[inline]
961 pub fn selected_text(&self) -> &str {
962 match self.str_slice(self.selection()) {
963 Cow::Borrowed(v) => v,
964 Cow::Owned(_) => {
965 unreachable!()
966 }
967 }
968 }
969}
970
971impl TextInputState {
972 #[inline]
974 pub fn is_empty(&self) -> bool {
975 self.value.is_empty()
976 }
977
978 #[inline]
980 pub fn value<T: for<'a> From<&'a str>>(&self) -> T {
981 self.value.text().as_str().into()
982 }
983
984 #[inline]
986 pub fn text(&self) -> &str {
987 self.value.text().as_str()
988 }
989
990 #[inline]
992 pub fn str_slice_byte(&self, range: Range<usize>) -> Cow<'_, str> {
993 self.value.str_slice_byte(range).expect("valid_range")
994 }
995
996 #[inline]
998 pub fn try_str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
999 self.value.str_slice_byte(range)
1000 }
1001
1002 #[inline]
1004 pub fn str_slice(&self, range: Range<upos_type>) -> Cow<'_, str> {
1005 self.value
1006 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1007 .expect("valid_range")
1008 }
1009
1010 #[inline]
1012 pub fn try_str_slice(&self, range: Range<upos_type>) -> Result<Cow<'_, str>, TextError> {
1013 self.value
1014 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1015 }
1016
1017 #[inline]
1019 pub fn len(&self) -> upos_type {
1020 self.value.line_width(0).expect("valid_row")
1021 }
1022
1023 #[inline]
1025 pub fn len_bytes(&self) -> usize {
1026 self.value.len_bytes()
1027 }
1028
1029 #[inline]
1031 pub fn line_width(&self) -> upos_type {
1032 self.value.line_width(0).expect("valid_row")
1033 }
1034
1035 #[inline]
1037 pub fn text_graphemes(&self, pos: upos_type) -> <TextString as TextStore>::GraphemeIter<'_> {
1038 self.value
1039 .text_graphemes(TextPosition::new(pos, 0))
1040 .expect("valid_pos")
1041 }
1042
1043 #[inline]
1045 pub fn try_text_graphemes(
1046 &self,
1047 pos: upos_type,
1048 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1049 self.value.text_graphemes(TextPosition::new(pos, 0))
1050 }
1051
1052 #[inline]
1054 pub fn graphemes(
1055 &self,
1056 range: Range<upos_type>,
1057 pos: upos_type,
1058 ) -> <TextString as TextStore>::GraphemeIter<'_> {
1059 self.value
1060 .graphemes(
1061 TextRange::new((range.start, 0), (range.end, 0)),
1062 TextPosition::new(pos, 0),
1063 )
1064 .expect("valid_args")
1065 }
1066
1067 #[inline]
1069 pub fn try_graphemes(
1070 &self,
1071 range: Range<upos_type>,
1072 pos: upos_type,
1073 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1074 self.value.graphemes(
1075 TextRange::new((range.start, 0), (range.end, 0)),
1076 TextPosition::new(pos, 0),
1077 )
1078 }
1079
1080 #[inline]
1083 pub fn byte_at(&self, pos: upos_type) -> Range<usize> {
1084 self.value
1085 .byte_at(TextPosition::new(pos, 0))
1086 .expect("valid_pos")
1087 }
1088
1089 #[inline]
1092 pub fn try_byte_at(&self, pos: upos_type) -> Result<Range<usize>, TextError> {
1093 self.value.byte_at(TextPosition::new(pos, 0))
1094 }
1095
1096 #[inline]
1098 pub fn bytes_at_range(&self, range: Range<upos_type>) -> Range<usize> {
1099 self.value
1100 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1101 .expect("valid_range")
1102 }
1103
1104 #[inline]
1106 pub fn try_bytes_at_range(&self, range: Range<upos_type>) -> Result<Range<usize>, TextError> {
1107 self.value
1108 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1109 }
1110
1111 #[inline]
1114 pub fn byte_pos(&self, byte: usize) -> upos_type {
1115 self.value.byte_pos(byte).map(|v| v.x).expect("valid_pos")
1116 }
1117
1118 #[inline]
1121 pub fn try_byte_pos(&self, byte: usize) -> Result<upos_type, TextError> {
1122 self.value.byte_pos(byte).map(|v| v.x)
1123 }
1124
1125 #[inline]
1127 pub fn byte_range(&self, bytes: Range<usize>) -> Range<upos_type> {
1128 self.value
1129 .byte_range(bytes)
1130 .map(|v| v.start.x..v.end.x)
1131 .expect("valid_range")
1132 }
1133
1134 #[inline]
1136 pub fn try_byte_range(&self, bytes: Range<usize>) -> Result<Range<upos_type>, TextError> {
1137 self.value.byte_range(bytes).map(|v| v.start.x..v.end.x)
1138 }
1139}
1140
1141impl TextInputState {
1142 #[inline]
1144 pub fn clear(&mut self) -> bool {
1145 if self.is_empty() {
1146 false
1147 } else {
1148 self.offset = 0;
1149 self.value.clear();
1150 true
1151 }
1152 }
1153
1154 #[inline]
1158 pub fn set_value<S: Into<String>>(&mut self, s: S) {
1159 self.offset = 0;
1160 self.value.set_text(TextString::new_string(s.into()));
1161 }
1162
1163 #[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 #[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 #[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 #[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 #[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 #[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 #[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 pub fn next_word_start(&self, pos: upos_type) -> upos_type {
1256 self.try_next_word_start(pos).expect("valid_pos")
1257 }
1258
1259 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 pub fn next_word_end(&self, pos: upos_type) -> upos_type {
1267 self.try_next_word_end(pos).expect("valid_pos")
1268 }
1269
1270 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 pub fn prev_word_start(&self, pos: upos_type) -> upos_type {
1280 self.try_prev_word_start(pos).expect("valid_pos")
1281 }
1282
1283 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 pub fn prev_word_end(&self, pos: upos_type) -> upos_type {
1294 self.try_prev_word_end(pos).expect("valid_pos")
1295 }
1296
1297 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 pub fn is_word_boundary(&self, pos: upos_type) -> bool {
1306 self.try_is_word_boundary(pos).expect("valid_pos")
1307 }
1308
1309 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 pub fn word_start(&self, pos: upos_type) -> upos_type {
1316 self.try_word_start(pos).expect("valid_pos")
1317 }
1318
1319 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 pub fn word_end(&self, pos: upos_type) -> upos_type {
1326 self.try_word_end(pos).expect("valid_pos")
1327 }
1328
1329 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 #[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 #[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 #[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 #[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 #[inline]
1386 pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1387 self.set_cursor(0, extend_selection)
1388 }
1389
1390 #[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 #[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 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, text_wrap,
1461 false,
1462 left_margin,
1463 right_margin,
1464 word_margin,
1465 )
1466 .expect("valid-row")
1467 }
1468
1469 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 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 #[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 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 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 pub fn scroll_left(&mut self, delta: upos_type) -> bool {
1565 self.set_offset(self.offset.saturating_sub(delta));
1566 true
1567 }
1568
1569 pub fn scroll_right(&mut self, delta: upos_type) -> bool {
1571 self.set_offset(self.offset + delta);
1572 true
1573 }
1574
1575 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 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.clear();
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!(key press CONTROL-'d') => {
1635 clear_overwrite(self);
1636 tc(self.clear())
1637 }
1638 ct_event!(key press CONTROL-'z') => {
1639 clear_overwrite(self);
1640 tc(self.undo())
1641 }
1642 ct_event!(key press CONTROL_SHIFT-'Z') => {
1643 clear_overwrite(self);
1644 tc(self.redo())
1645 }
1646
1647 ct_event!(key release _)
1648 | ct_event!(key release SHIFT-_)
1649 | ct_event!(key release CONTROL_ALT-_)
1650 | ct_event!(keycode release Tab)
1651 | ct_event!(keycode release Backspace)
1652 | ct_event!(keycode release Delete)
1653 | ct_event!(keycode release CONTROL-Backspace)
1654 | ct_event!(keycode release ALT-Backspace)
1655 | ct_event!(keycode release CONTROL-Delete)
1656 | ct_event!(key release CONTROL-'x')
1657 | ct_event!(key release CONTROL-'v')
1658 | ct_event!(key release CONTROL-'d')
1659 | ct_event!(key release CONTROL-'y')
1660 | ct_event!(key release CONTROL-'z')
1661 | ct_event!(key release CONTROL_SHIFT-'Z') => TextOutcome::Unchanged,
1662
1663 _ => TextOutcome::Continue,
1664 }
1665 } else {
1666 TextOutcome::Continue
1667 };
1668 if r == TextOutcome::Continue {
1669 r = self.handle(event, ReadOnly);
1670 }
1671 r
1672 }
1673}
1674
1675impl HandleEvent<Event, ReadOnly, TextOutcome> for TextInputState {
1676 fn handle(&mut self, event: &Event, _keymap: ReadOnly) -> TextOutcome {
1677 fn clear_overwrite(state: &mut TextInputState) {
1678 state.overwrite.set(false);
1679 }
1680
1681 let mut r = if self.is_focused() {
1682 match event {
1683 ct_event!(keycode press Left) => {
1684 clear_overwrite(self);
1685 self.move_left(false).into()
1686 }
1687 ct_event!(keycode press Right) => {
1688 clear_overwrite(self);
1689 self.move_right(false).into()
1690 }
1691 ct_event!(keycode press CONTROL-Left) => {
1692 clear_overwrite(self);
1693 self.move_to_prev_word(false).into()
1694 }
1695 ct_event!(keycode press CONTROL-Right) => {
1696 clear_overwrite(self);
1697 self.move_to_next_word(false).into()
1698 }
1699 ct_event!(keycode press Home) => {
1700 clear_overwrite(self);
1701 self.move_to_line_start(false).into()
1702 }
1703 ct_event!(keycode press End) => {
1704 clear_overwrite(self);
1705 self.move_to_line_end(false).into()
1706 }
1707 ct_event!(keycode press SHIFT-Left) => {
1708 clear_overwrite(self);
1709 self.move_left(true).into()
1710 }
1711 ct_event!(keycode press SHIFT-Right) => {
1712 clear_overwrite(self);
1713 self.move_right(true).into()
1714 }
1715 ct_event!(keycode press CONTROL_SHIFT-Left) => {
1716 clear_overwrite(self);
1717 self.move_to_prev_word(true).into()
1718 }
1719 ct_event!(keycode press CONTROL_SHIFT-Right) => {
1720 clear_overwrite(self);
1721 self.move_to_next_word(true).into()
1722 }
1723 ct_event!(keycode press SHIFT-Home) => {
1724 clear_overwrite(self);
1725 self.move_to_line_start(true).into()
1726 }
1727 ct_event!(keycode press SHIFT-End) => {
1728 clear_overwrite(self);
1729 self.move_to_line_end(true).into()
1730 }
1731 ct_event!(keycode press ALT-Left) => {
1732 clear_overwrite(self);
1733 self.scroll_left(1).into()
1734 }
1735 ct_event!(keycode press ALT-Right) => {
1736 clear_overwrite(self);
1737 self.scroll_right(1).into()
1738 }
1739 ct_event!(key press CONTROL-'a') => {
1740 clear_overwrite(self);
1741 self.select_all().into()
1742 }
1743 ct_event!(key press CONTROL-'c') => {
1744 clear_overwrite(self);
1745 self.copy_to_clip().into()
1746 }
1747
1748 ct_event!(keycode release Left)
1749 | ct_event!(keycode release Right)
1750 | ct_event!(keycode release CONTROL-Left)
1751 | ct_event!(keycode release CONTROL-Right)
1752 | ct_event!(keycode release Home)
1753 | ct_event!(keycode release End)
1754 | ct_event!(keycode release SHIFT-Left)
1755 | ct_event!(keycode release SHIFT-Right)
1756 | ct_event!(keycode release CONTROL_SHIFT-Left)
1757 | ct_event!(keycode release CONTROL_SHIFT-Right)
1758 | ct_event!(keycode release SHIFT-Home)
1759 | ct_event!(keycode release SHIFT-End)
1760 | ct_event!(key release CONTROL-'a')
1761 | ct_event!(key release CONTROL-'c') => TextOutcome::Unchanged,
1762
1763 _ => TextOutcome::Continue,
1764 }
1765 } else {
1766 TextOutcome::Continue
1767 };
1768
1769 if r == TextOutcome::Continue {
1770 r = self.handle(event, MouseOnly);
1771 }
1772 r
1773 }
1774}
1775
1776impl HandleEvent<Event, MouseOnly, TextOutcome> for TextInputState {
1777 fn handle(&mut self, event: &Event, _keymap: MouseOnly) -> TextOutcome {
1778 fn clear_overwrite(state: &mut TextInputState) {
1779 state.overwrite.set(false);
1780 }
1781
1782 match event {
1783 ct_event!(mouse any for m) if self.mouse.drag(self.inner, m) => {
1784 let c = (m.column as i16) - (self.inner.x as i16);
1785 clear_overwrite(self);
1786 self.set_screen_cursor(c, true).into()
1787 }
1788 ct_event!(mouse any for m) if self.mouse.drag2(self.inner, m, KeyModifiers::ALT) => {
1789 let cx = m.column as i16 - self.inner.x as i16;
1790 clear_overwrite(self);
1791 self.set_screen_cursor_words(cx, true).into()
1792 }
1793 ct_event!(mouse any for m) if self.mouse.doubleclick(self.inner, m) => {
1794 let tx = self.screen_to_col(m.column as i16 - self.inner.x as i16);
1795 let start = self.word_start(tx);
1796 let end = self.word_end(tx);
1797 clear_overwrite(self);
1798 self.set_selection(start, end).into()
1799 }
1800 ct_event!(mouse down Left for column,row) => {
1801 if self.gained_focus() {
1802 TextOutcome::Unchanged
1805 } else if self.inner.contains((*column, *row).into()) {
1806 let c = (column - self.inner.x) as i16;
1807 clear_overwrite(self);
1808 self.set_screen_cursor(c, false).into()
1809 } else {
1810 TextOutcome::Continue
1811 }
1812 }
1813 ct_event!(mouse down CONTROL-Left for column,row) => {
1814 if self.inner.contains((*column, *row).into()) {
1815 let cx = (column - self.inner.x) as i16;
1816 clear_overwrite(self);
1817 self.set_screen_cursor(cx, true).into()
1818 } else {
1819 TextOutcome::Continue
1820 }
1821 }
1822 ct_event!(mouse down ALT-Left for column,row) => {
1823 if self.inner.contains((*column, *row).into()) {
1824 let cx = (column - self.inner.x) as i16;
1825 clear_overwrite(self);
1826 self.set_screen_cursor_words(cx, true).into()
1827 } else {
1828 TextOutcome::Continue
1829 }
1830 }
1831 _ => TextOutcome::Continue,
1832 }
1833 }
1834}
1835
1836pub fn handle_events(state: &mut TextInputState, focus: bool, event: &Event) -> TextOutcome {
1840 state.focus.set(focus);
1841 state.handle(event, Regular)
1842}
1843
1844pub fn handle_readonly_events(
1848 state: &mut TextInputState,
1849 focus: bool,
1850 event: &Event,
1851) -> TextOutcome {
1852 state.focus.set(focus);
1853 state.handle(event, ReadOnly)
1854}
1855
1856pub fn handle_mouse_events(state: &mut TextInputState, event: &Event) -> TextOutcome {
1858 state.handle(event, MouseOnly)
1859}