Skip to content

Commit

Permalink
Make egu::menu types public (emilk#4544)
Browse files Browse the repository at this point in the history
Sometimes we need to fix the current state of the application in the
moment when you open the context menu, to save it, and to use it during
creation of context menu and response handling. Making some structs,
related with menu creating, allow us to create functions for this cases.
For example,
```rust
pub fn context_menu_custom<'a, T>(
    response: &Response,
    //variable for fixing state in the moment when you open context menu
    state: &mut T,
    //function which allow to get some king of state.
    //In this case state depends on cursor position, in other cases it may depend on system time or something else
    get_state: impl FnOnce(Pos2) -> T,
    //set contents of menu depending on state
    set_contents: impl 'a + FnOnce(&T) -> Box<dyn 'a + FnOnce(&mut Ui)>,
) -> Option<InnerResponse<()>> {
    let menu_id = Id::new("__egui::context_menu");
    let mut bar_state = BarState::load(&response.ctx, menu_id);
    let root = &mut bar_state;

    let menu_response = MenuRoot::context_interaction(response, root);
    if let egui::menu::MenuResponse::Create(p, _) = &menu_response {
        *state = get_state(*p);
    };

    let add_contents = set_contents(&state);

    MenuRoot::handle_menu_response(root, menu_response);
    let inner_response = bar_state.show(response, add_contents);

    bar_state.store(&response.ctx, menu_id);
    inner_response
}
```
The example of using such function you may see in [`my
repository`](https://github.com/sor-ca/context_menu)
It is very simple example, and is this case, the problem may be solved
without fn context_menu_custom, but in more complex situations, it may
be very useful
Related issue: emilk#4162

<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* The PR title is what ends up in the changelog, so make it descriptive!
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to add commits to your PR.
* Remember to run `cargo fmt` and `cargo clippy`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

---------

Co-authored-by: Emil Ernerfeldt <[email protected]>
  • Loading branch information
2 people authored and hacknus committed Oct 30, 2024
1 parent f96f2fc commit 47df7dd
Showing 1 changed file with 13 additions and 10 deletions.
23 changes: 13 additions & 10 deletions crates/egui/src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ use std::sync::Arc;

/// What is saved between frames.
#[derive(Clone, Default)]
pub(crate) struct BarState {
pub struct BarState {
open_menu: MenuRootManager,
}

impl BarState {
fn load(ctx: &Context, bar_id: Id) -> Self {
pub fn load(ctx: &Context, bar_id: Id) -> Self {
ctx.data_mut(|d| d.get_temp::<Self>(bar_id).unwrap_or_default())
}

fn store(self, ctx: &Context, bar_id: Id) {
pub fn store(self, ctx: &Context, bar_id: Id) {
ctx.data_mut(|d| d.insert_temp(bar_id, self));
}

Expand Down Expand Up @@ -242,7 +242,7 @@ pub(crate) fn context_menu_opened(response: &Response) -> bool {

/// Stores the state for the context menu.
#[derive(Clone, Default)]
pub(crate) struct MenuRootManager {
pub struct MenuRootManager {
inner: Option<MenuRoot>,
}

Expand Down Expand Up @@ -287,7 +287,7 @@ impl std::ops::DerefMut for MenuRootManager {

/// Menu root associated with an Id from a Response
#[derive(Clone)]
pub(crate) struct MenuRoot {
pub struct MenuRoot {
pub menu_state: Arc<RwLock<MenuState>>,
pub id: Id,
}
Expand Down Expand Up @@ -372,7 +372,7 @@ impl MenuRoot {
}

/// Interaction with a context menu (secondary click).
fn context_interaction(response: &Response, root: &mut Option<Self>) -> MenuResponse {
pub fn context_interaction(response: &Response, root: &mut Option<Self>) -> MenuResponse {
let response = response.interact(Sense::click());
let hovered = response.hovered();
let secondary_clicked = response.secondary_clicked();
Expand All @@ -398,7 +398,7 @@ impl MenuRoot {
})
}

fn handle_menu_response(root: &mut MenuRootManager, menu_response: MenuResponse) {
pub fn handle_menu_response(root: &mut MenuRootManager, menu_response: MenuResponse) {
match menu_response {
MenuResponse::Create(pos, id) => {
root.inner = Some(Self::new(pos, id));
Expand All @@ -421,8 +421,8 @@ impl MenuRoot {
}
}

#[derive(Copy, Clone, PartialEq)]
pub(crate) enum MenuResponse {
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum MenuResponse {
Close,
Stay,
Create(Pos2, Id),
Expand Down Expand Up @@ -562,7 +562,10 @@ impl SubMenu {
}
}

pub(crate) struct MenuState {
/// Components of menu state, public for advanced usage.
///
/// Usually you don't need to use it directly.
pub struct MenuState {
/// The opened sub-menu and its [`Id`]
sub_menu: Option<(Id, Arc<RwLock<MenuState>>)>,

Expand Down

0 comments on commit 47df7dd

Please sign in to comment.