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