eframe: allow aborting an exit event (#1038)
This commit is contained in:
parent
87ac7446da
commit
ab77099781
4 changed files with 79 additions and 4 deletions
|
@ -9,6 +9,7 @@ NOTE: [`egui_web`](egui_web/CHANGELOG.md), [`egui-winit`](egui-winit/CHANGELOG.m
|
||||||
* The default native backend is now `egui_glow` (instead of `egui_glium`) ([#1020](https://github.com/emilk/egui/pull/1020)).
|
* The default native backend is now `egui_glow` (instead of `egui_glium`) ([#1020](https://github.com/emilk/egui/pull/1020)).
|
||||||
* The default web painter is now `egui_glow` (instead of WebGL) ([#1020](https://github.com/emilk/egui/pull/1020)).
|
* The default web painter is now `egui_glow` (instead of WebGL) ([#1020](https://github.com/emilk/egui/pull/1020)).
|
||||||
* Fix horizontal scrolling direction on Linux.
|
* Fix horizontal scrolling direction on Linux.
|
||||||
|
* Added `App::on_exit_event` ([#1038](https://github.com/emilk/egui/pull/1038))
|
||||||
|
|
||||||
|
|
||||||
## 0.16.0 - 2021-12-29
|
## 0.16.0 - 2021-12-29
|
||||||
|
|
49
eframe/examples/confirm_exit.rs
Normal file
49
eframe/examples/confirm_exit.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
|
use eframe::{egui, epi};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct MyApp {
|
||||||
|
can_exit: bool,
|
||||||
|
is_exiting: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl epi::App for MyApp {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"Confirm exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_exit_event(&mut self) -> bool {
|
||||||
|
self.is_exiting = true;
|
||||||
|
self.can_exit
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, ctx: &egui::Context, frame: &epi::Frame) {
|
||||||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
ui.heading("Try to close the window");
|
||||||
|
});
|
||||||
|
|
||||||
|
if self.is_exiting {
|
||||||
|
egui::Window::new("Do you want to quit?")
|
||||||
|
.collapsible(false)
|
||||||
|
.resizable(false)
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if ui.button("Yes!").clicked() {
|
||||||
|
self.can_exit = true;
|
||||||
|
frame.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui.button("Not yet").clicked() {
|
||||||
|
self.is_exiting = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let options = eframe::NativeOptions::default();
|
||||||
|
eframe::run_native(Box::new(MyApp::default()), options);
|
||||||
|
}
|
|
@ -240,7 +240,11 @@ impl EpiIntegration {
|
||||||
self.app
|
self.app
|
||||||
.setup(&self.egui_ctx, &self.frame, self.persistence.storage());
|
.setup(&self.egui_ctx, &self.frame, self.persistence.storage());
|
||||||
let app_output = self.frame.take_app_output();
|
let app_output = self.frame.take_app_output();
|
||||||
self.quit |= app_output.quit;
|
|
||||||
|
if app_output.quit {
|
||||||
|
self.quit = self.app.on_exit_event();
|
||||||
|
}
|
||||||
|
|
||||||
crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
|
crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +264,12 @@ impl EpiIntegration {
|
||||||
|
|
||||||
pub fn on_event(&mut self, event: &winit::event::WindowEvent<'_>) {
|
pub fn on_event(&mut self, event: &winit::event::WindowEvent<'_>) {
|
||||||
use winit::event::WindowEvent;
|
use winit::event::WindowEvent;
|
||||||
self.quit |= matches!(event, WindowEvent::CloseRequested | WindowEvent::Destroyed);
|
if *event == WindowEvent::CloseRequested {
|
||||||
|
self.quit = self.app.on_exit_event();
|
||||||
|
} else if *event == WindowEvent::Destroyed {
|
||||||
|
self.quit = true;
|
||||||
|
}
|
||||||
|
|
||||||
self.egui_winit.on_event(&self.egui_ctx, event);
|
self.egui_winit.on_event(&self.egui_ctx, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +291,10 @@ impl EpiIntegration {
|
||||||
.handle_output(window, &self.egui_ctx, egui_output);
|
.handle_output(window, &self.egui_ctx, egui_output);
|
||||||
|
|
||||||
let app_output = self.frame.take_app_output();
|
let app_output = self.frame.take_app_output();
|
||||||
self.quit |= app_output.quit;
|
|
||||||
|
if app_output.quit {
|
||||||
|
self.quit = self.app.on_exit_event();
|
||||||
|
}
|
||||||
|
|
||||||
crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
|
crate::epi::handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,20 @@ pub trait App {
|
||||||
/// where `APPNAME` is what is returned by [`Self::name()`].
|
/// where `APPNAME` is what is returned by [`Self::name()`].
|
||||||
fn save(&mut self, _storage: &mut dyn Storage) {}
|
fn save(&mut self, _storage: &mut dyn Storage) {}
|
||||||
|
|
||||||
/// Called once on shutdown (before or after [`Self::save`])
|
/// Called before an exit that can be aborted.
|
||||||
|
/// By returning `false` the exit will be aborted. To continue the exit return `true`.
|
||||||
|
///
|
||||||
|
/// A scenario where this method will be run is after pressing the close button on a native
|
||||||
|
/// window, which allows you to ask the user whether they want to do something before exiting.
|
||||||
|
/// See the example `eframe/examples/confirm_exit.rs` for practical usage.
|
||||||
|
///
|
||||||
|
/// It will _not_ be called on the web or when the window is forcefully closed.
|
||||||
|
fn on_exit_event(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called once on shutdown (before or after [`Self::save`]). If you need to abort an exit use
|
||||||
|
/// [`Self::on_exit_event`]
|
||||||
fn on_exit(&mut self) {}
|
fn on_exit(&mut self) {}
|
||||||
|
|
||||||
// ---------
|
// ---------
|
||||||
|
|
Loading…
Reference in a new issue