1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Abstraction for buttons to be used in list items.

use crate::{Icon, UiExt as _};

// -------------------------------------------------------------------------------------------------

/// An [`super::ItemButton`] that acts as a popup menu.
pub struct ItemMenuButton<'a> {
    icon: &'static Icon,
    add_contents: Box<dyn FnOnce(&mut egui::Ui) + 'a>,
    enabled: bool,
    hover_text: Option<String>,
    disabled_hover_text: Option<String>,
}

impl<'a> ItemMenuButton<'a> {
    pub fn new(icon: &'static Icon, add_contents: impl FnOnce(&mut egui::Ui) + 'a) -> Self {
        Self {
            icon,
            add_contents: Box::new(add_contents),
            enabled: true,
            hover_text: None,
            disabled_hover_text: None,
        }
    }

    /// Sets enable/disable state of the button.
    #[inline]
    pub fn enabled(mut self, enabled: bool) -> Self {
        self.enabled = enabled;
        self
    }

    /// Sets text shown when the button hovered.
    #[inline]
    pub fn hover_text(mut self, hover_text: impl Into<String>) -> Self {
        self.hover_text = Some(hover_text.into());
        self
    }

    /// Sets text shown when the button is disabled and hovered.
    #[inline]
    pub fn disabled_hover_text(mut self, hover_text: impl Into<String>) -> Self {
        self.disabled_hover_text = Some(hover_text.into());
        self
    }
}

impl super::ItemButton for ItemMenuButton<'_> {
    fn ui(self: Box<Self>, ui: &mut egui::Ui) -> egui::Response {
        ui.add_enabled_ui(self.enabled, |ui| {
            ui.spacing_mut().item_spacing = egui::Vec2::ZERO;

            let mut response = egui::menu::menu_custom_button(
                ui,
                ui.small_icon_button_widget(self.icon),
                self.add_contents,
            )
            .response;
            if let Some(hover_text) = self.hover_text {
                response = response.on_hover_text(hover_text);
            }
            if let Some(disabled_hover_text) = self.disabled_hover_text {
                response = response.on_disabled_hover_text(disabled_hover_text);
            }

            response
        })
        .inner
    }
}

// -------------------------------------------------------------------------------------------------

/// An [`super::ItemButton`] that acts as an action button.
pub struct ItemActionButton<'a> {
    icon: &'static crate::icons::Icon,
    on_click: Box<dyn FnOnce() + 'a>,
    enabled: bool,
    hover_text: Option<String>,
    disabled_hover_text: Option<String>,
}

impl<'a> ItemActionButton<'a> {
    pub fn new(icon: &'static crate::icons::Icon, on_click: impl FnOnce() + 'a) -> Self {
        Self {
            icon,
            on_click: Box::new(on_click),
            enabled: true,
            hover_text: None,
            disabled_hover_text: None,
        }
    }

    /// Sets enable/disable state of the button.
    #[inline]
    pub fn enabled(mut self, enabled: bool) -> Self {
        self.enabled = enabled;
        self
    }

    /// Sets text shown when the button hovered.
    #[inline]
    pub fn hover_text(mut self, hover_text: impl Into<String>) -> Self {
        self.hover_text = Some(hover_text.into());
        self
    }

    /// Sets text shown when the button is disabled and hovered.
    #[inline]
    pub fn disabled_hover_text(mut self, hover_text: impl Into<String>) -> Self {
        self.disabled_hover_text = Some(hover_text.into());
        self
    }
}

impl super::ItemButton for ItemActionButton<'_> {
    fn ui(self: Box<Self>, ui: &mut egui::Ui) -> egui::Response {
        ui.add_enabled_ui(self.enabled, |ui| {
            ui.spacing_mut().item_spacing = egui::Vec2::ZERO;

            let mut response = ui.small_icon_button(self.icon);
            if response.clicked() {
                (self.on_click)();
            }

            if let Some(hover_text) = self.hover_text {
                response = response.on_hover_text(hover_text);
            }
            if let Some(disabled_hover_text) = self.disabled_hover_text {
                response = response.on_disabled_hover_text(disabled_hover_text);
            }

            response
        })
        .inner
    }
}