Skip to content

Commit 41f77ba

Browse files
committed
Clean up some of the new context menus
Follow-up to #543 * Add entry to CHANGELOG.md * Add entry to contributors in README.md * Improve documentation * Simplify demo
1 parent 46fb9ff commit 41f77ba

File tree

7 files changed

+106
-88
lines changed

7 files changed

+106
-88
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
77

88
## Unreleased
99

10+
### Added ⭐
11+
* Add context menus: See `Ui::menu_button` and `Response::context_menu` ([#543](https://github.com/emilk/egui/pull/543)).
12+
1013

1114
## 0.15.0 - 2021-10-24 - Syntax highlighting and hscroll
1215

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ Notable contributions by:
362362
* [@EmbersArc](https://github.com/EmbersArc): [Plots](https://github.com/emilk/egui/pulls?q=+is%3Apr+author%3AEmbersArc)
363363
* [@AsmPrgmC3](https://github.com/AsmPrgmC3): [Proper sRGBA blending in `egui_web`](https://github.com/emilk/egui/pull/650)
364364
* [@AlexApps99](https://github.com/AlexApps99): [`egui_glow`](https://github.com/emilk/egui/pull/685)
365+
* [@mankinskin](https://github.com/mankinskin): [Context menus](https://github.com/emilk/egui/pull/543)
365366
* And [many more](https://github.com/emilk/egui/graphs/contributors)
366367

367368
egui is licensed under [MIT](LICENSE-MIT) OR [Apache-2.0](LICENSE-APACHE).

egui/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ impl CtxRef {
305305
Self::layer_painter(self, LayerId::debug())
306306
}
307307

308+
/// Respond to secondary clicks (right-clicks) by showing the given menu.
308309
pub(crate) fn show_context_menu(
309310
&self,
310311
response: &Response,

egui/src/menu.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ impl MenuRoot {
349349
MenuResponse::Stay => {}
350350
}
351351
}
352+
/// Respond to secondary (right) clicks.
352353
pub fn context_click_interaction(response: &Response, root: &mut MenuRootManager, id: Id) {
353354
let menu_response = Self::context_interaction(response, root, id);
354355
Self::handle_menu_response(root, menu_response);

egui/src/response.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,17 @@ impl Response {
471471
}
472472
}
473473

474+
/// Response to secondary clicks (right-clicks) by showing the given menu.
475+
///
476+
/// ``` rust
477+
/// # let mut ui = &mut egui::Ui::__test();
478+
/// let response = ui.label("Right-click me!");
479+
/// response.context_menu(|ui|{
480+
/// if ui.button("Close the menu").clicked() {
481+
/// ui.close_menu();
482+
/// }
483+
/// });
484+
/// ```
474485
pub fn context_menu(&self, add_contents: impl FnOnce(&mut Ui)) -> &Self {
475486
self.ctx.show_context_menu(self, add_contents);
476487
self

egui/src/ui.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1737,27 +1737,33 @@ impl Ui {
17371737
self.advance_cursor_after_rect(Rect::from_min_size(top_left, size));
17381738
result
17391739
}
1740+
17401741
/// Close menu (with submenus), if any.
17411742
pub fn close_menu(&mut self) {
17421743
if let Some(menu_state) = &mut self.menu_state {
17431744
menu_state.write().close();
17441745
}
17451746
self.menu_state = None;
17461747
}
1748+
17471749
pub(crate) fn get_menu_state(&self) -> Option<Arc<RwLock<MenuState>>> {
17481750
self.menu_state.clone()
17491751
}
1752+
17501753
pub(crate) fn set_menu_state(&mut self, menu_state: Option<Arc<RwLock<MenuState>>>) {
17511754
self.menu_state = menu_state;
17521755
}
1756+
17531757
#[inline(always)]
17541758
/// Create a menu button. Creates a button for a sub-menu when the `Ui` is inside a menu.
17551759
///
17561760
/// ```
17571761
/// # let mut ui = egui::Ui::__test();
17581762
/// ui.menu_button("My menu", |ui| {
17591763
/// ui.menu_button("My sub-menu", |ui| {
1760-
/// ui.label("Item");
1764+
/// if ui.button("Close the menu").clicked() {
1765+
/// ui.close_menu();
1766+
/// }
17611767
/// });
17621768
/// });
17631769
/// ```

egui_demo_lib/src/apps/demo/context_menu.rs

Lines changed: 82 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ fn sigmoid(x: f64) -> f64 {
1717
#[derive(Clone, PartialEq)]
1818
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
1919
pub struct ContextMenus {
20-
title: String,
2120
plot: Plot,
2221
show_axes: [bool; 2],
2322
allow_drag: bool,
@@ -28,6 +27,87 @@ pub struct ContextMenus {
2827
height: f32,
2928
}
3029

30+
impl Default for ContextMenus {
31+
fn default() -> Self {
32+
Self {
33+
plot: Plot::Sin,
34+
show_axes: [true, true],
35+
allow_drag: true,
36+
allow_zoom: true,
37+
center_x_axis: false,
38+
center_y_axis: false,
39+
width: 400.0,
40+
height: 200.0,
41+
}
42+
}
43+
}
44+
45+
impl super::Demo for ContextMenus {
46+
fn name(&self) -> &'static str {
47+
"☰ Context Menus"
48+
}
49+
50+
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
51+
use super::View;
52+
egui::Window::new(self.name())
53+
.vscroll(false)
54+
.resizable(false)
55+
.open(open)
56+
.show(ctx, |ui| self.ui(ui));
57+
}
58+
}
59+
60+
impl super::View for ContextMenus {
61+
fn ui(&mut self, ui: &mut egui::Ui) {
62+
ui.horizontal(|ui| {
63+
ui.menu_button("Click for menu", Self::nested_menus);
64+
ui.button("Right-click for menu")
65+
.context_menu(Self::nested_menus);
66+
});
67+
68+
ui.separator();
69+
70+
ui.label("Right-click plot to edit it!");
71+
ui.horizontal(|ui| {
72+
ui.add(self.example_plot()).context_menu(|ui| {
73+
ui.menu_button("Plot", |ui| {
74+
if ui.radio_value(&mut self.plot, Plot::Sin, "Sin").clicked()
75+
|| ui
76+
.radio_value(&mut self.plot, Plot::Bell, "Gaussian")
77+
.clicked()
78+
|| ui
79+
.radio_value(&mut self.plot, Plot::Sigmoid, "Sigmoid")
80+
.clicked()
81+
{
82+
ui.close_menu();
83+
}
84+
});
85+
egui::Grid::new("button_grid").show(ui, |ui| {
86+
ui.add(
87+
egui::DragValue::new(&mut self.width)
88+
.speed(1.0)
89+
.prefix("Width:"),
90+
);
91+
ui.add(
92+
egui::DragValue::new(&mut self.height)
93+
.speed(1.0)
94+
.prefix("Height:"),
95+
);
96+
ui.end_row();
97+
ui.checkbox(&mut self.show_axes[0], "x-Axis");
98+
ui.checkbox(&mut self.show_axes[1], "y-Axis");
99+
ui.end_row();
100+
if ui.checkbox(&mut self.allow_drag, "Drag").changed()
101+
|| ui.checkbox(&mut self.allow_zoom, "Zoom").changed()
102+
{
103+
ui.close_menu();
104+
}
105+
});
106+
});
107+
});
108+
}
109+
}
110+
31111
impl ContextMenus {
32112
fn example_plot(&self) -> egui::plot::Plot {
33113
use egui::plot::{Line, Value, Values};
@@ -52,6 +132,7 @@ impl ContextMenus {
52132
.height(self.height)
53133
.data_aspect(1.0)
54134
}
135+
55136
fn nested_menus(ui: &mut egui::Ui) {
56137
if ui.button("Open...").clicked() {
57138
ui.close_menu();
@@ -86,89 +167,3 @@ impl ContextMenus {
86167
let _ = ui.button("Very long text for this item");
87168
}
88169
}
89-
90-
const DEFAULT_TITLE: &str = "☰ Context Menus";
91-
92-
impl Default for ContextMenus {
93-
fn default() -> Self {
94-
Self {
95-
title: DEFAULT_TITLE.to_owned(),
96-
plot: Plot::Sin,
97-
show_axes: [true, true],
98-
allow_drag: true,
99-
allow_zoom: true,
100-
center_x_axis: false,
101-
center_y_axis: false,
102-
width: 400.0,
103-
height: 200.0,
104-
}
105-
}
106-
}
107-
impl super::Demo for ContextMenus {
108-
fn name(&self) -> &'static str {
109-
DEFAULT_TITLE
110-
}
111-
112-
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
113-
let Self { title, .. } = self.clone();
114-
115-
use super::View;
116-
let window = egui::Window::new(title)
117-
.id(egui::Id::new("demo_context_menus")) // required since we change the title
118-
.vscroll(false)
119-
.open(open);
120-
window.show(ctx, |ui| self.ui(ui));
121-
}
122-
}
123-
124-
impl super::View for ContextMenus {
125-
fn ui(&mut self, ui: &mut egui::Ui) {
126-
ui.horizontal(|ui| ui.text_edit_singleline(&mut self.title));
127-
ui.horizontal(|ui| {
128-
ui.add(self.example_plot())
129-
.on_hover_text("Right click for options")
130-
.context_menu(|ui| {
131-
ui.menu_button("Plot", |ui| {
132-
if ui.radio_value(&mut self.plot, Plot::Sin, "Sin").clicked()
133-
|| ui
134-
.radio_value(&mut self.plot, Plot::Bell, "Gaussian")
135-
.clicked()
136-
|| ui
137-
.radio_value(&mut self.plot, Plot::Sigmoid, "Sigmoid")
138-
.clicked()
139-
{
140-
ui.close_menu();
141-
}
142-
});
143-
egui::Grid::new("button_grid").show(ui, |ui| {
144-
ui.add(
145-
egui::DragValue::new(&mut self.width)
146-
.speed(1.0)
147-
.prefix("Width:"),
148-
);
149-
ui.add(
150-
egui::DragValue::new(&mut self.height)
151-
.speed(1.0)
152-
.prefix("Height:"),
153-
);
154-
ui.end_row();
155-
ui.checkbox(&mut self.show_axes[0], "x-Axis");
156-
ui.checkbox(&mut self.show_axes[1], "y-Axis");
157-
ui.end_row();
158-
if ui.checkbox(&mut self.allow_drag, "Drag").changed()
159-
|| ui.checkbox(&mut self.allow_zoom, "Zoom").changed()
160-
{
161-
ui.close_menu();
162-
}
163-
});
164-
});
165-
});
166-
ui.label("Right-click plot to edit it!");
167-
ui.separator();
168-
ui.horizontal(|ui| {
169-
ui.menu_button("Click for menu", Self::nested_menus);
170-
ui.button("Right-click for menu")
171-
.context_menu(Self::nested_menus);
172-
});
173-
}
174-
}

0 commit comments

Comments
 (0)