1pub mod mask_op;
73pub(crate) mod mask_token;
74pub(crate) mod masked_graphemes;
75
76use crate::_private::NonExhaustive;
77use crate::clipboard::{Clipboard, global_clipboard};
78use crate::core::{TextCore, TextString};
79use crate::event::{ReadOnly, TextOutcome};
80use crate::glyph2::{Glyph2, GlyphIter2, TextWrap2};
81use crate::text_input::TextInputState;
82use crate::text_input_mask::mask_token::{EditDirection, Mask, MaskToken};
83use crate::text_input_mask::masked_graphemes::MaskedGraphemes;
84use crate::text_store::TextStore;
85use crate::undo_buffer::{UndoBuffer, UndoEntry, UndoVec};
86use crate::{
87 Grapheme, HasScreenCursor, TextError, TextFocusGained, TextFocusLost, TextPosition, TextRange,
88 TextStyle, ipos_type, upos_type,
89};
90use crossterm::event::KeyModifiers;
91use format_num_pattern::NumberSymbols;
92use rat_event::util::MouseFlags;
93use rat_event::{HandleEvent, MouseOnly, Regular, ct_event};
94use rat_focus::{FocusBuilder, FocusFlag, HasFocus, Navigation};
95use rat_reloc::{RelocatableState, relocate_area, relocate_dark_offset};
96use ratatui::buffer::Buffer;
97use ratatui::layout::{Rect, Size};
98use ratatui::prelude::BlockExt;
99use ratatui::style::{Style, Stylize};
100use ratatui::widgets::{Block, StatefulWidget, Widget};
101use std::borrow::Cow;
102use std::cell::Cell;
103use std::cmp::min;
104use std::fmt;
105use std::iter::once;
106use std::ops::Range;
107use std::rc::Rc;
108use unicode_segmentation::UnicodeSegmentation;
109
110#[derive(Debug, Default, Clone)]
116pub struct MaskedInput<'a> {
117 compact: bool,
118 block: Option<Block<'a>>,
119 style: Style,
120 focus_style: Option<Style>,
121 select_style: Option<Style>,
122 invalid_style: Option<Style>,
123 text_style: Vec<Style>,
124 on_focus_gained: TextFocusGained,
125 on_focus_lost: TextFocusLost,
126}
127
128#[derive(Debug)]
130pub struct MaskedInputState {
131 pub area: Rect,
134 pub inner: Rect,
137 pub rendered: Size,
140 pub compact: bool,
143
144 pub offset: upos_type,
147 pub dark_offset: (u16, u16),
150 pub scroll_to_cursor: Rc<Cell<bool>>,
152
153 pub value: TextCore<TextString>,
155 pub sym: Option<NumberSymbols>,
158 pub mask: Vec<MaskToken>,
161
162 pub invalid: bool,
165 pub overwrite: Rc<Cell<bool>>,
169 pub on_focus_gained: Rc<Cell<TextFocusGained>>,
172 pub on_focus_lost: Rc<Cell<TextFocusLost>>,
175
176 pub focus: FocusFlag,
179
180 pub mouse: MouseFlags,
183
184 pub non_exhaustive: NonExhaustive,
186}
187
188impl<'a> MaskedInput<'a> {
189 pub fn new() -> Self {
191 Self::default()
192 }
193
194 #[inline]
197 pub fn compact(mut self, show_compact: bool) -> Self {
198 self.compact = show_compact;
199 self
200 }
201
202 #[inline]
204 pub fn styles_opt(self, styles: Option<TextStyle>) -> Self {
205 if let Some(styles) = styles {
206 self.styles(styles)
207 } else {
208 self
209 }
210 }
211
212 #[inline]
214 pub fn styles(mut self, styles: TextStyle) -> Self {
215 self.style = styles.style;
216 if styles.focus.is_some() {
217 self.focus_style = styles.focus;
218 }
219 if styles.select.is_some() {
220 self.select_style = styles.select;
221 }
222 if styles.invalid.is_some() {
223 self.invalid_style = styles.invalid;
224 }
225 if let Some(of) = styles.on_focus_gained {
226 self.on_focus_gained = of;
227 }
228 if let Some(of) = styles.on_focus_lost {
229 self.on_focus_lost = of;
230 }
231 if let Some(border_style) = styles.border_style {
232 self.block = self.block.map(|v| v.border_style(border_style));
233 }
234 self.block = self.block.map(|v| v.style(self.style));
235 if styles.block.is_some() {
236 self.block = styles.block;
237 }
238 self.block = self.block.map(|v| v.style(self.style));
239 self
240 }
241
242 #[inline]
244 pub fn style(mut self, style: impl Into<Style>) -> Self {
245 self.style = style.into();
246 self.block = self.block.map(|v| v.style(self.style));
247 self
248 }
249
250 #[inline]
252 pub fn focus_style(mut self, style: impl Into<Style>) -> Self {
253 self.focus_style = Some(style.into());
254 self
255 }
256
257 #[inline]
259 pub fn select_style(mut self, style: impl Into<Style>) -> Self {
260 self.select_style = Some(style.into());
261 self
262 }
263
264 #[inline]
267 pub fn invalid_style(mut self, style: impl Into<Style>) -> Self {
268 self.invalid_style = Some(style.into());
269 self
270 }
271
272 pub fn text_style<T: IntoIterator<Item = Style>>(mut self, styles: T) -> Self {
277 self.text_style = styles.into_iter().collect();
278 self
279 }
280
281 #[inline]
283 pub fn block(mut self, block: Block<'a>) -> Self {
284 self.block = Some(block);
285 self.block = self.block.map(|v| v.style(self.style));
286 self
287 }
288
289 #[inline]
291 pub fn on_focus_gained(mut self, of: TextFocusGained) -> Self {
292 self.on_focus_gained = of;
293 self
294 }
295
296 #[inline]
298 pub fn on_focus_lost(mut self, of: TextFocusLost) -> Self {
299 self.on_focus_lost = of;
300 self
301 }
302}
303
304impl<'a> StatefulWidget for &MaskedInput<'a> {
305 type State = MaskedInputState;
306
307 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
308 render_ref(self, area, buf, state);
309 }
310}
311
312impl StatefulWidget for MaskedInput<'_> {
313 type State = MaskedInputState;
314
315 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
316 render_ref(&self, area, buf, state);
317 }
318}
319
320fn render_ref(
321 widget: &MaskedInput<'_>,
322 area: Rect,
323
324 buf: &mut Buffer,
325 state: &mut MaskedInputState,
326) {
327 state.area = area;
328 state.inner = widget.block.inner_if_some(area);
329 state.rendered = state.inner.as_size();
330 state.compact = widget.compact;
331 state.on_focus_gained.set(widget.on_focus_gained);
332 state.on_focus_lost.set(widget.on_focus_lost);
333
334 if state.scroll_to_cursor.get() {
335 let c = state.cursor();
336 let o = state.offset();
337 let mut no = if c < o {
338 c
339 } else if c >= o + state.rendered.width as upos_type {
340 c.saturating_sub(state.rendered.width as upos_type)
341 } else {
342 o
343 };
344 if c == no + state.rendered.width as upos_type {
347 no = no.saturating_add(1);
348 }
349 state.set_offset(no);
350 }
351
352 let style = widget.style;
353 let focus_style = if let Some(focus_style) = widget.focus_style {
354 focus_style
355 } else {
356 style
357 };
358 let select_style = if let Some(select_style) = widget.select_style {
359 select_style
360 } else {
361 Style::default().black().on_yellow()
362 };
363 let invalid_style = if let Some(invalid_style) = widget.invalid_style {
364 invalid_style
365 } else {
366 Style::default().red()
367 };
368
369 let (style, select_style) = if state.focus.get() {
370 if state.invalid {
371 (
372 style.patch(focus_style).patch(invalid_style),
373 style
374 .patch(focus_style)
375 .patch(select_style)
376 .patch(invalid_style),
377 )
378 } else {
379 (
380 style.patch(focus_style),
381 style.patch(focus_style).patch(select_style),
382 )
383 }
384 } else {
385 if state.invalid {
386 (
387 style.patch(invalid_style),
388 style.patch(select_style).patch(invalid_style),
389 )
390 } else {
391 (style, style.patch(select_style))
392 }
393 };
394
395 if let Some(block) = &widget.block {
397 block.render(area, buf);
398 } else {
399 buf.set_style(area, style);
400 }
401
402 if state.inner.width == 0 || state.inner.height == 0 {
403 return;
405 }
406
407 let ox = state.offset() as u16;
408 let show_range = {
410 let start = ox as upos_type;
411 let end = min(start + state.inner.width as upos_type, state.len());
412 state.bytes_at_range(start..end)
413 };
414 let selection = state.selection();
415 let mut styles = Vec::new();
416
417 for g in state.glyphs2() {
418 if g.screen_width() > 0 {
419 let mut style = style;
420 styles.clear();
421 state
422 .value
423 .styles_at_page(g.text_bytes().start, show_range.clone(), &mut styles);
424 for style_nr in &styles {
425 if let Some(s) = widget.text_style.get(*style_nr) {
426 style = style.patch(*s);
427 }
428 }
429 if selection.contains(&g.pos().x) {
431 style = style.patch(select_style);
432 };
433
434 let screen_pos = g.screen_pos();
436
437 if let Some(cell) =
439 buf.cell_mut((state.inner.x + screen_pos.0, state.inner.y + screen_pos.1))
440 {
441 cell.set_symbol(g.glyph());
442 cell.set_style(style);
443 }
444 for d in 1..g.screen_width() {
446 if let Some(cell) = buf.cell_mut((
447 state.inner.x + screen_pos.0 + d,
448 state.inner.y + screen_pos.1,
449 )) {
450 cell.reset();
451 cell.set_style(style);
452 }
453 }
454 }
455 }
456}
457
458impl Clone for MaskedInputState {
459 fn clone(&self) -> Self {
460 Self {
461 area: self.area,
462 inner: self.inner,
463 rendered: self.rendered,
464 compact: self.compact,
465 offset: self.offset,
466 dark_offset: self.dark_offset,
467 scroll_to_cursor: Rc::new(Cell::new(self.scroll_to_cursor.get())),
468 value: self.value.clone(),
469 sym: self.sym,
470 mask: self.mask.clone(),
471 invalid: self.invalid,
472 overwrite: Rc::new(Cell::new(self.overwrite.get())),
473 on_focus_gained: Rc::new(Cell::new(self.on_focus_gained.get())),
474 on_focus_lost: Rc::new(Cell::new(self.on_focus_lost.get())),
475 focus: self.focus_cb(FocusFlag::named(self.focus.name())),
476 mouse: Default::default(),
477 non_exhaustive: NonExhaustive,
478 }
479 }
480}
481
482impl Default for MaskedInputState {
483 fn default() -> Self {
484 let core = TextCore::new(
485 Some(Box::new(UndoVec::new(99))),
486 Some(Box::new(global_clipboard())),
487 );
488
489 let mut z = Self {
490 area: Default::default(),
491 inner: Default::default(),
492 rendered: Default::default(),
493 compact: Default::default(),
494 offset: Default::default(),
495 dark_offset: Default::default(),
496 scroll_to_cursor: Default::default(),
497 value: core,
498 sym: None,
499 mask: Default::default(),
500 invalid: Default::default(),
501 overwrite: Default::default(),
502 on_focus_gained: Default::default(),
503 on_focus_lost: Default::default(),
504 focus: Default::default(),
505 mouse: Default::default(),
506 non_exhaustive: NonExhaustive,
507 };
508 z.focus = z.focus_cb(FocusFlag::default());
509 z
510 }
511}
512
513impl MaskedInputState {
514 fn focus_cb(&self, flag: FocusFlag) -> FocusFlag {
515 let on_focus_lost = self.on_focus_lost.clone();
516 let cursor = self.value.shared_cursor();
517 let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
518 flag.on_lost(move || match on_focus_lost.get() {
519 TextFocusLost::None => {}
520 TextFocusLost::Position0 => {
521 scroll_cursor_to_visible.set(true);
522 let mut new_cursor = cursor.get();
523 new_cursor.cursor.x = 0;
524 new_cursor.anchor.x = 0;
525 cursor.set(new_cursor);
526 }
527 });
528 let on_focus_gained = self.on_focus_gained.clone();
529 let overwrite = self.overwrite.clone();
530 let cursor = self.value.shared_cursor();
531 let scroll_cursor_to_visible = self.scroll_to_cursor.clone();
532 flag.on_gained(move || match on_focus_gained.get() {
533 TextFocusGained::None => {}
534 TextFocusGained::Overwrite => {
535 overwrite.set(true);
536 }
537 TextFocusGained::SelectAll => {
538 scroll_cursor_to_visible.set(true);
539 let mut new_cursor = cursor.get();
540 new_cursor.anchor = TextPosition::new(0, 0);
541 new_cursor.cursor = TextPosition::new(0, 1);
542 cursor.set(new_cursor);
543 }
544 });
545
546 flag
547 }
548}
549
550impl HasFocus for MaskedInputState {
551 fn build(&self, builder: &mut FocusBuilder) {
552 builder.leaf_widget(self);
553 }
554
555 fn focus(&self) -> FocusFlag {
556 self.focus.clone()
557 }
558
559 fn area(&self) -> Rect {
560 self.area
561 }
562
563 fn navigable(&self) -> Navigation {
564 let sel = self.selection();
565
566 let has_next = self
567 .next_section_range(sel.end)
568 .map(|v| !v.is_empty())
569 .is_some();
570 let has_prev = self
571 .prev_section_range(sel.start.saturating_sub(1))
572 .map(|v| !v.is_empty())
573 .is_some();
574
575 if has_next {
576 if has_prev {
577 Navigation::Reach
578 } else {
579 Navigation::ReachLeaveFront
580 }
581 } else {
582 if has_prev {
583 Navigation::ReachLeaveBack
584 } else {
585 Navigation::Regular
586 }
587 }
588 }
589}
590
591impl MaskedInputState {
592 pub fn new() -> Self {
593 Self::default()
594 }
595
596 pub fn named(name: &str) -> Self {
597 let mut z = Self::default();
598 z.focus = z.focus_cb(FocusFlag::named(name));
599 z
600 }
601
602 #[inline]
604 pub fn with_symbols(mut self, sym: NumberSymbols) -> Self {
605 self.set_num_symbols(sym);
606 self
607 }
608
609 pub fn with_mask<S: AsRef<str>>(mut self, mask: S) -> Result<Self, fmt::Error> {
611 self.set_mask(mask.as_ref())?;
612 Ok(self)
613 }
614
615 #[inline]
620 pub fn set_num_symbols(&mut self, sym: NumberSymbols) {
621 self.sym = Some(sym);
622 }
623
624 fn dec_sep(&self) -> char {
625 if let Some(sym) = &self.sym {
626 sym.decimal_sep
627 } else {
628 '.'
629 }
630 }
631
632 fn grp_sep(&self) -> char {
633 if let Some(sym) = &self.sym {
634 sym.decimal_grp.unwrap_or(' ')
638 } else {
639 ','
640 }
641 }
642
643 fn neg_sym(&self) -> char {
644 if let Some(sym) = &self.sym {
645 sym.negative_sym
646 } else {
647 '-'
648 }
649 }
650
651 fn pos_sym(&self) -> char {
652 if let Some(sym) = &self.sym {
653 sym.positive_sym
654 } else {
655 ' '
656 }
657 }
658
659 #[inline]
690 pub fn set_mask<S: AsRef<str>>(&mut self, s: S) -> Result<(), fmt::Error> {
691 self.mask = Self::parse_mask(s.as_ref())?;
692 self.clear();
693 Ok(())
694 }
695
696 #[allow(clippy::needless_range_loop)]
697 fn parse_mask(mask_str: &str) -> Result<Vec<MaskToken>, fmt::Error> {
698 let mut out = Vec::<MaskToken>::new();
699
700 let mut start_sub = 0;
701 let mut start_sec = 0;
702 let mut sec_id = 0;
703 let mut last_mask = Mask::None;
704 let mut dec_dir = EditDirection::Rtol;
705 let mut esc = false;
706 let mut idx = 0;
707 for m in mask_str.graphemes(true).chain(once("")) {
708 let mask = if esc {
709 esc = false;
710 Mask::Separator(Box::from(m))
711 } else {
712 match m {
713 "0" => Mask::Digit0(dec_dir),
714 "9" => Mask::Digit(dec_dir),
715 "#" => Mask::Numeric(dec_dir),
716 "." => Mask::DecimalSep,
717 "," => Mask::GroupingSep,
718 "-" => Mask::Sign,
719 "+" => Mask::Plus,
720 "h" => Mask::Hex,
721 "H" => Mask::Hex0,
722 "o" => Mask::Oct,
723 "O" => Mask::Oct0,
724 "d" => Mask::Dec,
725 "D" => Mask::Dec0,
726 "l" => Mask::Letter,
727 "a" => Mask::LetterOrDigit,
728 "c" => Mask::LetterDigitSpace,
729 "_" => Mask::AnyChar,
730 "" => Mask::None,
731 " " => Mask::Separator(Box::from(m)),
732 "\\" => {
733 esc = true;
734 continue;
735 }
736 _ => return Err(fmt::Error),
737 }
738 };
739
740 match mask {
741 Mask::Digit0(_)
742 | Mask::Digit(_)
743 | Mask::Numeric(_)
744 | Mask::GroupingSep
745 | Mask::Sign
746 | Mask::Plus => {
747 }
749 Mask::DecimalSep => {
750 dec_dir = EditDirection::Ltor;
751 }
752 Mask::Hex0
753 | Mask::Hex
754 | Mask::Oct0
755 | Mask::Oct
756 | Mask::Dec0
757 | Mask::Dec
758 | Mask::Letter
759 | Mask::LetterOrDigit
760 | Mask::LetterDigitSpace
761 | Mask::AnyChar
762 | Mask::Separator(_) => {
763 dec_dir = EditDirection::Rtol
765 }
766 Mask::None => {
767 }
769 }
770
771 if matches!(mask, Mask::Separator(_)) || mask.section() != last_mask.section() {
772 for j in start_sec..idx {
773 out[j].sec_id = sec_id;
774 out[j].sec_start = start_sec as upos_type;
775 out[j].sec_end = idx as upos_type;
776 }
777 sec_id += 1;
778 start_sec = idx;
779 }
780 if matches!(mask, Mask::Separator(_)) || mask.sub_section() != last_mask.sub_section() {
781 for j in start_sub..idx {
782 out[j].sub_start = start_sub as upos_type;
783 out[j].sub_end = idx as upos_type;
784 }
785 start_sub = idx;
786 }
787
788 let tok = MaskToken {
789 sec_id: 0,
790 sec_start: 0,
791 sec_end: 0,
792 sub_start: 0,
793 sub_end: 0,
794 peek_left: last_mask,
795 right: mask.clone(),
796 edit: mask.edit_value().into(),
797 };
798 out.push(tok);
799
800 idx += 1;
801 last_mask = mask;
802 }
803 for j in start_sec..out.len() {
804 out[j].sec_id = sec_id;
805 out[j].sec_start = start_sec as upos_type;
806 out[j].sec_end = mask_str.graphemes(true).count() as upos_type;
807 }
808 for j in start_sub..out.len() {
809 out[j].sub_start = start_sub as upos_type;
810 out[j].sub_end = mask_str.graphemes(true).count() as upos_type;
811 }
812
813 Ok(out)
814 }
815
816 #[inline]
818 pub fn mask(&self) -> String {
819 use std::fmt::Write;
820
821 let mut buf = String::new();
822 for t in self.mask.iter() {
823 _ = write!(buf, "{}", t.right);
824 }
825 buf
826 }
827
828 #[inline]
830 pub fn set_invalid(&mut self, invalid: bool) {
831 self.invalid = invalid;
832 }
833
834 #[inline]
836 pub fn get_invalid(&self) -> bool {
837 self.invalid
838 }
839
840 #[inline]
844 pub fn set_overwrite(&mut self, overwrite: bool) {
845 self.overwrite.set(overwrite);
846 }
847
848 #[inline]
850 pub fn overwrite(&self) -> bool {
851 self.overwrite.get()
852 }
853}
854
855impl MaskedInputState {
856 #[inline]
859 pub fn set_clipboard(&mut self, clip: Option<impl Clipboard + 'static>) {
860 self.value.set_clipboard(clip.map(|v| {
861 let r: Box<dyn Clipboard> = Box::new(v);
862 r
863 }));
864 }
865
866 #[inline]
869 pub fn clipboard(&self) -> Option<&dyn Clipboard> {
870 self.value.clipboard()
871 }
872
873 #[inline]
875 pub fn copy_to_clip(&mut self) -> bool {
876 let Some(clip) = self.value.clipboard() else {
877 return false;
878 };
879
880 _ = clip.set_string(self.selected_text().as_ref());
881
882 true
883 }
884
885 #[inline]
887 pub fn cut_to_clip(&mut self) -> bool {
888 let Some(clip) = self.value.clipboard() else {
889 return false;
890 };
891
892 match clip.set_string(self.selected_text().as_ref()) {
893 Ok(_) => self.delete_range(self.selection()),
894 Err(_) => true,
895 }
896 }
897
898 #[inline]
900 pub fn paste_from_clip(&mut self) -> bool {
901 let Some(clip) = self.value.clipboard() else {
902 return false;
903 };
904
905 if let Ok(text) = clip.get_string() {
906 for c in text.chars() {
907 self.insert_char(c);
908 }
909 true
910 } else {
911 false
912 }
913 }
914}
915
916impl MaskedInputState {
917 #[inline]
919 pub fn set_undo_buffer(&mut self, undo: Option<impl UndoBuffer + 'static>) {
920 self.value.set_undo_buffer(undo.map(|v| {
921 let r: Box<dyn UndoBuffer> = Box::new(v);
922 r
923 }));
924 }
925
926 #[inline]
928 pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
929 self.value.undo_buffer()
930 }
931
932 #[inline]
934 pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
935 self.value.undo_buffer_mut()
936 }
937
938 #[inline]
940 pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
941 self.value.recent_replay_log()
942 }
943
944 #[inline]
946 pub fn replay_log(&mut self, replay: &[UndoEntry]) {
947 self.value.replay_log(replay)
948 }
949
950 #[inline]
952 pub fn begin_undo_seq(&mut self) {
953 self.value.begin_undo_seq();
954 }
955
956 #[inline]
958 pub fn end_undo_seq(&mut self) {
959 self.value.end_undo_seq();
960 }
961
962 #[inline]
964 pub fn undo(&mut self) -> bool {
965 self.value.undo()
966 }
967
968 #[inline]
970 pub fn redo(&mut self) -> bool {
971 self.value.redo()
972 }
973}
974
975impl MaskedInputState {
976 #[inline]
978 pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
979 self.value.set_styles(styles);
980 }
981
982 #[inline]
985 pub fn add_style(&mut self, range: Range<usize>, style: usize) {
986 self.value.add_style(range, style);
987 }
988
989 #[inline]
992 pub fn add_range_style(
993 &mut self,
994 range: Range<upos_type>,
995 style: usize,
996 ) -> Result<(), TextError> {
997 let r = self
998 .value
999 .bytes_at_range(TextRange::from((range.start, 0)..(range.end, 0)))?;
1000 self.value.add_style(r, style);
1001 Ok(())
1002 }
1003
1004 #[inline]
1006 pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
1007 self.value.remove_style(range, style);
1008 }
1009
1010 #[inline]
1012 pub fn remove_range_style(
1013 &mut self,
1014 range: Range<upos_type>,
1015 style: usize,
1016 ) -> Result<(), TextError> {
1017 let r = self
1018 .value
1019 .bytes_at_range(TextRange::from((range.start, 0)..(range.end, 0)))?;
1020 self.value.remove_style(r, style);
1021 Ok(())
1022 }
1023
1024 pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
1026 self.value.styles_in(range, buf)
1027 }
1028
1029 #[inline]
1031 pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
1032 self.value.styles_at(byte_pos, buf)
1033 }
1034
1035 #[inline]
1038 pub fn styles_at_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
1039 self.value.styles_at_match(byte_pos, style)
1040 }
1041
1042 #[inline]
1044 pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
1045 self.value.styles()
1046 }
1047}
1048
1049impl MaskedInputState {
1050 #[inline]
1052 pub fn offset(&self) -> upos_type {
1053 self.offset
1054 }
1055
1056 #[inline]
1058 pub fn set_offset(&mut self, offset: upos_type) {
1059 self.scroll_to_cursor.set(false);
1060 self.offset = offset;
1061 }
1062
1063 #[inline]
1065 pub fn cursor(&self) -> upos_type {
1066 self.value.cursor().x
1067 }
1068
1069 #[inline]
1072 pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
1073 self.scroll_cursor_to_visible();
1074 self.value
1075 .set_cursor(TextPosition::new(cursor, 0), extend_selection)
1076 }
1077
1078 fn number_cursor(&self, range: Range<upos_type>) -> upos_type {
1080 for (i, t) in self.mask[range.start as usize..range.end as usize]
1081 .iter()
1082 .enumerate()
1083 .rev()
1084 {
1085 match t.right {
1086 Mask::Digit(EditDirection::Rtol)
1087 | Mask::Digit0(EditDirection::Rtol)
1088 | Mask::Numeric(EditDirection::Rtol) => {
1089 return range.start + i as upos_type + 1;
1090 }
1091 _ => {}
1092 }
1093 }
1094 range.start
1095 }
1096
1097 pub fn section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1100 if cursor as usize >= self.mask.len() {
1101 return None;
1102 }
1103
1104 let mask = &self.mask[cursor as usize];
1105
1106 if mask.right.is_number() {
1107 Some(self.number_cursor(mask.sec_start..mask.sec_end))
1108 } else if mask.right.is_separator() {
1109 None
1110 } else if mask.right.is_none() {
1111 None
1112 } else {
1113 Some(mask.sec_start)
1114 }
1115 }
1116
1117 pub fn next_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1119 if cursor as usize >= self.mask.len() {
1120 return None;
1121 }
1122
1123 let mut mask = &self.mask[cursor as usize];
1124 let mut next;
1125 loop {
1126 if mask.right.is_none() {
1127 return None;
1128 }
1129
1130 next = mask.sec_end;
1131 mask = &self.mask[next as usize];
1132
1133 if mask.right.is_number() {
1134 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
1135 } else if mask.right.is_separator() {
1136 continue;
1137 } else if mask.right.is_none() {
1138 return None;
1139 } else {
1140 return Some(mask.sec_start);
1141 }
1142 }
1143 }
1144
1145 pub fn prev_section_cursor(&self, cursor: upos_type) -> Option<upos_type> {
1147 if cursor as usize >= self.mask.len() {
1148 return None;
1149 }
1150
1151 let mut prev = self.mask[cursor as usize].sec_start;
1152 let mut mask = &self.mask[prev as usize];
1153
1154 loop {
1155 if mask.peek_left.is_none() {
1156 return None;
1157 }
1158
1159 prev = self.mask[mask.sec_start as usize - 1].sec_start;
1160 mask = &self.mask[prev as usize];
1161
1162 if mask.right.is_number() {
1163 return Some(self.number_cursor(mask.sec_start..mask.sec_end));
1164 } else if mask.right.is_separator() {
1165 continue;
1166 } else {
1167 return Some(mask.sec_start);
1168 }
1169 }
1170 }
1171
1172 pub fn is_section_boundary(&self, pos: upos_type) -> bool {
1174 if pos == 0 {
1175 return false;
1176 }
1177 if pos as usize >= self.mask.len() {
1178 return false;
1179 }
1180 let prev = &self.mask[pos as usize - 1];
1181 let mask = &self.mask[pos as usize];
1182 prev.sec_id != mask.sec_id
1183 }
1184
1185 pub fn section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1188 if cursor as usize >= self.mask.len() {
1189 return None;
1190 }
1191
1192 let mask = &self.mask[cursor as usize];
1193 if mask.right.is_number() {
1194 Some(mask.sec_start..mask.sec_end)
1195 } else if mask.right.is_separator() {
1196 None
1197 } else if mask.right.is_none() {
1198 None
1199 } else {
1200 Some(mask.sec_start..mask.sec_end)
1201 }
1202 }
1203
1204 pub fn next_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1206 if cursor as usize >= self.mask.len() {
1207 return None;
1208 }
1209
1210 let mut mask = &self.mask[cursor as usize];
1211 let mut next;
1212 loop {
1213 if mask.right.is_none() {
1214 return None;
1215 }
1216
1217 next = mask.sec_end;
1218 mask = &self.mask[next as usize];
1219
1220 if mask.right.is_number() {
1221 return Some(mask.sec_start..mask.sec_end);
1222 } else if mask.right.is_separator() {
1223 continue;
1224 } else if mask.right.is_none() {
1225 return None;
1226 } else {
1227 return Some(mask.sec_start..mask.sec_end);
1228 }
1229 }
1230 }
1231
1232 pub fn prev_section_range(&self, cursor: upos_type) -> Option<Range<upos_type>> {
1234 if cursor as usize >= self.mask.len() {
1235 return None;
1236 }
1237
1238 let mut prev = self.mask[cursor as usize].sec_start;
1239 let mut mask = &self.mask[prev as usize];
1240 loop {
1241 if mask.peek_left.is_none() {
1242 return None;
1243 }
1244
1245 prev = self.mask[mask.sec_start as usize - 1].sec_start;
1246 mask = &self.mask[prev as usize];
1247
1248 if mask.right.is_number() {
1249 return Some(mask.sec_start..mask.sec_end);
1250 } else if mask.right.is_separator() {
1251 continue;
1252 } else {
1253 return Some(mask.sec_start..mask.sec_end);
1254 }
1255 }
1256 }
1257
1258 #[inline]
1262 pub fn set_default_cursor(&mut self) {
1263 self.scroll_cursor_to_visible();
1264 if let Some(pos) = self.section_cursor(0) {
1265 self.value.set_cursor(TextPosition::new(pos, 0), false);
1266 } else if let Some(pos) = self.next_section_cursor(0) {
1267 self.value.set_cursor(TextPosition::new(pos, 0), false);
1268 } else {
1269 self.value.set_cursor(TextPosition::new(0, 0), false);
1270 }
1271 }
1272
1273 #[inline]
1275 pub fn anchor(&self) -> upos_type {
1276 self.value.anchor().x
1277 }
1278
1279 #[inline]
1281 pub fn has_selection(&self) -> bool {
1282 self.value.has_selection()
1283 }
1284
1285 #[inline]
1287 pub fn selection(&self) -> Range<upos_type> {
1288 let mut v = self.value.selection();
1289 if v.start == TextPosition::new(0, 1) {
1290 v.start = TextPosition::new(self.line_width(), 0);
1291 }
1292 if v.end == TextPosition::new(0, 1) {
1293 v.end = TextPosition::new(self.line_width(), 0);
1294 }
1295 v.start.x..v.end.x
1296 }
1297
1298 #[inline]
1301 pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
1302 self.scroll_cursor_to_visible();
1303 self.value
1304 .set_selection(TextPosition::new(anchor, 0), TextPosition::new(cursor, 0))
1305 }
1306
1307 #[inline]
1310 pub fn select_all(&mut self) -> bool {
1311 self.scroll_cursor_to_visible();
1312 if let Some(section) = self.section_range(self.cursor()) {
1313 if self.selection() == section {
1314 self.value.select_all()
1315 } else {
1316 self.value.set_selection(
1317 TextPosition::new(section.start, 0),
1318 TextPosition::new(section.end, 0),
1319 )
1320 }
1321 } else {
1322 self.value.select_all()
1323 }
1324 }
1325
1326 #[inline]
1328 pub fn selected_text(&self) -> &str {
1329 match self
1330 .value
1331 .str_slice(self.value.selection())
1332 .expect("valid_range")
1333 {
1334 Cow::Borrowed(v) => v,
1335 Cow::Owned(_) => {
1336 unreachable!()
1337 }
1338 }
1339 }
1340}
1341
1342impl MaskedInputState {
1343 #[inline]
1345 pub fn is_empty(&self) -> bool {
1346 self.value.text().as_str() == self.default_value()
1347 }
1348
1349 #[inline]
1351 pub fn text(&self) -> &str {
1352 self.value.text().as_str()
1353 }
1354
1355 #[inline]
1357 pub fn str_slice_byte(&self, range: Range<usize>) -> Cow<'_, str> {
1358 self.value.str_slice_byte(range).expect("valid_range")
1359 }
1360
1361 #[inline]
1363 pub fn try_str_slice_byte(&self, range: Range<usize>) -> Result<Cow<'_, str>, TextError> {
1364 self.value.str_slice_byte(range)
1365 }
1366
1367 #[inline]
1369 pub fn str_slice(&self, range: Range<upos_type>) -> Cow<'_, str> {
1370 self.value
1371 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1372 .expect("valid_range")
1373 }
1374
1375 #[inline]
1377 pub fn try_str_slice(&self, range: Range<upos_type>) -> Result<Cow<'_, str>, TextError> {
1378 self.value
1379 .str_slice(TextRange::new((range.start, 0), (range.end, 0)))
1380 }
1381
1382 #[inline]
1384 pub fn len(&self) -> upos_type {
1385 self.value.line_width(0).expect("valid_row")
1386 }
1387
1388 #[inline]
1390 pub fn len_bytes(&self) -> usize {
1391 self.value.len_bytes()
1392 }
1393
1394 #[inline]
1396 pub fn line_width(&self) -> upos_type {
1397 self.value.line_width(0).expect("valid_row")
1398 }
1399
1400 #[inline]
1402 pub fn grapheme_at(&self, pos: upos_type) -> Result<Option<Grapheme<'_>>, TextError> {
1403 self.value.grapheme_at(TextPosition::new(pos, 0))
1404 }
1405
1406 #[inline]
1408 pub fn text_graphemes(&self, pos: upos_type) -> <TextString as TextStore>::GraphemeIter<'_> {
1409 self.try_text_graphemes(pos).expect("valid_pos")
1410 }
1411
1412 #[inline]
1414 pub fn try_text_graphemes(
1415 &self,
1416 pos: upos_type,
1417 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1418 self.value.text_graphemes(TextPosition::new(pos, 0))
1419 }
1420
1421 #[inline]
1423 pub fn graphemes(
1424 &self,
1425 range: Range<upos_type>,
1426 pos: upos_type,
1427 ) -> <TextString as TextStore>::GraphemeIter<'_> {
1428 self.try_graphemes(range, pos).expect("valid_args")
1429 }
1430
1431 #[inline]
1433 pub fn try_graphemes(
1434 &self,
1435 range: Range<upos_type>,
1436 pos: upos_type,
1437 ) -> Result<<TextString as TextStore>::GraphemeIter<'_>, TextError> {
1438 self.value.graphemes(
1439 TextRange::new((range.start, 0), (range.end, 0)),
1440 TextPosition::new(pos, 0),
1441 )
1442 }
1443
1444 #[inline]
1447 pub fn byte_at(&self, pos: upos_type) -> Range<usize> {
1448 self.try_byte_at(pos).expect("valid_pos")
1449 }
1450
1451 #[inline]
1454 pub fn try_byte_at(&self, pos: upos_type) -> Result<Range<usize>, TextError> {
1455 self.value.byte_at(TextPosition::new(pos, 0))
1456 }
1457
1458 #[inline]
1460 pub fn bytes_at_range(&self, range: Range<upos_type>) -> Range<usize> {
1461 self.try_bytes_at_range(range).expect("valid_range")
1462 }
1463
1464 #[inline]
1466 pub fn try_bytes_at_range(&self, range: Range<upos_type>) -> Result<Range<usize>, TextError> {
1467 self.value
1468 .bytes_at_range(TextRange::new((range.start, 0), (range.end, 0)))
1469 }
1470
1471 #[inline]
1474 pub fn byte_pos(&self, byte: usize) -> upos_type {
1475 self.try_byte_pos(byte).expect("valid_pos")
1476 }
1477
1478 #[inline]
1481 pub fn try_byte_pos(&self, byte: usize) -> Result<upos_type, TextError> {
1482 Ok(self.value.byte_pos(byte)?.x)
1483 }
1484
1485 #[inline]
1487 pub fn byte_range(&self, bytes: Range<usize>) -> Range<upos_type> {
1488 self.try_byte_range(bytes).expect("valid_range")
1489 }
1490
1491 #[inline]
1493 pub fn try_byte_range(&self, bytes: Range<usize>) -> Result<Range<upos_type>, TextError> {
1494 let r = self.value.byte_range(bytes)?;
1495 Ok(r.start.x..r.end.x)
1496 }
1497}
1498
1499impl MaskedInputState {
1500 #[inline]
1502 fn default_value(&self) -> String {
1503 MaskToken::empty_section(&self.mask)
1504 }
1505
1506 #[inline]
1508 pub fn clear(&mut self) -> bool {
1509 if self.is_empty() {
1510 false
1511 } else {
1512 self.offset = 0;
1513 self.value
1514 .set_text(TextString::new_string(self.default_value()));
1515 self.set_default_cursor();
1516 true
1517 }
1518 }
1519
1520 #[inline]
1526 pub fn set_text<S: Into<String>>(&mut self, s: S) {
1527 self.offset = 0;
1528 let mut text = s.into();
1529 while text.graphemes(true).count() > self.mask.len().saturating_sub(1) {
1530 text.pop();
1531 }
1532 while text.graphemes(true).count() < self.mask.len().saturating_sub(1) {
1533 text.push(' ');
1534 }
1535 let len = text.graphemes(true).count();
1536
1537 assert_eq!(len, self.mask.len().saturating_sub(1));
1538
1539 self.value.set_text(TextString::new_string(text));
1540 self.set_default_cursor();
1541 }
1542
1543 #[inline]
1545 pub fn insert_char(&mut self, c: char) -> bool {
1546 self.begin_undo_seq();
1547 if self.has_selection() {
1548 let sel = self.selection();
1549 mask_op::remove_range(self, sel.clone()).expect("valid_selection");
1550 self.set_cursor(sel.start, false);
1551 }
1552 let c0 = mask_op::advance_cursor(self, c);
1553 let c1 = mask_op::insert_char(self, c);
1554 self.end_undo_seq();
1555
1556 self.scroll_cursor_to_visible();
1557 c0 || c1
1558 }
1559
1560 #[inline]
1563 pub fn delete_range(&mut self, range: Range<upos_type>) -> bool {
1564 self.try_delete_range(range).expect("valid_range")
1565 }
1566
1567 #[inline]
1570 pub fn try_delete_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
1571 self.value.begin_undo_seq();
1572 let r = mask_op::remove_range(self, range.clone())?;
1573 if let Some(pos) = self.section_cursor(range.start) {
1574 self.set_cursor(pos, false);
1575 }
1576 self.value.end_undo_seq();
1577
1578 self.scroll_cursor_to_visible();
1579 Ok(r)
1580 }
1581}
1582
1583impl MaskedInputState {
1584 #[inline]
1586 pub fn delete_next_char(&mut self) -> bool {
1587 if self.has_selection() {
1588 self.delete_range(self.selection())
1589 } else if self.cursor() == self.len() {
1590 false
1591 } else {
1592 mask_op::remove_next(self);
1593 self.scroll_cursor_to_visible();
1594 true
1595 }
1596 }
1597
1598 #[inline]
1600 pub fn delete_prev_char(&mut self) -> bool {
1601 if self.has_selection() {
1602 self.delete_range(self.selection())
1603 } else if self.cursor() == 0 {
1604 false
1605 } else {
1606 mask_op::remove_prev(self);
1607 self.scroll_cursor_to_visible();
1608 true
1609 }
1610 }
1611
1612 #[inline]
1614 pub fn delete_prev_section(&mut self) -> bool {
1615 if self.has_selection() {
1616 self.delete_range(self.selection())
1617 } else {
1618 if let Some(range) = self.prev_section_range(self.cursor()) {
1619 self.delete_range(range)
1620 } else {
1621 false
1622 }
1623 }
1624 }
1625
1626 #[inline]
1628 pub fn delete_next_section(&mut self) -> bool {
1629 if self.has_selection() {
1630 self.delete_range(self.selection())
1631 } else {
1632 if let Some(range) = self.next_section_range(self.cursor()) {
1633 self.delete_range(range)
1634 } else {
1635 false
1636 }
1637 }
1638 }
1639
1640 #[inline]
1642 pub fn move_right(&mut self, extend_selection: bool) -> bool {
1643 let c = min(self.cursor() + 1, self.len());
1644 self.set_cursor(c, extend_selection)
1645 }
1646
1647 #[inline]
1649 pub fn move_left(&mut self, extend_selection: bool) -> bool {
1650 let c = self.cursor().saturating_sub(1);
1651 self.set_cursor(c, extend_selection)
1652 }
1653
1654 #[inline]
1656 pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1657 if let Some(c) = self.section_cursor(self.cursor()) {
1658 if c != self.cursor() {
1659 self.set_cursor(c, extend_selection)
1660 } else {
1661 self.set_cursor(0, extend_selection)
1662 }
1663 } else {
1664 self.set_cursor(0, extend_selection)
1665 }
1666 }
1667
1668 #[inline]
1670 pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
1671 self.set_cursor(self.len(), extend_selection)
1672 }
1673
1674 #[inline]
1676 pub fn move_to_prev_section(&mut self, extend_selection: bool) -> bool {
1677 if let Some(curr) = self.section_range(self.cursor()) {
1678 if self.cursor() != curr.start {
1679 return self.set_cursor(curr.start, extend_selection);
1680 }
1681 }
1682 if let Some(range) = self.prev_section_range(self.cursor()) {
1683 self.set_cursor(range.start, extend_selection)
1684 } else {
1685 false
1686 }
1687 }
1688
1689 #[inline]
1691 pub fn move_to_next_section(&mut self, extend_selection: bool) -> bool {
1692 if let Some(curr) = self.section_range(self.cursor()) {
1693 if self.cursor() != curr.end {
1694 return self.set_cursor(curr.end, extend_selection);
1695 }
1696 }
1697 if let Some(range) = self.next_section_range(self.cursor()) {
1698 self.set_cursor(range.end, extend_selection)
1699 } else {
1700 false
1701 }
1702 }
1703
1704 #[inline]
1706 pub fn select_current_section(&mut self) -> bool {
1707 let selection = self.selection();
1708
1709 if let Some(next) = self.section_range(selection.start.saturating_sub(1)) {
1710 if !next.is_empty() {
1711 self.set_selection(next.start, next.end)
1712 } else {
1713 false
1714 }
1715 } else {
1716 false
1717 }
1718 }
1719
1720 #[inline]
1722 pub fn select_next_section(&mut self) -> bool {
1723 let selection = self.selection();
1724
1725 if let Some(next) = self.next_section_range(selection.start) {
1726 if !next.is_empty() {
1727 self.set_selection(next.start, next.end)
1728 } else {
1729 false
1730 }
1731 } else {
1732 false
1733 }
1734 }
1735
1736 #[inline]
1738 pub fn select_prev_section(&mut self) -> bool {
1739 let selection = self.selection();
1740
1741 if let Some(next) = self.prev_section_range(selection.start.saturating_sub(1)) {
1742 if !next.is_empty() {
1743 self.set_selection(next.start, next.end)
1744 } else {
1745 false
1746 }
1747 } else {
1748 false
1749 }
1750 }
1751}
1752
1753impl HasScreenCursor for MaskedInputState {
1754 #[inline]
1756 fn screen_cursor(&self) -> Option<(u16, u16)> {
1757 if self.is_focused() {
1758 if self.has_selection() {
1759 None
1760 } else {
1761 let cx = self.cursor();
1762 let ox = self.offset();
1763
1764 if cx < ox {
1765 None
1766 } else if cx > ox + (self.inner.width + self.dark_offset.0) as upos_type {
1767 None
1768 } else {
1769 self.col_to_screen(cx)
1770 .map(|sc| (self.inner.x + sc, self.inner.y))
1771 }
1772 }
1773 } else {
1774 None
1775 }
1776 }
1777}
1778
1779impl RelocatableState for MaskedInputState {
1780 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
1781 self.dark_offset = relocate_dark_offset(self.inner, shift, clip);
1783 self.area = relocate_area(self.area, shift, clip);
1784 self.inner = relocate_area(self.inner, shift, clip);
1785 }
1786}
1787
1788impl MaskedInputState {
1789 fn glyphs2(&self) -> impl Iterator<Item = Glyph2<'_>> {
1790 let left_margin = self.offset();
1791 let right_margin = self.offset() + self.rendered.width as upos_type;
1792 let compact = self.compact && !self.is_focused();
1793
1794 let grapheme_iter = self
1795 .value
1796 .graphemes(TextRange::new((0, 0), (0, 1)), TextPosition::new(0, 0))
1797 .expect("valid-rows");
1798 let mask_iter = self.mask.iter();
1799
1800 let iter = MaskedGraphemes {
1801 iter_str: grapheme_iter,
1802 iter_mask: mask_iter,
1803 compact,
1804 sym_neg: self.neg_sym().to_string(),
1805 sym_dec: self.dec_sep().to_string(),
1806 sym_grp: self.grp_sep().to_string(),
1807 sym_pos: self.pos_sym().to_string(),
1808 byte_pos: 0,
1809 };
1810
1811 let mut it = GlyphIter2::new(TextPosition::new(0, 0), 0, iter, Default::default());
1812 it.set_tabs(0 );
1813 it.set_show_ctrl(self.value.glyph_ctrl());
1814 it.set_lf_breaks(false);
1815 it.set_text_wrap(TextWrap2::Shift);
1816 it.set_left_margin(left_margin);
1817 it.set_right_margin(right_margin);
1818 it.set_word_margin(right_margin);
1819 it.prepare().expect("valid-rows");
1820
1821 Box::new(it)
1822 }
1823
1824 pub fn screen_to_col(&self, scx: i16) -> upos_type {
1827 let ox = self.offset();
1828
1829 let scx = scx + self.dark_offset.0 as i16;
1830
1831 if scx < 0 {
1832 ox.saturating_sub((scx as ipos_type).unsigned_abs())
1833 } else if scx as u16 >= (self.inner.width + self.dark_offset.0) {
1834 min(ox + scx as upos_type, self.len())
1835 } else {
1836 let scx = scx as u16;
1837
1838 let line = self.glyphs2();
1839
1840 let mut col = ox;
1841 for g in line {
1842 if g.contains_screen_x(scx) {
1843 break;
1844 }
1845 col = g.pos().x + 1;
1846 }
1847 col
1848 }
1849 }
1850
1851 pub fn col_to_screen(&self, pos: upos_type) -> Option<u16> {
1854 let ox = self.offset();
1855
1856 if pos < ox {
1857 return None;
1858 }
1859
1860 let line = self.glyphs2();
1861 let mut screen_x = 0;
1862 for g in line {
1863 if g.pos().x == pos {
1864 break;
1865 }
1866 screen_x = g.screen_pos().0 + g.screen_width();
1867 }
1868
1869 if screen_x >= self.dark_offset.0 {
1870 Some(screen_x - self.dark_offset.0)
1871 } else {
1872 None
1873 }
1874 }
1875
1876 #[inline]
1880 pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
1881 let scx = cursor;
1882
1883 let cx = self.screen_to_col(scx);
1884
1885 self.set_cursor(cx, extend_selection)
1886 }
1887
1888 pub fn set_screen_cursor_sections(
1895 &mut self,
1896 screen_cursor: i16,
1897 extend_selection: bool,
1898 ) -> bool {
1899 let anchor = self.anchor();
1900 let cursor = self.screen_to_col(screen_cursor);
1901
1902 let Some(range) = self.section_range(cursor) else {
1903 return false;
1904 };
1905
1906 let cursor = if cursor < anchor {
1907 range.start
1908 } else {
1909 range.end
1910 };
1911
1912 if !self.is_section_boundary(anchor) {
1914 if let Some(range) = self.section_range(anchor) {
1915 if cursor < anchor {
1916 self.set_cursor(range.end, false);
1917 } else {
1918 self.set_cursor(range.start, false);
1919 }
1920 };
1921 }
1922
1923 self.set_cursor(cursor, extend_selection)
1924 }
1925
1926 pub fn scroll_left(&mut self, delta: upos_type) -> bool {
1928 self.set_offset(self.offset.saturating_sub(delta));
1929 true
1930 }
1931
1932 pub fn scroll_right(&mut self, delta: upos_type) -> bool {
1934 self.set_offset(self.offset + delta);
1935 true
1936 }
1937
1938 pub fn scroll_cursor_to_visible(&mut self) {
1940 self.scroll_to_cursor.set(true);
1941 }
1942}
1943
1944impl HandleEvent<crossterm::event::Event, Regular, TextOutcome> for MaskedInputState {
1945 fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> TextOutcome {
1946 fn tc(r: bool) -> TextOutcome {
1948 if r {
1949 TextOutcome::TextChanged
1950 } else {
1951 TextOutcome::Unchanged
1952 }
1953 }
1954 fn overwrite(state: &mut MaskedInputState) {
1955 if state.overwrite.get() {
1956 state.overwrite.set(false);
1957 state.clear();
1958 }
1959 }
1960 fn clear_overwrite(state: &mut MaskedInputState) {
1961 state.overwrite.set(false);
1962 }
1963
1964 let mut r = if self.is_focused() {
1989 match event {
1990 ct_event!(key press c)
1991 | ct_event!(key press SHIFT-c)
1992 | ct_event!(key press CONTROL_ALT-c) => {
1993 overwrite(self);
1994 tc(self.insert_char(*c))
1995 }
1996 ct_event!(keycode press Backspace) => {
1997 clear_overwrite(self);
1998 tc(self.delete_prev_char())
1999 }
2000 ct_event!(keycode press Delete) => {
2001 clear_overwrite(self);
2002 tc(self.delete_next_char())
2003 }
2004 ct_event!(keycode press CONTROL-Backspace)
2005 | ct_event!(keycode press ALT-Backspace) => {
2006 clear_overwrite(self);
2007 tc(self.delete_prev_section())
2008 }
2009 ct_event!(keycode press CONTROL-Delete) => {
2010 clear_overwrite(self);
2011 tc(self.delete_next_section())
2012 }
2013 ct_event!(key press CONTROL-'x') => {
2014 clear_overwrite(self);
2015 tc(self.cut_to_clip())
2016 }
2017 ct_event!(key press CONTROL-'v') => {
2018 clear_overwrite(self);
2019 tc(self.paste_from_clip())
2020 }
2021 ct_event!(key press CONTROL-'d') => {
2022 clear_overwrite(self);
2023 tc(self.clear())
2024 }
2025 ct_event!(key press CONTROL-'z') => {
2026 clear_overwrite(self);
2027 tc(self.undo())
2028 }
2029 ct_event!(key press CONTROL_SHIFT-'Z') => {
2030 clear_overwrite(self);
2031 tc(self.redo())
2032 }
2033
2034 ct_event!(key release _)
2035 | ct_event!(key release SHIFT-_)
2036 | ct_event!(key release CONTROL_ALT-_)
2037 | ct_event!(keycode release Backspace)
2038 | ct_event!(keycode release Delete)
2039 | ct_event!(keycode release CONTROL-Backspace)
2040 | ct_event!(keycode release ALT-Backspace)
2041 | ct_event!(keycode release CONTROL-Delete)
2042 | ct_event!(key release CONTROL-'x')
2043 | ct_event!(key release CONTROL-'v')
2044 | ct_event!(key release CONTROL-'d')
2045 | ct_event!(key release CONTROL-'z')
2046 | ct_event!(key release CONTROL_SHIFT-'Z') => TextOutcome::Unchanged,
2047
2048 _ => TextOutcome::Continue,
2049 }
2050 } else {
2051 TextOutcome::Continue
2052 };
2053
2054 if r == TextOutcome::Continue {
2055 r = self.handle(event, ReadOnly);
2056 }
2057 r
2058 }
2059}
2060
2061impl HandleEvent<crossterm::event::Event, ReadOnly, TextOutcome> for MaskedInputState {
2062 fn handle(&mut self, event: &crossterm::event::Event, _keymap: ReadOnly) -> TextOutcome {
2063 fn clear_overwrite(state: &mut MaskedInputState) {
2064 state.overwrite.set(false);
2065 }
2066
2067 let mut r = if self.is_focused() {
2068 match event {
2069 ct_event!(keycode press Left) => {
2070 clear_overwrite(self);
2071 self.move_left(false).into()
2072 }
2073 ct_event!(keycode press Right) => {
2074 clear_overwrite(self);
2075 self.move_right(false).into()
2076 }
2077 ct_event!(keycode press CONTROL-Left) => {
2078 clear_overwrite(self);
2079 self.move_to_prev_section(false).into()
2080 }
2081 ct_event!(keycode press CONTROL-Right) => {
2082 clear_overwrite(self);
2083 self.move_to_next_section(false).into()
2084 }
2085 ct_event!(keycode press Home) => {
2086 clear_overwrite(self);
2087 self.move_to_line_start(false).into()
2088 }
2089 ct_event!(keycode press End) => {
2090 clear_overwrite(self);
2091 self.move_to_line_end(false).into()
2092 }
2093 ct_event!(keycode press SHIFT-Left) => {
2094 clear_overwrite(self);
2095 self.move_left(true).into()
2096 }
2097 ct_event!(keycode press SHIFT-Right) => {
2098 clear_overwrite(self);
2099 self.move_right(true).into()
2100 }
2101 ct_event!(keycode press CONTROL_SHIFT-Left) => {
2102 clear_overwrite(self);
2103 self.move_to_prev_section(true).into()
2104 }
2105 ct_event!(keycode press CONTROL_SHIFT-Right) => {
2106 clear_overwrite(self);
2107 self.move_to_next_section(true).into()
2108 }
2109 ct_event!(keycode press SHIFT-Home) => {
2110 clear_overwrite(self);
2111 self.move_to_line_start(true).into()
2112 }
2113 ct_event!(keycode press SHIFT-End) => {
2114 clear_overwrite(self);
2115 self.move_to_line_end(true).into()
2116 }
2117 ct_event!(keycode press Tab) => {
2118 if !self.focus.gained() {
2120 clear_overwrite(self);
2121 self.select_next_section().into()
2122 } else {
2123 TextOutcome::Unchanged
2124 }
2125 }
2126 ct_event!(keycode press SHIFT-BackTab) => {
2127 if !self.focus.gained() {
2129 clear_overwrite(self);
2130 self.select_prev_section().into()
2131 } else {
2132 TextOutcome::Unchanged
2133 }
2134 }
2135 ct_event!(key press CONTROL-'a') => {
2136 clear_overwrite(self);
2137 self.select_all().into()
2138 }
2139 ct_event!(key press CONTROL-'c') => {
2140 clear_overwrite(self);
2141 self.copy_to_clip().into()
2142 }
2143
2144 ct_event!(keycode release Left)
2145 | ct_event!(keycode release Right)
2146 | ct_event!(keycode release CONTROL-Left)
2147 | ct_event!(keycode release CONTROL-Right)
2148 | ct_event!(keycode release Home)
2149 | ct_event!(keycode release End)
2150 | ct_event!(keycode release SHIFT-Left)
2151 | ct_event!(keycode release SHIFT-Right)
2152 | ct_event!(keycode release CONTROL_SHIFT-Left)
2153 | ct_event!(keycode release CONTROL_SHIFT-Right)
2154 | ct_event!(keycode release SHIFT-Home)
2155 | ct_event!(keycode release SHIFT-End)
2156 | ct_event!(key release CONTROL-'a')
2157 | ct_event!(key release CONTROL-'c') => TextOutcome::Unchanged,
2158
2159 _ => TextOutcome::Continue,
2160 }
2161 } else {
2162 TextOutcome::Continue
2163 };
2164
2165 if r == TextOutcome::Continue {
2166 r = self.handle(event, MouseOnly);
2167 }
2168 r
2169 }
2170}
2171
2172impl HandleEvent<crossterm::event::Event, MouseOnly, TextOutcome> for MaskedInputState {
2173 fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> TextOutcome {
2174 fn clear_overwrite(state: &mut MaskedInputState) {
2175 state.overwrite.set(false);
2176 }
2177
2178 match event {
2179 ct_event!(mouse any for m) if self.mouse.drag(self.inner, m) => {
2180 let c = (m.column as i16) - (self.inner.x as i16);
2181 clear_overwrite(self);
2182 self.set_screen_cursor(c, true).into()
2183 }
2184 ct_event!(mouse any for m) if self.mouse.drag2(self.inner, m, KeyModifiers::ALT) => {
2185 let cx = m.column as i16 - self.inner.x as i16;
2186 clear_overwrite(self);
2187 self.set_screen_cursor_sections(cx, true).into()
2188 }
2189 ct_event!(mouse any for m) if self.mouse.doubleclick(self.inner, m) => {
2190 let tx = self.screen_to_col(m.column as i16 - self.inner.x as i16);
2191 clear_overwrite(self);
2192 if let Some(range) = self.section_range(tx) {
2193 self.set_selection(range.start, range.end).into()
2194 } else {
2195 TextOutcome::Unchanged
2196 }
2197 }
2198 ct_event!(mouse down Left for column,row) => {
2199 if self.gained_focus() {
2200 TextOutcome::Unchanged
2203 } else if self.inner.contains((*column, *row).into()) {
2204 let c = (column - self.inner.x) as i16;
2205 clear_overwrite(self);
2206 self.set_screen_cursor(c, false).into()
2207 } else {
2208 TextOutcome::Continue
2209 }
2210 }
2211 ct_event!(mouse down CONTROL-Left for column,row) => {
2212 if self.inner.contains((*column, *row).into()) {
2213 let cx = (column - self.inner.x) as i16;
2214 clear_overwrite(self);
2215 self.set_screen_cursor(cx, true).into()
2216 } else {
2217 TextOutcome::Continue
2218 }
2219 }
2220 ct_event!(mouse down ALT-Left for column,row) => {
2221 if self.inner.contains((*column, *row).into()) {
2222 let cx = (column - self.inner.x) as i16;
2223 clear_overwrite(self);
2224 self.set_screen_cursor_sections(cx, true).into()
2225 } else {
2226 TextOutcome::Continue
2227 }
2228 }
2229 _ => TextOutcome::Continue,
2230 }
2231 }
2232}
2233
2234pub fn handle_events(
2238 state: &mut MaskedInputState,
2239 focus: bool,
2240 event: &crossterm::event::Event,
2241) -> TextOutcome {
2242 state.focus.set(focus);
2243 state.handle(event, Regular)
2244}
2245
2246pub fn handle_readonly_events(
2250 state: &mut TextInputState,
2251 focus: bool,
2252 event: &crossterm::event::Event,
2253) -> TextOutcome {
2254 state.focus.set(focus);
2255 state.handle(event, ReadOnly)
2256}
2257
2258pub fn handle_mouse_events(
2260 state: &mut MaskedInputState,
2261 event: &crossterm::event::Event,
2262) -> TextOutcome {
2263 state.handle(event, MouseOnly)
2264}