n00kii / egui-modal Goto Github PK
View Code? Open in Web Editor NEWa simple modal library for egui
License: MIT License
a simple modal library for egui
License: MIT License
I was hoping I could drop this into a bevy_egui app, which I am building to learn bevy (perhaps I'm the wrong person to get very detailed into what people would want!). But this indicates:
error[E0308]: mismatched types
--> src/menu.rs:100:14
|
100 | Modal::new(contexts.ctx_mut(), LOAD_MAP_MODAL_TITLE).show(|ui| {
| ---------- ^^^^^^^^^^^^^^^^^^ expected &Context
, found &mut Context
| |
| arguments to this function are incorrect
|
= note: bevy_egui::egui::Context
and egui::context::Context
have similar names, but are actually distinct types
I am making a desktop using egui
and really like your modal
library, but I am having a problem. The new()
for Modal
takes ctx
and id
as parameters. This is causing me some problems, as I am defining different parts of UI in different files.
Say I have a module (a file) app.rs
in which I define eframe::App
which has the update()
and all. And I have different files for different sections of the app like a settings dialog for which I want to use Modal
.
Now in app
I have,
pub struct App {
dark_mode: bool,
is_side_panel_open: bool,
is_window_fullscreen: bool,
waveform_viewer: WaveformViewer,
preferences_dialog: PreferencesDialog,
}
where WaveformViewer
is a egui::Window
and I have a new()
method for all sections like this and are initialized this like,
impl App {
pub fn new() -> Self {
Self {
dark_mode: true,
is_side_panel_open: false,
is_window_fullscreen: false,
waveform_viewer: WaveformViewwer::new(),
preferences_dialog: PreferencesDialog::new(),
}
}
// other methods..
}
now in order to call new()
from the PreferencesDialog
I need to have something like this,
pub struct PreferencesDialog {
dialog: Modal,
is_open: bool,
}
which I can initialize like this,
impl PreferencesDialog {
pub fn new(ctx: &egui::Context) -> Self {
Self {
dialog: Modal::new(ctx, "preferences_dialog"),
is_open: false,
}
}
now here comes the problem.. if I don't take ctx
as an argument in new()
I can't have dialog
as a data member of PreferencesDialog
and if I do I can't call it in my App::new()
.
But say I don't do any of this, then I have to initialize PreferencesDialog::new(ctx, id)
directly in update
and I won't be able to query other data and/or methods from PreferencesDialog
outside update()
.
I think perhaps you should have a set_ctx()
instead of directly taking ctx
as an argument in the new()
.
When a modal window is open, the user should not be able to interact with elements outside of this window.
Reproducing:
cargo run --example example
continuing discussion from #5 and using solution from #5 (comment)
basic implementation looks like this:
not too desirable, ideally the contents of the frame would be centered and the title and buttons would be at top and bottom, respectively
Simple error occurs when egaui serde feature is on:
error[E0277]: the trait bound `for<'a> ModalState: serde::de::Deserialize<'a>` is not satisfied
--> /home/xxx/.cargo/registry/src/github.com-1ecc6299db9ec823/egui-modal-0.1.6/src/modal.rs:128:20
|
128 | ctx.data().get_persisted(id).unwrap_or_default()
| ^^^^^^^^^^^^^ the trait `for<'a> serde::de::Deserialize<'a>` is not implemented for `ModalState`
|
= help: the following other types implement trait `serde::de::Deserialize<'de>`:
&'a [u8]
&'a std::path::Path
&'a str
()
(T0, T1)
(T0, T1, T2)
(T0, T1, T2, T3)
(T0, T1, T2, T3, T4)
and 225 others
= note: required because of the requirements on the impl of `SerializableAny` for `ModalState`
note: required by a bound in `IdTypeMap::get_persisted`
--> /home/xxx/.cargo/registry/src/github.com-1ecc6299db9ec823/egui-0.19.0/src/util/id_type_map.rs:370:29
|
370 | pub fn get_persisted<T: SerializableAny>(&mut self, id: Id) -> Option<T> {
| ^^^^^^^^^^^^^^^ required by this bound in `IdTypeMap::get_persisted`
This would help cutting down on bloat in end user applications a lot
In my application, I wanted to allow keyboard shortcuts to interact with/close the modal as well. This was my first attempt:
let modal = Modal::new(ui.ctx(), "confirmation_modal");
// shows the dialog if needed, as tracked by modal-internal state
modal.show(|ui| {
// <snip> add other UI...
modal.buttons(ui, |ui| {
if confirmation_modal.button(ui, "Cancel (N)").clicked() {
state.confirmation_modal_state.result = Some(ConfirmationAction::DoNothing);
}
if confirmation_modal.button(ui, "Delete New (Del)").clicked() {
state.confirmation_modal_state.result = Some(ConfirmationAction::DeleteNew);
}
if confirmation_modal.button(ui, "Move Anyway (M)").clicked() {
state.confirmation_modal_state.result = Some(ConfirmationAction::CopyAnyway);
}
if confirmation_modal
.button(ui, "Replace Existing (R)")
.clicked()
{
state.confirmation_modal_state.result = Some(ConfirmationAction::ReplaceOld);
}
});
ui.input_mut(|input| {
if input.consume_key(Modifiers::CTRL, Key::R) {
state.confirmation_modal_state.result = Some(ConfirmationAction::ReplaceOld);
modal.close();
} else if input.consume_key(Modifiers::CTRL, Key::M) {
state.confirmation_modal_state.result = Some(ConfirmationAction::CopyAnyway);
modal.close();
} else if input.consume_key(Modifiers::CTRL, Key::Delete) {
state.confirmation_modal_state.result = Some(ConfirmationAction::DeleteNew);
modal.close();
} else if input.consume_key(Modifiers::CTRL, Key::N) {
state.confirmation_modal_state.result = Some(ConfirmationAction::DoNothing);
modal.close();
}
});
});
However, this caused deadlocks when any of the consume_key
calls returned true. I worked around this issue by changing to the following:
let should_close = ui.input_mut(|input| {
if input.consume_key(Modifiers::CTRL, Key::R) {
state.confirmation_modal_state.result = Some(ConfirmationAction::ReplaceOld);
true
} else if input.consume_key(Modifiers::CTRL, Key::M) {
state.confirmation_modal_state.result = Some(ConfirmationAction::CopyAnyway);
true
} else if input.consume_key(Modifiers::CTRL, Key::Delete) {
state.confirmation_modal_state.result = Some(ConfirmationAction::DeleteNew);
true
} else if input.consume_key(Modifiers::CTRL, Key::N) {
state.confirmation_modal_state.result = Some(ConfirmationAction::DoNothing);
true
} else {
false
}
});
if should_close {
modal.close();
}
I believe this is because modal.close();
internally writes to the context IdTypeMap, which is also locked by input_mut
.
I'm not sure what the best solution is, unfortunately. Adding documentation to Modal::close
could be helpful, but easily miss-able.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.