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
//! Context Menu extension for egui Response
use egui::Response;
use egui_cha::ViewCtx;
use crate::Theme;
/// Context menu item
pub enum ContextMenuItem<Msg> {
/// Regular menu item with label and message
Item {
label: String,
msg: Msg,
danger: bool,
},
/// Separator line
Separator,
}
impl<Msg> ContextMenuItem<Msg> {
/// Create a new menu item
pub fn new(label: impl Into<String>, msg: Msg) -> Self {
Self::Item {
label: label.into(),
msg,
danger: false,
}
}
/// Create a danger-styled menu item (e.g., for delete actions)
pub fn danger(label: impl Into<String>, msg: Msg) -> Self {
Self::Item {
label: label.into(),
msg,
danger: true,
}
}
/// Create a separator
pub fn separator() -> Self {
Self::Separator
}
}
/// Extension trait for adding context menu to Response
pub trait ContextMenuExt {
/// Add a context menu (right-click menu) to this response
///
/// # Example
/// ```ignore
/// Button::primary("Item")
/// .show(ctx.ui)
/// .with_context_menu(ctx, [
/// ContextMenuItem::new("Edit", Msg::Edit),
/// ContextMenuItem::separator(),
/// ContextMenuItem::danger("Delete", Msg::Delete),
/// ]);
/// ```
fn with_context_menu<Msg>(
self,
ctx: &mut ViewCtx<'_, Msg>,
items: impl IntoIterator<Item = ContextMenuItem<Msg>>,
) -> Self
where
Msg: Clone;
}
impl ContextMenuExt for Response {
fn with_context_menu<Msg>(
self,
ctx: &mut ViewCtx<'_, Msg>,
items: impl IntoIterator<Item = ContextMenuItem<Msg>>,
) -> Self
where
Msg: Clone,
{
let items: Vec<_> = items.into_iter().collect();
self.context_menu(|ui| {
let theme = Theme::current(ui.ctx());
for item in items {
match item {
ContextMenuItem::Item { label, msg, danger } => {
let text_color = if danger {
theme.state_danger
} else {
theme.text_primary
};
let text = egui::RichText::new(&label).color(text_color);
if ui.button(text).clicked() {
ctx.emit(msg);
ui.close();
}
}
ContextMenuItem::Separator => {
ui.separator();
}
}
}
});
self
}
}