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