1pub mod mask_op;
73pub(crate) mod mask_token;
74pub(crate) mod masked_graphemes;
75
76use crate::_private::NonExhaustive;
77use crate::clipboard::{Clipboard, global_clipboard};
78use crate::core::{TextCore, TextString};
79use crate::event::{ReadOnly, TextOutcome};
80use crate::glyph2::{Glyph2, GlyphIter2, TextWrap2};
81use crate::text_input::TextInputState;
82use crate::text_input_mask::mask_token::{EditDirection, Mask, MaskToken};
83use crate::text_input_mask::masked_graphemes::MaskedGraphemes;
84use crate::text_store::TextStore;
85use crate::undo_buffer::{UndoBuffer, UndoEntry, UndoVec};
86use crate::{
87 Grapheme, HasScreenCursor, TextError, TextFocusGained, TextFocusLost, TextPosition, TextRange,
88 TextStyle, ipos_type, upos_type,
89};
90use crossterm::event::KeyModifiers;
91use format_num_pattern::NumberSymbols;
92use rat_event::util::MouseFlags;
93use rat_event::{HandleEvent, MouseOnly, Regular, ct_event};
94use rat_focus::{FocusBuilder, FocusFlag, HasFocus, Navigation};
95use rat_reloc::{RelocatableState, relocate_area, relocate_dark_offset};
96use ratatui::buffer::Buffer;
97use ratatui::layout::{Rect, Size};
98use ratatui::prelude::BlockExt;
99use ratatui::style::{Style, Stylize};
100use ratatui::widgets::{Block, StatefulWidget, Widget};
101use std::borrow::Cow;
102use std::cmp::min;
103use std::fmt;
104use std::iter::once;
105use std::ops::Range;
106use unicode_segmentation::UnicodeSegmentation;
107
108#[derive(Debug, Default, Clone)]
114pub struct MaskedInput<'a> {
115 compact: bool,
116 block: Option<Block<'a>>,
117 style: Style,
118 focus_style: Option<Style>,
119 select_style: Option<Style>,
120 invalid_style: Option<Style>,
121 text_style: Vec<Style>,
122 on_focus_gained: TextFocusGained,
123 on_focus_lost: TextFocusLost,
124}
125
126#[derive(Debug)]
128pub struct MaskedInputState {
129 pub area: Rect,
132 pub inner: Rect,
135 pub rendered: Size,
138 pub compact: bool,
141
142 pub offset: upos_type,
145 pub dark_offset: (u16, u16),
148 pub scroll_to_cursor: bool,
150
151 pub value: TextCore<TextString>,
153 pub sym: Option<NumberSymbols>,
155 pub mask: Vec<MaskToken>,
157
158 pub invalid: bool,
161 pub overwrite: bool,
164 pub on_focus_gained: TextFocusGained,
167 pub on_focus_lost: TextFocusLost,
170
171 pub focus: FocusFlag,
174
175 pub mouse: MouseFlags,
178
179 pub non_exhaustive: NonExhaustive,
181}
182
183impl<'a> MaskedInput<'a> {
184 pub fn new() -> Self {
186 Self::default()
187 }
188
189 #[inline]
192 pub fn compact(mut self, show_compact: bool) -> Self {
193 self.compact = show_compact;
194 self
195 }
196
197 #[inline]
199 pub fn styles_opt(self, styles: Option<TextStyle>) -> Self {
200 if let Some(styles) = styles {
201 self.styles(styles)
202 } else {
203 self
204 }
205 }
206
207 #[inline]
209 pub fn styles(mut self, styles: TextStyle) -> Self {
210 self.style = styles.style;
211 if styles.focus.is_some() {
212 self.focus_style = styles.focus;
213 }
214 if styles.select.is_some() {
215 self.select_style = styles.select;
216 }
217 if styles.invalid.is_some() {
218 self.invalid_style = styles.invalid;
219 }
220 if let Some(of) = styles.on_focus_gained {
221 self.on_focus_gained = of;
222 }
223 if let Some(of) = styles.on_focus_lost {
224 self.on_focus_lost = of;
225 }
226 if let Some(border_style) = styles.border_style {
227 self.block = self.block.map(|v| v.border_style(border_style));
228 }
229 self.block = self.block.map(|v| v.style(self.style));
230 if styles.block.is_some() {
231 self.block = styles.block;
232 }
233 self.block = self.block.map(|v| v.style(self.style));
234 self
235 }
236
237 #[inline]
239 pub fn style(mut self, style: impl Into<Style>) -> Self {
240 self.style = style.into();
241 self.block = self.block.map(|v| v.style(self.style));
242 self
243 }
244
245 #[inline]
247 pub fn focus_style(mut self, style: impl Into<Style>) -> Self {
248 self.focus_style = Some(style.into());
249 self
250 }
251
252 #[inline]
254 pub fn select_style(mut self, style: impl Into<Style>) -> Self {
255 self.select_style = Some(style.into());
256 self
257 }
258
259 #[inline]
262 pub fn invalid_style(mut self, style: impl Into<Style>) -> Self {
263 self.invalid_style = Some(style.into());
264 self
265 }
266
267 pub fn text_style<T: IntoIterator<Item = Style>>(mut self, styles: T) -> Self {
272 self.text_style = styles.into_iter().collect();
273 self
274 }
275
276 #[inline]
278 pub fn block(mut self, block: Block<'a>) -> Self {
279 self.block = Some(block);
280 self.block = self.block.map(|v| v.style(self.style));
281 self
282 }
283
284 #[inline]
286 pub fn on_focus_gained(mut self, of: TextFocusGained) -> Self {
287 self.on_focus_gained = of;
288 self
289 }
290
291 #[inline]
293 pub fn on_focus_lost(mut self, of: TextFocusLost) -> Self {
294 self.on_focus_lost = of;
295 self
296 }
297}
298
299impl<'a> StatefulWidget for &MaskedInput<'a> {
300 type State = MaskedInputState;
301
302 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
303 render_ref(self, area, buf, state);
304 }
305}
306
307impl StatefulWidget for MaskedInput<'_> {
308 type State = MaskedInputState;
309
310 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
311 render_ref(&self, area, buf, state);
312 }
313}
314
315fn render_ref(
316 widget: &MaskedInput<'_>,
317 area: Rect,
318
319 buf: &mut Buffer,
320 state: &mut MaskedInputState,
321) {
322 state.area = area;
323 state.inner = widget.block.inner_if_some(area);
324 state.rendered = state.inner.as_size();
325 state.compact = widget.compact;
326 state.on_focus_gained = widget.on_focus_gained;
327 state.on_focus_lost = widget.on_focus_lost;
328
329 if state.scroll_to_cursor {
330 let c = state.cursor();
331 let o = state.offset();
332 let mut no = if c < o {
333 c
334 } else if c >= o + state.rendered.width as upos_type {
335 c.saturating_sub(state.rendered.width as upos_type)
336 } else {
337 o
338 };
339 if c == no + state.rendered.width as upos_type {
342 no = no.saturating_add(1);
343 }
344 state.set_offset(no);
345 }
346
347 let style = widget.style;
348 let focus_style = if let Some(focus_style) = widget.focus_style {
349 focus_style
350 } else {
351 style
352 };
353 let select_style = if let Some(select_style) = widget.select_style {
354 select_style
355 } else {
356 Style::default().black().on_yellow()
357 };
358 let invalid_style = if let Some(invalid_style) = widget.invalid_style {
359 invalid_style
360 } else {
361 Style::default().red()
362 };
363
364 let (style, select_style) = if state.focus.get() {
365 if state.invalid {
366 (
367 style.patch(focus_style).patch(invalid_style),
368 style
369 .patch(focus_style)
370 .patch(select_style)
371 .patch(invalid_style),
372 )
373 } else {
374 (
375 style.patch(focus_style),
376 style.patch(focus_style).patch(select_style),
377 )
378 }
379 } else {
380 if state.invalid {
381 (
382 style.patch(invalid_style),
383 style.patch(select_style).patch(invalid_style),
384 )
385 } else {
386 (style, style.patch(select_style))
387 }
388 };
389
390 if let Some(block) = &widget.block {
392 block.render(area, buf);
393 } else {
394 buf.set_style(area, style);
395 }
396
397 if state.inner.width == 0 || state.inner.height == 0 {
398 return;
400 }
401
402 let ox = state.offset() as u16;
403 let show_range = {
405 let start = ox as upos_type;
406 let end = min(start + state.inner.width as upos_type, state.len());
407 state.bytes_at_range(start..end)
408 };
409 let selection = state.selection();
410 let mut styles = Vec::new();
411
412 for g in state.glyphs2() {
413 if g.screen_width() > 0 {
414 let mut style = style;
415 styles.clear();
416 state
417 .value
418 .styles_at_page(g.text_bytes().start, show_range.clone(), &mut styles);
419 for style_nr in &styles {
420 if let Some(s) = widget.text_style.get(*style_nr) {
421 style = style.patch(*s);
422 }
423 }
424 if selection.contains(&g.pos().x) {
426 style = style.patch(select_style);
427 };
428
429 let screen_pos = g.screen_pos();
431
432 if let Some(cell) =
434 buf.cell_mut((state.inner.x + screen_pos.0, state.inner.y + screen_pos.1))
435 {
436 cell.set_symbol(g.glyph());
437 cell.set_style(style);
438 }
439 for d in 1..g.screen_width() {
441 if let Some(cell) = buf.cell_mut((
442 state.inner.x + screen_pos.0 + d,
443 state.inner.y + screen_pos.1,
444 )) {
445 cell.reset();
446 cell.set_style(style);
447 }
448 }
449 }
450 }
451}
452
453impl Clone for MaskedInputState {
454 fn clone(&self) -> Self {
455 Self {
456 area: self.area,
457 inner: self.inner,
458 rendered: self.rendered,
459 compact: self.compact,
460 offset: self.offset,
461 dark_offset: self.dark_offset,
462 scroll_to_cursor: self.scroll_to_cursor,
463 value: self.value.clone(),
464 sym: self.sym,
465 mask: self.mask.clone(),
466 invalid: self.invalid,
467 overwrite: Default::default(),
468 on_focus_gained: Default::default(),
469 on_focus_lost: Default::default(),
470 focus: FocusFlag::named(self.focus.name()),
471 mouse: Default::default(),
472 non_exhaustive: NonExhaustive,
473 }
474 }
475}
476
477impl Default for MaskedInputState {
478 fn default() -> Self {
479 let core = TextCore::new(
480 Some(Box::new(UndoVec::new(99))),
481 Some(Box::new(global_clipboard())),
482 );
483
484 Self {
485 area: Default::default(),
486 inner: Default::default(),
487 rendered: Default::default(),
488 compact: Default::default(),
489 offset: Default::default(),
490 dark_offset: Default::default(),
491 scroll_to_cursor: Default::default(),
492 value: core,
493 sym: None,
494 mask: Default::default(),
495 invalid: Default::default(),
496 overwrite: Default::default(),
497 on_focus_gained: Default::default(),
498 on_focus_lost: Default::default(),
499 focus: Default::default(),
500 mouse: Default::default(),
501 non_exhaustive: NonExhaustive,
502 }
503 }
504}
505
506impl HasFocus for MaskedInputState {
507 fn build(&self, builder: &mut FocusBuilder) {
508 builder.leaf_widget(self);
509 }
510
511 fn focus(&self) -> FocusFlag {
512 self.focus.clone()
513 }
514
515 fn area(&self) -> Rect {
516 self.area
517 }
518
519 fn navigable(&self) -> Navigation {
520 let sel = self.selection();
521
522 let has_next = self
523 .next_section_range(sel.end)
524 .map(|v| !v.is_empty())
525 .is_some();
526 let has_prev = self
527 .prev_section_range(sel.start.saturating_sub(1))
528 .map(|v| !v.is_empty())
529 .is_some();
530
531 if has_next {
532 if has_prev {
533 Navigation::Reach
534 } else {
535 Navigation::ReachLeaveFront
536 }
537 } else {
538 if has_prev {
539 Navigation::ReachLeaveBack
540 } else {
541 Navigation::Regular
542 }
543 }
544 }
545}
546
547impl MaskedInputState {
548 pub fn new() -> Self {
549 Self::default()
550 }
551
552 pub fn named(name: &str) -> Self {
553 Self {
554 focus: FocusFlag::named(name),
555 ..MaskedInputState::default()
556 }
557 }
558
559 #[inline]
561 pub fn with_symbols(mut self, sym: NumberSymbols) -> Self {
562 self.set_num_symbols(sym);
563 self
564 }
565
566 pub fn with_mask<S: AsRef<str>>(mut self, mask: S) -> Result<Self, fmt::Error> {
568 self.set_mask(mask.as_ref())?;
569 Ok(self)
570 }
571
572 #[inline]
577 pub fn set_num_symbols(&mut self, sym: NumberSymbols) {
578 self.sym = Some(sym);
579 }
580
581 fn dec_sep(&self) -> char {
582 if let Some(sym) = &self.sym {
583 sym.decimal_sep
584 } else {
585 '.'
586 }
587 }
588
589 fn grp_sep(&self) -> char {
590 if let Some(sym) = &self.sym {
591 sym.decimal_grp.unwrap_or(' ')
595 } else {
596 ','
597 }
598 }
599
600 fn neg_sym(&self) -> char {
601 if let Some(sym) = &self.sym {
602 sym.negative_sym
603 } else {
604 '-'
605 }
606 }
607
608 fn pos_sym(&self) -> char {
609 if let Some(sym) = &self.sym {
610 sym.positive_sym
611 } else {
612 ' '
613 }
614 }
615
616 #[inline]
647 pub fn set_mask<S: AsRef<str>>(&mut self, s: S) -> Result<(), fmt::Error> {
648 self.mask = Self::parse_mask(s.as_ref())?;
649 self.clear();
650 Ok(())
651 }
652
653 #[allow(clippy::needless_range_loop)]
654 fn parse_mask(mask_str: &str) -> Result<Vec<MaskToken>, fmt::Error> {
655 let mut out = Vec::<MaskToken>::new();
656
657 let mut start_sub = 0;
658 let mut start_sec = 0;
659 let mut sec_id = 0;
660 let mut last_mask = Mask::None;
661 let mut dec_dir = EditDirection::Rtol;
662 let mut esc = false;
663 let mut idx = 0;
664 for m in mask_str.graphemes(true).chain(once("")) {
665 let mask = if esc {
666 esc = false;
667 Mask::Separator(Box::from(m))
668 } else {
669 match m {
670 "0" => Mask::Digit0(dec_dir),
671 "9" => Mask::Digit(dec_dir),
672 "#" => Mask::Numeric(dec_dir),
673 "." => Mask::DecimalSep,
674 "," => Mask::GroupingSep,
675 "-" => Mask::Sign,
676 "+" => Mask::Plus,
677 "h" => Mask::Hex,
678 "H" => Mask::Hex0,
679 "o" => Mask::Oct,
680 "O" => Mask::Oct0,
681 "d" => Mask::Dec,
682 "D" => Mask::Dec0,
683 "l" => Mask::Letter,
684 "a" => Mask::LetterOrDigit,
685 "c" => Mask::LetterDigitSpace,
686 "_" => Mask::AnyChar,
687 "" => Mask::None,
688 " " => Mask::Separator(Box::from(m)),
689 "\\" => {
690 esc = true;
691 continue;
692 }
693 _ => return Err(fmt::Error),
694 }
695 };
696
697 match mask {
698 Mask::Digit0(_)
699 | Mask::Digit(_)
700 | Mask::Numeric(_)
701 | Mask::GroupingSep
702 | Mask::Sign
703 | Mask::Plus => {
704 }
706 Mask::DecimalSep => {
707 dec_dir = EditDirection::Ltor;
708 }
709 Mask::Hex0
710 | Mask::Hex
711 | Mask::Oct0
712 | Mask::Oct
713 | Mask::Dec0
714 | Mask::Dec
715 | Mask::Letter
716 | Mask::LetterOrDigit
717 | Mask::LetterDigitSpace
718 | Mask::AnyChar
719 | Mask::Separator(_) => {
720 dec_dir = EditDirection::Rtol
722 }
723 Mask::None => {
724 }
726 }
727
728 if matches!(mask, Mask::Separator(_)) || mask.section() != last_mask.section() {
729 for j in start_sec..idx {
730 out[j].sec_id = sec_id;
731 out[j].sec_start = start_sec as upos_type;
732 out[j].sec_end = idx as upos_type;
733 }
734 sec_id += 1;
735 start_sec = idx;
736 }
737 if matches!(mask, Mask::Separator(_)) || mask.sub_section() != last_mask.sub_section() {
738 for j in start_sub..idx {
739 out[j].sub_start = start_sub as upos_type;
740 out[j].sub_end = idx as upos_type;
741 }
742 start_sub = idx;
743 }
744
745 let tok = MaskToken {
746 sec_id: 0,
747 sec_start: 0,
748 sec_end: 0,
749 sub_start: 0,
750 sub_end: 0,
751 peek_left: last_mask,
752 right: mask.clone(),
753 edit: mask.edit_value().into(),
754 };
755 out.push(tok);
756
757 idx += 1;
758 last_mask = mask;
759 }
760 for j in start_sec..out.len() {
761 out[j].sec_id = sec_id;
762 out[j].sec_start = start_sec as upos_type;
763 out[j].sec_end = mask_str.graphemes(true).count() as upos_type;
764 }
765 for j in start_sub..out.len() {
766 out[j].sub_start = start_sub as upos_type;
767 out[j].sub_end = mask_str.graphemes(true).count() as upos_type;
768 }
769
770 Ok(out)
771 }
772
773 #[inline]
775 pub fn mask(&self) -> String {
776 use std::fmt::Write;
777
778 let mut buf = String::new();
779 for t in self.mask.iter() {
780 _ = write!(buf, "{}", t.right);
781 }
782 buf
783 }
784
785 #[inline]
787 pub fn set_invalid(&mut self, invalid: bool) {
788 self.invalid = invalid;
789 }
790
791 #[inline]
793 pub fn get_invalid(&self) -> bool {
794 self.invalid
795 }
796
797 #[inline]
801 pub fn set_overwrite(&mut self, overwrite: bool) {
802 self.overwrite = overwrite;
803 }
804
805 #[inline]
807 pub fn overwrite(&self) -> bool {
808 self.overwrite
809 }
810}
811
812impl MaskedInputState {
813 #[inline]
816 pub fn set_clipboard(&mut self, clip: Option<impl Clipboard + 'static>) {
817 self.value.set_clipboard(clip.map(|v| {
818 let r: Box<dyn Clipboard> = Box::new(v);
819 r
820 }));
821 }
822
823 #[inline]
826 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
827 self.value.clipboard()
828 }
829
830 #[inline]
832 pub fn copy_to_clip(&mut self) -> bool {
833 let Some(clip) = self.value.clipboard() else {
834 return false;
835 };
836
837 _ = clip.set_string(self.selected_text().as_ref());
838
839 true
840 }
841
842 #[inline]
844 pub fn cut_to_clip(&mut self) -> bool {
845 let Some(clip) = self.value.clipboard() else {
846 return false;
847 };
848
849 match clip.set_string(self.selected_text().as_ref()) {
850 Ok(_) => self.delete_range(self.selection()),
851 Err(_) => true,
852 }
853 }
854
855 #[inline]
857 pub fn paste_from_clip(&mut self) -> bool {
858 let Some(clip) = self.value.clipboard() else {
859 return false;
860 };
861
862 if let Ok(text) = clip.get_string() {
863 for c in text.chars() {
864 self.insert_char(c);
865 }
866 true
867 } else {
868 false
869 }
870 }
871}
872
873impl MaskedInputState {
874 #[inline]
876 pub fn set_undo_buffer(&mut self, undo: Option<impl UndoBuffer + 'static>) {
877 self.value.set_undo_buffer(undo.map(|v| {
878 let r: Box<dyn UndoBuffer> = Box::new(v);
879 r
880 }));
881 }
882
883 #[inline]
885 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
886 self.value.undo_buffer()
887 }
888
889 #[inline]
891 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
892 self.value.undo_buffer_mut()
893 }
894
895 #[inline]
897 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
898 self.value.recent_replay_log()
899 }
900
901 #[inline]
903 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
904 self.value.replay_log(replay)
905 }
906
907 #[inline]
909 pub fn begin_undo_seq(&mut self) {
910 self.value.begin_undo_seq();
911 }
912
913 #[inline]
915 pub fn end_undo_seq(&mut self) {
916 self.value.end_undo_seq();
917 }
918
919 #[inline]
921 pub fn undo(&mut self) -> bool {
922 self.value.undo()
923 }
924
925 #[inline]
927 pub fn redo(&mut self) -> bool {
928 self.value.redo()
929 }
930}
931
932impl MaskedInputState {
933 #[inline]
935 pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
936 self.value.set_styles(styles);
937 }
938
939 #[inline]
942 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
943 self.value.add_style(range, style);
944 }
945
946 #[inline]
949 pub fn add_range_style(
950 &mut self,
951 range: Range<upos_type>,
952 style: usize,
953 ) -> Result<(), TextError> {
954 let r = self
955 .value
956 .bytes_at_range(TextRange::from((range.start, 0)..(range.end, 0)))?;
957 self.value.add_style(r, style);
958 Ok(())
959 }
960
961 #[inline]
963 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
964 self.value.remove_style(range, style);
965 }
966
967 #[inline]
969 pub fn remove_range_style(
970 &mut self,
971 range: Range<upos_type>,
972 style: usize,
973 ) -> Result<(), TextError> {
974 let r = self
975 .value
976 .bytes_at_range(TextRange::from((range.start, 0)..(range.end, 0)))?;
977 self.value.remove_style(r, style);
978 Ok(())
979 }
980
981 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
983 self.value.styles_in(range, buf)
984 }
985
986 #[inline]
988 pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
989 self.value.styles_at(byte_pos, buf)
990 }
991
992 #[inline]
995 pub fn styles_at_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
996 self.value.styles_at_match(byte_pos, style)
997 }
998
999 #[inline]
1001 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
1002 self.value.styles()
1003 }
1004}
1005
1006impl MaskedInputState {
1007 #[inline]
1009 pub fn offset(&self) -> upos_type {
1010 self.offset
1011 }
1012
1013 #[inline]
1015 pub fn set_offset(&mut self, offset: upos_type) {
1016 self.scroll_to_cursor = false;
1017 self.offset = offset;
1018 }
1019
1020 #[inline]
1022 pub fn cursor(&self) -> upos_type {
1023 self.value.cursor().x
1024 }
1025
1026 #[inline]
1029 pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
1030 self.scroll_cursor_to_visible();
1031 self.value
1032 .set_cursor(TextPosition::new(cursor, 0), extend_selection)
1033 }
1034
1035 fn number_cursor(&self, range: Range<upos_type>) -> upos_type {
1037 for (i, t) in self.mask[range.start as usize..range.end as usize]
1038 .iter()
1039 .enumerate()
1040 .rev()
1041 {
1042 match t.right {
1043 Mask::Digit(EditDirection::Rtol)
1044 | Mask::Digit0(EditDirection::Rtol)
1045 | Mask::Numeric(EditDirection::Rtol) => {
1046 return range.start + i as upos_type + 1;
1047 }
1048 _ => {}
1049 }
1050 }
1051 range.start
1052 }
1053
1054 pub fn section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1057 if cursor as usize >= self.mask.len() {
1058 return None;
1059 }
1060
1061 let mask = &self.mask[cursor as usize];
1062
1063 if mask.right.is_number() {
1064 Some(self.number_cursor(mask.sec_start..mask.sec_end))
1065 } else if mask.right.is_separator() {
1066 None
1067 } else if mask.right.is_none() {
1068 None
1069 } else {
1070 Some(mask.sec_start)
1071 }
1072 }
1073
1074 pub fn next_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1076 if cursor as usize >= self.mask.len() {
1077 return None;
1078 }
1079
1080 let mut mask = &self.mask[cursor as usize];
1081 let mut next;
1082 loop {
1083 if mask.right.is_none() {
1084 return None;
1085 }
1086
1087 next = mask.sec_end;
1088 mask = &self.mask[next as usize];
1089
1090 if mask.right.is_number() {
1091 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
1092 } else if mask.right.is_separator() {
1093 continue;
1094 } else if mask.right.is_none() {
1095 return None;
1096 } else {
1097 return Some(mask.sec_start);
1098 }
1099 }
1100 }
1101
1102 pub fn prev_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1104 if cursor as usize >= self.mask.len() {
1105 return None;
1106 }
1107
1108 let mut prev = self.mask[cursor as usize].sec_start;
1109 let mut mask = &self.mask[prev as usize];
1110
1111 loop {
1112 if mask.peek_left.is_none() {
1113 return None;
1114 }
1115
1116 prev = self.mask[mask.sec_start as usize - 1].sec_start;
1117 mask = &self.mask[prev as usize];
1118
1119 if mask.right.is_number() {
1120 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
1121 } else if mask.right.is_separator() {
1122 continue;
1123 } else {
1124 return Some(mask.sec_start);
1125 }
1126 }
1127 }
1128
1129 pub fn is_section_boundary(&self, pos: upos_type) -> bool {
1131 if pos == 0 {
1132 return false;
1133 }
1134 if pos as usize >= self.mask.len() {
1135 return false;
1136 }
1137 let prev = &self.mask[pos as usize - 1];
1138 let mask = &self.mask[pos as usize];
1139 prev.sec_id != mask.sec_id
1140 }
1141
1142 pub fn section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1145 if cursor as usize >= self.mask.len() {
1146 return None;
1147 }
1148
1149 let mask = &self.mask[cursor as usize];
1150 if mask.right.is_number() {
1151 Some(mask.sec_start..mask.sec_end)
1152 } else if mask.right.is_separator() {
1153 None
1154 } else if mask.right.is_none() {
1155 None
1156 } else {
1157 Some(mask.sec_start..mask.sec_end)
1158 }
1159 }
1160
1161 pub fn next_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1163 if cursor as usize >= self.mask.len() {
1164 return None;
1165 }
1166
1167 let mut mask = &self.mask[cursor as usize];
1168 let mut next;
1169 loop {
1170 if mask.right.is_none() {
1171 return None;
1172 }
1173
1174 next = mask.sec_end;
1175 mask = &self.mask[next as usize];
1176
1177 if mask.right.is_number() {
1178 return Some(mask.sec_start..mask.sec_end);
1179 } else if mask.right.is_separator() {
1180 continue;
1181 } else if mask.right.is_none() {
1182 return None;
1183 } else {
1184 return Some(mask.sec_start..mask.sec_end);
1185 }
1186 }
1187 }
1188
1189 pub fn prev_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1191 if cursor as usize >= self.mask.len() {
1192 return None;
1193 }
1194
1195 let mut prev = self.mask[cursor as usize].sec_start;
1196 let mut mask = &self.mask[prev as usize];
1197 loop {
1198 if mask.peek_left.is_none() {
1199 return None;
1200 }
1201
1202 prev = self.mask[mask.sec_start as usize - 1].sec_start;
1203 mask = &self.mask[prev as usize];
1204
1205 if mask.right.is_number() {
1206 return Some(mask.sec_start..mask.sec_end);
1207 } else if mask.right.is_separator() {
1208 continue;
1209 } else {
1210 return Some(mask.sec_start..mask.sec_end);
1211 }
1212 }
1213 }
1214
1215 #[inline]
1219 pub fn set_default_cursor(&mut self) {
1220 self.scroll_cursor_to_visible();
1221 if let Some(pos) = self.section_cursor(0) {
1222 self.value.set_cursor(TextPosition::new(pos, 0), false);
1223 } else if let Some(pos) = self.next_section_cursor(0) {
1224 self.value.set_cursor(TextPosition::new(pos, 0), false);
1225 } else {
1226 self.value.set_cursor(TextPosition::new(0, 0), false);
1227 }
1228 }
1229
1230 #[inline]
1232 pub fn anchor(&self) -> upos_type {
1233 self.value.anchor().x
1234 }
1235
1236 #[inline]
1238 pub fn has_selection(&self) -> bool {
1239 self.value.has_selection()
1240 }
1241
1242 #[inline]
1244 pub fn selection(&self) -> Range<upos_type> {
1245 let mut v = self.value.selection();
1246 if v.start == TextPosition::new(0, 1) {
1247 v.start = TextPosition::new(self.line_width(), 0);
1248 }
1249 if v.end == TextPosition::new(0, 1) {
1250 v.end = TextPosition::new(self.line_width(), 0);
1251 }
1252 v.start.x..v.end.x
1253 }
1254
1255 #[inline]
1258 pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
1259 self.scroll_cursor_to_visible();
1260 self.value
1261 .set_selection(TextPosition::new(anchor, 0), TextPosition::new(cursor, 0))
1262 }
1263
1264 #[inline]
1267 pub fn select_all(&mut self) -> bool {
1268 self.scroll_cursor_to_visible();
1269 if let Some(section) = self.section_range(self.cursor()) {
1270 if self.selection() == section {
1271 self.value.select_all()
1272 } else {
1273 self.value.set_selection(
1274 TextPosition::new(section.start, 0),
1275 TextPosition::new(section.end, 0),
1276 )
1277 }
1278 } else {
1279 self.value.select_all()
1280 }
1281 }
1282
1283 #[inline]
1285 pub fn selected_text(&self) -> &str {
1286 match self
1287 .value
1288 .str_slice(self.value.selection())
1289 .expect("valid_range")
1290 {
1291 Cow::Borrowed(v) => v,
1292 Cow::Owned(_) => {
1293 unreachable!()
1294 }
1295 }
1296 }
1297}
1298
1299impl MaskedInputState {
1300 #[inline]
1302 pub fn is_empty(&self) -> bool {
1303 self.value.text().as_str() == self.default_value()
1304 }
1305
1306 #[inline]
1308 pub fn text(&self) -> &str {
1309 self.value.text().as_str()
1310 }
1311
1312 #[inline]
1314 pub fn str_slice_byte(&self, range: Range<usize>) -> Cow<'_, str> {
1315 self.value.str_slice_byte(range).expect("valid_range")
1316 }
1317
1318 #[inline]
1320 pub fn try_str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
1321 self.value.str_slice_byte(range)
1322 }
1323
1324 #[inline]
1326 pub fn str_slice(&self, range: Range<upos_type>) -> Cow<'_, str> {
1327 self.value
1328 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1329 .expect("valid_range")
1330 }
1331
1332 #[inline]
1334 pub fn try_str_slice(&self, range: Range<upos_type>) -> Result<Cow<'_, str>, TextError> {
1335 self.value
1336 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1337 }
1338
1339 #[inline]
1341 pub fn len(&self) -> upos_type {
1342 self.value.line_width(0).expect("valid_row")
1343 }
1344
1345 #[inline]
1347 pub fn len_bytes(&self) -> usize {
1348 self.value.len_bytes()
1349 }
1350
1351 #[inline]
1353 pub fn line_width(&self) -> upos_type {
1354 self.value.line_width(0).expect("valid_row")
1355 }
1356
1357 #[inline]
1359 pub fn grapheme_at(&self, pos: upos_type) -> Result<Option<Grapheme<'_>>, TextError> {
1360 self.value.grapheme_at(TextPosition::new(pos, 0))
1361 }
1362
1363 #[inline]
1365 pub fn text_graphemes(&self, pos: upos_type) -> <TextString as TextStore>::GraphemeIter<'_> {
1366 self.try_text_graphemes(pos).expect("valid_pos")
1367 }
1368
1369 #[inline]
1371 pub fn try_text_graphemes(
1372 &self,
1373 pos: upos_type,
1374 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1375 self.value.text_graphemes(TextPosition::new(pos, 0))
1376 }
1377
1378 #[inline]
1380 pub fn graphemes(
1381 &self,
1382 range: Range<upos_type>,
1383 pos: upos_type,
1384 ) -> <TextString as TextStore>::GraphemeIter<'_> {
1385 self.try_graphemes(range, pos).expect("valid_args")
1386 }
1387
1388 #[inline]
1390 pub fn try_graphemes(
1391 &self,
1392 range: Range<upos_type>,
1393 pos: upos_type,
1394 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1395 self.value.graphemes(
1396 TextRange::new((range.start, 0), (range.end, 0)),
1397 TextPosition::new(pos, 0),
1398 )
1399 }
1400
1401 #[inline]
1404 pub fn byte_at(&self, pos: upos_type) -> Range<usize> {
1405 self.try_byte_at(pos).expect("valid_pos")
1406 }
1407
1408 #[inline]
1411 pub fn try_byte_at(&self, pos: upos_type) -> Result<Range<usize>, TextError> {
1412 self.value.byte_at(TextPosition::new(pos, 0))
1413 }
1414
1415 #[inline]
1417 pub fn bytes_at_range(&self, range: Range<upos_type>) -> Range<usize> {
1418 self.try_bytes_at_range(range).expect("valid_range")
1419 }
1420
1421 #[inline]
1423 pub fn try_bytes_at_range(&self, range: Range<upos_type>) -> Result<Range<usize>, TextError> {
1424 self.value
1425 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1426 }
1427
1428 #[inline]
1431 pub fn byte_pos(&self, byte: usize) -> upos_type {
1432 self.try_byte_pos(byte).expect("valid_pos")
1433 }
1434
1435 #[inline]
1438 pub fn try_byte_pos(&self, byte: usize) -> Result<upos_type, TextError> {
1439 Ok(self.value.byte_pos(byte)?.x)
1440 }
1441
1442 #[inline]
1444 pub fn byte_range(&self, bytes: Range<usize>) -> Range<upos_type> {
1445 self.try_byte_range(bytes).expect("valid_range")
1446 }
1447
1448 #[inline]
1450 pub fn try_byte_range(&self, bytes: Range<usize>) -> Result<Range<upos_type>, TextError> {
1451 let r = self.value.byte_range(bytes)?;
1452 Ok(r.start.x..r.end.x)
1453 }
1454}
1455
1456impl MaskedInputState {
1457 #[inline]
1459 fn default_value(&self) -> String {
1460 MaskToken::empty_section(&self.mask)
1461 }
1462
1463 #[inline]
1465 pub fn clear(&mut self) -> bool {
1466 if self.is_empty() {
1467 false
1468 } else {
1469 self.offset = 0;
1470 self.value
1471 .set_text(TextString::new_string(self.default_value()));
1472 self.set_default_cursor();
1473 true
1474 }
1475 }
1476
1477 #[inline]
1483 pub fn set_text<S: Into<String>>(&mut self, s: S) {
1484 self.offset = 0;
1485 let mut text = s.into();
1486 while text.graphemes(true).count() > self.mask.len().saturating_sub(1) {
1487 text.pop();
1488 }
1489 while text.graphemes(true).count() < self.mask.len().saturating_sub(1) {
1490 text.push(' ');
1491 }
1492 let len = text.graphemes(true).count();
1493
1494 assert_eq!(len, self.mask.len().saturating_sub(1));
1495
1496 self.value.set_text(TextString::new_string(text));
1497 self.set_default_cursor();
1498 }
1499
1500 #[inline]
1502 pub fn insert_char(&mut self, c: char) -> bool {
1503 self.begin_undo_seq();
1504 if self.has_selection() {
1505 let sel = self.selection();
1506 mask_op::remove_range(self, sel.clone()).expect("valid_selection");
1507 self.set_cursor(sel.start, false);
1508 }
1509 let c0 = mask_op::advance_cursor(self, c);
1510 let c1 = mask_op::insert_char(self, c);
1511 self.end_undo_seq();
1512
1513 self.scroll_cursor_to_visible();
1514 c0 || c1
1515 }
1516
1517 #[inline]
1520 pub fn delete_range(&mut self, range: Range<upos_type>) -> bool {
1521 self.try_delete_range(range).expect("valid_range")
1522 }
1523
1524 #[inline]
1527 pub fn try_delete_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
1528 self.value.begin_undo_seq();
1529 let r = mask_op::remove_range(self, range.clone())?;
1530 if let Some(pos) = self.section_cursor(range.start) {
1531 self.set_cursor(pos, false);
1532 }
1533 self.value.end_undo_seq();
1534
1535 self.scroll_cursor_to_visible();
1536 Ok(r)
1537 }
1538}
1539
1540impl MaskedInputState {
1541 #[inline]
1543 pub fn delete_next_char(&mut self) -> bool {
1544 if self.has_selection() {
1545 self.delete_range(self.selection())
1546 } else if self.cursor() == self.len() {
1547 false
1548 } else {
1549 mask_op::remove_next(self);
1550 self.scroll_cursor_to_visible();
1551 true
1552 }
1553 }
1554
1555 #[inline]
1557 pub fn delete_prev_char(&mut self) -> bool {
1558 if self.has_selection() {
1559 self.delete_range(self.selection())
1560 } else if self.cursor() == 0 {
1561 false
1562 } else {
1563 mask_op::remove_prev(self);
1564 self.scroll_cursor_to_visible();
1565 true
1566 }
1567 }
1568
1569 #[inline]
1571 pub fn delete_prev_section(&mut self) -> bool {
1572 if self.has_selection() {
1573 self.delete_range(self.selection())
1574 } else {
1575 if let Some(range) = self.prev_section_range(self.cursor()) {
1576 self.delete_range(range)
1577 } else {
1578 false
1579 }
1580 }
1581 }
1582
1583 #[inline]
1585 pub fn delete_next_section(&mut self) -> bool {
1586 if self.has_selection() {
1587 self.delete_range(self.selection())
1588 } else {
1589 if let Some(range) = self.next_section_range(self.cursor()) {
1590 self.delete_range(range)
1591 } else {
1592 false
1593 }
1594 }
1595 }
1596
1597 #[inline]
1599 pub fn move_right(&mut self, extend_selection: bool) -> bool {
1600 let c = min(self.cursor() + 1, self.len());
1601 self.set_cursor(c, extend_selection)
1602 }
1603
1604 #[inline]
1606 pub fn move_left(&mut self, extend_selection: bool) -> bool {
1607 let c = self.cursor().saturating_sub(1);
1608 self.set_cursor(c, extend_selection)
1609 }
1610
1611 #[inline]
1613 pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1614 if let Some(c) = self.section_cursor(self.cursor()) {
1615 if c != self.cursor() {
1616 self.set_cursor(c, extend_selection)
1617 } else {
1618 self.set_cursor(0, extend_selection)
1619 }
1620 } else {
1621 self.set_cursor(0, extend_selection)
1622 }
1623 }
1624
1625 #[inline]
1627 pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
1628 self.set_cursor(self.len(), extend_selection)
1629 }
1630
1631 #[inline]
1633 pub fn move_to_prev_section(&mut self, extend_selection: bool) -> bool {
1634 if let Some(curr) = self.section_range(self.cursor()) {
1635 if self.cursor() != curr.start {
1636 return self.set_cursor(curr.start, extend_selection);
1637 }
1638 }
1639 if let Some(range) = self.prev_section_range(self.cursor()) {
1640 self.set_cursor(range.start, extend_selection)
1641 } else {
1642 false
1643 }
1644 }
1645
1646 #[inline]
1648 pub fn move_to_next_section(&mut self, extend_selection: bool) -> bool {
1649 if let Some(curr) = self.section_range(self.cursor()) {
1650 if self.cursor() != curr.end {
1651 return self.set_cursor(curr.end, extend_selection);
1652 }
1653 }
1654 if let Some(range) = self.next_section_range(self.cursor()) {
1655 self.set_cursor(range.end, extend_selection)
1656 } else {
1657 false
1658 }
1659 }
1660
1661 #[inline]
1663 pub fn select_current_section(&mut self) -> bool {
1664 let selection = self.selection();
1665
1666 if let Some(next) = self.section_range(selection.start.saturating_sub(1)) {
1667 if !next.is_empty() {
1668 self.set_selection(next.start, next.end)
1669 } else {
1670 false
1671 }
1672 } else {
1673 false
1674 }
1675 }
1676
1677 #[inline]
1679 pub fn select_next_section(&mut self) -> bool {
1680 let selection = self.selection();
1681
1682 if let Some(next) = self.next_section_range(selection.start) {
1683 if !next.is_empty() {
1684 self.set_selection(next.start, next.end)
1685 } else {
1686 false
1687 }
1688 } else {
1689 false
1690 }
1691 }
1692
1693 #[inline]
1695 pub fn select_prev_section(&mut self) -> bool {
1696 let selection = self.selection();
1697
1698 if let Some(next) = self.prev_section_range(selection.start.saturating_sub(1)) {
1699 if !next.is_empty() {
1700 self.set_selection(next.start, next.end)
1701 } else {
1702 false
1703 }
1704 } else {
1705 false
1706 }
1707 }
1708}
1709
1710impl HasScreenCursor for MaskedInputState {
1711 #[inline]
1713 fn screen_cursor(&self) -> Option<(u16, u16)> {
1714 if self.is_focused() {
1715 if self.has_selection() {
1716 None
1717 } else {
1718 let cx = self.cursor();
1719 let ox = self.offset();
1720
1721 if cx < ox {
1722 None
1723 } else if cx > ox + (self.inner.width + self.dark_offset.0) as upos_type {
1724 None
1725 } else {
1726 self.col_to_screen(cx)
1727 .map(|sc| (self.inner.x + sc, self.inner.y))
1728 }
1729 }
1730 } else {
1731 None
1732 }
1733 }
1734}
1735
1736impl RelocatableState for MaskedInputState {
1737 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
1738 self.dark_offset = relocate_dark_offset(self.inner, shift, clip);
1740 self.area = relocate_area(self.area, shift, clip);
1741 self.inner = relocate_area(self.inner, shift, clip);
1742 }
1743}
1744
1745impl MaskedInputState {
1746 fn glyphs2(&self) -> impl Iterator<Item = Glyph2<'_>> {
1747 let left_margin = self.offset();
1748 let right_margin = self.offset() + self.rendered.width as upos_type;
1749 let compact = self.compact && !self.is_focused();
1750
1751 let grapheme_iter = self
1752 .value
1753 .graphemes(TextRange::new((0, 0), (0, 1)), TextPosition::new(0, 0))
1754 .expect("valid-rows");
1755 let mask_iter = self.mask.iter();
1756
1757 let iter = MaskedGraphemes {
1758 iter_str: grapheme_iter,
1759 iter_mask: mask_iter,
1760 compact,
1761 sym_neg: self.neg_sym().to_string(),
1762 sym_dec: self.dec_sep().to_string(),
1763 sym_grp: self.grp_sep().to_string(),
1764 sym_pos: self.pos_sym().to_string(),
1765 byte_pos: 0,
1766 };
1767
1768 let mut it = GlyphIter2::new(TextPosition::new(0, 0), 0, iter, Default::default());
1769 it.set_tabs(0 );
1770 it.set_show_ctrl(self.value.glyph_ctrl());
1771 it.set_lf_breaks(false);
1772 it.set_text_wrap(TextWrap2::Shift);
1773 it.set_left_margin(left_margin);
1774 it.set_right_margin(right_margin);
1775 it.set_word_margin(right_margin);
1776 it.prepare().expect("valid-rows");
1777
1778 Box::new(it)
1779 }
1780
1781 pub fn screen_to_col(&self, scx: i16) -> upos_type {
1784 let ox = self.offset();
1785
1786 let scx = scx + self.dark_offset.0 as i16;
1787
1788 if scx < 0 {
1789 ox.saturating_sub((scx as ipos_type).unsigned_abs())
1790 } else if scx as u16 >= (self.inner.width + self.dark_offset.0) {
1791 min(ox + scx as upos_type, self.len())
1792 } else {
1793 let scx = scx as u16;
1794
1795 let line = self.glyphs2();
1796
1797 let mut col = ox;
1798 for g in line {
1799 if g.contains_screen_x(scx) {
1800 break;
1801 }
1802 col = g.pos().x + 1;
1803 }
1804 col
1805 }
1806 }
1807
1808 pub fn col_to_screen(&self, pos: upos_type) -> Option<u16> {
1811 let ox = self.offset();
1812
1813 if pos < ox {
1814 return None;
1815 }
1816
1817 let line = self.glyphs2();
1818 let mut screen_x = 0;
1819 for g in line {
1820 if g.pos().x == pos {
1821 break;
1822 }
1823 screen_x = g.screen_pos().0 + g.screen_width();
1824 }
1825
1826 if screen_x >= self.dark_offset.0 {
1827 Some(screen_x - self.dark_offset.0)
1828 } else {
1829 None
1830 }
1831 }
1832
1833 #[inline]
1837 pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
1838 let scx = cursor;
1839
1840 let cx = self.screen_to_col(scx);
1841
1842 self.set_cursor(cx, extend_selection)
1843 }
1844
1845 pub fn set_screen_cursor_sections(
1852 &mut self,
1853 screen_cursor: i16,
1854 extend_selection: bool,
1855 ) -> bool {
1856 let anchor = self.anchor();
1857 let cursor = self.screen_to_col(screen_cursor);
1858
1859 let Some(range) = self.section_range(cursor) else {
1860 return false;
1861 };
1862
1863 let cursor = if cursor < anchor {
1864 range.start
1865 } else {
1866 range.end
1867 };
1868
1869 if !self.is_section_boundary(anchor) {
1871 if let Some(range) = self.section_range(anchor) {
1872 if cursor < anchor {
1873 self.set_cursor(range.end, false);
1874 } else {
1875 self.set_cursor(range.start, false);
1876 }
1877 };
1878 }
1879
1880 self.set_cursor(cursor, extend_selection)
1881 }
1882
1883 pub fn scroll_left(&mut self, delta: upos_type) -> bool {
1885 self.set_offset(self.offset.saturating_sub(delta));
1886 true
1887 }
1888
1889 pub fn scroll_right(&mut self, delta: upos_type) -> bool {
1891 self.set_offset(self.offset + delta);
1892 true
1893 }
1894
1895 pub fn scroll_cursor_to_visible(&mut self) {
1897 self.scroll_to_cursor = true;
1898 }
1899}
1900
1901impl HandleEvent<crossterm::event::Event, Regular, TextOutcome> for MaskedInputState {
1902 fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> TextOutcome {
1903 fn tc(r: bool) -> TextOutcome {
1905 if r {
1906 TextOutcome::TextChanged
1907 } else {
1908 TextOutcome::Unchanged
1909 }
1910 }
1911 fn overwrite(state: &mut MaskedInputState) {
1912 if state.overwrite {
1913 state.overwrite = false;
1914 state.clear();
1915 }
1916 }
1917 fn clear_overwrite(state: &mut MaskedInputState) {
1918 state.overwrite = false;
1919 }
1920
1921 if self.lost_focus() {
1923 match self.on_focus_lost {
1924 TextFocusLost::None => {}
1925 TextFocusLost::Position0 => {
1926 self.set_default_cursor();
1927 self.scroll_cursor_to_visible();
1928 }
1930 }
1931 }
1932 if self.gained_focus() {
1933 match self.on_focus_gained {
1934 TextFocusGained::None => {}
1935 TextFocusGained::Overwrite => {
1936 self.overwrite = true;
1937 }
1938 TextFocusGained::SelectAll => {
1939 self.select_all();
1940 }
1942 }
1943 }
1944
1945 let mut r = if self.is_focused() {
1946 match event {
1947 ct_event!(key press c)
1948 | ct_event!(key press SHIFT-c)
1949 | ct_event!(key press CONTROL_ALT-c) => {
1950 overwrite(self);
1951 tc(self.insert_char(*c))
1952 }
1953 ct_event!(keycode press Backspace) => {
1954 clear_overwrite(self);
1955 tc(self.delete_prev_char())
1956 }
1957 ct_event!(keycode press Delete) => {
1958 clear_overwrite(self);
1959 tc(self.delete_next_char())
1960 }
1961 ct_event!(keycode press CONTROL-Backspace)
1962 | ct_event!(keycode press ALT-Backspace) => {
1963 clear_overwrite(self);
1964 tc(self.delete_prev_section())
1965 }
1966 ct_event!(keycode press CONTROL-Delete) => {
1967 clear_overwrite(self);
1968 tc(self.delete_next_section())
1969 }
1970 ct_event!(key press CONTROL-'x') => {
1971 clear_overwrite(self);
1972 tc(self.cut_to_clip())
1973 }
1974 ct_event!(key press CONTROL-'v') => {
1975 clear_overwrite(self);
1976 tc(self.paste_from_clip())
1977 }
1978 ct_event!(key press CONTROL-'d') => {
1979 clear_overwrite(self);
1980 tc(self.clear())
1981 }
1982 ct_event!(key press CONTROL-'z') => {
1983 clear_overwrite(self);
1984 tc(self.undo())
1985 }
1986 ct_event!(key press CONTROL_SHIFT-'Z') => {
1987 clear_overwrite(self);
1988 tc(self.redo())
1989 }
1990
1991 ct_event!(key release _)
1992 | ct_event!(key release SHIFT-_)
1993 | ct_event!(key release CONTROL_ALT-_)
1994 | ct_event!(keycode release Backspace)
1995 | ct_event!(keycode release Delete)
1996 | ct_event!(keycode release CONTROL-Backspace)
1997 | ct_event!(keycode release ALT-Backspace)
1998 | ct_event!(keycode release CONTROL-Delete)
1999 | ct_event!(key release CONTROL-'x')
2000 | ct_event!(key release CONTROL-'v')
2001 | ct_event!(key release CONTROL-'d')
2002 | ct_event!(key release CONTROL-'z')
2003 | ct_event!(key release CONTROL_SHIFT-'Z') => TextOutcome::Unchanged,
2004
2005 _ => TextOutcome::Continue,
2006 }
2007 } else {
2008 TextOutcome::Continue
2009 };
2010
2011 if r == TextOutcome::Continue {
2012 r = self.handle(event, ReadOnly);
2013 }
2014 r
2015 }
2016}
2017
2018impl HandleEvent<crossterm::event::Event, ReadOnly, TextOutcome> for MaskedInputState {
2019 fn handle(&mut self, event: &crossterm::event::Event, _keymap: ReadOnly) -> TextOutcome {
2020 fn clear_overwrite(state: &mut MaskedInputState) {
2021 state.overwrite = false;
2022 }
2023
2024 let mut r = if self.is_focused() {
2025 match event {
2026 ct_event!(keycode press Left) => {
2027 clear_overwrite(self);
2028 self.move_left(false).into()
2029 }
2030 ct_event!(keycode press Right) => {
2031 clear_overwrite(self);
2032 self.move_right(false).into()
2033 }
2034 ct_event!(keycode press CONTROL-Left) => {
2035 clear_overwrite(self);
2036 self.move_to_prev_section(false).into()
2037 }
2038 ct_event!(keycode press CONTROL-Right) => {
2039 clear_overwrite(self);
2040 self.move_to_next_section(false).into()
2041 }
2042 ct_event!(keycode press Home) => {
2043 clear_overwrite(self);
2044 self.move_to_line_start(false).into()
2045 }
2046 ct_event!(keycode press End) => {
2047 clear_overwrite(self);
2048 self.move_to_line_end(false).into()
2049 }
2050 ct_event!(keycode press SHIFT-Left) => {
2051 clear_overwrite(self);
2052 self.move_left(true).into()
2053 }
2054 ct_event!(keycode press SHIFT-Right) => {
2055 clear_overwrite(self);
2056 self.move_right(true).into()
2057 }
2058 ct_event!(keycode press CONTROL_SHIFT-Left) => {
2059 clear_overwrite(self);
2060 self.move_to_prev_section(true).into()
2061 }
2062 ct_event!(keycode press CONTROL_SHIFT-Right) => {
2063 clear_overwrite(self);
2064 self.move_to_next_section(true).into()
2065 }
2066 ct_event!(keycode press SHIFT-Home) => {
2067 clear_overwrite(self);
2068 self.move_to_line_start(true).into()
2069 }
2070 ct_event!(keycode press SHIFT-End) => {
2071 clear_overwrite(self);
2072 self.move_to_line_end(true).into()
2073 }
2074 ct_event!(keycode press Tab) => {
2075 if !self.focus.gained() {
2077 clear_overwrite(self);
2078 self.select_next_section().into()
2079 } else {
2080 TextOutcome::Unchanged
2081 }
2082 }
2083 ct_event!(keycode press SHIFT-BackTab) => {
2084 if !self.focus.gained() {
2086 clear_overwrite(self);
2087 self.select_prev_section().into()
2088 } else {
2089 TextOutcome::Unchanged
2090 }
2091 }
2092 ct_event!(key press CONTROL-'a') => {
2093 clear_overwrite(self);
2094 self.select_all().into()
2095 }
2096 ct_event!(key press CONTROL-'c') => {
2097 clear_overwrite(self);
2098 self.copy_to_clip().into()
2099 }
2100
2101 ct_event!(keycode release Left)
2102 | ct_event!(keycode release Right)
2103 | ct_event!(keycode release CONTROL-Left)
2104 | ct_event!(keycode release CONTROL-Right)
2105 | ct_event!(keycode release Home)
2106 | ct_event!(keycode release End)
2107 | ct_event!(keycode release SHIFT-Left)
2108 | ct_event!(keycode release SHIFT-Right)
2109 | ct_event!(keycode release CONTROL_SHIFT-Left)
2110 | ct_event!(keycode release CONTROL_SHIFT-Right)
2111 | ct_event!(keycode release SHIFT-Home)
2112 | ct_event!(keycode release SHIFT-End)
2113 | ct_event!(key release CONTROL-'a')
2114 | ct_event!(key release CONTROL-'c') => TextOutcome::Unchanged,
2115
2116 _ => TextOutcome::Continue,
2117 }
2118 } else {
2119 TextOutcome::Continue
2120 };
2121
2122 if r == TextOutcome::Continue {
2123 r = self.handle(event, MouseOnly);
2124 }
2125 r
2126 }
2127}
2128
2129impl HandleEvent<crossterm::event::Event, MouseOnly, TextOutcome> for MaskedInputState {
2130 fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> TextOutcome {
2131 fn clear_overwrite(state: &mut MaskedInputState) {
2132 state.overwrite = false;
2133 }
2134
2135 match event {
2136 ct_event!(mouse any for m) if self.mouse.drag(self.inner, m) => {
2137 let c = (m.column as i16) - (self.inner.x as i16);
2138 clear_overwrite(self);
2139 self.set_screen_cursor(c, true).into()
2140 }
2141 ct_event!(mouse any for m) if self.mouse.drag2(self.inner, m, KeyModifiers::ALT) => {
2142 let cx = m.column as i16 - self.inner.x as i16;
2143 clear_overwrite(self);
2144 self.set_screen_cursor_sections(cx, true).into()
2145 }
2146 ct_event!(mouse any for m) if self.mouse.doubleclick(self.inner, m) => {
2147 let tx = self.screen_to_col(m.column as i16 - self.inner.x as i16);
2148 clear_overwrite(self);
2149 if let Some(range) = self.section_range(tx) {
2150 self.set_selection(range.start, range.end).into()
2151 } else {
2152 TextOutcome::Unchanged
2153 }
2154 }
2155 ct_event!(mouse down Left for column,row) => {
2156 if self.gained_focus() {
2157 TextOutcome::Unchanged
2160 } else if self.inner.contains((*column, *row).into()) {
2161 let c = (column - self.inner.x) as i16;
2162 clear_overwrite(self);
2163 self.set_screen_cursor(c, false).into()
2164 } else {
2165 TextOutcome::Continue
2166 }
2167 }
2168 ct_event!(mouse down CONTROL-Left for column,row) => {
2169 if self.inner.contains((*column, *row).into()) {
2170 let cx = (column - self.inner.x) as i16;
2171 clear_overwrite(self);
2172 self.set_screen_cursor(cx, true).into()
2173 } else {
2174 TextOutcome::Continue
2175 }
2176 }
2177 ct_event!(mouse down ALT-Left for column,row) => {
2178 if self.inner.contains((*column, *row).into()) {
2179 let cx = (column - self.inner.x) as i16;
2180 clear_overwrite(self);
2181 self.set_screen_cursor_sections(cx, true).into()
2182 } else {
2183 TextOutcome::Continue
2184 }
2185 }
2186 _ => TextOutcome::Continue,
2187 }
2188 }
2189}
2190
2191pub fn handle_events(
2195 state: &mut MaskedInputState,
2196 focus: bool,
2197 event: &crossterm::event::Event,
2198) -> TextOutcome {
2199 state.focus.set(focus);
2200 state.handle(event, Regular)
2201}
2202
2203pub fn handle_readonly_events(
2207 state: &mut TextInputState,
2208 focus: bool,
2209 event: &crossterm::event::Event,
2210) -> TextOutcome {
2211 state.focus.set(focus);
2212 state.handle(event, ReadOnly)
2213}
2214
2215pub fn handle_mouse_events(
2217 state: &mut MaskedInputState,
2218 event: &crossterm::event::Event,
2219) -> TextOutcome {
2220 state.handle(event, MouseOnly)
2221}