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 let mut z = 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.new_instance(),
573 mouse: Default::default(),
574 non_exhaustive: NonExhaustive,
575 };
576 z.focus = z.focus_cb(z.focus.clone());
577 z
578 }
579}
580
581impl Default for MaskedInputState {
582 fn default() -> Self {
583 let core = TextCore::new(
584 Some(Box::new(UndoVec::new(99))),
585 Some(Box::new(global_clipboard())),
586 );
587
588 let mut z = Self {
589 area: Default::default(),
590 inner: Default::default(),
591 rendered: Default::default(),
592 compact: Default::default(),
593 offset: Default::default(),
594 dark_offset: Default::default(),
595 scroll_to_cursor: Default::default(),
596 value: core,
597 sym: None,
598 mask: Default::default(),
599 invalid: Default::default(),
600 overwrite: Default::default(),
601 on_focus_gained: Default::default(),
602 on_focus_lost: Default::default(),
603 on_tab: Default::default(),
604 focus: Default::default(),
605 mouse: Default::default(),
606 non_exhaustive: NonExhaustive,
607 };
608 z.focus = z.focus_cb(FocusFlag::default());
609 z
610 }
611}
612
613impl MaskedInputState {
614 fn focus_cb(&self, flag: FocusFlag) -> FocusFlag {
615 let on_focus_lost = self.on_focus_lost.clone();
616 let cursor = self.value.shared_cursor();
617 let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
618 flag.on_lost(move || match on_focus_lost.get() {
619 TextFocusLost::None => {}
620 TextFocusLost::Position0 => {
621 scroll_cursor_to_visible.set(true);
622 let mut new_cursor = cursor.get();
623 new_cursor.cursor.x = 0;
624 new_cursor.anchor.x = 0;
625 cursor.set(new_cursor);
626 }
627 });
628 let on_focus_gained = self.on_focus_gained.clone();
629 let overwrite = self.overwrite.clone();
630 let cursor = self.value.shared_cursor();
631 let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
632 flag.on_gained(move || match on_focus_gained.get() {
633 TextFocusGained::None => {}
634 TextFocusGained::Overwrite => {
635 overwrite.set(true);
636 }
637 TextFocusGained::SelectAll => {
638 scroll_cursor_to_visible.set(true);
639 let mut new_cursor = cursor.get();
640 new_cursor.anchor = TextPosition::new(0, 0);
641 new_cursor.cursor = TextPosition::new(0, 1);
642 cursor.set(new_cursor);
643 }
644 });
645
646 flag
647 }
648}
649
650impl HasFocus for MaskedInputState {
651 fn build(&self, builder: &mut FocusBuilder) {
652 builder.leaf_widget(self);
653 }
654
655 fn focus(&self) -> FocusFlag {
656 self.focus.clone()
657 }
658
659 fn area(&self) -> Rect {
660 self.area
661 }
662
663 fn navigable(&self) -> Navigation {
664 if self.on_tab == TextTab::MoveToNextSection {
665 let sel = self.selection();
666
667 let has_next = self
668 .next_section_range(sel.end)
669 .map(|v| !v.is_empty())
670 .is_some();
671 let has_prev = self
672 .prev_section_range(sel.start.saturating_sub(1))
673 .map(|v| !v.is_empty())
674 .is_some();
675
676 if has_next {
677 if has_prev {
678 Navigation::Reach
679 } else {
680 Navigation::ReachLeaveFront
681 }
682 } else {
683 if has_prev {
684 Navigation::ReachLeaveBack
685 } else {
686 Navigation::Regular
687 }
688 }
689 } else {
690 Navigation::Regular
691 }
692 }
693}
694
695impl MaskedInputState {
696 pub fn new() -> Self {
697 Self::default()
698 }
699
700 pub fn named(name: &str) -> Self {
701 let mut z = Self::default();
702 z.focus = z.focus.with_name(name);
703 z
704 }
705
706 #[inline]
708 pub fn with_symbols(mut self, sym: NumberSymbols) -> Self {
709 self.set_num_symbols(sym);
710 self
711 }
712
713 pub fn with_mask<S: AsRef<str>>(mut self, mask: S) -> Result<Self, fmt::Error> {
715 self.set_mask(mask.as_ref())?;
716 Ok(self)
717 }
718
719 #[inline]
724 pub fn set_num_symbols(&mut self, sym: NumberSymbols) {
725 self.sym = Some(sym);
726 }
727
728 fn dec_sep(&self) -> char {
729 if let Some(sym) = &self.sym {
730 sym.decimal_sep
731 } else {
732 '.'
733 }
734 }
735
736 fn grp_sep(&self) -> char {
737 if let Some(sym) = &self.sym {
738 sym.decimal_grp.unwrap_or(' ')
742 } else {
743 ','
744 }
745 }
746
747 fn neg_sym(&self) -> char {
748 if let Some(sym) = &self.sym {
749 sym.negative_sym
750 } else {
751 '-'
752 }
753 }
754
755 fn pos_sym(&self) -> char {
756 if let Some(sym) = &self.sym {
757 sym.positive_sym
758 } else {
759 ' '
760 }
761 }
762
763 #[inline]
794 pub fn set_mask<S: AsRef<str>>(&mut self, s: S) -> Result<(), fmt::Error> {
795 self.mask = Self::parse_mask(s.as_ref())?;
796 self.clear();
797 Ok(())
798 }
799
800 #[allow(clippy::needless_range_loop)]
801 fn parse_mask(mask_str: &str) -> Result<Vec<MaskToken>, fmt::Error> {
802 let mut out = Vec::<MaskToken>::new();
803
804 let mut start_sub = 0;
805 let mut start_sec = 0;
806 let mut sec_id = 0;
807 let mut last_mask = Mask::None;
808 let mut dec_dir = EditDirection::Rtol;
809 let mut esc = false;
810 let mut idx = 0;
811 for m in mask_str.graphemes(true).chain(once("")) {
812 let mask = if esc {
813 esc = false;
814 Mask::Separator(Box::from(m))
815 } else {
816 match m {
817 "0" => Mask::Digit0(dec_dir),
818 "9" => Mask::Digit(dec_dir),
819 "#" => Mask::Numeric(dec_dir),
820 "." => Mask::DecimalSep,
821 "," => Mask::GroupingSep,
822 "-" => Mask::Sign,
823 "+" => Mask::Plus,
824 "h" => Mask::Hex,
825 "H" => Mask::Hex0,
826 "o" => Mask::Oct,
827 "O" => Mask::Oct0,
828 "d" => Mask::Dec,
829 "D" => Mask::Dec0,
830 "l" => Mask::Letter,
831 "a" => Mask::LetterOrDigit,
832 "c" => Mask::LetterDigitSpace,
833 "_" => Mask::AnyChar,
834 "" => Mask::None,
835 " " => Mask::Separator(Box::from(m)),
836 "\\" => {
837 esc = true;
838 continue;
839 }
840 _ => return Err(fmt::Error),
841 }
842 };
843
844 match mask {
845 Mask::Digit0(_)
846 | Mask::Digit(_)
847 | Mask::Numeric(_)
848 | Mask::GroupingSep
849 | Mask::Sign
850 | Mask::Plus => {
851 }
853 Mask::DecimalSep => {
854 dec_dir = EditDirection::Ltor;
855 }
856 Mask::Hex0
857 | Mask::Hex
858 | Mask::Oct0
859 | Mask::Oct
860 | Mask::Dec0
861 | Mask::Dec
862 | Mask::Letter
863 | Mask::LetterOrDigit
864 | Mask::LetterDigitSpace
865 | Mask::AnyChar
866 | Mask::Separator(_) => {
867 dec_dir = EditDirection::Rtol
869 }
870 Mask::None => {
871 }
873 }
874
875 if matches!(mask, Mask::Separator(_)) || mask.section() != last_mask.section() {
876 for j in start_sec..idx {
877 out[j].sec_id = sec_id;
878 out[j].sec_start = start_sec as upos_type;
879 out[j].sec_end = idx as upos_type;
880 }
881 sec_id += 1;
882 start_sec = idx;
883 }
884 if matches!(mask, Mask::Separator(_)) || mask.sub_section() != last_mask.sub_section() {
885 for j in start_sub..idx {
886 out[j].sub_start = start_sub as upos_type;
887 out[j].sub_end = idx as upos_type;
888 }
889 start_sub = idx;
890 }
891
892 let tok = MaskToken {
893 sec_id: 0,
894 sec_start: 0,
895 sec_end: 0,
896 sub_start: 0,
897 sub_end: 0,
898 peek_left: last_mask,
899 right: mask.clone(),
900 edit: mask.edit_value().into(),
901 };
902 out.push(tok);
903
904 idx += 1;
905 last_mask = mask;
906 }
907 for j in start_sec..out.len() {
908 out[j].sec_id = sec_id;
909 out[j].sec_start = start_sec as upos_type;
910 out[j].sec_end = mask_str.graphemes(true).count() as upos_type;
911 }
912 for j in start_sub..out.len() {
913 out[j].sub_start = start_sub as upos_type;
914 out[j].sub_end = mask_str.graphemes(true).count() as upos_type;
915 }
916
917 Ok(out)
918 }
919
920 #[inline]
922 pub fn mask(&self) -> String {
923 use std::fmt::Write;
924
925 let mut buf = String::new();
926 for t in self.mask.iter() {
927 _ = write!(buf, "{}", t.right);
928 }
929 buf
930 }
931
932 #[inline]
934 pub fn set_invalid(&mut self, invalid: bool) {
935 self.invalid = invalid;
936 }
937
938 #[inline]
940 pub fn get_invalid(&self) -> bool {
941 self.invalid
942 }
943
944 #[inline]
948 pub fn set_overwrite(&mut self, overwrite: bool) {
949 self.overwrite.set(overwrite);
950 }
951
952 #[inline]
954 pub fn overwrite(&self) -> bool {
955 self.overwrite.get()
956 }
957}
958
959impl MaskedInputState {
960 #[inline]
963 pub fn set_clipboard(&mut self, clip: Option<impl Clipboard + 'static>) {
964 self.value.set_clipboard(clip.map(|v| {
965 let r: Box<dyn Clipboard> = Box::new(v);
966 r
967 }));
968 }
969
970 #[inline]
973 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
974 self.value.clipboard()
975 }
976
977 #[inline]
979 pub fn copy_to_clip(&mut self) -> bool {
980 let Some(clip) = self.value.clipboard() else {
981 return false;
982 };
983
984 _ = clip.set_string(self.selected_text().as_ref());
985
986 true
987 }
988
989 #[inline]
991 pub fn cut_to_clip(&mut self) -> bool {
992 let Some(clip) = self.value.clipboard() else {
993 return false;
994 };
995
996 match clip.set_string(self.selected_text().as_ref()) {
997 Ok(_) => self.delete_range(self.selection()),
998 Err(_) => true,
999 }
1000 }
1001
1002 #[inline]
1004 pub fn paste_from_clip(&mut self) -> bool {
1005 let Some(clip) = self.value.clipboard() else {
1006 return false;
1007 };
1008
1009 if let Ok(text) = clip.get_string() {
1010 for c in text.chars() {
1011 self.insert_char(c);
1012 }
1013 true
1014 } else {
1015 false
1016 }
1017 }
1018}
1019
1020impl MaskedInputState {
1021 #[inline]
1023 pub fn set_undo_buffer(&mut self, undo: Option<impl UndoBuffer + 'static>) {
1024 self.value.set_undo_buffer(undo.map(|v| {
1025 let r: Box<dyn UndoBuffer> = Box::new(v);
1026 r
1027 }));
1028 }
1029
1030 #[inline]
1032 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
1033 self.value.undo_buffer()
1034 }
1035
1036 #[inline]
1038 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
1039 self.value.undo_buffer_mut()
1040 }
1041
1042 #[inline]
1044 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
1045 self.value.recent_replay_log()
1046 }
1047
1048 #[inline]
1050 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
1051 self.value.replay_log(replay)
1052 }
1053
1054 #[inline]
1056 pub fn begin_undo_seq(&mut self) {
1057 self.value.begin_undo_seq();
1058 }
1059
1060 #[inline]
1062 pub fn end_undo_seq(&mut self) {
1063 self.value.end_undo_seq();
1064 }
1065
1066 #[inline]
1068 pub fn undo(&mut self) -> bool {
1069 self.value.undo()
1070 }
1071
1072 #[inline]
1074 pub fn redo(&mut self) -> bool {
1075 self.value.redo()
1076 }
1077}
1078
1079impl MaskedInputState {
1080 #[inline]
1082 pub fn clear_styles(&mut self) {
1083 self.value.set_styles(Vec::default());
1084 }
1085
1086 #[inline]
1088 pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
1089 self.value.set_styles(styles);
1090 }
1091
1092 #[inline]
1095 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
1096 self.value.add_style(range, style);
1097 }
1098
1099 #[inline]
1102 pub fn add_range_style(
1103 &mut self,
1104 range: Range<upos_type>,
1105 style: usize,
1106 ) -> Result<(), TextError> {
1107 let r = self
1108 .value
1109 .bytes_at_range(TextRange::from((range.start, 0)..(range.end, 0)))?;
1110 self.value.add_style(r, style);
1111 Ok(())
1112 }
1113
1114 #[inline]
1116 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
1117 self.value.remove_style(range, style);
1118 }
1119
1120 #[inline]
1122 pub fn remove_range_style(
1123 &mut self,
1124 range: Range<upos_type>,
1125 style: usize,
1126 ) -> Result<(), TextError> {
1127 let r = self
1128 .value
1129 .bytes_at_range(TextRange::from((range.start, 0)..(range.end, 0)))?;
1130 self.value.remove_style(r, style);
1131 Ok(())
1132 }
1133
1134 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
1136 self.value.styles_in(range, buf)
1137 }
1138
1139 #[inline]
1141 pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
1142 self.value.styles_at(byte_pos, buf)
1143 }
1144
1145 #[inline]
1148 pub fn styles_at_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
1149 self.value.styles_at_match(byte_pos, style)
1150 }
1151
1152 #[inline]
1154 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
1155 self.value.styles()
1156 }
1157}
1158
1159impl MaskedInputState {
1160 #[inline]
1162 pub fn offset(&self) -> upos_type {
1163 self.offset
1164 }
1165
1166 #[inline]
1168 pub fn set_offset(&mut self, offset: upos_type) {
1169 self.scroll_to_cursor.set(false);
1170 self.offset = offset;
1171 }
1172
1173 #[inline]
1175 pub fn cursor(&self) -> upos_type {
1176 self.value.cursor().x
1177 }
1178
1179 #[inline]
1182 pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
1183 self.scroll_cursor_to_visible();
1184 self.value
1185 .set_cursor(TextPosition::new(cursor, 0), extend_selection)
1186 }
1187
1188 fn number_cursor(&self, range: Range<upos_type>) -> upos_type {
1190 for (i, t) in self.mask[range.start as usize..range.end as usize]
1191 .iter()
1192 .enumerate()
1193 .rev()
1194 {
1195 match t.right {
1196 Mask::Digit(EditDirection::Rtol)
1197 | Mask::Digit0(EditDirection::Rtol)
1198 | Mask::Numeric(EditDirection::Rtol) => {
1199 return range.start + i as upos_type + 1;
1200 }
1201 _ => {}
1202 }
1203 }
1204 range.start
1205 }
1206
1207 pub fn section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1210 if cursor as usize >= self.mask.len() {
1211 return None;
1212 }
1213
1214 let mask = &self.mask[cursor as usize];
1215
1216 if mask.right.is_number() {
1217 Some(self.number_cursor(mask.sec_start..mask.sec_end))
1218 } else if mask.right.is_separator() {
1219 None
1220 } else if mask.right.is_none() {
1221 None
1222 } else {
1223 Some(mask.sec_start)
1224 }
1225 }
1226
1227 pub fn next_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1229 if cursor as usize >= self.mask.len() {
1230 return None;
1231 }
1232
1233 let mut mask = &self.mask[cursor as usize];
1234 let mut next;
1235 loop {
1236 if mask.right.is_none() {
1237 return None;
1238 }
1239
1240 next = mask.sec_end;
1241 mask = &self.mask[next as usize];
1242
1243 if mask.right.is_number() {
1244 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
1245 } else if mask.right.is_separator() {
1246 continue;
1247 } else if mask.right.is_none() {
1248 return None;
1249 } else {
1250 return Some(mask.sec_start);
1251 }
1252 }
1253 }
1254
1255 pub fn prev_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1257 if cursor as usize >= self.mask.len() {
1258 return None;
1259 }
1260
1261 let mut prev = self.mask[cursor as usize].sec_start;
1262 let mut mask = &self.mask[prev as usize];
1263
1264 loop {
1265 if mask.peek_left.is_none() {
1266 return None;
1267 }
1268
1269 prev = self.mask[mask.sec_start as usize - 1].sec_start;
1270 mask = &self.mask[prev as usize];
1271
1272 if mask.right.is_number() {
1273 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
1274 } else if mask.right.is_separator() {
1275 continue;
1276 } else {
1277 return Some(mask.sec_start);
1278 }
1279 }
1280 }
1281
1282 pub fn is_section_boundary(&self, pos: upos_type) -> bool {
1284 if pos == 0 {
1285 return false;
1286 }
1287 if pos as usize >= self.mask.len() {
1288 return false;
1289 }
1290 let prev = &self.mask[pos as usize - 1];
1291 let mask = &self.mask[pos as usize];
1292 prev.sec_id != mask.sec_id
1293 }
1294
1295 pub fn section_id(&self, cursor: upos_type) -> u16 {
1297 let mask = &self.mask[cursor as usize];
1298 if mask.peek_left.is_rtol() && (mask.right.is_ltor() || mask.right.is_none()) {
1299 self.mask[cursor.saturating_sub(1) as usize].sec_id
1300 } else {
1301 mask.sec_id
1302 }
1303 }
1304
1305 pub fn section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1308 if cursor as usize >= self.mask.len() {
1309 return None;
1310 }
1311
1312 let mask = &self.mask[cursor as usize];
1313 if mask.right.is_number() {
1314 Some(mask.sec_start..mask.sec_end)
1315 } else if mask.right.is_separator() {
1316 None
1317 } else if mask.right.is_none() {
1318 None
1319 } else {
1320 Some(mask.sec_start..mask.sec_end)
1321 }
1322 }
1323
1324 pub fn next_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1326 if cursor as usize >= self.mask.len() {
1327 return None;
1328 }
1329
1330 let mut mask = &self.mask[cursor as usize];
1331 let mut next;
1332 loop {
1333 if mask.right.is_none() {
1334 return None;
1335 }
1336
1337 next = mask.sec_end;
1338 mask = &self.mask[next as usize];
1339
1340 if mask.right.is_number() {
1341 return Some(mask.sec_start..mask.sec_end);
1342 } else if mask.right.is_separator() {
1343 continue;
1344 } else if mask.right.is_none() {
1345 return None;
1346 } else {
1347 return Some(mask.sec_start..mask.sec_end);
1348 }
1349 }
1350 }
1351
1352 pub fn prev_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1354 if cursor as usize >= self.mask.len() {
1355 return None;
1356 }
1357
1358 let mut prev = self.mask[cursor as usize].sec_start;
1359 let mut mask = &self.mask[prev as usize];
1360 loop {
1361 if mask.peek_left.is_none() {
1362 return None;
1363 }
1364
1365 prev = self.mask[mask.sec_start as usize - 1].sec_start;
1366 mask = &self.mask[prev as usize];
1367
1368 if mask.right.is_number() {
1369 return Some(mask.sec_start..mask.sec_end);
1370 } else if mask.right.is_separator() {
1371 continue;
1372 } else {
1373 return Some(mask.sec_start..mask.sec_end);
1374 }
1375 }
1376 }
1377
1378 #[inline]
1382 pub fn set_default_cursor(&mut self) {
1383 self.scroll_cursor_to_visible();
1384 if let Some(pos) = self.section_cursor(0) {
1385 self.value.set_cursor(TextPosition::new(pos, 0), false);
1386 } else if let Some(pos) = self.next_section_cursor(0) {
1387 self.value.set_cursor(TextPosition::new(pos, 0), false);
1388 } else {
1389 self.value.set_cursor(TextPosition::new(0, 0), false);
1390 }
1391 }
1392
1393 #[inline]
1395 pub fn anchor(&self) -> upos_type {
1396 self.value.anchor().x
1397 }
1398
1399 #[inline]
1401 pub fn has_selection(&self) -> bool {
1402 self.value.has_selection()
1403 }
1404
1405 #[inline]
1407 pub fn selection(&self) -> Range<upos_type> {
1408 let mut v = self.value.selection();
1409 if v.start == TextPosition::new(0, 1) {
1410 v.start = TextPosition::new(self.line_width(), 0);
1411 }
1412 if v.end == TextPosition::new(0, 1) {
1413 v.end = TextPosition::new(self.line_width(), 0);
1414 }
1415 v.start.x..v.end.x
1416 }
1417
1418 #[inline]
1421 pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
1422 self.scroll_cursor_to_visible();
1423 self.value
1424 .set_selection(TextPosition::new(anchor, 0), TextPosition::new(cursor, 0))
1425 }
1426
1427 #[inline]
1430 pub fn select_all(&mut self) -> bool {
1431 self.scroll_cursor_to_visible();
1432 if let Some(section) = self.section_range(self.cursor()) {
1433 if self.selection() == section {
1434 self.value.select_all()
1435 } else {
1436 self.value.set_selection(
1437 TextPosition::new(section.start, 0),
1438 TextPosition::new(section.end, 0),
1439 )
1440 }
1441 } else {
1442 self.value.select_all()
1443 }
1444 }
1445
1446 #[inline]
1448 pub fn selected_text(&self) -> &str {
1449 match self
1450 .value
1451 .str_slice(self.value.selection())
1452 .expect("valid_range")
1453 {
1454 Cow::Borrowed(v) => v,
1455 Cow::Owned(_) => {
1456 unreachable!()
1457 }
1458 }
1459 }
1460}
1461
1462impl MaskedInputState {
1463 #[inline]
1465 pub fn is_empty(&self) -> bool {
1466 self.value.text().as_str() == self.default_value()
1467 }
1468
1469 #[inline]
1471 pub fn text(&self) -> &str {
1472 self.value.text().as_str()
1473 }
1474
1475 #[inline]
1477 pub fn value<T: FromStr>(&self) -> Result<T, <T as FromStr>::Err> {
1478 self.value.text().as_str().parse::<T>()
1479 }
1480
1481 #[inline]
1487 pub fn section_value<T: FromStr>(&self, section: u16) -> Result<T, <T as FromStr>::Err> {
1488 self.section_text(section).trim().parse::<T>()
1489 }
1490
1491 #[inline]
1497 pub fn set_section_value<T: ToString>(&mut self, section: u16, value: T) {
1498 let mut len = None;
1499 let mut align_left = true;
1500 for mask in &self.mask {
1501 if mask.sec_id == section {
1502 len = Some((mask.sec_end - mask.sec_start) as usize);
1503 align_left = !mask.right.is_rtol();
1504 break;
1505 }
1506 }
1507 if let Some(len) = len {
1508 let txt = if align_left {
1509 format!("{:1$}", value.to_string(), len)
1510 } else {
1511 format!("{:>1$}", value.to_string(), len)
1512 };
1513 self.set_section_text(section, txt);
1514 } else {
1515 panic!("invalid section {}", section);
1516 }
1517 }
1518
1519 #[inline]
1525 pub fn section_text(&self, section: u16) -> &str {
1526 for v in &self.mask {
1527 if v.sec_id == section {
1528 match self.str_slice(v.sec_start..v.sec_end) {
1529 Cow::Borrowed(s) => return s,
1530 Cow::Owned(_) => {
1531 unreachable!("should not be owned")
1532 }
1533 };
1534 }
1535 }
1536 panic!("invalid section {}", section);
1537 }
1538
1539 pub fn set_section_text<S: Into<String>>(&mut self, section: u16, txt: S) {
1542 let mut txt = txt.into();
1543 for v in &self.mask {
1544 if v.sec_id == section {
1545 let len = (v.sec_end - v.sec_start) as usize;
1546 while txt.graphemes(true).count() > len {
1547 txt.pop();
1548 }
1549 while txt.graphemes(true).count() < len {
1550 txt.push(' ');
1551 }
1552 assert_eq!(txt.graphemes(true).count(), len);
1553
1554 self.value.begin_undo_seq();
1555 self.value
1556 .remove_str_range(TextRange::from(
1557 TextPosition::new(v.sec_start, 0)..TextPosition::new(v.sec_end, 0),
1558 ))
1559 .expect("valid-range");
1560 self.value
1561 .insert_str(TextPosition::new(v.sec_start, 0), txt.as_str())
1562 .expect("valid-range");
1563 self.value.end_undo_seq();
1564 return;
1565 }
1566 }
1567 panic!("invalid section {}", section);
1568 }
1569
1570 #[inline]
1572 pub fn str_slice_byte(&self, range: Range<usize>) -> Cow<'_, str> {
1573 self.value.str_slice_byte(range).expect("valid_range")
1574 }
1575
1576 #[inline]
1578 pub fn try_str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
1579 self.value.str_slice_byte(range)
1580 }
1581
1582 #[inline]
1584 pub fn str_slice(&self, range: Range<upos_type>) -> Cow<'_, str> {
1585 self.value
1586 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1587 .expect("valid_range")
1588 }
1589
1590 #[inline]
1592 pub fn try_str_slice(&self, range: Range<upos_type>) -> Result<Cow<'_, str>, TextError> {
1593 self.value
1594 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1595 }
1596
1597 #[inline]
1599 pub fn len(&self) -> upos_type {
1600 self.value.line_width(0).expect("valid_row")
1601 }
1602
1603 #[inline]
1605 pub fn len_bytes(&self) -> usize {
1606 self.value.len_bytes()
1607 }
1608
1609 #[inline]
1611 pub fn line_width(&self) -> upos_type {
1612 self.value.line_width(0).expect("valid_row")
1613 }
1614
1615 #[inline]
1617 pub fn grapheme_at(&self, pos: upos_type) -> Result<Option<Grapheme<'_>>, TextError> {
1618 self.value.grapheme_at(TextPosition::new(pos, 0))
1619 }
1620
1621 #[inline]
1623 pub fn text_graphemes(&self, pos: upos_type) -> <TextString as TextStore>::GraphemeIter<'_> {
1624 self.try_text_graphemes(pos).expect("valid_pos")
1625 }
1626
1627 #[inline]
1629 pub fn try_text_graphemes(
1630 &self,
1631 pos: upos_type,
1632 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1633 self.value.text_graphemes(TextPosition::new(pos, 0))
1634 }
1635
1636 #[inline]
1638 pub fn graphemes(
1639 &self,
1640 range: Range<upos_type>,
1641 pos: upos_type,
1642 ) -> <TextString as TextStore>::GraphemeIter<'_> {
1643 self.try_graphemes(range, pos).expect("valid_args")
1644 }
1645
1646 #[inline]
1648 pub fn try_graphemes(
1649 &self,
1650 range: Range<upos_type>,
1651 pos: upos_type,
1652 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1653 self.value.graphemes(
1654 TextRange::new((range.start, 0), (range.end, 0)),
1655 TextPosition::new(pos, 0),
1656 )
1657 }
1658
1659 #[inline]
1662 pub fn byte_at(&self, pos: upos_type) -> Range<usize> {
1663 self.try_byte_at(pos).expect("valid_pos")
1664 }
1665
1666 #[inline]
1669 pub fn try_byte_at(&self, pos: upos_type) -> Result<Range<usize>, TextError> {
1670 self.value.byte_at(TextPosition::new(pos, 0))
1671 }
1672
1673 #[inline]
1675 pub fn bytes_at_range(&self, range: Range<upos_type>) -> Range<usize> {
1676 self.try_bytes_at_range(range).expect("valid_range")
1677 }
1678
1679 #[inline]
1681 pub fn try_bytes_at_range(&self, range: Range<upos_type>) -> Result<Range<usize>, TextError> {
1682 self.value
1683 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1684 }
1685
1686 #[inline]
1689 pub fn byte_pos(&self, byte: usize) -> upos_type {
1690 self.try_byte_pos(byte).expect("valid_pos")
1691 }
1692
1693 #[inline]
1696 pub fn try_byte_pos(&self, byte: usize) -> Result<upos_type, TextError> {
1697 Ok(self.value.byte_pos(byte)?.x)
1698 }
1699
1700 #[inline]
1702 pub fn byte_range(&self, bytes: Range<usize>) -> Range<upos_type> {
1703 self.try_byte_range(bytes).expect("valid_range")
1704 }
1705
1706 #[inline]
1708 pub fn try_byte_range(&self, bytes: Range<usize>) -> Result<Range<upos_type>, TextError> {
1709 let r = self.value.byte_range(bytes)?;
1710 Ok(r.start.x..r.end.x)
1711 }
1712}
1713
1714impl MaskedInputState {
1715 #[inline]
1717 fn default_value(&self) -> String {
1718 MaskToken::empty_section(&self.mask)
1719 }
1720
1721 #[inline]
1723 pub fn clear(&mut self) -> bool {
1724 if self.is_empty() {
1725 false
1726 } else {
1727 self.offset = 0;
1728 self.value
1729 .set_text(TextString::new_string(self.default_value()));
1730 self.set_default_cursor();
1731 true
1732 }
1733 }
1734
1735 #[inline]
1738 pub fn set_value<S: ToString>(&mut self, s: S) {
1739 self.set_text(s.to_string());
1740 }
1741
1742 #[inline]
1750 pub fn set_text<S: Into<String>>(&mut self, s: S) {
1751 self.offset = 0;
1752 let mut text = s.into();
1753 while text.graphemes(true).count() > self.mask.len().saturating_sub(1) {
1754 text.pop();
1755 }
1756 while text.graphemes(true).count() < self.mask.len().saturating_sub(1) {
1757 text.push(' ');
1758 }
1759 let len = text.graphemes(true).count();
1760
1761 assert_eq!(len, self.mask.len().saturating_sub(1));
1762
1763 self.value.set_text(TextString::new_string(text));
1764 self.set_default_cursor();
1765 }
1766
1767 #[inline]
1769 pub fn insert_char(&mut self, c: char) -> bool {
1770 self.begin_undo_seq();
1771 if self.has_selection() {
1772 let sel = self.selection();
1773 mask_op::remove_range(self, sel.clone()).expect("valid_selection");
1774 self.set_cursor(sel.start, false);
1775 }
1776 let c0 = mask_op::advance_cursor(self, c);
1777 let c1 = mask_op::insert_char(self, c);
1778 self.end_undo_seq();
1779
1780 self.scroll_cursor_to_visible();
1781 c0 || c1
1782 }
1783
1784 #[inline]
1787 pub fn delete_range(&mut self, range: Range<upos_type>) -> bool {
1788 self.try_delete_range(range).expect("valid_range")
1789 }
1790
1791 #[inline]
1794 pub fn try_delete_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
1795 self.value.begin_undo_seq();
1796 let r = mask_op::remove_range(self, range.clone())?;
1797 if let Some(pos) = self.section_cursor(range.start) {
1798 self.set_cursor(pos, false);
1799 }
1800 self.value.end_undo_seq();
1801
1802 self.scroll_cursor_to_visible();
1803 Ok(r)
1804 }
1805}
1806
1807impl MaskedInputState {
1808 #[inline]
1810 pub fn delete_next_char(&mut self) -> bool {
1811 if self.has_selection() {
1812 self.delete_range(self.selection())
1813 } else if self.cursor() == self.len() {
1814 false
1815 } else {
1816 mask_op::remove_next(self);
1817 self.scroll_cursor_to_visible();
1818 true
1819 }
1820 }
1821
1822 #[inline]
1824 pub fn delete_prev_char(&mut self) -> bool {
1825 if self.has_selection() {
1826 self.delete_range(self.selection())
1827 } else if self.cursor() == 0 {
1828 false
1829 } else {
1830 mask_op::remove_prev(self);
1831 self.scroll_cursor_to_visible();
1832 true
1833 }
1834 }
1835
1836 #[inline]
1838 pub fn delete_prev_section(&mut self) -> bool {
1839 if self.has_selection() {
1840 self.delete_range(self.selection())
1841 } else {
1842 if let Some(range) = self.prev_section_range(self.cursor()) {
1843 self.delete_range(range)
1844 } else {
1845 false
1846 }
1847 }
1848 }
1849
1850 #[inline]
1852 pub fn delete_next_section(&mut self) -> bool {
1853 if self.has_selection() {
1854 self.delete_range(self.selection())
1855 } else {
1856 if let Some(range) = self.next_section_range(self.cursor()) {
1857 self.delete_range(range)
1858 } else {
1859 false
1860 }
1861 }
1862 }
1863
1864 #[inline]
1866 pub fn move_right(&mut self, extend_selection: bool) -> bool {
1867 let c = min(self.cursor() + 1, self.len());
1868 self.set_cursor(c, extend_selection)
1869 }
1870
1871 #[inline]
1873 pub fn move_left(&mut self, extend_selection: bool) -> bool {
1874 let c = self.cursor().saturating_sub(1);
1875 self.set_cursor(c, extend_selection)
1876 }
1877
1878 #[inline]
1880 pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1881 if let Some(c) = self.section_cursor(self.cursor()) {
1882 if c != self.cursor() {
1883 self.set_cursor(c, extend_selection)
1884 } else {
1885 self.set_cursor(0, extend_selection)
1886 }
1887 } else {
1888 self.set_cursor(0, extend_selection)
1889 }
1890 }
1891
1892 #[inline]
1894 pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
1895 self.set_cursor(self.len(), extend_selection)
1896 }
1897
1898 #[inline]
1900 pub fn move_to_prev_section(&mut self, extend_selection: bool) -> bool {
1901 if let Some(curr) = self.section_range(self.cursor()) {
1902 if self.cursor() != curr.start {
1903 return self.set_cursor(curr.start, extend_selection);
1904 }
1905 }
1906 if let Some(range) = self.prev_section_range(self.cursor()) {
1907 self.set_cursor(range.start, extend_selection)
1908 } else {
1909 false
1910 }
1911 }
1912
1913 #[inline]
1915 pub fn move_to_next_section(&mut self, extend_selection: bool) -> bool {
1916 if let Some(curr) = self.section_range(self.cursor()) {
1917 if self.cursor() != curr.end {
1918 return self.set_cursor(curr.end, extend_selection);
1919 }
1920 }
1921 if let Some(range) = self.next_section_range(self.cursor()) {
1922 self.set_cursor(range.end, extend_selection)
1923 } else {
1924 false
1925 }
1926 }
1927
1928 #[inline]
1930 pub fn select_current_section(&mut self) -> bool {
1931 let selection = self.selection();
1932
1933 if let Some(next) = self.section_range(selection.start.saturating_sub(1)) {
1934 if !next.is_empty() {
1935 self.set_selection(next.start, next.end)
1936 } else {
1937 false
1938 }
1939 } else {
1940 false
1941 }
1942 }
1943
1944 #[inline]
1946 pub fn select_next_section(&mut self) -> bool {
1947 let selection = self.selection();
1948
1949 if let Some(next) = self.next_section_range(selection.start) {
1950 if !next.is_empty() {
1951 self.set_selection(next.start, next.end)
1952 } else {
1953 false
1954 }
1955 } else {
1956 false
1957 }
1958 }
1959
1960 #[inline]
1962 pub fn select_prev_section(&mut self) -> bool {
1963 let selection = self.selection();
1964
1965 if let Some(next) = self.prev_section_range(selection.start.saturating_sub(1)) {
1966 if !next.is_empty() {
1967 self.set_selection(next.start, next.end)
1968 } else {
1969 false
1970 }
1971 } else {
1972 false
1973 }
1974 }
1975}
1976
1977impl HasScreenCursor for MaskedInputState {
1978 #[inline]
1980 fn screen_cursor(&self) -> Option<(u16, u16)> {
1981 if self.is_focused() {
1982 if self.has_selection() {
1983 None
1984 } else {
1985 let cx = self.cursor();
1986 let ox = self.offset();
1987
1988 if cx < ox {
1989 None
1990 } else if cx > ox + (self.inner.width + self.dark_offset.0) as upos_type {
1991 None
1992 } else {
1993 self.col_to_screen(cx)
1994 .map(|sc| (self.inner.x + sc, self.inner.y))
1995 }
1996 }
1997 } else {
1998 None
1999 }
2000 }
2001}
2002
2003impl RelocatableState for MaskedInputState {
2004 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
2005 self.area.relocate(shift, clip);
2006 self.inner.relocate(shift, clip);
2007 self.dark_offset = relocate_dark_offset(self.inner, shift, clip);
2009 }
2010}
2011
2012impl MaskedInputState {
2013 fn glyphs2(&self) -> impl Iterator<Item = Glyph2<'_>> {
2014 let left_margin = self.offset();
2015 let right_margin = self.offset() + self.rendered.width as upos_type;
2016 let compact = self.compact && !self.is_focused();
2017
2018 let grapheme_iter = self
2019 .value
2020 .graphemes(TextRange::new((0, 0), (0, 1)), TextPosition::new(0, 0))
2021 .expect("valid-rows");
2022 let mask_iter = self.mask.iter();
2023
2024 let iter = MaskedGraphemes {
2025 iter_str: grapheme_iter,
2026 iter_mask: mask_iter,
2027 compact,
2028 sym_neg: self.neg_sym().to_string(),
2029 sym_dec: self.dec_sep().to_string(),
2030 sym_grp: self.grp_sep().to_string(),
2031 sym_pos: self.pos_sym().to_string(),
2032 byte_pos: 0,
2033 };
2034
2035 let mut it = GlyphIter2::new(TextPosition::new(0, 0), 0, iter, Default::default());
2036 it.set_tabs(0 );
2037 it.set_show_ctrl(self.value.glyph_ctrl());
2038 it.set_lf_breaks(false);
2039 it.set_text_wrap(TextWrap2::Shift);
2040 it.set_left_margin(left_margin);
2041 it.set_right_margin(right_margin);
2042 it.set_word_margin(right_margin);
2043 it.prepare().expect("valid-rows");
2044
2045 Box::new(it)
2046 }
2047
2048 pub fn screen_to_col(&self, scx: i16) -> upos_type {
2051 let ox = self.offset();
2052
2053 let scx = scx + self.dark_offset.0 as i16;
2054
2055 if scx < 0 {
2056 ox.saturating_sub((scx as ipos_type).unsigned_abs())
2057 } else if scx as u16 >= (self.inner.width + self.dark_offset.0) {
2058 min(ox + scx as upos_type, self.len())
2059 } else {
2060 let scx = scx as u16;
2061
2062 let line = self.glyphs2();
2063
2064 let mut col = ox;
2065 for g in line {
2066 if g.contains_screen_x(scx) {
2067 break;
2068 }
2069 col = g.pos().x + 1;
2070 }
2071 col
2072 }
2073 }
2074
2075 pub fn col_to_screen(&self, pos: upos_type) -> Option<u16> {
2078 let ox = self.offset();
2079
2080 if pos < ox {
2081 return None;
2082 }
2083
2084 let line = self.glyphs2();
2085 let mut screen_x = 0;
2086 for g in line {
2087 if g.pos().x == pos {
2088 break;
2089 }
2090 screen_x = g.screen_pos().0 + g.screen_width();
2091 }
2092
2093 if screen_x >= self.dark_offset.0 {
2094 Some(screen_x - self.dark_offset.0)
2095 } else {
2096 None
2097 }
2098 }
2099
2100 #[inline]
2104 pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
2105 let scx = cursor;
2106
2107 let cx = self.screen_to_col(scx);
2108
2109 self.set_cursor(cx, extend_selection)
2110 }
2111
2112 pub fn set_screen_cursor_sections(
2119 &mut self,
2120 screen_cursor: i16,
2121 extend_selection: bool,
2122 ) -> bool {
2123 let anchor = self.anchor();
2124 let cursor = self.screen_to_col(screen_cursor);
2125
2126 let Some(range) = self.section_range(cursor) else {
2127 return false;
2128 };
2129
2130 let cursor = if cursor < anchor {
2131 range.start
2132 } else {
2133 range.end
2134 };
2135
2136 if !self.is_section_boundary(anchor) {
2138 if let Some(range) = self.section_range(anchor) {
2139 if cursor < anchor {
2140 self.set_cursor(range.end, false);
2141 } else {
2142 self.set_cursor(range.start, false);
2143 }
2144 };
2145 }
2146
2147 self.set_cursor(cursor, extend_selection)
2148 }
2149
2150 pub fn scroll_left(&mut self, delta: upos_type) -> bool {
2152 self.set_offset(self.offset.saturating_sub(delta));
2153 true
2154 }
2155
2156 pub fn scroll_right(&mut self, delta: upos_type) -> bool {
2158 self.set_offset(self.offset + delta);
2159 true
2160 }
2161
2162 pub fn scroll_cursor_to_visible(&mut self) {
2164 self.scroll_to_cursor.set(true);
2165 }
2166}
2167
2168impl HandleEvent<Event, Regular, TextOutcome> for MaskedInputState {
2169 fn handle(&mut self, event: &Event, _keymap: Regular) -> TextOutcome {
2170 fn tc(r: bool) -> TextOutcome {
2172 if r {
2173 TextOutcome::TextChanged
2174 } else {
2175 TextOutcome::Unchanged
2176 }
2177 }
2178 fn overwrite(state: &mut MaskedInputState) {
2179 if state.overwrite.get() {
2180 state.overwrite.set(false);
2181 state.delete_range(0..state.len());
2182 }
2183 }
2184 fn clear_overwrite(state: &mut MaskedInputState) {
2185 state.overwrite.set(false);
2186 }
2187
2188 let mut r = if self.is_focused() {
2189 match event {
2190 ct_event!(key press c)
2191 | ct_event!(key press SHIFT-c)
2192 | ct_event!(key press CONTROL_ALT-c) => {
2193 overwrite(self);
2194 tc(self.insert_char(*c))
2195 }
2196 ct_event!(keycode press Backspace) | ct_event!(keycode press SHIFT-Backspace) => {
2197 clear_overwrite(self);
2198 tc(self.delete_prev_char())
2199 }
2200 ct_event!(keycode press Delete) | ct_event!(keycode press SHIFT-Delete) => {
2201 clear_overwrite(self);
2202 tc(self.delete_next_char())
2203 }
2204 ct_event!(keycode press CONTROL-Backspace)
2205 | ct_event!(keycode press ALT-Backspace) => {
2206 clear_overwrite(self);
2207 tc(self.delete_prev_section())
2208 }
2209 ct_event!(keycode press CONTROL-Delete) => {
2210 clear_overwrite(self);
2211 tc(self.delete_next_section())
2212 }
2213 ct_event!(key press CONTROL-'x') => {
2214 clear_overwrite(self);
2215 tc(self.cut_to_clip())
2216 }
2217 ct_event!(key press CONTROL-'v') => {
2218 overwrite(self);
2219 tc(self.paste_from_clip())
2220 }
2221 ct_event!(paste v) => {
2222 overwrite(self);
2223 for c in v.chars() {
2224 self.insert_char(c);
2225 }
2226 TextOutcome::TextChanged
2227 }
2228 ct_event!(key press CONTROL-'d') => {
2229 clear_overwrite(self);
2230 tc(self.clear())
2231 }
2232 ct_event!(key press CONTROL-'z') => {
2233 clear_overwrite(self);
2234 tc(self.undo())
2235 }
2236 ct_event!(key press CONTROL_SHIFT-'Z') => {
2237 clear_overwrite(self);
2238 tc(self.redo())
2239 }
2240 ct_event!(keycode press Tab) => {
2241 if self.on_tab == TextTab::MoveToNextSection {
2242 if !self.focus.gained() {
2244 clear_overwrite(self);
2245 self.select_next_section().into()
2246 } else {
2247 TextOutcome::Unchanged
2248 }
2249 } else {
2250 TextOutcome::Continue
2251 }
2252 }
2253 ct_event!(keycode press SHIFT-BackTab) => {
2254 if self.on_tab == TextTab::MoveToNextSection {
2255 if !self.focus.gained() {
2257 clear_overwrite(self);
2258 self.select_prev_section().into()
2259 } else {
2260 TextOutcome::Unchanged
2261 }
2262 } else {
2263 TextOutcome::Continue
2264 }
2265 }
2266 ct_event!(keycode press ALT-Left) => {
2267 clear_overwrite(self);
2268 self.select_prev_section().into()
2269 }
2270 ct_event!(keycode press ALT-Right) => {
2271 clear_overwrite(self);
2272 self.select_next_section().into()
2273 }
2274
2275 ct_event!(key release _)
2276 | ct_event!(key release SHIFT-_)
2277 | ct_event!(key release CONTROL_ALT-_)
2278 | ct_event!(keycode release Backspace)
2279 | ct_event!(keycode release Delete)
2280 | ct_event!(keycode release CONTROL-Backspace)
2281 | ct_event!(keycode release ALT-Backspace)
2282 | ct_event!(keycode release CONTROL-Delete)
2283 | ct_event!(key release CONTROL-'x')
2284 | ct_event!(key release CONTROL-'v')
2285 | ct_event!(key release CONTROL-'d')
2286 | ct_event!(key release CONTROL-'z')
2287 | ct_event!(key release CONTROL_SHIFT-'Z') => TextOutcome::Unchanged,
2288
2289 _ => TextOutcome::Continue,
2290 }
2291 } else {
2292 TextOutcome::Continue
2293 };
2294
2295 if r == TextOutcome::Continue {
2296 r = self.handle(event, ReadOnly);
2297 }
2298 r
2299 }
2300}
2301
2302impl HandleEvent<Event, ReadOnly, TextOutcome> for MaskedInputState {
2303 fn handle(&mut self, event: &Event, _keymap: ReadOnly) -> TextOutcome {
2304 fn clear_overwrite(state: &mut MaskedInputState) {
2305 state.overwrite.set(false);
2306 }
2307
2308 let mut r = if self.is_focused() {
2309 match event {
2310 ct_event!(keycode press Left) => {
2311 clear_overwrite(self);
2312 self.move_left(false).into()
2313 }
2314 ct_event!(keycode press Right) => {
2315 clear_overwrite(self);
2316 self.move_right(false).into()
2317 }
2318 ct_event!(keycode press CONTROL-Left) => {
2319 clear_overwrite(self);
2320 self.move_to_prev_section(false).into()
2321 }
2322 ct_event!(keycode press CONTROL-Right) => {
2323 clear_overwrite(self);
2324 self.move_to_next_section(false).into()
2325 }
2326 ct_event!(keycode press Home) => {
2327 clear_overwrite(self);
2328 self.move_to_line_start(false).into()
2329 }
2330 ct_event!(keycode press End) => {
2331 clear_overwrite(self);
2332 self.move_to_line_end(false).into()
2333 }
2334 ct_event!(keycode press SHIFT-Left) => {
2335 clear_overwrite(self);
2336 self.move_left(true).into()
2337 }
2338 ct_event!(keycode press SHIFT-Right) => {
2339 clear_overwrite(self);
2340 self.move_right(true).into()
2341 }
2342 ct_event!(keycode press CONTROL_SHIFT-Left) => {
2343 clear_overwrite(self);
2344 self.move_to_prev_section(true).into()
2345 }
2346 ct_event!(keycode press CONTROL_SHIFT-Right) => {
2347 clear_overwrite(self);
2348 self.move_to_next_section(true).into()
2349 }
2350 ct_event!(keycode press SHIFT-Home) => {
2351 clear_overwrite(self);
2352 self.move_to_line_start(true).into()
2353 }
2354 ct_event!(keycode press SHIFT-End) => {
2355 clear_overwrite(self);
2356 self.move_to_line_end(true).into()
2357 }
2358 ct_event!(key press CONTROL-'a') => {
2359 clear_overwrite(self);
2360 self.select_all().into()
2361 }
2362 ct_event!(key press CONTROL-'c') => {
2363 clear_overwrite(self);
2364 self.copy_to_clip().into()
2365 }
2366
2367 ct_event!(keycode release Left)
2368 | ct_event!(keycode release Right)
2369 | ct_event!(keycode release CONTROL-Left)
2370 | ct_event!(keycode release CONTROL-Right)
2371 | ct_event!(keycode release Home)
2372 | ct_event!(keycode release End)
2373 | ct_event!(keycode release SHIFT-Left)
2374 | ct_event!(keycode release SHIFT-Right)
2375 | ct_event!(keycode release CONTROL_SHIFT-Left)
2376 | ct_event!(keycode release CONTROL_SHIFT-Right)
2377 | ct_event!(keycode release SHIFT-Home)
2378 | ct_event!(keycode release SHIFT-End)
2379 | ct_event!(key release CONTROL-'a')
2380 | ct_event!(key release CONTROL-'c') => TextOutcome::Unchanged,
2381
2382 _ => TextOutcome::Continue,
2383 }
2384 } else {
2385 TextOutcome::Continue
2386 };
2387
2388 if r == TextOutcome::Continue {
2389 r = self.handle(event, MouseOnly);
2390 }
2391 r
2392 }
2393}
2394
2395impl HandleEvent<Event, MouseOnly, TextOutcome> for MaskedInputState {
2396 fn handle(&mut self, event: &Event, _keymap: MouseOnly) -> TextOutcome {
2397 if self.is_obscured() {
2398 return TextOutcome::Continue;
2399 }
2400
2401 fn clear_overwrite(state: &mut MaskedInputState) {
2402 state.overwrite.set(false);
2403 }
2404
2405 match event {
2406 ct_event!(mouse any for m) if self.mouse.drag(self.inner, m) => {
2407 let c = (m.column as i16) - (self.inner.x as i16);
2408 clear_overwrite(self);
2409 self.set_screen_cursor(c, true).into()
2410 }
2411 ct_event!(mouse any for m) if self.mouse.drag2(self.inner, m, KeyModifiers::ALT) => {
2412 let cx = m.column as i16 - self.inner.x as i16;
2413 clear_overwrite(self);
2414 self.set_screen_cursor_sections(cx, true).into()
2415 }
2416 ct_event!(mouse any for m) if self.mouse.doubleclick(self.inner, m) => {
2417 let tx = self.screen_to_col(m.column as i16 - self.inner.x as i16);
2418 clear_overwrite(self);
2419 if let Some(range) = self.section_range(tx) {
2420 self.set_selection(range.start, range.end).into()
2421 } else {
2422 TextOutcome::Unchanged
2423 }
2424 }
2425 ct_event!(mouse down Left for column,row) => {
2426 if self.gained_focus() {
2427 TextOutcome::Unchanged
2430 } else if self.inner.contains((*column, *row).into()) {
2431 let c = (column - self.inner.x) as i16;
2432 clear_overwrite(self);
2433 self.set_screen_cursor(c, false).into()
2434 } else {
2435 TextOutcome::Continue
2436 }
2437 }
2438 ct_event!(mouse down CONTROL-Left for column,row) => {
2439 if self.inner.contains((*column, *row).into()) {
2440 let cx = (column - self.inner.x) as i16;
2441 clear_overwrite(self);
2442 self.set_screen_cursor(cx, true).into()
2443 } else {
2444 TextOutcome::Continue
2445 }
2446 }
2447 ct_event!(mouse down ALT-Left for column,row) => {
2448 if self.inner.contains((*column, *row).into()) {
2449 let cx = (column - self.inner.x) as i16;
2450 clear_overwrite(self);
2451 self.set_screen_cursor_sections(cx, true).into()
2452 } else {
2453 TextOutcome::Continue
2454 }
2455 }
2456 _ => TextOutcome::Continue,
2457 }
2458 }
2459}
2460
2461pub fn handle_events(state: &mut MaskedInputState, focus: bool, event: &Event) -> TextOutcome {
2465 state.focus.set(focus);
2466 state.handle(event, Regular)
2467}
2468
2469pub fn handle_readonly_events(
2473 state: &mut TextInputState,
2474 focus: bool,
2475 event: &Event,
2476) -> TextOutcome {
2477 state.focus.set(focus);
2478 state.handle(event, ReadOnly)
2479}
2480
2481pub fn handle_mouse_events(state: &mut MaskedInputState, event: &Event) -> TextOutcome {
2483 state.handle(event, MouseOnly)
2484}