Skip to content
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

Allow aborting an exit event #1038

Merged
merged 1 commit into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eframe/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 49 additions & 0 deletions eframe/examples/confirm_exit.rs
Original file line number Diff line number Diff line change
@@ -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);
}
18 changes: 15 additions & 3 deletions egui-winit/src/epi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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);

Expand Down
15 changes: 14 additions & 1 deletion epi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}

// ---------
Expand Down