rat_text/
color_input.rs

1/// Widget for color input.
2///
3/// Currently, supports
4/// * RGB
5/// * HSV
6/// * hexdigits
7///
8/// __Keybindings__
9///
10/// * Switch between color-mode with Up/Down. (or m/M)
11/// * '+' and Alt-'+' increase the value
12/// * '-' and Alt-'-' decrease the value
13/// * 'r', 'h', 'x' switch mode
14///
15/// __Clipboard__
16///
17/// Recognizes common formats when pasted from the clipboard.
18/// * #000000 and #00000000
19/// * 0x000000 and 0x00000000
20/// * 000000 and 00000000
21///
22use crate::_private::NonExhaustive;
23use crate::clipboard::Clipboard;
24use crate::event::{ReadOnly, TextOutcome};
25use crate::text_input_mask::{MaskedInput, MaskedInputState};
26use crate::undo_buffer::{UndoBuffer, UndoEntry};
27use crate::{TextError, TextFocusGained, TextFocusLost, TextStyle, upos_type};
28use palette::{FromColor, Hsv, Srgb};
29use rat_cursor::HasScreenCursor;
30use rat_event::{HandleEvent, MouseOnly, Regular, ct_event, flow};
31use rat_focus::{FocusBuilder, FocusFlag, HasFocus};
32use rat_reloc::RelocatableState;
33use ratatui::buffer::Buffer;
34use ratatui::layout::Rect;
35use ratatui::prelude::BlockExt;
36use ratatui::style::{Color, Style};
37use ratatui::text::Line;
38use ratatui::widgets::{Block, StatefulWidget, Widget};
39use std::cmp::min;
40use std::ops::Range;
41
42/// Color input widget.
43///
44/// A text input for colors.
45///
46#[derive(Debug, Default)]
47pub struct ColorInput<'a> {
48    style: Style,
49    disable_modes: bool,
50    mode: Option<Mode>,
51    block: Option<Block<'a>>,
52    widget: MaskedInput<'a>,
53}
54
55/// Combined styles.
56#[derive(Debug)]
57pub struct ColorInputStyle {
58    /// Base style.
59    pub text: TextStyle,
60    /// Highlighting the field of the input.
61    pub field_style: Option<Style>,
62    /// Disable mode switching.
63    pub disable_modes: Option<bool>,
64    /// Define default mode.
65    pub mode: Option<Mode>,
66    ///
67    pub non_exhaustive: NonExhaustive,
68}
69
70impl Default for ColorInputStyle {
71    fn default() -> Self {
72        Self {
73            text: Default::default(),
74            field_style: Default::default(),
75            disable_modes: Default::default(),
76            mode: Default::default(),
77            non_exhaustive: NonExhaustive,
78        }
79    }
80}
81
82/// Color mode.
83#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
84pub enum Mode {
85    #[default]
86    RGB,
87    HEX,
88    HSV,
89}
90
91/// State for the color input.
92#[derive(Debug)]
93pub struct ColorInputState {
94    /// Area of the widget.
95    /// __read only__ renewed with each render.
96    pub area: Rect,
97    /// Area inside the block.
98    pub widget_area: Rect,
99    /// Area for the mode.
100    /// __read_only__ renewed with each render.
101    pub mode_area: Rect,
102    /// Area for the mode label.
103    /// __read_only__ renewed with each render.
104    pub label_area: Rect,
105
106    /// value as RGB with 0.0..1.0 ranges.
107    pub value: (f32, f32, f32),
108
109    /// Disable keys for mode switching.
110    /// __read only__
111    pub disable_modes: bool,
112    /// __read only__
113    pub mode: Mode,
114    /// __read only__
115    pub widget: MaskedInputState,
116
117    pub non_exhaustive: NonExhaustive,
118}
119
120impl<'a> ColorInput<'a> {
121    pub fn new() -> Self {
122        Self::default()
123    }
124
125    /// Set the combined style.
126    #[inline]
127    pub fn styles(mut self, mut style: ColorInputStyle) -> Self {
128        self.style = style.text.style;
129        if let Some(border_style) = style.text.border_style {
130            self.block = self.block.map(|v| v.style(border_style));
131        }
132        if let Some(block) = style.text.block.take() {
133            self.block = Some(block);
134        }
135        self.widget = self.widget.styles(style.text);
136        if let Some(disable_modes) = style.disable_modes {
137            self.disable_modes = disable_modes;
138        }
139        if let Some(mode) = style.mode {
140            self.mode = Some(mode);
141        }
142        if let Some(field_style) = style.field_style {
143            self.widget = self.widget.text_style_idx(1, field_style);
144        }
145        self
146    }
147
148    /// Base text style.
149    #[inline]
150    pub fn style(mut self, style: impl Into<Style>) -> Self {
151        let style = style.into();
152        self.style = style;
153        self.widget = self.widget.style(style);
154        self
155    }
156
157    /// Style for the fields of the input.
158    #[inline]
159    pub fn field_style(mut self, style: impl Into<Style>) -> Self {
160        self.widget = self.widget.text_style_idx(1, style.into());
161        self
162    }
163
164    /// Disable switching the mode.
165    #[inline]
166    pub fn disable_modes(mut self) -> Self {
167        self.disable_modes = true;
168        self
169    }
170
171    /// Color mode.
172    #[inline]
173    pub fn mode(mut self, mode: Mode) -> Self {
174        self.mode = Some(mode);
175        self
176    }
177
178    /// Style when focused.
179    #[inline]
180    pub fn focus_style(mut self, style: impl Into<Style>) -> Self {
181        self.widget = self.widget.focus_style(style);
182        self
183    }
184
185    /// Style for selection
186    #[inline]
187    pub fn select_style(mut self, style: impl Into<Style>) -> Self {
188        self.widget = self.widget.select_style(style);
189        self
190    }
191
192    /// Style for the invalid indicator.
193    #[inline]
194    pub fn invalid_style(mut self, style: impl Into<Style>) -> Self {
195        self.widget = self.widget.invalid_style(style);
196        self
197    }
198
199    /// Block
200    #[inline]
201    pub fn block(mut self, block: Block<'a>) -> Self {
202        self.block = Some(block);
203        self
204    }
205
206    /// Focus behaviour
207    #[inline]
208    pub fn on_focus_gained(mut self, of: TextFocusGained) -> Self {
209        self.widget = self.widget.on_focus_gained(of);
210        self
211    }
212
213    /// Focus behaviour
214    #[inline]
215    pub fn on_focus_lost(mut self, of: TextFocusLost) -> Self {
216        self.widget = self.widget.on_focus_lost(of);
217        self
218    }
219}
220
221impl<'a> StatefulWidget for &ColorInput<'a> {
222    type State = ColorInputState;
223
224    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
225        render(self, area, buf, state);
226    }
227}
228
229impl StatefulWidget for ColorInput<'_> {
230    type State = ColorInputState;
231
232    fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
233        render(&self, area, buf, state);
234    }
235}
236
237fn render(widget: &ColorInput<'_>, area: Rect, buf: &mut Buffer, state: &mut ColorInputState) {
238    state.disable_modes = widget.disable_modes;
239    if let Some(mode) = widget.mode {
240        state.mode = mode;
241    }
242
243    let inner = widget.block.inner_if_some(area);
244
245    let mode_area = Rect::new(inner.x, inner.y, 4, inner.height);
246    let mode_label = Rect::new(mode_area.x, mode_area.y + mode_area.height / 2, 4, 1);
247    let widget_area = Rect::new(
248        inner.x + mode_area.width,
249        inner.y,
250        inner.width.saturating_sub(mode_area.width),
251        inner.height,
252    );
253
254    state.widget_area = inner;
255    state.mode_area = mode_area;
256    state.label_area = mode_label;
257
258    let bg = state.value();
259    let fg_colors = [Color::Black, Color::White];
260    let style = high_contrast_color(bg, &fg_colors);
261
262    widget.block.render(area, buf);
263
264    buf.set_style(mode_area, style);
265    let mode_str = match state.mode {
266        Mode::RGB => "RGB",
267        Mode::HEX => "  #",
268        Mode::HSV => "HSV",
269    };
270    Line::from(mode_str).render(mode_label, buf);
271
272    (&widget.widget).render(widget_area, buf, &mut state.widget);
273}
274
275impl Default for ColorInputState {
276    fn default() -> Self {
277        let mut z = Self {
278            area: Default::default(),
279            widget_area: Default::default(),
280            mode_area: Default::default(),
281            label_area: Default::default(),
282            value: Default::default(),
283            disable_modes: Default::default(),
284            mode: Default::default(),
285            widget: Default::default(),
286            non_exhaustive: NonExhaustive,
287        };
288        z.set_mode(Mode::RGB);
289        z
290    }
291}
292
293impl HasFocus for ColorInputState {
294    fn build(&self, builder: &mut FocusBuilder) {
295        builder.widget_with_flags(
296            self.widget.focus(),
297            self.area,
298            self.widget.area_z(),
299            self.widget.navigable(),
300        );
301    }
302
303    fn focus(&self) -> FocusFlag {
304        self.widget.focus()
305    }
306
307    fn area(&self) -> Rect {
308        self.area
309    }
310}
311
312impl ColorInputState {
313    pub fn new() -> Self {
314        Self::default()
315    }
316
317    pub fn named(name: &str) -> Self {
318        Self {
319            widget: MaskedInputState::named(name),
320            ..Default::default()
321        }
322    }
323
324    /// The next edit operation will overwrite the current content
325    /// instead of adding text. Any move operations will cancel
326    /// this overwrite.
327    #[inline]
328    pub fn set_overwrite(&mut self, overwrite: bool) {
329        self.widget.set_overwrite(overwrite);
330    }
331
332    /// Will the next edit operation overwrite the content?
333    #[inline]
334    pub fn overwrite(&self) -> bool {
335        self.widget.overwrite()
336    }
337}
338
339impl ColorInputState {
340    /// Clipboard used.
341    /// Default is to use the [global_clipboard](crate::clipboard::global_clipboard).
342    #[inline]
343    pub fn set_clipboard(&mut self, clip: Option<impl Clipboard + 'static>) {
344        self.widget.set_clipboard(clip);
345    }
346
347    /// Clipboard used.
348    /// Default is to use the [global_clipboard](crate::clipboard::global_clipboard).
349    #[inline]
350    pub fn clipboard(&self) -> Option<&dyn Clipboard> {
351        self.widget.clipboard()
352    }
353
354    /// Copy to clipboard
355    #[inline]
356    pub fn copy_to_clip(&mut self) -> bool {
357        let Some(clip) = self.widget.value.clipboard() else {
358            return false;
359        };
360
361        if self.has_selection() {
362            _ = clip.set_string(self.selected_text().as_ref());
363        } else {
364            let r = (self.value.0 * 255f32) as u32;
365            let g = (self.value.1 * 255f32) as u32;
366            let b = (self.value.2 * 255f32) as u32;
367            let value_str = format!("{:06x}", (r << 16) + (g << 8) + b);
368            _ = clip.set_string(&value_str);
369        }
370        true
371    }
372
373    /// Cut to clipboard
374    #[inline]
375    pub fn cut_to_clip(&mut self) -> bool {
376        let Some(clip) = self.widget.value.clipboard() else {
377            return false;
378        };
379
380        if self.has_selection() {
381            match clip.set_string(self.selected_text().as_ref()) {
382                Ok(_) => self.delete_range(self.selection()),
383                Err(_) => false,
384            }
385        } else {
386            let r = (self.value.0 * 255f32) as u32;
387            let g = (self.value.1 * 255f32) as u32;
388            let b = (self.value.2 * 255f32) as u32;
389            let value_str = format!("{:06x}", (r << 16) + (g << 8) + b);
390
391            match clip.set_string(&value_str) {
392                Ok(_) => self.clear(),
393                Err(_) => {}
394            }
395            true
396        }
397    }
398
399    /// Paste from clipboard.
400    #[inline]
401    pub fn paste_from_clip(&mut self) -> bool {
402        let Some(clip) = self.widget.value.clipboard() else {
403            return false;
404        };
405
406        if let Ok(text) = clip.get_string() {
407            if text.starts_with("#") && text.len() == 7 {
408                // #aabbcc
409                if let Ok(v) = u32::from_str_radix(&text[1..7], 16) {
410                    self.set_value_u32(v);
411                }
412            } else if text.starts_with("#") && text.len() == 9 {
413                // #aabbccdd
414                if let Ok(v) = u32::from_str_radix(&text[1..7], 16) {
415                    self.set_value_u32(v);
416                }
417            } else if text.starts_with("0x") && text.len() == 8 {
418                // 0xaabbcc
419                if let Ok(v) = u32::from_str_radix(&text[2..8], 16) {
420                    self.set_value_u32(v);
421                }
422            } else if text.starts_with("0x") && text.len() == 10 {
423                // 0xaabbccdd
424                if let Ok(v) = u32::from_str_radix(&text[2..8], 16) {
425                    self.set_value_u32(v);
426                }
427            } else if text.len() == 6 {
428                // aabbcc
429                if let Ok(v) = u32::from_str_radix(&text[0..6], 16) {
430                    self.set_value_u32(v);
431                }
432            } else if text.len() == 8 {
433                // aabbccdd
434                if let Ok(v) = u32::from_str_radix(&text[0..6], 16) {
435                    self.set_value_u32(v);
436                }
437            } else {
438                for c in text.chars() {
439                    self.widget.insert_char(c);
440                }
441            }
442            true
443        } else {
444            false
445        }
446    }
447}
448
449impl ColorInputState {
450    /// Set undo buffer.
451    #[inline]
452    pub fn set_undo_buffer(&mut self, undo: Option<impl UndoBuffer + 'static>) {
453        self.widget.set_undo_buffer(undo);
454    }
455
456    /// Undo
457    #[inline]
458    pub fn undo_buffer(&self) -> Option<&dyn UndoBuffer> {
459        self.widget.undo_buffer()
460    }
461
462    /// Undo
463    #[inline]
464    pub fn undo_buffer_mut(&mut self) -> Option<&mut dyn UndoBuffer> {
465        self.widget.undo_buffer_mut()
466    }
467
468    /// Get all recent replay recordings.
469    #[inline]
470    pub fn recent_replay_log(&mut self) -> Vec<UndoEntry> {
471        self.widget.recent_replay_log()
472    }
473
474    /// Apply the replay recording.
475    #[inline]
476    pub fn replay_log(&mut self, replay: &[UndoEntry]) {
477        self.widget.replay_log(replay)
478    }
479
480    /// Undo operation
481    #[inline]
482    pub fn undo(&mut self) -> bool {
483        self.widget.undo()
484    }
485
486    /// Redo operation
487    #[inline]
488    pub fn redo(&mut self) -> bool {
489        self.widget.redo()
490    }
491}
492
493impl ColorInputState {
494    /// Set and replace all styles.
495    #[inline]
496    pub fn set_styles(&mut self, styles: Vec<(Range<usize>, usize)>) {
497        self.widget.set_styles(styles);
498    }
499
500    /// Add a style for a byte-range.
501    #[inline]
502    pub fn add_style(&mut self, range: Range<usize>, style: usize) {
503        self.widget.add_style(range, style);
504    }
505
506    /// Add a style for a `Range<upos_type>` .
507    /// The style-nr refers to one of the styles set with the widget.
508    #[inline]
509    pub fn add_range_style(
510        &mut self,
511        range: Range<upos_type>,
512        style: usize,
513    ) -> Result<(), TextError> {
514        self.widget.add_range_style(range, style)
515    }
516
517    /// Remove the exact TextRange and style.
518    #[inline]
519    pub fn remove_style(&mut self, range: Range<usize>, style: usize) {
520        self.widget.remove_style(range, style);
521    }
522
523    /// Remove the exact `Range<upos_type>` and style.
524    #[inline]
525    pub fn remove_range_style(
526        &mut self,
527        range: Range<upos_type>,
528        style: usize,
529    ) -> Result<(), TextError> {
530        self.widget.remove_range_style(range, style)
531    }
532
533    /// Find all styles that touch the given range.
534    pub fn styles_in(&self, range: Range<usize>, buf: &mut Vec<(Range<usize>, usize)>) {
535        self.widget.styles_in(range, buf)
536    }
537
538    /// All styles active at the given position.
539    #[inline]
540    pub fn styles_at(&self, byte_pos: usize, buf: &mut Vec<(Range<usize>, usize)>) {
541        self.widget.styles_at(byte_pos, buf)
542    }
543
544    /// Check if the given style applies at the position and
545    /// return the complete range for the style.
546    #[inline]
547    pub fn style_match(&self, byte_pos: usize, style: usize) -> Option<Range<usize>> {
548        self.widget.styles_at_match(byte_pos, style)
549    }
550
551    /// List of all styles.
552    #[inline]
553    pub fn styles(&self) -> Option<impl Iterator<Item = (Range<usize>, usize)> + '_> {
554        self.widget.styles()
555    }
556}
557
558impl ColorInputState {
559    /// Offset shown.
560    #[inline]
561    pub fn offset(&self) -> upos_type {
562        self.widget.offset()
563    }
564
565    /// Offset shown. This is corrected if the cursor wouldn't be visible.
566    #[inline]
567    pub fn set_offset(&mut self, offset: upos_type) {
568        self.widget.set_offset(offset)
569    }
570
571    /// Cursor position
572    #[inline]
573    pub fn cursor(&self) -> upos_type {
574        self.widget.cursor()
575    }
576
577    /// Set the cursor position, reset selection.
578    #[inline]
579    pub fn set_cursor(&mut self, cursor: upos_type, extend_selection: bool) -> bool {
580        self.widget.set_cursor(cursor, extend_selection)
581    }
582
583    /// Place cursor at some sensible position according to the mask.
584    #[inline]
585    pub fn set_default_cursor(&mut self) {
586        self.widget.set_default_cursor()
587    }
588
589    /// Selection anchor.
590    #[inline]
591    pub fn anchor(&self) -> upos_type {
592        self.widget.anchor()
593    }
594
595    /// Selection
596    #[inline]
597    pub fn has_selection(&self) -> bool {
598        self.widget.has_selection()
599    }
600
601    /// Selection
602    #[inline]
603    pub fn selection(&self) -> Range<upos_type> {
604        self.widget.selection()
605    }
606
607    /// Selection
608    #[inline]
609    pub fn set_selection(&mut self, anchor: upos_type, cursor: upos_type) -> bool {
610        self.widget.set_selection(anchor, cursor)
611    }
612
613    /// Select all text.
614    #[inline]
615    pub fn select_all(&mut self) {
616        self.widget.select_all();
617    }
618
619    /// Selection
620    #[inline]
621    pub fn selected_text(&self) -> &str {
622        self.widget.selected_text()
623    }
624}
625
626impl ColorInputState {
627    /// Empty
628    #[inline]
629    pub fn is_empty(&self) -> bool {
630        self.widget.is_empty()
631    }
632
633    /// Value as Color.
634    pub fn value(&self) -> Color {
635        Color::Rgb(
636            (self.value.0 * 255f32) as u8,
637            (self.value.1 * 255f32) as u8,
638            (self.value.2 * 255f32) as u8,
639        )
640    }
641
642    fn parse_value(&self) -> (f32, f32, f32) {
643        let r = match self.mode {
644            Mode::RGB => {
645                let r = self.widget.section_value::<f32>(SEC_R).unwrap_or_default();
646                let g = self.widget.section_value::<f32>(SEC_G).unwrap_or_default();
647                let b = self.widget.section_value::<f32>(SEC_B).unwrap_or_default();
648                (r / 255f32, g / 255f32, b / 255f32)
649            }
650            Mode::HEX => {
651                let v = u32::from_str_radix(self.widget.section_text(1), 16).expect("hex");
652                let r = ((v >> 16) & 255) as f32;
653                let g = ((v >> 8) & 255) as f32;
654                let b = (v & 255) as f32;
655                (r / 255f32, g / 255f32, b / 255f32)
656            }
657            Mode::HSV => {
658                let h = self.widget.section_value::<f32>(SEC_H).unwrap_or_default();
659                let s = self.widget.section_value::<f32>(SEC_S).unwrap_or_default();
660                let v = self.widget.section_value::<f32>(SEC_V).unwrap_or_default();
661
662                let h = palette::RgbHue::from_degrees(h);
663                let s = s / 100f32;
664                let v = v / 100f32;
665
666                let hsv = Hsv::from_components((h, s, v));
667                let rgb = Srgb::from_color(hsv);
668
669                rgb.into_components()
670            }
671        };
672        r
673    }
674
675    /// Length in grapheme count.
676    #[inline]
677    pub fn len(&self) -> upos_type {
678        self.widget.len()
679    }
680
681    /// Length as grapheme count.
682    #[inline]
683    pub fn line_width(&self) -> upos_type {
684        self.widget.line_width()
685    }
686}
687
688impl ColorInputState {
689    /// Reset to empty.
690    #[inline]
691    pub fn clear(&mut self) {
692        self.widget.clear();
693    }
694
695    /// Set the color as u32
696    pub fn set_value_u32(&mut self, color: u32) {
697        let r = ((color >> 16) & 255) as f32;
698        let g = ((color >> 8) & 255) as f32;
699        let b = (color & 255) as f32;
700        self.value = (r / 255f32, g / 255f32, b / 255f32);
701        self.value_to_text();
702    }
703
704    /// Set the color as Color.
705    pub fn set_value(&mut self, color: Color) {
706        let (r, g, b) = color2rgb(color);
707        self.value = (r as f32 / 255f32, g as f32 / 255f32, b as f32 / 255f32);
708        self.value_to_text();
709    }
710
711    fn value_to_text(&mut self) {
712        match self.mode {
713            Mode::RGB => {
714                let r = (self.value.0 * 255f32) as u8;
715                let g = (self.value.1 * 255f32) as u8;
716                let b = (self.value.2 * 255f32) as u8;
717                let value_str = format!("{:3} {:3} {:3}", r, g, b);
718                self.widget.set_text(value_str);
719                self.set_mode_styles();
720            }
721            Mode::HEX => {
722                let r = (self.value.0 * 255f32) as u32;
723                let g = (self.value.1 * 255f32) as u32;
724                let b = (self.value.2 * 255f32) as u32;
725                let value_str = format!("{:06x}", (r << 16) + (g << 8) + b);
726                self.widget.set_text(value_str);
727                self.set_mode_styles();
728            }
729            Mode::HSV => {
730                let r = self.value.0;
731                let g = self.value.1;
732                let b = self.value.2;
733                let srgb = Srgb::new(r, g, b);
734                let hsv = Hsv::from_color(srgb);
735                let (h, s, v) = hsv.into_components();
736                let h = h.into_positive_degrees() as u32;
737                let s = (s * 100f32) as u32;
738                let v = (v * 100f32) as u32;
739                let value_str = format!("{:3} {:3} {:3}", h, s, v);
740                self.widget.set_text(value_str);
741                self.set_mode_styles();
742            }
743        }
744    }
745
746    /// Insert a char at the current position.
747    #[inline]
748    pub fn insert_char(&mut self, c: char) -> bool {
749        let r = self.widget.insert_char(c);
750        self.normalize();
751        r
752    }
753
754    /// Remove the selected range. The text will be replaced with the default value
755    /// as defined by the mask.
756    #[inline]
757    pub fn delete_range(&mut self, range: Range<upos_type>) -> bool {
758        let r = self.widget.delete_range(range);
759        self.normalize();
760        r
761    }
762
763    /// Remove the selected range. The text will be replaced with the default value
764    /// as defined by the mask.
765    #[inline]
766    pub fn try_delete_range(&mut self, range: Range<upos_type>) -> Result<bool, TextError> {
767        let r = self.widget.try_delete_range(range);
768        self.normalize();
769        r
770    }
771}
772
773const PAT_RGB: &'static str = "##0 ##0 ##0";
774const SEC_R: u16 = 1;
775const SEC_G: u16 = 3;
776const SEC_B: u16 = 5;
777
778const PAT_HEX: &'static str = "HHHHHH";
779#[allow(dead_code)]
780const SEC_X: u16 = 1;
781
782const PAT_HSV: &'static str = "##0 ##0 ##0";
783const SEC_H: u16 = 1;
784const SEC_S: u16 = 3;
785const SEC_V: u16 = 5;
786
787impl ColorInputState {
788    fn clamp_section(&mut self, section: u16, clamp: u32) -> bool {
789        let r = self
790            .widget
791            .section_value::<u32>(section)
792            .unwrap_or_default();
793        let r_min = min(r, clamp);
794        if r_min != r {
795            self.widget.set_section_value(section, r_min);
796            true
797        } else {
798            false
799        }
800    }
801
802    /// Correct the numeric values for each component.
803    fn normalize(&mut self) -> bool {
804        let r = match self.mode {
805            Mode::RGB => {
806                self.clamp_section(SEC_R, 255)
807                    || self.clamp_section(SEC_G, 255)
808                    || self.clamp_section(SEC_B, 255)
809            }
810            Mode::HEX => {
811                // noop
812                false
813            }
814            Mode::HSV => {
815                self.clamp_section(SEC_H, 360)
816                    || self.clamp_section(SEC_S, 100)
817                    || self.clamp_section(SEC_V, 100)
818            }
819        };
820        self.set_mode_styles();
821        r
822    }
823
824    /// Increment the value at the cursor position.
825    pub fn increment(&mut self, n: u32) -> bool {
826        let section = self.widget.section_id(self.widget.cursor());
827        let r = match self.mode {
828            Mode::RGB => match section {
829                SEC_R | SEC_G | SEC_B => {
830                    let r = self
831                        .widget
832                        .section_value::<u32>(section)
833                        .unwrap_or_default();
834                    let r_min = min(r + n, 255);
835                    if r_min != r {
836                        self.widget.set_section_value(section, r_min);
837                        self.set_mode_styles();
838                        true
839                    } else {
840                        false
841                    }
842                }
843                _ => false,
844            },
845            Mode::HEX => {
846                // noop
847                false
848            }
849            Mode::HSV => match section {
850                SEC_H => {
851                    let r = self
852                        .widget
853                        .section_value::<u32>(section)
854                        .unwrap_or_default();
855                    let r_min = (r + n) % 360;
856                    if r_min != r {
857                        self.widget.set_section_value(section, r_min);
858                        self.set_mode_styles();
859                        true
860                    } else {
861                        false
862                    }
863                }
864                SEC_S | SEC_V => {
865                    let r = self
866                        .widget
867                        .section_value::<u32>(section)
868                        .unwrap_or_default();
869                    let r_min = min(r + n, 100);
870                    if r_min != r {
871                        self.widget.set_section_value(section, r_min);
872                        self.set_mode_styles();
873                        true
874                    } else {
875                        false
876                    }
877                }
878                _ => false,
879            },
880        };
881
882        if r {
883            self.value = self.parse_value();
884        }
885        r
886    }
887
888    /// Decrement the value at the cursor position.
889    pub fn decrement(&mut self, n: u32) -> bool {
890        let section = self.widget.section_id(self.widget.cursor());
891        let r = match self.mode {
892            Mode::RGB => match section {
893                SEC_R | SEC_G | SEC_B => {
894                    let r = self
895                        .widget
896                        .section_value::<u32>(section)
897                        .unwrap_or_default();
898                    let r_min = r.saturating_sub(n);
899                    if r_min != r {
900                        self.widget.set_section_value(section, r_min);
901                        self.set_mode_styles();
902                        true
903                    } else {
904                        false
905                    }
906                }
907                _ => false,
908            },
909            Mode::HEX => {
910                // noop
911                false
912            }
913            Mode::HSV => match section {
914                SEC_H => {
915                    let r = self
916                        .widget
917                        .section_value::<u32>(section)
918                        .unwrap_or_default();
919                    let r_min = if r > n {
920                        r - n
921                    } else {
922                        360u32.saturating_sub(n - r)
923                    };
924                    if r_min != r {
925                        self.widget.set_section_value(section, r_min);
926                        self.set_mode_styles();
927                        true
928                    } else {
929                        false
930                    }
931                }
932                SEC_S | SEC_V => {
933                    let r = self
934                        .widget
935                        .section_value::<u32>(section)
936                        .unwrap_or_default();
937                    let r_min = r.saturating_sub(n);
938                    if r_min != r {
939                        self.widget.set_section_value(section, r_min);
940                        self.set_mode_styles();
941                        true
942                    } else {
943                        false
944                    }
945                }
946                _ => false,
947            },
948        };
949
950        if r {
951            self.value = self.parse_value();
952        }
953        r
954    }
955
956    fn set_mode_styles(&mut self) {
957        match self.mode {
958            Mode::RGB => {
959                // "##0 ##0 ##0"
960                self.widget.clear_styles();
961                self.widget.add_range_style(0..3, 1).expect("fine");
962                self.widget.add_range_style(4..7, 1).expect("fine");
963                self.widget.add_range_style(8..11, 1).expect("fine");
964            }
965            Mode::HEX => {
966                // "hhhhhH"
967                self.widget.clear_styles();
968                self.widget.add_range_style(0..6, 1).expect("fine");
969            }
970            Mode::HSV => {
971                // "##0 ##0 ##0"
972                self.widget.clear_styles();
973                self.widget.add_range_style(0..3, 1).expect("fine");
974                self.widget.add_range_style(4..7, 1).expect("fine");
975                self.widget.add_range_style(8..11, 1).expect("fine");
976            }
977        }
978    }
979
980    /// Set the color mode.
981    pub fn set_mode(&mut self, mode: Mode) {
982        self.mode = mode;
983        match self.mode {
984            Mode::RGB => {
985                // "##0 ##0 ##0"
986                self.widget.set_mask(PAT_RGB).expect("valid-mask");
987            }
988            Mode::HEX => {
989                // "hhhhhH"
990                self.widget.set_mask(PAT_HEX).expect("valid-mask");
991            }
992            Mode::HSV => {
993                // "##0 ##0 ##0"
994                self.widget.set_mask(PAT_HSV).expect("valid-mask");
995            }
996        }
997
998        self.set_mode_styles();
999        self.value_to_text();
1000        self.widget.set_default_cursor();
1001    }
1002
1003    /// Switch to next mode.
1004    pub fn next_mode(&mut self) {
1005        match self.mode {
1006            Mode::RGB => self.set_mode(Mode::HEX),
1007            Mode::HEX => self.set_mode(Mode::HSV),
1008            Mode::HSV => self.set_mode(Mode::RGB),
1009        }
1010    }
1011
1012    /// Switch to prev mode.
1013    pub fn prev_mode(&mut self) {
1014        match self.mode {
1015            Mode::RGB => self.set_mode(Mode::HSV),
1016            Mode::HEX => self.set_mode(Mode::RGB),
1017            Mode::HSV => self.set_mode(Mode::HEX),
1018        }
1019    }
1020
1021    /// Move to the next char.
1022    #[inline]
1023    pub fn move_right(&mut self, extend_selection: bool) -> bool {
1024        self.widget.move_right(extend_selection)
1025    }
1026
1027    /// Move to the previous char.
1028    #[inline]
1029    pub fn move_left(&mut self, extend_selection: bool) -> bool {
1030        self.widget.move_left(extend_selection)
1031    }
1032
1033    /// Start of line
1034    #[inline]
1035    pub fn move_to_line_start(&mut self, extend_selection: bool) -> bool {
1036        self.widget.move_to_line_start(extend_selection)
1037    }
1038
1039    /// End of line
1040    #[inline]
1041    pub fn move_to_line_end(&mut self, extend_selection: bool) -> bool {
1042        self.widget.move_to_line_end(extend_selection)
1043    }
1044}
1045
1046impl HasScreenCursor for ColorInputState {
1047    /// The current text cursor as an absolute screen position.
1048    #[inline]
1049    fn screen_cursor(&self) -> Option<(u16, u16)> {
1050        self.widget.screen_cursor()
1051    }
1052}
1053
1054impl RelocatableState for ColorInputState {
1055    fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
1056        self.widget.relocate(shift, clip);
1057    }
1058}
1059
1060impl ColorInputState {
1061    /// Converts a grapheme based position to a screen position
1062    /// relative to the widget area.
1063    #[inline]
1064    pub fn col_to_screen(&self, pos: upos_type) -> Option<u16> {
1065        self.widget.col_to_screen(pos)
1066    }
1067
1068    /// Converts from a widget relative screen coordinate to a grapheme index.
1069    /// x is the relative screen position.
1070    #[inline]
1071    pub fn screen_to_col(&self, scx: i16) -> upos_type {
1072        self.widget.screen_to_col(scx)
1073    }
1074
1075    /// Set the cursor position from a screen position relative to the origin
1076    /// of the widget. This value can be negative, which selects a currently
1077    /// not visible position and scrolls to it.
1078    #[inline]
1079    pub fn set_screen_cursor(&mut self, cursor: i16, extend_selection: bool) -> bool {
1080        self.widget.set_screen_cursor(cursor, extend_selection)
1081    }
1082}
1083
1084/// Gives the luminance according to BT.709.
1085fn luminance_bt_srgb(color: Color) -> f32 {
1086    let (r, g, b) = color2rgb(color);
1087    0.2126f32 * ((r as f32) / 255f32).powf(2.2f32)
1088        + 0.7152f32 * ((g as f32) / 255f32).powf(2.2f32)
1089        + 0.0722f32 * ((b as f32) / 255f32).powf(2.2f32)
1090}
1091
1092/// Contrast between two colors.
1093fn contrast_bt_srgb(color: Color, color2: Color) -> f32 {
1094    let lum1 = luminance_bt_srgb(color);
1095    let lum2 = luminance_bt_srgb(color2);
1096    (lum1 - lum2).abs()
1097    // Don't use this prescribed method.
1098    // The abs diff comes out better.
1099    // (lum1 + 0.05f32) / (lum2 + 0.05f32)
1100}
1101
1102pub fn high_contrast_color(bg: Color, text: &[Color]) -> Style {
1103    let mut color0 = text[0];
1104    let mut color1 = text[0];
1105    let mut contrast1 = contrast_bt_srgb(color1, bg);
1106
1107    for text_color in text {
1108        let test = contrast_bt_srgb(*text_color, bg);
1109        if test > contrast1 {
1110            color0 = color1;
1111            color1 = *text_color;
1112            contrast1 = test;
1113        }
1114    }
1115    // don't use the second brightest.
1116    _ = color0;
1117
1118    Style::new().bg(bg).fg(color1)
1119}
1120
1121/// Gives back the rgb for any ratatui Color.
1122/// Has the indexed and the named colors too.
1123const fn color2rgb(color: Color) -> (u8, u8, u8) {
1124    match color {
1125        Color::Black => (0x00, 0x00, 0x00),
1126        Color::Red => (0xaa, 0x00, 0x00),
1127        Color::Green => (0x00, 0xaa, 0x00),
1128        Color::Yellow => (0xaa, 0x55, 0x00),
1129        Color::Blue => (0x00, 0x00, 0xaa),
1130        Color::Magenta => (0xaa, 0x00, 0xaa),
1131        Color::Cyan => (0x00, 0xaa, 0xaa),
1132        Color::Gray => (0xaa, 0xaa, 0xaa),
1133        Color::DarkGray => (0x55, 0x55, 0x55),
1134        Color::LightRed => (0xff, 0x55, 0x55),
1135        Color::LightGreen => (0x55, 0xff, 0x55),
1136        Color::LightYellow => (0xff, 0xff, 0x55),
1137        Color::LightBlue => (0x55, 0x55, 0xff),
1138        Color::LightMagenta => (0xff, 0x55, 0xff),
1139        Color::LightCyan => (0x55, 0xff, 0xff),
1140        Color::White => (0xff, 0xff, 0xff),
1141        Color::Rgb(r, g, b) => (r, g, b),
1142        Color::Indexed(i) => {
1143            const VGA256: [(u8, u8, u8); 256] = [
1144                (0x00, 0x00, 0x00),
1145                (0x80, 0x00, 0x00),
1146                (0x00, 0x80, 0x00),
1147                (0x80, 0x80, 0x00),
1148                (0x00, 0x00, 0x80),
1149                (0x80, 0x00, 0x80),
1150                (0x00, 0x80, 0x80),
1151                (0xc0, 0xc0, 0xc0),
1152                (0x80, 0x80, 0x80),
1153                (0xff, 0x00, 0x00),
1154                (0x00, 0xff, 0x00),
1155                (0xff, 0xff, 0x00),
1156                (0x00, 0x00, 0xff),
1157                (0xff, 0x00, 0xff),
1158                (0x00, 0xff, 0xff),
1159                (0xff, 0xff, 0xff),
1160                (0x00, 0x00, 0x00),
1161                (0x00, 0x00, 0x5f),
1162                (0x00, 0x00, 0x87),
1163                (0x00, 0x00, 0xaf),
1164                (0x00, 0x00, 0xd7),
1165                (0x00, 0x00, 0xff),
1166                (0x00, 0x5f, 0x00),
1167                (0x00, 0x5f, 0x5f),
1168                (0x00, 0x5f, 0x87),
1169                (0x00, 0x5f, 0xaf),
1170                (0x00, 0x5f, 0xd7),
1171                (0x00, 0x5f, 0xff),
1172                (0x00, 0x87, 0x00),
1173                (0x00, 0x87, 0x5f),
1174                (0x00, 0x87, 0x87),
1175                (0x00, 0x87, 0xaf),
1176                (0x00, 0x87, 0xd7),
1177                (0x00, 0x87, 0xff),
1178                (0x00, 0xaf, 0x00),
1179                (0x00, 0xaf, 0x5f),
1180                (0x00, 0xaf, 0x87),
1181                (0x00, 0xaf, 0xaf),
1182                (0x00, 0xaf, 0xd7),
1183                (0x00, 0xaf, 0xff),
1184                (0x00, 0xd7, 0x00),
1185                (0x00, 0xd7, 0x5f),
1186                (0x00, 0xd7, 0x87),
1187                (0x00, 0xd7, 0xaf),
1188                (0x00, 0xd7, 0xd7),
1189                (0x00, 0xd7, 0xff),
1190                (0x00, 0xff, 0x00),
1191                (0x00, 0xff, 0x5f),
1192                (0x00, 0xff, 0x87),
1193                (0x00, 0xff, 0xaf),
1194                (0x00, 0xff, 0xd7),
1195                (0x00, 0xff, 0xff),
1196                (0x5f, 0x00, 0x00),
1197                (0x5f, 0x00, 0x5f),
1198                (0x5f, 0x00, 0x87),
1199                (0x5f, 0x00, 0xaf),
1200                (0x5f, 0x00, 0xd7),
1201                (0x5f, 0x00, 0xff),
1202                (0x5f, 0x5f, 0x00),
1203                (0x5f, 0x5f, 0x5f),
1204                (0x5f, 0x5f, 0x87),
1205                (0x5f, 0x5f, 0xaf),
1206                (0x5f, 0x5f, 0xd7),
1207                (0x5f, 0x5f, 0xff),
1208                (0x5f, 0x87, 0x00),
1209                (0x5f, 0x87, 0x5f),
1210                (0x5f, 0x87, 0x87),
1211                (0x5f, 0x87, 0xaf),
1212                (0x5f, 0x87, 0xd7),
1213                (0x5f, 0x87, 0xff),
1214                (0x5f, 0xaf, 0x00),
1215                (0x5f, 0xaf, 0x5f),
1216                (0x5f, 0xaf, 0x87),
1217                (0x5f, 0xaf, 0xaf),
1218                (0x5f, 0xaf, 0xd7),
1219                (0x5f, 0xaf, 0xff),
1220                (0x5f, 0xd7, 0x00),
1221                (0x5f, 0xd7, 0x5f),
1222                (0x5f, 0xd7, 0x87),
1223                (0x5f, 0xd7, 0xaf),
1224                (0x5f, 0xd7, 0xd7),
1225                (0x5f, 0xd7, 0xff),
1226                (0x5f, 0xff, 0x00),
1227                (0x5f, 0xff, 0x5f),
1228                (0x5f, 0xff, 0x87),
1229                (0x5f, 0xff, 0xaf),
1230                (0x5f, 0xff, 0xd7),
1231                (0x5f, 0xff, 0xff),
1232                (0x87, 0x00, 0x00),
1233                (0x87, 0x00, 0x5f),
1234                (0x87, 0x00, 0x87),
1235                (0x87, 0x00, 0xaf),
1236                (0x87, 0x00, 0xd7),
1237                (0x87, 0x00, 0xff),
1238                (0x87, 0x5f, 0x00),
1239                (0x87, 0x5f, 0x5f),
1240                (0x87, 0x5f, 0x87),
1241                (0x87, 0x5f, 0xaf),
1242                (0x87, 0x5f, 0xd7),
1243                (0x87, 0x5f, 0xff),
1244                (0x87, 0x87, 0x00),
1245                (0x87, 0x87, 0x5f),
1246                (0x87, 0x87, 0x87),
1247                (0x87, 0x87, 0xaf),
1248                (0x87, 0x87, 0xd7),
1249                (0x87, 0x87, 0xff),
1250                (0x87, 0xaf, 0x00),
1251                (0x87, 0xaf, 0x5f),
1252                (0x87, 0xaf, 0x87),
1253                (0x87, 0xaf, 0xaf),
1254                (0x87, 0xaf, 0xd7),
1255                (0x87, 0xaf, 0xff),
1256                (0x87, 0xd7, 0x00),
1257                (0x87, 0xd7, 0x5f),
1258                (0x87, 0xd7, 0x87),
1259                (0x87, 0xd7, 0xaf),
1260                (0x87, 0xd7, 0xd7),
1261                (0x87, 0xd7, 0xff),
1262                (0x87, 0xff, 0x00),
1263                (0x87, 0xff, 0x5f),
1264                (0x87, 0xff, 0x87),
1265                (0x87, 0xff, 0xaf),
1266                (0x87, 0xff, 0xd7),
1267                (0x87, 0xff, 0xff),
1268                (0xaf, 0x00, 0x00),
1269                (0xaf, 0x00, 0x5f),
1270                (0xaf, 0x00, 0x87),
1271                (0xaf, 0x00, 0xaf),
1272                (0xaf, 0x00, 0xd7),
1273                (0xaf, 0x00, 0xff),
1274                (0xaf, 0x5f, 0x00),
1275                (0xaf, 0x5f, 0x5f),
1276                (0xaf, 0x5f, 0x87),
1277                (0xaf, 0x5f, 0xaf),
1278                (0xaf, 0x5f, 0xd7),
1279                (0xaf, 0x5f, 0xff),
1280                (0xaf, 0x87, 0x00),
1281                (0xaf, 0x87, 0x5f),
1282                (0xaf, 0x87, 0x87),
1283                (0xaf, 0x87, 0xaf),
1284                (0xaf, 0x87, 0xd7),
1285                (0xaf, 0x87, 0xff),
1286                (0xaf, 0xaf, 0x00),
1287                (0xaf, 0xaf, 0x5f),
1288                (0xaf, 0xaf, 0x87),
1289                (0xaf, 0xaf, 0xaf),
1290                (0xaf, 0xaf, 0xd7),
1291                (0xaf, 0xaf, 0xff),
1292                (0xaf, 0xd7, 0x00),
1293                (0xaf, 0xd7, 0x5f),
1294                (0xaf, 0xd7, 0x87),
1295                (0xaf, 0xd7, 0xaf),
1296                (0xaf, 0xd7, 0xd7),
1297                (0xaf, 0xd7, 0xff),
1298                (0xaf, 0xff, 0x00),
1299                (0xaf, 0xff, 0x5f),
1300                (0xaf, 0xff, 0x87),
1301                (0xaf, 0xff, 0xaf),
1302                (0xaf, 0xff, 0xd7),
1303                (0xaf, 0xff, 0xff),
1304                (0xd7, 0x00, 0x00),
1305                (0xd7, 0x00, 0x5f),
1306                (0xd7, 0x00, 0x87),
1307                (0xd7, 0x00, 0xaf),
1308                (0xd7, 0x00, 0xd7),
1309                (0xd7, 0x00, 0xff),
1310                (0xd7, 0x5f, 0x00),
1311                (0xd7, 0x5f, 0x5f),
1312                (0xd7, 0x5f, 0x87),
1313                (0xd7, 0x5f, 0xaf),
1314                (0xd7, 0x5f, 0xd7),
1315                (0xd7, 0x5f, 0xff),
1316                (0xd7, 0x87, 0x00),
1317                (0xd7, 0x87, 0x5f),
1318                (0xd7, 0x87, 0x87),
1319                (0xd7, 0x87, 0xaf),
1320                (0xd7, 0x87, 0xd7),
1321                (0xd7, 0x87, 0xff),
1322                (0xd7, 0xaf, 0x00),
1323                (0xd7, 0xaf, 0x5f),
1324                (0xd7, 0xaf, 0x87),
1325                (0xd7, 0xaf, 0xaf),
1326                (0xd7, 0xaf, 0xd7),
1327                (0xd7, 0xaf, 0xff),
1328                (0xd7, 0xd7, 0x00),
1329                (0xd7, 0xd7, 0x5f),
1330                (0xd7, 0xd7, 0x87),
1331                (0xd7, 0xd7, 0xaf),
1332                (0xd7, 0xd7, 0xd7),
1333                (0xd7, 0xd7, 0xff),
1334                (0xd7, 0xff, 0x00),
1335                (0xd7, 0xff, 0x5f),
1336                (0xd7, 0xff, 0x87),
1337                (0xd7, 0xff, 0xaf),
1338                (0xd7, 0xff, 0xd7),
1339                (0xd7, 0xff, 0xff),
1340                (0xff, 0x00, 0x00),
1341                (0xff, 0x00, 0x5f),
1342                (0xff, 0x00, 0x87),
1343                (0xff, 0x00, 0xaf),
1344                (0xff, 0x00, 0xd7),
1345                (0xff, 0x00, 0xff),
1346                (0xff, 0x5f, 0x00),
1347                (0xff, 0x5f, 0x5f),
1348                (0xff, 0x5f, 0x87),
1349                (0xff, 0x5f, 0xaf),
1350                (0xff, 0x5f, 0xd7),
1351                (0xff, 0x5f, 0xff),
1352                (0xff, 0x87, 0x00),
1353                (0xff, 0x87, 0x5f),
1354                (0xff, 0x87, 0x87),
1355                (0xff, 0x87, 0xaf),
1356                (0xff, 0x87, 0xd7),
1357                (0xff, 0x87, 0xff),
1358                (0xff, 0xaf, 0x00),
1359                (0xff, 0xaf, 0x5f),
1360                (0xff, 0xaf, 0x87),
1361                (0xff, 0xaf, 0xaf),
1362                (0xff, 0xaf, 0xd7),
1363                (0xff, 0xaf, 0xff),
1364                (0xff, 0xd7, 0x00),
1365                (0xff, 0xd7, 0x5f),
1366                (0xff, 0xd7, 0x87),
1367                (0xff, 0xd7, 0xaf),
1368                (0xff, 0xd7, 0xd7),
1369                (0xff, 0xd7, 0xff),
1370                (0xff, 0xff, 0x00),
1371                (0xff, 0xff, 0x5f),
1372                (0xff, 0xff, 0x87),
1373                (0xff, 0xff, 0xaf),
1374                (0xff, 0xff, 0xd7),
1375                (0xff, 0xff, 0xff),
1376                (0x08, 0x08, 0x08),
1377                (0x12, 0x12, 0x12),
1378                (0x1c, 0x1c, 0x1c),
1379                (0x26, 0x26, 0x26),
1380                (0x30, 0x30, 0x30),
1381                (0x3a, 0x3a, 0x3a),
1382                (0x44, 0x44, 0x44),
1383                (0x4e, 0x4e, 0x4e),
1384                (0x58, 0x58, 0x58),
1385                (0x62, 0x62, 0x62),
1386                (0x6c, 0x6c, 0x6c),
1387                (0x76, 0x76, 0x76),
1388                (0x80, 0x80, 0x80),
1389                (0x8a, 0x8a, 0x8a),
1390                (0x94, 0x94, 0x94),
1391                (0x9e, 0x9e, 0x9e),
1392                (0xa8, 0xa8, 0xa8),
1393                (0xb2, 0xb2, 0xb2),
1394                (0xbc, 0xbc, 0xbc),
1395                (0xc6, 0xc6, 0xc6),
1396                (0xd0, 0xd0, 0xd0),
1397                (0xda, 0xda, 0xda),
1398                (0xe4, 0xe4, 0xe4),
1399                (0xee, 0xee, 0xee),
1400            ];
1401            VGA256[i as usize]
1402        }
1403        Color::Reset => (0, 0, 0),
1404    }
1405}
1406
1407// + #
1408
1409impl HandleEvent<crossterm::event::Event, Regular, TextOutcome> for ColorInputState {
1410    fn handle(&mut self, event: &crossterm::event::Event, _keymap: Regular) -> TextOutcome {
1411        flow!(match event {
1412            ct_event!(key press '+') => {
1413                self.increment(1);
1414                TextOutcome::Changed
1415            }
1416            ct_event!(key press '-') => {
1417                self.decrement(1);
1418                TextOutcome::Changed
1419            }
1420            ct_event!(key press ALT-'+') => {
1421                self.increment(15);
1422                TextOutcome::Changed
1423            }
1424            ct_event!(key press ALT-'-') => {
1425                self.decrement(15);
1426                TextOutcome::Changed
1427            }
1428            ct_event!(key press CONTROL-'v') => {
1429                if self.paste_from_clip() {
1430                    TextOutcome::Changed
1431                } else {
1432                    TextOutcome::Continue
1433                }
1434            }
1435            ct_event!(key press CONTROL-'c') => {
1436                if self.copy_to_clip() {
1437                    TextOutcome::Changed
1438                } else {
1439                    TextOutcome::Continue
1440                }
1441            }
1442            ct_event!(key press CONTROL-'x') => {
1443                if self.cut_to_clip() {
1444                    TextOutcome::Changed
1445                } else {
1446                    TextOutcome::Continue
1447                }
1448            }
1449            _ => TextOutcome::Continue,
1450        });
1451        if !self.disable_modes {
1452            flow!(match event {
1453                ct_event!(key press 'r') => {
1454                    self.set_mode(Mode::RGB);
1455                    TextOutcome::Changed
1456                }
1457                ct_event!(key press 'h') => {
1458                    self.set_mode(Mode::HSV);
1459                    TextOutcome::Changed
1460                }
1461                ct_event!(key press 'x') => {
1462                    self.set_mode(Mode::HEX);
1463                    TextOutcome::Changed
1464                }
1465                ct_event!(key press 'm') | ct_event!(keycode press Up) => {
1466                    self.next_mode();
1467                    TextOutcome::Changed
1468                }
1469                ct_event!(key press SHIFT-'M') | ct_event!(keycode press Down) => {
1470                    self.prev_mode();
1471                    TextOutcome::Changed
1472                }
1473                _ => TextOutcome::Continue,
1474            });
1475        }
1476        match self.widget.handle(event, Regular) {
1477            TextOutcome::TextChanged => {
1478                self.normalize();
1479                self.value = self.parse_value();
1480                TextOutcome::TextChanged
1481            }
1482            r => r,
1483        }
1484    }
1485}
1486
1487impl HandleEvent<crossterm::event::Event, ReadOnly, TextOutcome> for ColorInputState {
1488    fn handle(&mut self, event: &crossterm::event::Event, _keymap: ReadOnly) -> TextOutcome {
1489        self.widget.handle(event, ReadOnly)
1490    }
1491}
1492
1493impl HandleEvent<crossterm::event::Event, MouseOnly, TextOutcome> for ColorInputState {
1494    fn handle(&mut self, event: &crossterm::event::Event, _keymap: MouseOnly) -> TextOutcome {
1495        self.widget.handle(event, MouseOnly)
1496    }
1497}
1498
1499/// Handle all events.
1500/// Text events are only processed if focus is true.
1501/// Mouse events are processed if they are in range.
1502pub fn handle_events(
1503    state: &mut ColorInputState,
1504    focus: bool,
1505    event: &crossterm::event::Event,
1506) -> TextOutcome {
1507    state.widget.focus.set(focus);
1508    HandleEvent::handle(state, event, Regular)
1509}
1510
1511/// Handle only navigation events.
1512/// Text events are only processed if focus is true.
1513/// Mouse events are processed if they are in range.
1514pub fn handle_readonly_events(
1515    state: &mut ColorInputState,
1516    focus: bool,
1517    event: &crossterm::event::Event,
1518) -> TextOutcome {
1519    state.widget.focus.set(focus);
1520    state.handle(event, ReadOnly)
1521}
1522
1523/// Handle only mouse-events.
1524pub fn handle_mouse_events(
1525    state: &mut ColorInputState,
1526    event: &crossterm::event::Event,
1527) -> TextOutcome {
1528    HandleEvent::handle(state, event, MouseOnly)
1529}