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]
1737 pub fn set_value<S: ToString>(&mut self, s: S) {
1738 self.set_text(s.to_string());
1739 }
1740
1741 #[inline]
1747 pub fn set_text<S: Into<String>>(&mut self, s: S) {
1748 self.offset = 0;
1749 let mut text = s.into();
1750 while text.graphemes(true).count() > self.mask.len().saturating_sub(1) {
1751 text.pop();
1752 }
1753 while text.graphemes(true).count() < self.mask.len().saturating_sub(1) {
1754 text.push(' ');
1755 }
1756 let len = text.graphemes(true).count();
1757
1758 assert_eq!(len, self.mask.len().saturating_sub(1));
1759
1760 self.value.set_text(TextString::new_string(text));
1761 self.set_default_cursor();
1762 }
1763
1764 #[inline]
1766 pub fn insert_char(&mut self, c: char) -> bool {
1767 self.begin_undo_seq();
1768 if self.has_selection() {
1769 let sel = self.selection();
1770 mask_op::remove_range(self, sel.clone()).expect("valid_selection");
1771 self.set_cursor(sel.start, false);
1772 }
1773 let c0 = mask_op::advance_cursor(self, c);
1774 let c1 = mask_op::insert_char(self, c);
1775 self.end_undo_seq();
1776
1777 self.scroll_cursor_to_visible();
1778 c0 || c1
1779 }
1780
1781 #[inline]
1784 pub fn delete_range(&mut self, range: Range<upos_type>) -> bool {
1785 self.try_delete_range(range).expect("valid_range")
1786 }
1787
1788 #[inline]
1791 pub fn try_delete_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
1792 self.value.begin_undo_seq();
1793 let r = mask_op::remove_range(self, range.clone())?;
1794 if let Some(pos) = self.section_cursor(range.start) {
1795 self.set_cursor(pos, false);
1796 }
1797 self.value.end_undo_seq();
1798
1799 self.scroll_cursor_to_visible();
1800 Ok(r)
1801 }
1802}
1803
1804impl MaskedInputState {
1805 #[inline]
1807 pub fn delete_next_char(&mut self) -> bool {
1808 if self.has_selection() {
1809 self.delete_range(self.selection())
1810 } else if self.cursor() == self.len() {
1811 false
1812 } else {
1813 mask_op::remove_next(self);
1814 self.scroll_cursor_to_visible();
1815 true
1816 }
1817 }
1818
1819 #[inline]
1821 pub fn delete_prev_char(&mut self) -> bool {
1822 if self.has_selection() {
1823 self.delete_range(self.selection())
1824 } else if self.cursor() == 0 {
1825 false
1826 } else {
1827 mask_op::remove_prev(self);
1828 self.scroll_cursor_to_visible();
1829 true
1830 }
1831 }
1832
1833 #[inline]
1835 pub fn delete_prev_section(&mut self) -> bool {
1836 if self.has_selection() {
1837 self.delete_range(self.selection())
1838 } else {
1839 if let Some(range) = self.prev_section_range(self.cursor()) {
1840 self.delete_range(range)
1841 } else {
1842 false
1843 }
1844 }
1845 }
1846
1847 #[inline]
1849 pub fn delete_next_section(&mut self) -> bool {
1850 if self.has_selection() {
1851 self.delete_range(self.selection())
1852 } else {
1853 if let Some(range) = self.next_section_range(self.cursor()) {
1854 self.delete_range(range)
1855 } else {
1856 false
1857 }
1858 }
1859 }
1860
1861 #[inline]
1863 pub fn move_right(&mut self, extend_selection: bool) -> bool {
1864 let c = min(self.cursor() + 1, self.len());
1865 self.set_cursor(c, extend_selection)
1866 }
1867
1868 #[inline]
1870 pub fn move_left(&mut self, extend_selection: bool) -> bool {
1871 let c = self.cursor().saturating_sub(1);
1872 self.set_cursor(c, extend_selection)
1873 }
1874
1875 #[inline]
1877 pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1878 if let Some(c) = self.section_cursor(self.cursor()) {
1879 if c != self.cursor() {
1880 self.set_cursor(c, extend_selection)
1881 } else {
1882 self.set_cursor(0, extend_selection)
1883 }
1884 } else {
1885 self.set_cursor(0, extend_selection)
1886 }
1887 }
1888
1889 #[inline]
1891 pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
1892 self.set_cursor(self.len(), extend_selection)
1893 }
1894
1895 #[inline]
1897 pub fn move_to_prev_section(&mut self, extend_selection: bool) -> bool {
1898 if let Some(curr) = self.section_range(self.cursor()) {
1899 if self.cursor() != curr.start {
1900 return self.set_cursor(curr.start, extend_selection);
1901 }
1902 }
1903 if let Some(range) = self.prev_section_range(self.cursor()) {
1904 self.set_cursor(range.start, extend_selection)
1905 } else {
1906 false
1907 }
1908 }
1909
1910 #[inline]
1912 pub fn move_to_next_section(&mut self, extend_selection: bool) -> bool {
1913 if let Some(curr) = self.section_range(self.cursor()) {
1914 if self.cursor() != curr.end {
1915 return self.set_cursor(curr.end, extend_selection);
1916 }
1917 }
1918 if let Some(range) = self.next_section_range(self.cursor()) {
1919 self.set_cursor(range.end, extend_selection)
1920 } else {
1921 false
1922 }
1923 }
1924
1925 #[inline]
1927 pub fn select_current_section(&mut self) -> bool {
1928 let selection = self.selection();
1929
1930 if let Some(next) = self.section_range(selection.start.saturating_sub(1)) {
1931 if !next.is_empty() {
1932 self.set_selection(next.start, next.end)
1933 } else {
1934 false
1935 }
1936 } else {
1937 false
1938 }
1939 }
1940
1941 #[inline]
1943 pub fn select_next_section(&mut self) -> bool {
1944 let selection = self.selection();
1945
1946 if let Some(next) = self.next_section_range(selection.start) {
1947 if !next.is_empty() {
1948 self.set_selection(next.start, next.end)
1949 } else {
1950 false
1951 }
1952 } else {
1953 false
1954 }
1955 }
1956
1957 #[inline]
1959 pub fn select_prev_section(&mut self) -> bool {
1960 let selection = self.selection();
1961
1962 if let Some(next) = self.prev_section_range(selection.start.saturating_sub(1)) {
1963 if !next.is_empty() {
1964 self.set_selection(next.start, next.end)
1965 } else {
1966 false
1967 }
1968 } else {
1969 false
1970 }
1971 }
1972}
1973
1974impl HasScreenCursor for MaskedInputState {
1975 #[inline]
1977 fn screen_cursor(&self) -> Option<(u16, u16)> {
1978 if self.is_focused() {
1979 if self.has_selection() {
1980 None
1981 } else {
1982 let cx = self.cursor();
1983 let ox = self.offset();
1984
1985 if cx < ox {
1986 None
1987 } else if cx > ox + (self.inner.width + self.dark_offset.0) as upos_type {
1988 None
1989 } else {
1990 self.col_to_screen(cx)
1991 .map(|sc| (self.inner.x + sc, self.inner.y))
1992 }
1993 }
1994 } else {
1995 None
1996 }
1997 }
1998}
1999
2000impl RelocatableState for MaskedInputState {
2001 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
2002 self.area.relocate(shift, clip);
2003 self.inner.relocate(shift, clip);
2004 self.dark_offset = relocate_dark_offset(self.inner, shift, clip);
2006 }
2007}
2008
2009impl MaskedInputState {
2010 fn glyphs2(&self) -> impl Iterator<Item = Glyph2<'_>> {
2011 let left_margin = self.offset();
2012 let right_margin = self.offset() + self.rendered.width as upos_type;
2013 let compact = self.compact && !self.is_focused();
2014
2015 let grapheme_iter = self
2016 .value
2017 .graphemes(TextRange::new((0, 0), (0, 1)), TextPosition::new(0, 0))
2018 .expect("valid-rows");
2019 let mask_iter = self.mask.iter();
2020
2021 let iter = MaskedGraphemes {
2022 iter_str: grapheme_iter,
2023 iter_mask: mask_iter,
2024 compact,
2025 sym_neg: self.neg_sym().to_string(),
2026 sym_dec: self.dec_sep().to_string(),
2027 sym_grp: self.grp_sep().to_string(),
2028 sym_pos: self.pos_sym().to_string(),
2029 byte_pos: 0,
2030 };
2031
2032 let mut it = GlyphIter2::new(TextPosition::new(0, 0), 0, iter, Default::default());
2033 it.set_tabs(0 );
2034 it.set_show_ctrl(self.value.glyph_ctrl());
2035 it.set_lf_breaks(false);
2036 it.set_text_wrap(TextWrap2::Shift);
2037 it.set_left_margin(left_margin);
2038 it.set_right_margin(right_margin);
2039 it.set_word_margin(right_margin);
2040 it.prepare().expect("valid-rows");
2041
2042 Box::new(it)
2043 }
2044
2045 pub fn screen_to_col(&self, scx: i16) -> upos_type {
2048 let ox = self.offset();
2049
2050 let scx = scx + self.dark_offset.0 as i16;
2051
2052 if scx < 0 {
2053 ox.saturating_sub((scx as ipos_type).unsigned_abs())
2054 } else if scx as u16 >= (self.inner.width + self.dark_offset.0) {
2055 min(ox + scx as upos_type, self.len())
2056 } else {
2057 let scx = scx as u16;
2058
2059 let line = self.glyphs2();
2060
2061 let mut col = ox;
2062 for g in line {
2063 if g.contains_screen_x(scx) {
2064 break;
2065 }
2066 col = g.pos().x + 1;
2067 }
2068 col
2069 }
2070 }
2071
2072 pub fn col_to_screen(&self, pos: upos_type) -> Option<u16> {
2075 let ox = self.offset();
2076
2077 if pos < ox {
2078 return None;
2079 }
2080
2081 let line = self.glyphs2();
2082 let mut screen_x = 0;
2083 for g in line {
2084 if g.pos().x == pos {
2085 break;
2086 }
2087 screen_x = g.screen_pos().0 + g.screen_width();
2088 }
2089
2090 if screen_x >= self.dark_offset.0 {
2091 Some(screen_x - self.dark_offset.0)
2092 } else {
2093 None
2094 }
2095 }
2096
2097 #[inline]
2101 pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
2102 let scx = cursor;
2103
2104 let cx = self.screen_to_col(scx);
2105
2106 self.set_cursor(cx, extend_selection)
2107 }
2108
2109 pub fn set_screen_cursor_sections(
2116 &mut self,
2117 screen_cursor: i16,
2118 extend_selection: bool,
2119 ) -> bool {
2120 let anchor = self.anchor();
2121 let cursor = self.screen_to_col(screen_cursor);
2122
2123 let Some(range) = self.section_range(cursor) else {
2124 return false;
2125 };
2126
2127 let cursor = if cursor < anchor {
2128 range.start
2129 } else {
2130 range.end
2131 };
2132
2133 if !self.is_section_boundary(anchor) {
2135 if let Some(range) = self.section_range(anchor) {
2136 if cursor < anchor {
2137 self.set_cursor(range.end, false);
2138 } else {
2139 self.set_cursor(range.start, false);
2140 }
2141 };
2142 }
2143
2144 self.set_cursor(cursor, extend_selection)
2145 }
2146
2147 pub fn scroll_left(&mut self, delta: upos_type) -> bool {
2149 self.set_offset(self.offset.saturating_sub(delta));
2150 true
2151 }
2152
2153 pub fn scroll_right(&mut self, delta: upos_type) -> bool {
2155 self.set_offset(self.offset + delta);
2156 true
2157 }
2158
2159 pub fn scroll_cursor_to_visible(&mut self) {
2161 self.scroll_to_cursor.set(true);
2162 }
2163}
2164
2165impl HandleEvent<Event, Regular, TextOutcome> for MaskedInputState {
2166 fn handle(&mut self, event: &Event, _keymap: Regular) -> TextOutcome {
2167 fn tc(r: bool) -> TextOutcome {
2169 if r {
2170 TextOutcome::TextChanged
2171 } else {
2172 TextOutcome::Unchanged
2173 }
2174 }
2175 fn overwrite(state: &mut MaskedInputState) {
2176 if state.overwrite.get() {
2177 state.overwrite.set(false);
2178 state.clear();
2179 }
2180 }
2181 fn clear_overwrite(state: &mut MaskedInputState) {
2182 state.overwrite.set(false);
2183 }
2184
2185 let mut r = if self.is_focused() {
2186 match event {
2187 ct_event!(key press c)
2188 | ct_event!(key press SHIFT-c)
2189 | ct_event!(key press CONTROL_ALT-c) => {
2190 overwrite(self);
2191 tc(self.insert_char(*c))
2192 }
2193 ct_event!(keycode press Backspace) | ct_event!(keycode press SHIFT-Backspace) => {
2194 clear_overwrite(self);
2195 tc(self.delete_prev_char())
2196 }
2197 ct_event!(keycode press Delete) | ct_event!(keycode press SHIFT-Delete) => {
2198 clear_overwrite(self);
2199 tc(self.delete_next_char())
2200 }
2201 ct_event!(keycode press CONTROL-Backspace)
2202 | ct_event!(keycode press ALT-Backspace) => {
2203 clear_overwrite(self);
2204 tc(self.delete_prev_section())
2205 }
2206 ct_event!(keycode press CONTROL-Delete) => {
2207 clear_overwrite(self);
2208 tc(self.delete_next_section())
2209 }
2210 ct_event!(key press CONTROL-'x') => {
2211 clear_overwrite(self);
2212 tc(self.cut_to_clip())
2213 }
2214 ct_event!(key press CONTROL-'v') => {
2215 clear_overwrite(self);
2216 tc(self.paste_from_clip())
2217 }
2218 ct_event!(key press CONTROL-'d') => {
2219 clear_overwrite(self);
2220 tc(self.clear())
2221 }
2222 ct_event!(key press CONTROL-'z') => {
2223 clear_overwrite(self);
2224 tc(self.undo())
2225 }
2226 ct_event!(key press CONTROL_SHIFT-'Z') => {
2227 clear_overwrite(self);
2228 tc(self.redo())
2229 }
2230 ct_event!(keycode press Tab) => {
2231 if self.on_tab == TextTab::MoveToNextSection {
2232 if !self.focus.gained() {
2234 clear_overwrite(self);
2235 self.select_next_section().into()
2236 } else {
2237 TextOutcome::Unchanged
2238 }
2239 } else {
2240 TextOutcome::Continue
2241 }
2242 }
2243 ct_event!(keycode press SHIFT-BackTab) => {
2244 if self.on_tab == TextTab::MoveToNextSection {
2245 if !self.focus.gained() {
2247 clear_overwrite(self);
2248 self.select_prev_section().into()
2249 } else {
2250 TextOutcome::Unchanged
2251 }
2252 } else {
2253 TextOutcome::Continue
2254 }
2255 }
2256 ct_event!(keycode press ALT-Left) => {
2257 clear_overwrite(self);
2258 self.select_prev_section().into()
2259 }
2260 ct_event!(keycode press ALT-Right) => {
2261 clear_overwrite(self);
2262 self.select_next_section().into()
2263 }
2264
2265 ct_event!(key release _)
2266 | ct_event!(key release SHIFT-_)
2267 | ct_event!(key release CONTROL_ALT-_)
2268 | ct_event!(keycode release Backspace)
2269 | ct_event!(keycode release Delete)
2270 | ct_event!(keycode release CONTROL-Backspace)
2271 | ct_event!(keycode release ALT-Backspace)
2272 | ct_event!(keycode release CONTROL-Delete)
2273 | ct_event!(key release CONTROL-'x')
2274 | ct_event!(key release CONTROL-'v')
2275 | ct_event!(key release CONTROL-'d')
2276 | ct_event!(key release CONTROL-'z')
2277 | ct_event!(key release CONTROL_SHIFT-'Z') => TextOutcome::Unchanged,
2278
2279 _ => TextOutcome::Continue,
2280 }
2281 } else {
2282 TextOutcome::Continue
2283 };
2284
2285 if r == TextOutcome::Continue {
2286 r = self.handle(event, ReadOnly);
2287 }
2288 r
2289 }
2290}
2291
2292impl HandleEvent<Event, ReadOnly, TextOutcome> for MaskedInputState {
2293 fn handle(&mut self, event: &Event, _keymap: ReadOnly) -> TextOutcome {
2294 fn clear_overwrite(state: &mut MaskedInputState) {
2295 state.overwrite.set(false);
2296 }
2297
2298 let mut r = if self.is_focused() {
2299 match event {
2300 ct_event!(keycode press Left) => {
2301 clear_overwrite(self);
2302 self.move_left(false).into()
2303 }
2304 ct_event!(keycode press Right) => {
2305 clear_overwrite(self);
2306 self.move_right(false).into()
2307 }
2308 ct_event!(keycode press CONTROL-Left) => {
2309 clear_overwrite(self);
2310 self.move_to_prev_section(false).into()
2311 }
2312 ct_event!(keycode press CONTROL-Right) => {
2313 clear_overwrite(self);
2314 self.move_to_next_section(false).into()
2315 }
2316 ct_event!(keycode press Home) => {
2317 clear_overwrite(self);
2318 self.move_to_line_start(false).into()
2319 }
2320 ct_event!(keycode press End) => {
2321 clear_overwrite(self);
2322 self.move_to_line_end(false).into()
2323 }
2324 ct_event!(keycode press SHIFT-Left) => {
2325 clear_overwrite(self);
2326 self.move_left(true).into()
2327 }
2328 ct_event!(keycode press SHIFT-Right) => {
2329 clear_overwrite(self);
2330 self.move_right(true).into()
2331 }
2332 ct_event!(keycode press CONTROL_SHIFT-Left) => {
2333 clear_overwrite(self);
2334 self.move_to_prev_section(true).into()
2335 }
2336 ct_event!(keycode press CONTROL_SHIFT-Right) => {
2337 clear_overwrite(self);
2338 self.move_to_next_section(true).into()
2339 }
2340 ct_event!(keycode press SHIFT-Home) => {
2341 clear_overwrite(self);
2342 self.move_to_line_start(true).into()
2343 }
2344 ct_event!(keycode press SHIFT-End) => {
2345 clear_overwrite(self);
2346 self.move_to_line_end(true).into()
2347 }
2348 ct_event!(key press CONTROL-'a') => {
2349 clear_overwrite(self);
2350 self.select_all().into()
2351 }
2352 ct_event!(key press CONTROL-'c') => {
2353 clear_overwrite(self);
2354 self.copy_to_clip().into()
2355 }
2356
2357 ct_event!(keycode release Left)
2358 | ct_event!(keycode release Right)
2359 | ct_event!(keycode release CONTROL-Left)
2360 | ct_event!(keycode release CONTROL-Right)
2361 | ct_event!(keycode release Home)
2362 | ct_event!(keycode release End)
2363 | ct_event!(keycode release SHIFT-Left)
2364 | ct_event!(keycode release SHIFT-Right)
2365 | ct_event!(keycode release CONTROL_SHIFT-Left)
2366 | ct_event!(keycode release CONTROL_SHIFT-Right)
2367 | ct_event!(keycode release SHIFT-Home)
2368 | ct_event!(keycode release SHIFT-End)
2369 | ct_event!(key release CONTROL-'a')
2370 | ct_event!(key release CONTROL-'c') => TextOutcome::Unchanged,
2371
2372 _ => TextOutcome::Continue,
2373 }
2374 } else {
2375 TextOutcome::Continue
2376 };
2377
2378 if r == TextOutcome::Continue {
2379 r = self.handle(event, MouseOnly);
2380 }
2381 r
2382 }
2383}
2384
2385impl HandleEvent<Event, MouseOnly, TextOutcome> for MaskedInputState {
2386 fn handle(&mut self, event: &Event, _keymap: MouseOnly) -> TextOutcome {
2387 fn clear_overwrite(state: &mut MaskedInputState) {
2388 state.overwrite.set(false);
2389 }
2390
2391 match event {
2392 ct_event!(mouse any for m) if self.mouse.drag(self.inner, m) => {
2393 let c = (m.column as i16) - (self.inner.x as i16);
2394 clear_overwrite(self);
2395 self.set_screen_cursor(c, true).into()
2396 }
2397 ct_event!(mouse any for m) if self.mouse.drag2(self.inner, m, KeyModifiers::ALT) => {
2398 let cx = m.column as i16 - self.inner.x as i16;
2399 clear_overwrite(self);
2400 self.set_screen_cursor_sections(cx, true).into()
2401 }
2402 ct_event!(mouse any for m) if self.mouse.doubleclick(self.inner, m) => {
2403 let tx = self.screen_to_col(m.column as i16 - self.inner.x as i16);
2404 clear_overwrite(self);
2405 if let Some(range) = self.section_range(tx) {
2406 self.set_selection(range.start, range.end).into()
2407 } else {
2408 TextOutcome::Unchanged
2409 }
2410 }
2411 ct_event!(mouse down Left for column,row) => {
2412 if self.gained_focus() {
2413 TextOutcome::Unchanged
2416 } else if self.inner.contains((*column, *row).into()) {
2417 let c = (column - self.inner.x) as i16;
2418 clear_overwrite(self);
2419 self.set_screen_cursor(c, false).into()
2420 } else {
2421 TextOutcome::Continue
2422 }
2423 }
2424 ct_event!(mouse down CONTROL-Left for column,row) => {
2425 if self.inner.contains((*column, *row).into()) {
2426 let cx = (column - self.inner.x) as i16;
2427 clear_overwrite(self);
2428 self.set_screen_cursor(cx, true).into()
2429 } else {
2430 TextOutcome::Continue
2431 }
2432 }
2433 ct_event!(mouse down ALT-Left for column,row) => {
2434 if self.inner.contains((*column, *row).into()) {
2435 let cx = (column - self.inner.x) as i16;
2436 clear_overwrite(self);
2437 self.set_screen_cursor_sections(cx, true).into()
2438 } else {
2439 TextOutcome::Continue
2440 }
2441 }
2442 _ => TextOutcome::Continue,
2443 }
2444 }
2445}
2446
2447pub fn handle_events(state: &mut MaskedInputState, focus: bool, event: &Event) -> TextOutcome {
2451 state.focus.set(focus);
2452 state.handle(event, Regular)
2453}
2454
2455pub fn handle_readonly_events(
2459 state: &mut TextInputState,
2460 focus: bool,
2461 event: &Event,
2462) -> TextOutcome {
2463 state.focus.set(focus);
2464 state.handle(event, ReadOnly)
2465}
2466
2467pub fn handle_mouse_events(state: &mut MaskedInputState, event: &Event) -> TextOutcome {
2469 state.handle(event, MouseOnly)
2470}