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