Skip to main content

egui_table_kit/filter/
highlight.rs

1use std::sync::{Arc, LazyLock};
2
3use parking_lot::RwLock;
4
5use crate::error::TableError;
6
7pub static SELECT_COLOR: LazyLock<Arc<RwLock<u8>>> =
8    LazyLock::new(|| Arc::new(RwLock::new(Default::default())));
9
10pub fn select_color_meta(
11    index: u8,
12    org: &[[u8; 3]],
13    user: &[[u8; 3]],
14) -> Result<(usize, usize, [u8; 3]), TableError> {
15    let index = index as usize;
16    let org_color_len = org.len();
17
18    let color = if index < org_color_len {
19        Some(*org.get(index).ok_or(TableError::CorruptedState)?)
20    } else {
21        user.get(index - org_color_len).copied()
22    };
23    Ok((index, org_color_len, color.unwrap_or_else(Default::default)))
24}
25
26pub fn select_color(index: u8, org: &[[u8; 3]], user: &[[u8; 3]]) -> Result<[u8; 3], TableError> {
27    select_color_meta(index, org, user).map(|(_, _, color)| color)
28}
29
30pub fn color_select_button(
31    ui: &mut egui::Ui,
32    color: egui::Color32,
33    selected: bool,
34    skinny: bool,
35) -> egui::Response {
36    let size = ui.spacing().interact_size;
37    let (rect, response) = ui.allocate_exact_size(
38        egui::vec2(if skinny { size.x / 2.0 } else { size.x }, size.y),
39        egui::Sense::click(),
40    );
41    response.widget_info(|| egui::WidgetInfo::new(egui::WidgetType::ColorButton));
42
43    if ui.is_rect_visible(rect) {
44        let visuals = if selected {
45            let mut selected_visuals = ui.visuals().widgets.open;
46            selected_visuals.bg_stroke.color = egui::Color32::DARK_BLUE;
47            selected_visuals.bg_stroke.width = 2.0;
48            selected_visuals
49        } else {
50            *ui.style().interact(&response)
51        };
52
53        let rect = rect.expand(visuals.expansion);
54        egui::color_picker::show_color_at(ui.painter(), color, rect);
55
56        let rounding = visuals.corner_radius.at_most(2);
57        ui.painter()
58            .rect_stroke(rect, rounding, visuals.bg_stroke, egui::StrokeKind::Middle);
59    }
60
61    response
62}
63
64pub fn opt_color_select_button(
65    ui: &mut egui::Ui,
66    label: &str,
67    color: &mut Option<u8>,
68    selected: bool,
69    skinny: bool,
70    highlight_options_r1: &[[u8; 3]],
71    highlight_options_r2: &[[u8; 3]],
72) -> Result<(), TableError> {
73    ui.label(label);
74
75    match color {
76        Some(inner) => {
77            let [r, g, b] = select_color(*inner, highlight_options_r1, highlight_options_r2)?;
78            if color_select_button(ui, egui::Color32::from_rgb(r, g, b), selected, skinny).clicked()
79            {
80                *color = None;
81            }
82        }
83        None => {
84            if ui.button("➕").clicked() {
85                *color = Some(*SELECT_COLOR.read());
86            }
87        }
88    }
89
90    Ok(())
91}
92
93pub struct HighlightFilter<'a> {
94    label: &'a str,
95}
96
97impl<'a> HighlightFilter<'a> {
98    #[must_use]
99    pub const fn new(label: &'a str) -> Self {
100        Self { label }
101    }
102
103    pub fn ui(
104        self,
105        ui: &mut egui::Ui,
106        highlight_select: &mut Option<Option<u8>>,
107        highlight_options_r1: &[[u8; 3]],
108        highlight_options_r2: &[[u8; 3]],
109    ) -> Result<(), TableError> {
110        ui.horizontal(|ui| {
111            if let Some(highlight_filter) = highlight_select {
112                opt_color_select_button(
113                    ui,
114                    self.label,
115                    highlight_filter,
116                    false,
117                    false,
118                    highlight_options_r1,
119                    highlight_options_r2,
120                )?;
121
122                if ui.button("❌").on_hover_text("Remove Filter").clicked() {
123                    *highlight_select = None;
124                }
125            } else if ui.button(self.label).clicked() {
126                *highlight_select = Some(None);
127            }
128
129            Ok(())
130        })
131        .inner
132    }
133}