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::cell::Cell;
103use std::cmp::min;
104use std::collections::HashMap;
105use std::fmt;
106use std::iter::once;
107use std::ops::Range;
108use std::rc::Rc;
109use std::str::FromStr;
110use unicode_segmentation::UnicodeSegmentation;
111
112#[derive(Debug, Default, Clone)]
118pub struct MaskedInput<'a> {
119 compact: bool,
120 block: Option<Block<'a>>,
121 style: Style,
122 focus_style: Option<Style>,
123 select_style: Option<Style>,
124 invalid_style: Option<Style>,
125 text_style: HashMap<usize, Style>,
126 on_focus_gained: TextFocusGained,
127 on_focus_lost: TextFocusLost,
128}
129
130#[derive(Debug)]
132pub struct MaskedInputState {
133 pub area: Rect,
136 pub inner: Rect,
139 pub rendered: Size,
142 pub compact: bool,
145
146 pub offset: upos_type,
149 pub dark_offset: (u16, u16),
152 pub scroll_to_cursor: Rc<Cell<bool>>,
154
155 pub value: TextCore<TextString>,
157 pub sym: Option<NumberSymbols>,
160 pub mask: Vec<MaskToken>,
163
164 pub invalid: bool,
167 pub overwrite: Rc<Cell<bool>>,
171 pub on_focus_gained: Rc<Cell<TextFocusGained>>,
174 pub on_focus_lost: Rc<Cell<TextFocusLost>>,
177
178 pub focus: FocusFlag,
181
182 pub mouse: MouseFlags,
185
186 pub non_exhaustive: NonExhaustive,
188}
189
190impl<'a> MaskedInput<'a> {
191 pub fn new() -> Self {
193 Self::default()
194 }
195
196 #[inline]
199 pub fn compact(mut self, show_compact: bool) -> Self {
200 self.compact = show_compact;
201 self
202 }
203
204 #[inline]
206 pub fn styles_opt(self, styles: Option<TextStyle>) -> Self {
207 if let Some(styles) = styles {
208 self.styles(styles)
209 } else {
210 self
211 }
212 }
213
214 #[inline]
216 pub fn styles(mut self, styles: TextStyle) -> Self {
217 self.style = styles.style;
218 if styles.focus.is_some() {
219 self.focus_style = styles.focus;
220 }
221 if styles.select.is_some() {
222 self.select_style = styles.select;
223 }
224 if styles.invalid.is_some() {
225 self.invalid_style = styles.invalid;
226 }
227 if let Some(of) = styles.on_focus_gained {
228 self.on_focus_gained = of;
229 }
230 if let Some(of) = styles.on_focus_lost {
231 self.on_focus_lost = of;
232 }
233 self.block = self.block.map(|v| v.style(self.style));
234 if let Some(border_style) = styles.border_style {
235 self.block = self.block.map(|v| v.border_style(border_style));
236 }
237 if styles.block.is_some() {
238 self.block = styles.block;
239 }
240 self
241 }
242
243 #[inline]
245 pub fn style(mut self, style: impl Into<Style>) -> Self {
246 self.style = style.into();
247 self.block = self.block.map(|v| v.style(self.style));
248 self
249 }
250
251 #[inline]
253 pub fn focus_style(mut self, style: impl Into<Style>) -> Self {
254 self.focus_style = Some(style.into());
255 self
256 }
257
258 #[inline]
260 pub fn select_style(mut self, style: impl Into<Style>) -> Self {
261 self.select_style = Some(style.into());
262 self
263 }
264
265 #[inline]
268 pub fn invalid_style(mut self, style: impl Into<Style>) -> Self {
269 self.invalid_style = Some(style.into());
270 self
271 }
272
273 pub fn text_style_idx(mut self, idx: usize, style: Style) -> Self {
278 self.text_style.insert(idx, style);
279 self
280 }
281
282 pub fn text_style<T: IntoIterator<Item = Style>>(mut self, styles: T) -> Self {
287 for (i, s) in styles.into_iter().enumerate() {
288 self.text_style.insert(i, s);
289 }
290 self
291 }
292
293 pub fn text_style_map<T: Into<Style>>(mut self, styles: HashMap<usize, T>) -> Self {
298 for (i, s) in styles.into_iter() {
299 self.text_style.insert(i, s.into());
300 }
301 self
302 }
303
304 #[inline]
306 pub fn block(mut self, block: Block<'a>) -> Self {
307 self.block = Some(block);
308 self.block = self.block.map(|v| v.style(self.style));
309 self
310 }
311
312 #[inline]
314 pub fn on_focus_gained(mut self, of: TextFocusGained) -> Self {
315 self.on_focus_gained = of;
316 self
317 }
318
319 #[inline]
321 pub fn on_focus_lost(mut self, of: TextFocusLost) -> Self {
322 self.on_focus_lost = of;
323 self
324 }
325}
326
327impl<'a> StatefulWidget for &MaskedInput<'a> {
328 type State = MaskedInputState;
329
330 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
331 render_ref(self, area, buf, state);
332 }
333}
334
335impl StatefulWidget for MaskedInput<'_> {
336 type State = MaskedInputState;
337
338 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
339 render_ref(&self, area, buf, state);
340 }
341}
342
343fn render_ref(
344 widget: &MaskedInput<'_>,
345 area: Rect,
346
347 buf: &mut Buffer,
348 state: &mut MaskedInputState,
349) {
350 state.area = area;
351 state.inner = widget.block.inner_if_some(area);
352 state.rendered = state.inner.as_size();
353 state.compact = widget.compact;
354 state.on_focus_gained.set(widget.on_focus_gained);
355 state.on_focus_lost.set(widget.on_focus_lost);
356
357 if state.scroll_to_cursor.get() {
358 let c = state.cursor();
359 let o = state.offset();
360 let mut no = if c < o {
361 c
362 } else if c >= o + state.rendered.width as upos_type {
363 c.saturating_sub(state.rendered.width as upos_type)
364 } else {
365 o
366 };
367 if c == no + state.rendered.width as upos_type {
370 no = no.saturating_add(1);
371 }
372 state.set_offset(no);
373 }
374
375 let style = widget.style;
376 let focus_style = if let Some(focus_style) = widget.focus_style {
377 focus_style
378 } else {
379 style
380 };
381 let select_style = if let Some(select_style) = widget.select_style {
382 select_style
383 } else {
384 Style::default().black().on_yellow()
385 };
386 let invalid_style = if let Some(invalid_style) = widget.invalid_style {
387 invalid_style
388 } else {
389 Style::default().red()
390 };
391
392 let (style, select_style) = if state.focus.get() {
393 if state.invalid {
394 (
395 style.patch(focus_style).patch(invalid_style),
396 style
397 .patch(focus_style)
398 .patch(select_style)
399 .patch(invalid_style),
400 )
401 } else {
402 (
403 style.patch(focus_style),
404 style.patch(focus_style).patch(select_style),
405 )
406 }
407 } else {
408 if state.invalid {
409 (
410 style.patch(invalid_style),
411 style.patch(select_style).patch(invalid_style),
412 )
413 } else {
414 (style, style.patch(select_style))
415 }
416 };
417
418 if let Some(block) = &widget.block {
420 block.render(area, buf);
421 } else {
422 buf.set_style(area, style);
423 }
424
425 if state.inner.width == 0 || state.inner.height == 0 {
426 return;
428 }
429
430 let ox = state.offset() as u16;
431 let show_range = {
433 let start = ox as upos_type;
434 let end = min(start + state.inner.width as upos_type, state.len());
435 state.bytes_at_range(start..end)
436 };
437 let selection = state.selection();
438 let mut styles = Vec::new();
439
440 for g in state.glyphs2() {
441 if g.screen_width() > 0 {
442 let mut style = style;
443 styles.clear();
444 state
445 .value
446 .styles_at_page(g.text_bytes().start, show_range.clone(), &mut styles);
447 for style_nr in &styles {
448 if let Some(s) = widget.text_style.get(style_nr) {
449 style = style.patch(*s);
450 }
451 }
452 if selection.contains(&g.pos().x) {
454 style = style.patch(select_style);
455 };
456
457 let screen_pos = g.screen_pos();
459
460 if let Some(cell) =
462 buf.cell_mut((state.inner.x + screen_pos.0, state.inner.y + screen_pos.1))
463 {
464 cell.set_symbol(g.glyph());
465 cell.set_style(style);
466 }
467 for d in 1..g.screen_width() {
469 if let Some(cell) = buf.cell_mut((
470 state.inner.x + screen_pos.0 + d,
471 state.inner.y + screen_pos.1,
472 )) {
473 cell.reset();
474 cell.set_style(style);
475 }
476 }
477 }
478 }
479}
480
481impl Clone for MaskedInputState {
482 fn clone(&self) -> Self {
483 Self {
484 area: self.area,
485 inner: self.inner,
486 rendered: self.rendered,
487 compact: self.compact,
488 offset: self.offset,
489 dark_offset: self.dark_offset,
490 scroll_to_cursor: Rc::new(Cell::new(self.scroll_to_cursor.get())),
491 value: self.value.clone(),
492 sym: self.sym,
493 mask: self.mask.clone(),
494 invalid: self.invalid,
495 overwrite: Rc::new(Cell::new(self.overwrite.get())),
496 on_focus_gained: Rc::new(Cell::new(self.on_focus_gained.get())),
497 on_focus_lost: Rc::new(Cell::new(self.on_focus_lost.get())),
498 focus: self.focus_cb(FocusFlag::named(self.focus.name())),
499 mouse: Default::default(),
500 non_exhaustive: NonExhaustive,
501 }
502 }
503}
504
505impl Default for MaskedInputState {
506 fn default() -> Self {
507 let core = TextCore::new(
508 Some(Box::new(UndoVec::new(99))),
509 Some(Box::new(global_clipboard())),
510 );
511
512 let mut z = Self {
513 area: Default::default(),
514 inner: Default::default(),
515 rendered: Default::default(),
516 compact: Default::default(),
517 offset: Default::default(),
518 dark_offset: Default::default(),
519 scroll_to_cursor: Default::default(),
520 value: core,
521 sym: None,
522 mask: Default::default(),
523 invalid: Default::default(),
524 overwrite: Default::default(),
525 on_focus_gained: Default::default(),
526 on_focus_lost: Default::default(),
527 focus: Default::default(),
528 mouse: Default::default(),
529 non_exhaustive: NonExhaustive,
530 };
531 z.focus = z.focus_cb(FocusFlag::default());
532 z
533 }
534}
535
536impl MaskedInputState {
537 fn focus_cb(&self, flag: FocusFlag) -> FocusFlag {
538 let on_focus_lost = self.on_focus_lost.clone();
539 let cursor = self.value.shared_cursor();
540 let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
541 flag.on_lost(move || match on_focus_lost.get() {
542 TextFocusLost::None => {}
543 TextFocusLost::Position0 => {
544 scroll_cursor_to_visible.set(true);
545 let mut new_cursor = cursor.get();
546 new_cursor.cursor.x = 0;
547 new_cursor.anchor.x = 0;
548 cursor.set(new_cursor);
549 }
550 });
551 let on_focus_gained = self.on_focus_gained.clone();
552 let overwrite = self.overwrite.clone();
553 let cursor = self.value.shared_cursor();
554 let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
555 flag.on_gained(move || match on_focus_gained.get() {
556 TextFocusGained::None => {}
557 TextFocusGained::Overwrite => {
558 overwrite.set(true);
559 }
560 TextFocusGained::SelectAll => {
561 scroll_cursor_to_visible.set(true);
562 let mut new_cursor = cursor.get();
563 new_cursor.anchor = TextPosition::new(0, 0);
564 new_cursor.cursor = TextPosition::new(0, 1);
565 cursor.set(new_cursor);
566 }
567 });
568
569 flag
570 }
571}
572
573impl HasFocus for MaskedInputState {
574 fn build(&self, builder: &mut FocusBuilder) {
575 builder.leaf_widget(self);
576 }
577
578 fn focus(&self) -> FocusFlag {
579 self.focus.clone()
580 }
581
582 fn area(&self) -> Rect {
583 self.area
584 }
585
586 fn navigable(&self) -> Navigation {
587 let sel = self.selection();
588
589 let has_next = self
590 .next_section_range(sel.end)
591 .map(|v| !v.is_empty())
592 .is_some();
593 let has_prev = self
594 .prev_section_range(sel.start.saturating_sub(1))
595 .map(|v| !v.is_empty())
596 .is_some();
597
598 if has_next {
599 if has_prev {
600 Navigation::Reach
601 } else {
602 Navigation::ReachLeaveFront
603 }
604 } else {
605 if has_prev {
606 Navigation::ReachLeaveBack
607 } else {
608 Navigation::Regular
609 }
610 }
611 }
612}
613
614impl MaskedInputState {
615 pub fn new() -> Self {
616 Self::default()
617 }
618
619 pub fn named(name: &str) -> Self {
620 let mut z = Self::default();
621 z.focus = z.focus_cb(FocusFlag::named(name));
622 z
623 }
624
625 #[inline]
627 pub fn with_symbols(mut self, sym: NumberSymbols) -> Self {
628 self.set_num_symbols(sym);
629 self
630 }
631
632 pub fn with_mask<S: AsRef<str>>(mut self, mask: S) -> Result<Self, fmt::Error> {
634 self.set_mask(mask.as_ref())?;
635 Ok(self)
636 }
637
638 #[inline]
643 pub fn set_num_symbols(&mut self, sym: NumberSymbols) {
644 self.sym = Some(sym);
645 }
646
647 fn dec_sep(&self) -> char {
648 if let Some(sym) = &self.sym {
649 sym.decimal_sep
650 } else {
651 '.'
652 }
653 }
654
655 fn grp_sep(&self) -> char {
656 if let Some(sym) = &self.sym {
657 sym.decimal_grp.unwrap_or(' ')
661 } else {
662 ','
663 }
664 }
665
666 fn neg_sym(&self) -> char {
667 if let Some(sym) = &self.sym {
668 sym.negative_sym
669 } else {
670 '-'
671 }
672 }
673
674 fn pos_sym(&self) -> char {
675 if let Some(sym) = &self.sym {
676 sym.positive_sym
677 } else {
678 ' '
679 }
680 }
681
682 #[inline]
713 pub fn set_mask<S: AsRef<str>>(&mut self, s: S) -> Result<(), fmt::Error> {
714 self.mask = Self::parse_mask(s.as_ref())?;
715 self.clear();
716 Ok(())
717 }
718
719 #[allow(clippy::needless_range_loop)]
720 fn parse_mask(mask_str: &str) -> Result<Vec<MaskToken>, fmt::Error> {
721 let mut out = Vec::<MaskToken>::new();
722
723 let mut start_sub = 0;
724 let mut start_sec = 0;
725 let mut sec_id = 0;
726 let mut last_mask = Mask::None;
727 let mut dec_dir = EditDirection::Rtol;
728 let mut esc = false;
729 let mut idx = 0;
730 for m in mask_str.graphemes(true).chain(once("")) {
731 let mask = if esc {
732 esc = false;
733 Mask::Separator(Box::from(m))
734 } else {
735 match m {
736 "0" => Mask::Digit0(dec_dir),
737 "9" => Mask::Digit(dec_dir),
738 "#" => Mask::Numeric(dec_dir),
739 "." => Mask::DecimalSep,
740 "," => Mask::GroupingSep,
741 "-" => Mask::Sign,
742 "+" => Mask::Plus,
743 "h" => Mask::Hex,
744 "H" => Mask::Hex0,
745 "o" => Mask::Oct,
746 "O" => Mask::Oct0,
747 "d" => Mask::Dec,
748 "D" => Mask::Dec0,
749 "l" => Mask::Letter,
750 "a" => Mask::LetterOrDigit,
751 "c" => Mask::LetterDigitSpace,
752 "_" => Mask::AnyChar,
753 "" => Mask::None,
754 " " => Mask::Separator(Box::from(m)),
755 "\\" => {
756 esc = true;
757 continue;
758 }
759 _ => return Err(fmt::Error),
760 }
761 };
762
763 match mask {
764 Mask::Digit0(_)
765 | Mask::Digit(_)
766 | Mask::Numeric(_)
767 | Mask::GroupingSep
768 | Mask::Sign
769 | Mask::Plus => {
770 }
772 Mask::DecimalSep => {
773 dec_dir = EditDirection::Ltor;
774 }
775 Mask::Hex0
776 | Mask::Hex
777 | Mask::Oct0
778 | Mask::Oct
779 | Mask::Dec0
780 | Mask::Dec
781 | Mask::Letter
782 | Mask::LetterOrDigit
783 | Mask::LetterDigitSpace
784 | Mask::AnyChar
785 | Mask::Separator(_) => {
786 dec_dir = EditDirection::Rtol
788 }
789 Mask::None => {
790 }
792 }
793
794 if matches!(mask, Mask::Separator(_)) || mask.section() != last_mask.section() {
795 for j in start_sec..idx {
796 out[j].sec_id = sec_id;
797 out[j].sec_start = start_sec as upos_type;
798 out[j].sec_end = idx as upos_type;
799 }
800 sec_id += 1;
801 start_sec = idx;
802 }
803 if matches!(mask, Mask::Separator(_)) || mask.sub_section() != last_mask.sub_section() {
804 for j in start_sub..idx {
805 out[j].sub_start = start_sub as upos_type;
806 out[j].sub_end = idx as upos_type;
807 }
808 start_sub = idx;
809 }
810
811 let tok = MaskToken {
812 sec_id: 0,
813 sec_start: 0,
814 sec_end: 0,
815 sub_start: 0,
816 sub_end: 0,
817 peek_left: last_mask,
818 right: mask.clone(),
819 edit: mask.edit_value().into(),
820 };
821 out.push(tok);
822
823 idx += 1;
824 last_mask = mask;
825 }
826 for j in start_sec..out.len() {
827 out[j].sec_id = sec_id;
828 out[j].sec_start = start_sec as upos_type;
829 out[j].sec_end = mask_str.graphemes(true).count() as upos_type;
830 }
831 for j in start_sub..out.len() {
832 out[j].sub_start = start_sub as upos_type;
833 out[j].sub_end = mask_str.graphemes(true).count() as upos_type;
834 }
835
836 Ok(out)
837 }
838
839 #[inline]
841 pub fn mask(&self) -> String {
842 use std::fmt::Write;
843
844 let mut buf = String::new();
845 for t in self.mask.iter() {
846 _ = write!(buf, "{}", t.right);
847 }
848 buf
849 }
850
851 #[inline]
853 pub fn set_invalid(&mut self, invalid: bool) {
854 self.invalid = invalid;
855 }
856
857 #[inline]
859 pub fn get_invalid(&self) -> bool {
860 self.invalid
861 }
862
863 #[inline]
867 pub fn set_overwrite(&mut self, overwrite: bool) {
868 self.overwrite.set(overwrite);
869 }
870
871 #[inline]
873 pub fn overwrite(&self) -> bool {
874 self.overwrite.get()
875 }
876}
877
878impl MaskedInputState {
879 #[inline]
882 pub fn set_clipboard(&mut self, clip: Option<impl Clipboard + 'static>) {
883 self.value.set_clipboard(clip.map(|v| {
884 let r: Box<dyn Clipboard> = Box::new(v);
885 r
886 }));
887 }
888
889 #[inline]
892 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
893 self.value.clipboard()
894 }
895
896 #[inline]
898 pub fn copy_to_clip(&mut self) -> bool {
899 let Some(clip) = self.value.clipboard() else {
900 return false;
901 };
902
903 _ = clip.set_string(self.selected_text().as_ref());
904
905 true
906 }
907
908 #[inline]
910 pub fn cut_to_clip(&mut self) -> bool {
911 let Some(clip) = self.value.clipboard() else {
912 return false;
913 };
914
915 match clip.set_string(self.selected_text().as_ref()) {
916 Ok(_) => self.delete_range(self.selection()),
917 Err(_) => true,
918 }
919 }
920
921 #[inline]
923 pub fn paste_from_clip(&mut self) -> bool {
924 let Some(clip) = self.value.clipboard() else {
925 return false;
926 };
927
928 if let Ok(text) = clip.get_string() {
929 for c in text.chars() {
930 self.insert_char(c);
931 }
932 true
933 } else {
934 false
935 }
936 }
937}
938
939impl MaskedInputState {
940 #[inline]
942 pub fn set_undo_buffer(&mut self, undo: Option<impl UndoBuffer + 'static>) {
943 self.value.set_undo_buffer(undo.map(|v| {
944 let r: Box<dyn UndoBuffer> = Box::new(v);
945 r
946 }));
947 }
948
949 #[inline]
951 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
952 self.value.undo_buffer()
953 }
954
955 #[inline]
957 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
958 self.value.undo_buffer_mut()
959 }
960
961 #[inline]
963 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
964 self.value.recent_replay_log()
965 }
966
967 #[inline]
969 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
970 self.value.replay_log(replay)
971 }
972
973 #[inline]
975 pub fn begin_undo_seq(&mut self) {
976 self.value.begin_undo_seq();
977 }
978
979 #[inline]
981 pub fn end_undo_seq(&mut self) {
982 self.value.end_undo_seq();
983 }
984
985 #[inline]
987 pub fn undo(&mut self) -> bool {
988 self.value.undo()
989 }
990
991 #[inline]
993 pub fn redo(&mut self) -> bool {
994 self.value.redo()
995 }
996}
997
998impl MaskedInputState {
999 #[inline]
1001 pub fn clear_styles(&mut self) {
1002 self.value.set_styles(Vec::default());
1003 }
1004
1005 #[inline]
1007 pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
1008 self.value.set_styles(styles);
1009 }
1010
1011 #[inline]
1014 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
1015 self.value.add_style(range, style);
1016 }
1017
1018 #[inline]
1021 pub fn add_range_style(
1022 &mut self,
1023 range: Range<upos_type>,
1024 style: usize,
1025 ) -> Result<(), TextError> {
1026 let r = self
1027 .value
1028 .bytes_at_range(TextRange::from((range.start, 0)..(range.end, 0)))?;
1029 self.value.add_style(r, style);
1030 Ok(())
1031 }
1032
1033 #[inline]
1035 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
1036 self.value.remove_style(range, style);
1037 }
1038
1039 #[inline]
1041 pub fn remove_range_style(
1042 &mut self,
1043 range: Range<upos_type>,
1044 style: usize,
1045 ) -> Result<(), TextError> {
1046 let r = self
1047 .value
1048 .bytes_at_range(TextRange::from((range.start, 0)..(range.end, 0)))?;
1049 self.value.remove_style(r, style);
1050 Ok(())
1051 }
1052
1053 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
1055 self.value.styles_in(range, buf)
1056 }
1057
1058 #[inline]
1060 pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
1061 self.value.styles_at(byte_pos, buf)
1062 }
1063
1064 #[inline]
1067 pub fn styles_at_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
1068 self.value.styles_at_match(byte_pos, style)
1069 }
1070
1071 #[inline]
1073 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
1074 self.value.styles()
1075 }
1076}
1077
1078impl MaskedInputState {
1079 #[inline]
1081 pub fn offset(&self) -> upos_type {
1082 self.offset
1083 }
1084
1085 #[inline]
1087 pub fn set_offset(&mut self, offset: upos_type) {
1088 self.scroll_to_cursor.set(false);
1089 self.offset = offset;
1090 }
1091
1092 #[inline]
1094 pub fn cursor(&self) -> upos_type {
1095 self.value.cursor().x
1096 }
1097
1098 #[inline]
1101 pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
1102 self.scroll_cursor_to_visible();
1103 self.value
1104 .set_cursor(TextPosition::new(cursor, 0), extend_selection)
1105 }
1106
1107 fn number_cursor(&self, range: Range<upos_type>) -> upos_type {
1109 for (i, t) in self.mask[range.start as usize..range.end as usize]
1110 .iter()
1111 .enumerate()
1112 .rev()
1113 {
1114 match t.right {
1115 Mask::Digit(EditDirection::Rtol)
1116 | Mask::Digit0(EditDirection::Rtol)
1117 | Mask::Numeric(EditDirection::Rtol) => {
1118 return range.start + i as upos_type + 1;
1119 }
1120 _ => {}
1121 }
1122 }
1123 range.start
1124 }
1125
1126 pub fn section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1129 if cursor as usize >= self.mask.len() {
1130 return None;
1131 }
1132
1133 let mask = &self.mask[cursor as usize];
1134
1135 if mask.right.is_number() {
1136 Some(self.number_cursor(mask.sec_start..mask.sec_end))
1137 } else if mask.right.is_separator() {
1138 None
1139 } else if mask.right.is_none() {
1140 None
1141 } else {
1142 Some(mask.sec_start)
1143 }
1144 }
1145
1146 pub fn next_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1148 if cursor as usize >= self.mask.len() {
1149 return None;
1150 }
1151
1152 let mut mask = &self.mask[cursor as usize];
1153 let mut next;
1154 loop {
1155 if mask.right.is_none() {
1156 return None;
1157 }
1158
1159 next = mask.sec_end;
1160 mask = &self.mask[next as usize];
1161
1162 if mask.right.is_number() {
1163 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
1164 } else if mask.right.is_separator() {
1165 continue;
1166 } else if mask.right.is_none() {
1167 return None;
1168 } else {
1169 return Some(mask.sec_start);
1170 }
1171 }
1172 }
1173
1174 pub fn prev_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1176 if cursor as usize >= self.mask.len() {
1177 return None;
1178 }
1179
1180 let mut prev = self.mask[cursor as usize].sec_start;
1181 let mut mask = &self.mask[prev as usize];
1182
1183 loop {
1184 if mask.peek_left.is_none() {
1185 return None;
1186 }
1187
1188 prev = self.mask[mask.sec_start as usize - 1].sec_start;
1189 mask = &self.mask[prev as usize];
1190
1191 if mask.right.is_number() {
1192 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
1193 } else if mask.right.is_separator() {
1194 continue;
1195 } else {
1196 return Some(mask.sec_start);
1197 }
1198 }
1199 }
1200
1201 pub fn is_section_boundary(&self, pos: upos_type) -> bool {
1203 if pos == 0 {
1204 return false;
1205 }
1206 if pos as usize >= self.mask.len() {
1207 return false;
1208 }
1209 let prev = &self.mask[pos as usize - 1];
1210 let mask = &self.mask[pos as usize];
1211 prev.sec_id != mask.sec_id
1212 }
1213
1214 pub fn section_id(&self, cursor: upos_type) -> u16 {
1216 let mask = &self.mask[cursor as usize];
1217 if mask.peek_left.is_rtol() && (mask.right.is_ltor() || mask.right.is_none()) {
1218 return self.mask[cursor.saturating_sub(1) as usize].sec_id;
1219 } else {
1220 mask.sec_id
1221 }
1222 }
1223
1224 pub fn section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1227 if cursor as usize >= self.mask.len() {
1228 return None;
1229 }
1230
1231 let mask = &self.mask[cursor as usize];
1232 if mask.right.is_number() {
1233 Some(mask.sec_start..mask.sec_end)
1234 } else if mask.right.is_separator() {
1235 None
1236 } else if mask.right.is_none() {
1237 None
1238 } else {
1239 Some(mask.sec_start..mask.sec_end)
1240 }
1241 }
1242
1243 pub fn next_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1245 if cursor as usize >= self.mask.len() {
1246 return None;
1247 }
1248
1249 let mut mask = &self.mask[cursor as usize];
1250 let mut next;
1251 loop {
1252 if mask.right.is_none() {
1253 return None;
1254 }
1255
1256 next = mask.sec_end;
1257 mask = &self.mask[next as usize];
1258
1259 if mask.right.is_number() {
1260 return Some(mask.sec_start..mask.sec_end);
1261 } else if mask.right.is_separator() {
1262 continue;
1263 } else if mask.right.is_none() {
1264 return None;
1265 } else {
1266 return Some(mask.sec_start..mask.sec_end);
1267 }
1268 }
1269 }
1270
1271 pub fn prev_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1273 if cursor as usize >= self.mask.len() {
1274 return None;
1275 }
1276
1277 let mut prev = self.mask[cursor as usize].sec_start;
1278 let mut mask = &self.mask[prev as usize];
1279 loop {
1280 if mask.peek_left.is_none() {
1281 return None;
1282 }
1283
1284 prev = self.mask[mask.sec_start as usize - 1].sec_start;
1285 mask = &self.mask[prev as usize];
1286
1287 if mask.right.is_number() {
1288 return Some(mask.sec_start..mask.sec_end);
1289 } else if mask.right.is_separator() {
1290 continue;
1291 } else {
1292 return Some(mask.sec_start..mask.sec_end);
1293 }
1294 }
1295 }
1296
1297 #[inline]
1301 pub fn set_default_cursor(&mut self) {
1302 self.scroll_cursor_to_visible();
1303 if let Some(pos) = self.section_cursor(0) {
1304 self.value.set_cursor(TextPosition::new(pos, 0), false);
1305 } else if let Some(pos) = self.next_section_cursor(0) {
1306 self.value.set_cursor(TextPosition::new(pos, 0), false);
1307 } else {
1308 self.value.set_cursor(TextPosition::new(0, 0), false);
1309 }
1310 }
1311
1312 #[inline]
1314 pub fn anchor(&self) -> upos_type {
1315 self.value.anchor().x
1316 }
1317
1318 #[inline]
1320 pub fn has_selection(&self) -> bool {
1321 self.value.has_selection()
1322 }
1323
1324 #[inline]
1326 pub fn selection(&self) -> Range<upos_type> {
1327 let mut v = self.value.selection();
1328 if v.start == TextPosition::new(0, 1) {
1329 v.start = TextPosition::new(self.line_width(), 0);
1330 }
1331 if v.end == TextPosition::new(0, 1) {
1332 v.end = TextPosition::new(self.line_width(), 0);
1333 }
1334 v.start.x..v.end.x
1335 }
1336
1337 #[inline]
1340 pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
1341 self.scroll_cursor_to_visible();
1342 self.value
1343 .set_selection(TextPosition::new(anchor, 0), TextPosition::new(cursor, 0))
1344 }
1345
1346 #[inline]
1349 pub fn select_all(&mut self) -> bool {
1350 self.scroll_cursor_to_visible();
1351 if let Some(section) = self.section_range(self.cursor()) {
1352 if self.selection() == section {
1353 self.value.select_all()
1354 } else {
1355 self.value.set_selection(
1356 TextPosition::new(section.start, 0),
1357 TextPosition::new(section.end, 0),
1358 )
1359 }
1360 } else {
1361 self.value.select_all()
1362 }
1363 }
1364
1365 #[inline]
1367 pub fn selected_text(&self) -> &str {
1368 match self
1369 .value
1370 .str_slice(self.value.selection())
1371 .expect("valid_range")
1372 {
1373 Cow::Borrowed(v) => v,
1374 Cow::Owned(_) => {
1375 unreachable!()
1376 }
1377 }
1378 }
1379}
1380
1381impl MaskedInputState {
1382 #[inline]
1384 pub fn is_empty(&self) -> bool {
1385 self.value.text().as_str() == self.default_value()
1386 }
1387
1388 #[inline]
1390 pub fn text(&self) -> &str {
1391 self.value.text().as_str()
1392 }
1393
1394 #[inline]
1396 pub fn value<T: FromStr>(&self) -> Result<T, <T as FromStr>::Err> {
1397 self.value.text().as_str().parse::<T>()
1398 }
1399
1400 #[inline]
1406 pub fn section_value<T: FromStr>(&self, section: u16) -> Result<T, <T as FromStr>::Err> {
1407 self.section_text(section).trim().parse::<T>()
1408 }
1409
1410 #[inline]
1416 pub fn set_section_value<T: ToString>(&mut self, section: u16, value: T) {
1417 let mut len = None;
1418 let mut align_left = true;
1419 for mask in &self.mask {
1420 if mask.sec_id == section {
1421 len = Some((mask.sec_end - mask.sec_start) as usize);
1422 if mask.right.is_rtol() {
1423 align_left = false;
1424 } else {
1425 align_left = true;
1426 }
1427 break;
1428 }
1429 }
1430 if let Some(len) = len {
1431 let txt = if align_left {
1432 format!("{:1$}", value.to_string(), len)
1433 } else {
1434 format!("{:>1$}", value.to_string(), len)
1435 };
1436 self.set_section_text(section, txt);
1437 } else {
1438 panic!("invalid section {}", section);
1439 }
1440 }
1441
1442 #[inline]
1448 pub fn section_text(&self, section: u16) -> &str {
1449 for v in &self.mask {
1450 if v.sec_id == section {
1451 match self.str_slice(v.sec_start..v.sec_end) {
1452 Cow::Borrowed(s) => return s,
1453 Cow::Owned(_) => {
1454 unreachable!("should not be owned")
1455 }
1456 };
1457 }
1458 }
1459 panic!("invalid section {}", section);
1460 }
1461
1462 pub fn set_section_text<S: Into<String>>(&mut self, section: u16, txt: S) {
1465 let mut txt = txt.into();
1466 for v in &self.mask {
1467 if v.sec_id == section {
1468 let len = (v.sec_end - v.sec_start) as usize;
1469 while txt.graphemes(true).count() > len {
1470 txt.pop();
1471 }
1472 while txt.graphemes(true).count() < len {
1473 txt.push(' ');
1474 }
1475 assert_eq!(txt.graphemes(true).count(), len);
1476
1477 self.value.begin_undo_seq();
1478 self.value
1479 .remove_str_range(TextRange::from(
1480 TextPosition::new(v.sec_start, 0)..TextPosition::new(v.sec_end, 0),
1481 ))
1482 .expect("valid-range");
1483 self.value
1484 .insert_str(TextPosition::new(v.sec_start, 0), txt.as_str())
1485 .expect("valid-range");
1486 self.value.end_undo_seq();
1487 return;
1488 }
1489 }
1490 panic!("invalid section {}", section);
1491 }
1492
1493 #[inline]
1495 pub fn str_slice_byte(&self, range: Range<usize>) -> Cow<'_, str> {
1496 self.value.str_slice_byte(range).expect("valid_range")
1497 }
1498
1499 #[inline]
1501 pub fn try_str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
1502 self.value.str_slice_byte(range)
1503 }
1504
1505 #[inline]
1507 pub fn str_slice(&self, range: Range<upos_type>) -> Cow<'_, str> {
1508 self.value
1509 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1510 .expect("valid_range")
1511 }
1512
1513 #[inline]
1515 pub fn try_str_slice(&self, range: Range<upos_type>) -> Result<Cow<'_, str>, TextError> {
1516 self.value
1517 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1518 }
1519
1520 #[inline]
1522 pub fn len(&self) -> upos_type {
1523 self.value.line_width(0).expect("valid_row")
1524 }
1525
1526 #[inline]
1528 pub fn len_bytes(&self) -> usize {
1529 self.value.len_bytes()
1530 }
1531
1532 #[inline]
1534 pub fn line_width(&self) -> upos_type {
1535 self.value.line_width(0).expect("valid_row")
1536 }
1537
1538 #[inline]
1540 pub fn grapheme_at(&self, pos: upos_type) -> Result<Option<Grapheme<'_>>, TextError> {
1541 self.value.grapheme_at(TextPosition::new(pos, 0))
1542 }
1543
1544 #[inline]
1546 pub fn text_graphemes(&self, pos: upos_type) -> <TextString as TextStore>::GraphemeIter<'_> {
1547 self.try_text_graphemes(pos).expect("valid_pos")
1548 }
1549
1550 #[inline]
1552 pub fn try_text_graphemes(
1553 &self,
1554 pos: upos_type,
1555 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1556 self.value.text_graphemes(TextPosition::new(pos, 0))
1557 }
1558
1559 #[inline]
1561 pub fn graphemes(
1562 &self,
1563 range: Range<upos_type>,
1564 pos: upos_type,
1565 ) -> <TextString as TextStore>::GraphemeIter<'_> {
1566 self.try_graphemes(range, pos).expect("valid_args")
1567 }
1568
1569 #[inline]
1571 pub fn try_graphemes(
1572 &self,
1573 range: Range<upos_type>,
1574 pos: upos_type,
1575 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1576 self.value.graphemes(
1577 TextRange::new((range.start, 0), (range.end, 0)),
1578 TextPosition::new(pos, 0),
1579 )
1580 }
1581
1582 #[inline]
1585 pub fn byte_at(&self, pos: upos_type) -> Range<usize> {
1586 self.try_byte_at(pos).expect("valid_pos")
1587 }
1588
1589 #[inline]
1592 pub fn try_byte_at(&self, pos: upos_type) -> Result<Range<usize>, TextError> {
1593 self.value.byte_at(TextPosition::new(pos, 0))
1594 }
1595
1596 #[inline]
1598 pub fn bytes_at_range(&self, range: Range<upos_type>) -> Range<usize> {
1599 self.try_bytes_at_range(range).expect("valid_range")
1600 }
1601
1602 #[inline]
1604 pub fn try_bytes_at_range(&self, range: Range<upos_type>) -> Result<Range<usize>, TextError> {
1605 self.value
1606 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1607 }
1608
1609 #[inline]
1612 pub fn byte_pos(&self, byte: usize) -> upos_type {
1613 self.try_byte_pos(byte).expect("valid_pos")
1614 }
1615
1616 #[inline]
1619 pub fn try_byte_pos(&self, byte: usize) -> Result<upos_type, TextError> {
1620 Ok(self.value.byte_pos(byte)?.x)
1621 }
1622
1623 #[inline]
1625 pub fn byte_range(&self, bytes: Range<usize>) -> Range<upos_type> {
1626 self.try_byte_range(bytes).expect("valid_range")
1627 }
1628
1629 #[inline]
1631 pub fn try_byte_range(&self, bytes: Range<usize>) -> Result<Range<upos_type>, TextError> {
1632 let r = self.value.byte_range(bytes)?;
1633 Ok(r.start.x..r.end.x)
1634 }
1635}
1636
1637impl MaskedInputState {
1638 #[inline]
1640 fn default_value(&self) -> String {
1641 MaskToken::empty_section(&self.mask)
1642 }
1643
1644 #[inline]
1646 pub fn clear(&mut self) -> bool {
1647 if self.is_empty() {
1648 false
1649 } else {
1650 self.offset = 0;
1651 self.value
1652 .set_text(TextString::new_string(self.default_value()));
1653 self.set_default_cursor();
1654 true
1655 }
1656 }
1657
1658 #[inline]
1662 pub fn set_value<S: ToString>(&mut self, s: S) {
1663 self.set_text(s.to_string());
1664 }
1665
1666 #[inline]
1672 pub fn set_text<S: Into<String>>(&mut self, s: S) {
1673 self.offset = 0;
1674 let mut text = s.into();
1675 while text.graphemes(true).count() > self.mask.len().saturating_sub(1) {
1676 text.pop();
1677 }
1678 while text.graphemes(true).count() < self.mask.len().saturating_sub(1) {
1679 text.push(' ');
1680 }
1681 let len = text.graphemes(true).count();
1682
1683 assert_eq!(len, self.mask.len().saturating_sub(1));
1684
1685 self.value.set_text(TextString::new_string(text));
1686 self.set_default_cursor();
1687 }
1688
1689 #[inline]
1691 pub fn insert_char(&mut self, c: char) -> bool {
1692 self.begin_undo_seq();
1693 if self.has_selection() {
1694 let sel = self.selection();
1695 mask_op::remove_range(self, sel.clone()).expect("valid_selection");
1696 self.set_cursor(sel.start, false);
1697 }
1698 let c0 = mask_op::advance_cursor(self, c);
1699 let c1 = mask_op::insert_char(self, c);
1700 self.end_undo_seq();
1701
1702 self.scroll_cursor_to_visible();
1703 c0 || c1
1704 }
1705
1706 #[inline]
1709 pub fn delete_range(&mut self, range: Range<upos_type>) -> bool {
1710 self.try_delete_range(range).expect("valid_range")
1711 }
1712
1713 #[inline]
1716 pub fn try_delete_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
1717 self.value.begin_undo_seq();
1718 let r = mask_op::remove_range(self, range.clone())?;
1719 if let Some(pos) = self.section_cursor(range.start) {
1720 self.set_cursor(pos, false);
1721 }
1722 self.value.end_undo_seq();
1723
1724 self.scroll_cursor_to_visible();
1725 Ok(r)
1726 }
1727}
1728
1729impl MaskedInputState {
1730 #[inline]
1732 pub fn delete_next_char(&mut self) -> bool {
1733 if self.has_selection() {
1734 self.delete_range(self.selection())
1735 } else if self.cursor() == self.len() {
1736 false
1737 } else {
1738 mask_op::remove_next(self);
1739 self.scroll_cursor_to_visible();
1740 true
1741 }
1742 }
1743
1744 #[inline]
1746 pub fn delete_prev_char(&mut self) -> bool {
1747 if self.has_selection() {
1748 self.delete_range(self.selection())
1749 } else if self.cursor() == 0 {
1750 false
1751 } else {
1752 mask_op::remove_prev(self);
1753 self.scroll_cursor_to_visible();
1754 true
1755 }
1756 }
1757
1758 #[inline]
1760 pub fn delete_prev_section(&mut self) -> bool {
1761 if self.has_selection() {
1762 self.delete_range(self.selection())
1763 } else {
1764 if let Some(range) = self.prev_section_range(self.cursor()) {
1765 self.delete_range(range)
1766 } else {
1767 false
1768 }
1769 }
1770 }
1771
1772 #[inline]
1774 pub fn delete_next_section(&mut self) -> bool {
1775 if self.has_selection() {
1776 self.delete_range(self.selection())
1777 } else {
1778 if let Some(range) = self.next_section_range(self.cursor()) {
1779 self.delete_range(range)
1780 } else {
1781 false
1782 }
1783 }
1784 }
1785
1786 #[inline]
1788 pub fn move_right(&mut self, extend_selection: bool) -> bool {
1789 let c = min(self.cursor() + 1, self.len());
1790 self.set_cursor(c, extend_selection)
1791 }
1792
1793 #[inline]
1795 pub fn move_left(&mut self, extend_selection: bool) -> bool {
1796 let c = self.cursor().saturating_sub(1);
1797 self.set_cursor(c, extend_selection)
1798 }
1799
1800 #[inline]
1802 pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1803 if let Some(c) = self.section_cursor(self.cursor()) {
1804 if c != self.cursor() {
1805 self.set_cursor(c, extend_selection)
1806 } else {
1807 self.set_cursor(0, extend_selection)
1808 }
1809 } else {
1810 self.set_cursor(0, extend_selection)
1811 }
1812 }
1813
1814 #[inline]
1816 pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
1817 self.set_cursor(self.len(), extend_selection)
1818 }
1819
1820 #[inline]
1822 pub fn move_to_prev_section(&mut self, extend_selection: bool) -> bool {
1823 if let Some(curr) = self.section_range(self.cursor()) {
1824 if self.cursor() != curr.start {
1825 return self.set_cursor(curr.start, extend_selection);
1826 }
1827 }
1828 if let Some(range) = self.prev_section_range(self.cursor()) {
1829 self.set_cursor(range.start, extend_selection)
1830 } else {
1831 false
1832 }
1833 }
1834
1835 #[inline]
1837 pub fn move_to_next_section(&mut self, extend_selection: bool) -> bool {
1838 if let Some(curr) = self.section_range(self.cursor()) {
1839 if self.cursor() != curr.end {
1840 return self.set_cursor(curr.end, extend_selection);
1841 }
1842 }
1843 if let Some(range) = self.next_section_range(self.cursor()) {
1844 self.set_cursor(range.end, extend_selection)
1845 } else {
1846 false
1847 }
1848 }
1849
1850 #[inline]
1852 pub fn select_current_section(&mut self) -> bool {
1853 let selection = self.selection();
1854
1855 if let Some(next) = self.section_range(selection.start.saturating_sub(1)) {
1856 if !next.is_empty() {
1857 self.set_selection(next.start, next.end)
1858 } else {
1859 false
1860 }
1861 } else {
1862 false
1863 }
1864 }
1865
1866 #[inline]
1868 pub fn select_next_section(&mut self) -> bool {
1869 let selection = self.selection();
1870
1871 if let Some(next) = self.next_section_range(selection.start) {
1872 if !next.is_empty() {
1873 self.set_selection(next.start, next.end)
1874 } else {
1875 false
1876 }
1877 } else {
1878 false
1879 }
1880 }
1881
1882 #[inline]
1884 pub fn select_prev_section(&mut self) -> bool {
1885 let selection = self.selection();
1886
1887 if let Some(next) = self.prev_section_range(selection.start.saturating_sub(1)) {
1888 if !next.is_empty() {
1889 self.set_selection(next.start, next.end)
1890 } else {
1891 false
1892 }
1893 } else {
1894 false
1895 }
1896 }
1897}
1898
1899impl HasScreenCursor for MaskedInputState {
1900 #[inline]
1902 fn screen_cursor(&self) -> Option<(u16, u16)> {
1903 if self.is_focused() {
1904 if self.has_selection() {
1905 None
1906 } else {
1907 let cx = self.cursor();
1908 let ox = self.offset();
1909
1910 if cx < ox {
1911 None
1912 } else if cx > ox + (self.inner.width + self.dark_offset.0) as upos_type {
1913 None
1914 } else {
1915 self.col_to_screen(cx)
1916 .map(|sc| (self.inner.x + sc, self.inner.y))
1917 }
1918 }
1919 } else {
1920 None
1921 }
1922 }
1923}
1924
1925impl RelocatableState for MaskedInputState {
1926 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
1927 self.dark_offset = relocate_dark_offset(self.inner, shift, clip);
1929 self.area = relocate_area(self.area, shift, clip);
1930 self.inner = relocate_area(self.inner, shift, clip);
1931 }
1932}
1933
1934impl MaskedInputState {
1935 fn glyphs2(&self) -> impl Iterator<Item = Glyph2<'_>> {
1936 let left_margin = self.offset();
1937 let right_margin = self.offset() + self.rendered.width as upos_type;
1938 let compact = self.compact && !self.is_focused();
1939
1940 let grapheme_iter = self
1941 .value
1942 .graphemes(TextRange::new((0, 0), (0, 1)), TextPosition::new(0, 0))
1943 .expect("valid-rows");
1944 let mask_iter = self.mask.iter();
1945
1946 let iter = MaskedGraphemes {
1947 iter_str: grapheme_iter,
1948 iter_mask: mask_iter,
1949 compact,
1950 sym_neg: self.neg_sym().to_string(),
1951 sym_dec: self.dec_sep().to_string(),
1952 sym_grp: self.grp_sep().to_string(),
1953 sym_pos: self.pos_sym().to_string(),
1954 byte_pos: 0,
1955 };
1956
1957 let mut it = GlyphIter2::new(TextPosition::new(0, 0), 0, iter, Default::default());
1958 it.set_tabs(0 );
1959 it.set_show_ctrl(self.value.glyph_ctrl());
1960 it.set_lf_breaks(false);
1961 it.set_text_wrap(TextWrap2::Shift);
1962 it.set_left_margin(left_margin);
1963 it.set_right_margin(right_margin);
1964 it.set_word_margin(right_margin);
1965 it.prepare().expect("valid-rows");
1966
1967 Box::new(it)
1968 }
1969
1970 pub fn screen_to_col(&self, scx: i16) -> upos_type {
1973 let ox = self.offset();
1974
1975 let scx = scx + self.dark_offset.0 as i16;
1976
1977 if scx < 0 {
1978 ox.saturating_sub((scx as ipos_type).unsigned_abs())
1979 } else if scx as u16 >= (self.inner.width + self.dark_offset.0) {
1980 min(ox + scx as upos_type, self.len())
1981 } else {
1982 let scx = scx as u16;
1983
1984 let line = self.glyphs2();
1985
1986 let mut col = ox;
1987 for g in line {
1988 if g.contains_screen_x(scx) {
1989 break;
1990 }
1991 col = g.pos().x + 1;
1992 }
1993 col
1994 }
1995 }
1996
1997 pub fn col_to_screen(&self, pos: upos_type) -> Option<u16> {
2000 let ox = self.offset();
2001
2002 if pos < ox {
2003 return None;
2004 }
2005
2006 let line = self.glyphs2();
2007 let mut screen_x = 0;
2008 for g in line {
2009 if g.pos().x == pos {
2010 break;
2011 }
2012 screen_x = g.screen_pos().0 + g.screen_width();
2013 }
2014
2015 if screen_x >= self.dark_offset.0 {
2016 Some(screen_x - self.dark_offset.0)
2017 } else {
2018 None
2019 }
2020 }
2021
2022 #[inline]
2026 pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
2027 let scx = cursor;
2028
2029 let cx = self.screen_to_col(scx);
2030
2031 self.set_cursor(cx, extend_selection)
2032 }
2033
2034 pub fn set_screen_cursor_sections(
2041 &mut self,
2042 screen_cursor: i16,
2043 extend_selection: bool,
2044 ) -> bool {
2045 let anchor = self.anchor();
2046 let cursor = self.screen_to_col(screen_cursor);
2047
2048 let Some(range) = self.section_range(cursor) else {
2049 return false;
2050 };
2051
2052 let cursor = if cursor < anchor {
2053 range.start
2054 } else {
2055 range.end
2056 };
2057
2058 if !self.is_section_boundary(anchor) {
2060 if let Some(range) = self.section_range(anchor) {
2061 if cursor < anchor {
2062 self.set_cursor(range.end, false);
2063 } else {
2064 self.set_cursor(range.start, false);
2065 }
2066 };
2067 }
2068
2069 self.set_cursor(cursor, extend_selection)
2070 }
2071
2072 pub fn scroll_left(&mut self, delta: upos_type) -> bool {
2074 self.set_offset(self.offset.saturating_sub(delta));
2075 true
2076 }
2077
2078 pub fn scroll_right(&mut self, delta: upos_type) -> bool {
2080 self.set_offset(self.offset + delta);
2081 true
2082 }
2083
2084 pub fn scroll_cursor_to_visible(&mut self) {
2086 self.scroll_to_cursor.set(true);
2087 }
2088}
2089
2090impl HandleEvent<crossterm::event::Event, Regular, TextOutcome> for MaskedInputState {
2091 fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> TextOutcome {
2092 fn tc(r: bool) -> TextOutcome {
2094 if r {
2095 TextOutcome::TextChanged
2096 } else {
2097 TextOutcome::Unchanged
2098 }
2099 }
2100 fn overwrite(state: &mut MaskedInputState) {
2101 if state.overwrite.get() {
2102 state.overwrite.set(false);
2103 state.clear();
2104 }
2105 }
2106 fn clear_overwrite(state: &mut MaskedInputState) {
2107 state.overwrite.set(false);
2108 }
2109
2110 let mut r = if self.is_focused() {
2135 match event {
2136 ct_event!(key press c)
2137 | ct_event!(key press SHIFT-c)
2138 | ct_event!(key press CONTROL_ALT-c) => {
2139 overwrite(self);
2140 tc(self.insert_char(*c))
2141 }
2142 ct_event!(keycode press Backspace) => {
2143 clear_overwrite(self);
2144 tc(self.delete_prev_char())
2145 }
2146 ct_event!(keycode press Delete) => {
2147 clear_overwrite(self);
2148 tc(self.delete_next_char())
2149 }
2150 ct_event!(keycode press CONTROL-Backspace)
2151 | ct_event!(keycode press ALT-Backspace) => {
2152 clear_overwrite(self);
2153 tc(self.delete_prev_section())
2154 }
2155 ct_event!(keycode press CONTROL-Delete) => {
2156 clear_overwrite(self);
2157 tc(self.delete_next_section())
2158 }
2159 ct_event!(key press CONTROL-'x') => {
2160 clear_overwrite(self);
2161 tc(self.cut_to_clip())
2162 }
2163 ct_event!(key press CONTROL-'v') => {
2164 clear_overwrite(self);
2165 tc(self.paste_from_clip())
2166 }
2167 ct_event!(key press CONTROL-'d') => {
2168 clear_overwrite(self);
2169 tc(self.clear())
2170 }
2171 ct_event!(key press CONTROL-'z') => {
2172 clear_overwrite(self);
2173 tc(self.undo())
2174 }
2175 ct_event!(key press CONTROL_SHIFT-'Z') => {
2176 clear_overwrite(self);
2177 tc(self.redo())
2178 }
2179
2180 ct_event!(key release _)
2181 | ct_event!(key release SHIFT-_)
2182 | ct_event!(key release CONTROL_ALT-_)
2183 | ct_event!(keycode release Backspace)
2184 | ct_event!(keycode release Delete)
2185 | ct_event!(keycode release CONTROL-Backspace)
2186 | ct_event!(keycode release ALT-Backspace)
2187 | ct_event!(keycode release CONTROL-Delete)
2188 | ct_event!(key release CONTROL-'x')
2189 | ct_event!(key release CONTROL-'v')
2190 | ct_event!(key release CONTROL-'d')
2191 | ct_event!(key release CONTROL-'z')
2192 | ct_event!(key release CONTROL_SHIFT-'Z') => TextOutcome::Unchanged,
2193
2194 _ => TextOutcome::Continue,
2195 }
2196 } else {
2197 TextOutcome::Continue
2198 };
2199
2200 if r == TextOutcome::Continue {
2201 r = self.handle(event, ReadOnly);
2202 }
2203 r
2204 }
2205}
2206
2207impl HandleEvent<crossterm::event::Event, ReadOnly, TextOutcome> for MaskedInputState {
2208 fn handle(&mut self, event: &crossterm::event::Event, _keymap: ReadOnly) -> TextOutcome {
2209 fn clear_overwrite(state: &mut MaskedInputState) {
2210 state.overwrite.set(false);
2211 }
2212
2213 let mut r = if self.is_focused() {
2214 match event {
2215 ct_event!(keycode press Left) => {
2216 clear_overwrite(self);
2217 self.move_left(false).into()
2218 }
2219 ct_event!(keycode press Right) => {
2220 clear_overwrite(self);
2221 self.move_right(false).into()
2222 }
2223 ct_event!(keycode press CONTROL-Left) => {
2224 clear_overwrite(self);
2225 self.move_to_prev_section(false).into()
2226 }
2227 ct_event!(keycode press CONTROL-Right) => {
2228 clear_overwrite(self);
2229 self.move_to_next_section(false).into()
2230 }
2231 ct_event!(keycode press Home) => {
2232 clear_overwrite(self);
2233 self.move_to_line_start(false).into()
2234 }
2235 ct_event!(keycode press End) => {
2236 clear_overwrite(self);
2237 self.move_to_line_end(false).into()
2238 }
2239 ct_event!(keycode press SHIFT-Left) => {
2240 clear_overwrite(self);
2241 self.move_left(true).into()
2242 }
2243 ct_event!(keycode press SHIFT-Right) => {
2244 clear_overwrite(self);
2245 self.move_right(true).into()
2246 }
2247 ct_event!(keycode press CONTROL_SHIFT-Left) => {
2248 clear_overwrite(self);
2249 self.move_to_prev_section(true).into()
2250 }
2251 ct_event!(keycode press CONTROL_SHIFT-Right) => {
2252 clear_overwrite(self);
2253 self.move_to_next_section(true).into()
2254 }
2255 ct_event!(keycode press SHIFT-Home) => {
2256 clear_overwrite(self);
2257 self.move_to_line_start(true).into()
2258 }
2259 ct_event!(keycode press SHIFT-End) => {
2260 clear_overwrite(self);
2261 self.move_to_line_end(true).into()
2262 }
2263 ct_event!(keycode press Tab) => {
2264 if !self.focus.gained() {
2266 clear_overwrite(self);
2267 self.select_next_section().into()
2268 } else {
2269 TextOutcome::Unchanged
2270 }
2271 }
2272 ct_event!(keycode press SHIFT-BackTab) => {
2273 if !self.focus.gained() {
2275 clear_overwrite(self);
2276 self.select_prev_section().into()
2277 } else {
2278 TextOutcome::Unchanged
2279 }
2280 }
2281 ct_event!(key press CONTROL-'a') => {
2282 clear_overwrite(self);
2283 self.select_all().into()
2284 }
2285 ct_event!(key press CONTROL-'c') => {
2286 clear_overwrite(self);
2287 self.copy_to_clip().into()
2288 }
2289
2290 ct_event!(keycode release Left)
2291 | ct_event!(keycode release Right)
2292 | ct_event!(keycode release CONTROL-Left)
2293 | ct_event!(keycode release CONTROL-Right)
2294 | ct_event!(keycode release Home)
2295 | ct_event!(keycode release End)
2296 | ct_event!(keycode release SHIFT-Left)
2297 | ct_event!(keycode release SHIFT-Right)
2298 | ct_event!(keycode release CONTROL_SHIFT-Left)
2299 | ct_event!(keycode release CONTROL_SHIFT-Right)
2300 | ct_event!(keycode release SHIFT-Home)
2301 | ct_event!(keycode release SHIFT-End)
2302 | ct_event!(key release CONTROL-'a')
2303 | ct_event!(key release CONTROL-'c') => TextOutcome::Unchanged,
2304
2305 _ => TextOutcome::Continue,
2306 }
2307 } else {
2308 TextOutcome::Continue
2309 };
2310
2311 if r == TextOutcome::Continue {
2312 r = self.handle(event, MouseOnly);
2313 }
2314 r
2315 }
2316}
2317
2318impl HandleEvent<crossterm::event::Event, MouseOnly, TextOutcome> for MaskedInputState {
2319 fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> TextOutcome {
2320 fn clear_overwrite(state: &mut MaskedInputState) {
2321 state.overwrite.set(false);
2322 }
2323
2324 match event {
2325 ct_event!(mouse any for m) if self.mouse.drag(self.inner, m) => {
2326 let c = (m.column as i16) - (self.inner.x as i16);
2327 clear_overwrite(self);
2328 self.set_screen_cursor(c, true).into()
2329 }
2330 ct_event!(mouse any for m) if self.mouse.drag2(self.inner, m, KeyModifiers::ALT) => {
2331 let cx = m.column as i16 - self.inner.x as i16;
2332 clear_overwrite(self);
2333 self.set_screen_cursor_sections(cx, true).into()
2334 }
2335 ct_event!(mouse any for m) if self.mouse.doubleclick(self.inner, m) => {
2336 let tx = self.screen_to_col(m.column as i16 - self.inner.x as i16);
2337 clear_overwrite(self);
2338 if let Some(range) = self.section_range(tx) {
2339 self.set_selection(range.start, range.end).into()
2340 } else {
2341 TextOutcome::Unchanged
2342 }
2343 }
2344 ct_event!(mouse down Left for column,row) => {
2345 if self.gained_focus() {
2346 TextOutcome::Unchanged
2349 } else if self.inner.contains((*column, *row).into()) {
2350 let c = (column - self.inner.x) as i16;
2351 clear_overwrite(self);
2352 self.set_screen_cursor(c, false).into()
2353 } else {
2354 TextOutcome::Continue
2355 }
2356 }
2357 ct_event!(mouse down CONTROL-Left for column,row) => {
2358 if self.inner.contains((*column, *row).into()) {
2359 let cx = (column - self.inner.x) as i16;
2360 clear_overwrite(self);
2361 self.set_screen_cursor(cx, true).into()
2362 } else {
2363 TextOutcome::Continue
2364 }
2365 }
2366 ct_event!(mouse down ALT-Left for column,row) => {
2367 if self.inner.contains((*column, *row).into()) {
2368 let cx = (column - self.inner.x) as i16;
2369 clear_overwrite(self);
2370 self.set_screen_cursor_sections(cx, true).into()
2371 } else {
2372 TextOutcome::Continue
2373 }
2374 }
2375 _ => TextOutcome::Continue,
2376 }
2377 }
2378}
2379
2380pub fn handle_events(
2384 state: &mut MaskedInputState,
2385 focus: bool,
2386 event: &crossterm::event::Event,
2387) -> TextOutcome {
2388 state.focus.set(focus);
2389 state.handle(event, Regular)
2390}
2391
2392pub fn handle_readonly_events(
2396 state: &mut TextInputState,
2397 focus: bool,
2398 event: &crossterm::event::Event,
2399) -> TextOutcome {
2400 state.focus.set(focus);
2401 state.handle(event, ReadOnly)
2402}
2403
2404pub fn handle_mouse_events(
2406 state: &mut MaskedInputState,
2407 event: &crossterm::event::Event,
2408) -> TextOutcome {
2409 state.handle(event, MouseOnly)
2410}