Skip to content

Ability to pass data / control state of context_menu #4162

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
enomado opened this issue Mar 12, 2024 · 0 comments
Open

Ability to pass data / control state of context_menu #4162

enomado opened this issue Mar 12, 2024 · 0 comments

Comments

@enomado
Copy link
Contributor

enomado commented Mar 12, 2024

Current API relied on response.rect. When we want to show menu, we associate it with response, e.g. menu call context_interaction to get menu events(create, close, stay) internally. All this stuff is private and couldnt be accessed outside egui.

This behavior dont work if we want to track entity user clicked inside response.rect in our own.

When I have map, diagram, timeline - there is no way to know exact point was clicked on menu creation.

I have my own fork with workaround inside:
It is context_menu function

     let menu_response = egui::menu::MenuRoot::context_interaction(response, root, id);

added code is here. we just inject some inter-frame-object

    let my_state = match &menu_response {
        egui::menu::MenuResponse::Create(_, _) => {
            my_state.store()
        }
        _ => MyState::load()
    };
        

and pass my_state to the render function

bar_state.show(response, |ui| my_context_menu_render(ui, my_state));         

But it requires a lot of doing pub(crate) -> pub replacements.

Then I forked menu.rs, but it couldnt work because ui.set_menu_state is private as well.

  1. So my naive API, just to check out the idea, may be something like:
response
.menu_clicked(|my_state, menu_response| 
    if menu_response == 'create'{ my_state = row_id}
    if menu_response == 'close'{ clean_resources() }
true
)
.show_menu(|ui, my_state| {...})
  1. Much easier API would be
resp.context_menu(|ui, menu_handle|{
menu_handle. is_just_created() ?
menu_handle. some_handle_i_could_associate the data() ?
menu_handle. is_about_to_close() ?
})

Btw, looks like currently we have ui.close_menu() as this menu_handle germ.

  1. Probably, simplest and most useful API would to just make ui.menu_state.response public.

so I could do

resp.context_menu(|ui|{
    if ui.menu_state.response == 'create'{
     memory.save_my_data()
    }
})

(but currently show is earlier that setting the response)

  1. Make context_menu and all related stuff public to allow everybody inline it on his own function and add some logic. Current implementation is very easy to do this, except private visibility.

personally I like №4

PS: MenuResponse::Create(**pos**, id) is not enough, because map could be scrolled after menu was created. we need ability to user make his own associated data.

@enomado enomado changed the title Ability to pass data / control state of context menu Ability to pass data / control state of context_menu Mar 12, 2024
emilk added a commit that referenced this issue May 31, 2024
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: #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]>
hacknus pushed a commit to hacknus/egui that referenced this issue Oct 30, 2024
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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant