eframe: allow aborting an exit event (#1038)

This commit is contained in:
Erlend Walstad 2022-01-17 18:45:09 +01:00 committed by GitHub
parent 87ac7446da
commit ab77099781
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 4 deletions

View file

@ -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 web painter is now `egui_glow` (instead of WebGL) ([#1020](https://github.com/emilk/egui/pull/1020)).
* 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

View 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);
}

View file

@ -240,7 +240,11 @@ impl EpiIntegration {
self.app
.setup(&self.egui_ctx, &self.frame, self.persistence.storage());
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);
}
@ -260,7 +264,12 @@ impl EpiIntegration {
pub fn on_event(&mut self, event: &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);
}
@ -282,7 +291,10 @@ impl EpiIntegration {
.handle_output(window, &self.egui_ctx, egui_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);

View file

@ -144,7 +144,20 @@ pub trait App {
/// where `APPNAME` is what is returned by [`Self::name()`].
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) {}
// ---------