2022-05-22 18:24:41 +00:00
|
|
|
use winit::event_loop::EventLoopWindowTarget;
|
2022-04-29 06:17:49 +00:00
|
|
|
|
2022-09-16 12:31:21 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
use winit::platform::macos::WindowBuilderExtMacOS as _;
|
|
|
|
|
2022-12-04 18:17:12 +00:00
|
|
|
#[cfg(feature = "accesskit")]
|
|
|
|
use egui::accesskit;
|
2022-12-13 08:09:36 +00:00
|
|
|
use egui::NumExt as _;
|
2022-12-04 18:17:12 +00:00
|
|
|
#[cfg(feature = "accesskit")]
|
|
|
|
use egui_winit::accesskit_winit;
|
2022-08-29 09:20:19 +00:00
|
|
|
use egui_winit::{native_pixels_per_point, EventResponse, WindowSettings};
|
|
|
|
|
|
|
|
use crate::{epi, Theme, WindowInfo};
|
|
|
|
|
2022-02-22 16:13:53 +00:00
|
|
|
pub fn points_to_size(points: egui::Vec2) -> winit::dpi::LogicalSize<f64> {
|
2022-02-02 15:47:27 +00:00
|
|
|
winit::dpi::LogicalSize {
|
|
|
|
width: points.x as f64,
|
|
|
|
height: points.y as f64,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-29 12:37:23 +00:00
|
|
|
pub fn read_window_info(window: &winit::window::Window, pixels_per_point: f32) -> WindowInfo {
|
|
|
|
let position = window
|
|
|
|
.outer_position()
|
|
|
|
.ok()
|
|
|
|
.map(|pos| pos.to_logical::<f32>(pixels_per_point.into()))
|
|
|
|
.map(|pos| egui::Pos2 { x: pos.x, y: pos.y });
|
|
|
|
|
2022-09-17 09:20:40 +00:00
|
|
|
let monitor = window.current_monitor().is_some();
|
|
|
|
let monitor_size = if monitor {
|
|
|
|
let size = window.current_monitor().unwrap().size();
|
|
|
|
Some(egui::vec2(size.width as _, size.height as _))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2022-07-29 12:37:23 +00:00
|
|
|
let size = window
|
|
|
|
.inner_size()
|
|
|
|
.to_logical::<f32>(pixels_per_point.into());
|
|
|
|
|
|
|
|
WindowInfo {
|
|
|
|
position,
|
|
|
|
fullscreen: window.fullscreen().is_some(),
|
|
|
|
size: egui::Vec2 {
|
|
|
|
x: size.width,
|
|
|
|
y: size.height,
|
|
|
|
},
|
2022-09-17 09:20:40 +00:00
|
|
|
monitor_size,
|
2022-05-13 08:15:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-30 14:52:30 +00:00
|
|
|
pub fn build_window<E>(
|
2022-12-13 08:09:36 +00:00
|
|
|
event_loop: &EventLoopWindowTarget<E>,
|
2022-12-12 14:16:32 +00:00
|
|
|
title: &str,
|
2021-10-19 19:40:55 +00:00
|
|
|
native_options: &epi::NativeOptions,
|
2022-12-13 08:09:36 +00:00
|
|
|
window_settings: Option<WindowSettings>,
|
2023-01-30 14:52:30 +00:00
|
|
|
) -> Result<winit::window::Window, winit::error::OsError> {
|
2022-02-05 18:12:03 +00:00
|
|
|
let epi::NativeOptions {
|
|
|
|
always_on_top,
|
|
|
|
maximized,
|
|
|
|
decorated,
|
2022-07-29 12:21:23 +00:00
|
|
|
fullscreen,
|
2022-09-16 12:31:21 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
fullsize_content,
|
2022-02-05 18:12:03 +00:00
|
|
|
drag_and_drop_support,
|
|
|
|
icon_data,
|
|
|
|
initial_window_pos,
|
|
|
|
initial_window_size,
|
|
|
|
min_window_size,
|
|
|
|
max_window_size,
|
|
|
|
resizable,
|
|
|
|
transparent,
|
2023-01-30 14:52:30 +00:00
|
|
|
centered,
|
2022-06-09 15:41:59 +00:00
|
|
|
..
|
2022-02-05 18:12:03 +00:00
|
|
|
} = native_options;
|
|
|
|
|
|
|
|
let window_icon = icon_data.clone().and_then(load_icon);
|
2021-10-19 19:40:55 +00:00
|
|
|
|
|
|
|
let mut window_builder = winit::window::WindowBuilder::new()
|
2022-12-12 14:16:32 +00:00
|
|
|
.with_title(title)
|
2022-02-05 18:12:03 +00:00
|
|
|
.with_decorations(*decorated)
|
2022-07-29 12:21:23 +00:00
|
|
|
.with_fullscreen(fullscreen.then(|| winit::window::Fullscreen::Borderless(None)))
|
|
|
|
.with_maximized(*maximized)
|
2022-02-05 18:12:03 +00:00
|
|
|
.with_resizable(*resizable)
|
|
|
|
.with_transparent(*transparent)
|
2022-12-12 14:16:32 +00:00
|
|
|
.with_window_icon(window_icon)
|
|
|
|
// Keep hidden until we've painted something. See https://github.com/emilk/egui/pull/2279
|
|
|
|
// We must also keep the window hidden until AccessKit is initialized.
|
|
|
|
.with_visible(false);
|
2021-10-19 19:40:55 +00:00
|
|
|
|
2022-09-16 12:31:21 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
if *fullsize_content {
|
|
|
|
window_builder = window_builder
|
|
|
|
.with_title_hidden(true)
|
|
|
|
.with_titlebar_transparent(true)
|
|
|
|
.with_fullsize_content_view(true);
|
|
|
|
}
|
|
|
|
|
2022-02-05 18:12:03 +00:00
|
|
|
if let Some(min_size) = *min_window_size {
|
2022-02-02 15:47:27 +00:00
|
|
|
window_builder = window_builder.with_min_inner_size(points_to_size(min_size));
|
|
|
|
}
|
2022-02-05 18:12:03 +00:00
|
|
|
if let Some(max_size) = *max_window_size {
|
2022-02-02 15:47:27 +00:00
|
|
|
window_builder = window_builder.with_max_inner_size(points_to_size(max_size));
|
|
|
|
}
|
|
|
|
|
2022-02-05 18:12:03 +00:00
|
|
|
window_builder = window_builder_drag_and_drop(window_builder, *drag_and_drop_support);
|
2021-10-19 19:40:55 +00:00
|
|
|
|
2023-01-30 14:52:30 +00:00
|
|
|
let inner_size_points = if let Some(mut window_settings) = window_settings {
|
2022-12-13 08:09:36 +00:00
|
|
|
// Restore pos/size from previous session
|
|
|
|
window_settings.clamp_to_sane_values(largest_monitor_point_size(event_loop));
|
2021-10-19 19:40:55 +00:00
|
|
|
window_builder = window_settings.initialize_window(window_builder);
|
2023-01-30 14:52:30 +00:00
|
|
|
window_settings.inner_size_points()
|
2022-02-05 18:12:03 +00:00
|
|
|
} else {
|
|
|
|
if let Some(pos) = *initial_window_pos {
|
2023-01-30 14:52:30 +00:00
|
|
|
window_builder = window_builder.with_position(winit::dpi::LogicalPosition {
|
2022-02-05 18:12:03 +00:00
|
|
|
x: pos.x as f64,
|
|
|
|
y: pos.y as f64,
|
|
|
|
});
|
|
|
|
}
|
2022-12-13 08:09:36 +00:00
|
|
|
|
2022-02-05 18:12:03 +00:00
|
|
|
if let Some(initial_window_size) = *initial_window_size {
|
2022-12-13 08:09:36 +00:00
|
|
|
let initial_window_size =
|
|
|
|
initial_window_size.at_most(largest_monitor_point_size(event_loop));
|
2022-02-05 18:12:03 +00:00
|
|
|
window_builder = window_builder.with_inner_size(points_to_size(initial_window_size));
|
|
|
|
}
|
2023-01-30 14:52:30 +00:00
|
|
|
|
|
|
|
*initial_window_size
|
|
|
|
};
|
|
|
|
|
|
|
|
if *centered {
|
|
|
|
if let Some(monitor) = event_loop.available_monitors().next() {
|
|
|
|
let monitor_size = monitor.size();
|
|
|
|
let inner_size = inner_size_points.unwrap_or(egui::Vec2 { x: 800.0, y: 600.0 });
|
|
|
|
if monitor_size.width > 0 && monitor_size.height > 0 {
|
|
|
|
let x = (monitor_size.width - inner_size.x as u32) / 2;
|
|
|
|
let y = (monitor_size.height - inner_size.y as u32) / 2;
|
|
|
|
window_builder = window_builder.with_position(winit::dpi::LogicalPosition {
|
|
|
|
x: x as f64,
|
|
|
|
y: y as f64,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2021-10-19 19:40:55 +00:00
|
|
|
}
|
|
|
|
|
2023-02-04 11:43:43 +00:00
|
|
|
let window = window_builder.build(event_loop)?;
|
|
|
|
|
|
|
|
use winit::window::WindowLevel;
|
|
|
|
window.set_window_level(if *always_on_top {
|
|
|
|
WindowLevel::AlwaysOnTop
|
|
|
|
} else {
|
|
|
|
WindowLevel::Normal
|
|
|
|
});
|
|
|
|
|
|
|
|
Ok(window)
|
2021-10-19 19:40:55 +00:00
|
|
|
}
|
|
|
|
|
2022-12-13 08:09:36 +00:00
|
|
|
fn largest_monitor_point_size<E>(event_loop: &EventLoopWindowTarget<E>) -> egui::Vec2 {
|
|
|
|
let mut max_size = egui::Vec2::ZERO;
|
|
|
|
|
|
|
|
for monitor in event_loop.available_monitors() {
|
|
|
|
let size = monitor.size().to_logical::<f32>(monitor.scale_factor());
|
|
|
|
let size = egui::vec2(size.width, size.height);
|
|
|
|
max_size = max_size.max(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if max_size == egui::Vec2::ZERO {
|
|
|
|
egui::Vec2::splat(16000.0)
|
|
|
|
} else {
|
|
|
|
max_size
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-19 19:40:55 +00:00
|
|
|
fn load_icon(icon_data: epi::IconData) -> Option<winit::window::Icon> {
|
|
|
|
winit::window::Icon::from_rgba(icon_data.rgba, icon_data.width, icon_data.height).ok()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
fn window_builder_drag_and_drop(
|
|
|
|
window_builder: winit::window::WindowBuilder,
|
|
|
|
enable: bool,
|
|
|
|
) -> winit::window::WindowBuilder {
|
2021-10-20 07:51:21 +00:00
|
|
|
use winit::platform::windows::WindowBuilderExtWindows as _;
|
2023-02-03 12:19:12 +00:00
|
|
|
window_builder.with_drag_and_drop(enable)
|
2021-10-19 19:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
|
|
fn window_builder_drag_and_drop(
|
|
|
|
window_builder: winit::window::WindowBuilder,
|
|
|
|
_enable: bool,
|
|
|
|
) -> winit::window::WindowBuilder {
|
|
|
|
// drag and drop can only be disabled on windows
|
|
|
|
window_builder
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn handle_app_output(
|
|
|
|
window: &winit::window::Window,
|
|
|
|
current_pixels_per_point: f32,
|
|
|
|
app_output: epi::backend::AppOutput,
|
2022-01-15 12:59:52 +00:00
|
|
|
) {
|
2021-10-19 19:40:55 +00:00
|
|
|
let epi::backend::AppOutput {
|
2022-08-20 14:08:59 +00:00
|
|
|
close: _,
|
2021-10-19 19:40:55 +00:00
|
|
|
window_size,
|
2021-10-22 22:03:17 +00:00
|
|
|
window_title,
|
2021-10-19 19:40:55 +00:00
|
|
|
decorated,
|
2022-07-29 12:21:23 +00:00
|
|
|
fullscreen,
|
2021-10-19 19:40:55 +00:00
|
|
|
drag_window,
|
2022-04-16 20:27:22 +00:00
|
|
|
window_pos,
|
2022-11-13 19:30:52 +00:00
|
|
|
visible: _, // handled in post_present
|
2022-09-17 09:20:40 +00:00
|
|
|
always_on_top,
|
2023-02-04 13:42:42 +00:00
|
|
|
minimized,
|
|
|
|
maximized,
|
2021-10-19 19:40:55 +00:00
|
|
|
} = app_output;
|
|
|
|
|
|
|
|
if let Some(decorated) = decorated {
|
|
|
|
window.set_decorations(decorated);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(window_size) = window_size {
|
|
|
|
window.set_inner_size(
|
|
|
|
winit::dpi::PhysicalSize {
|
|
|
|
width: (current_pixels_per_point * window_size.x).round(),
|
|
|
|
height: (current_pixels_per_point * window_size.y).round(),
|
|
|
|
}
|
2022-04-29 06:17:49 +00:00
|
|
|
.to_logical::<f32>(native_pixels_per_point(window) as f64),
|
2021-10-19 19:40:55 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-07-29 12:21:23 +00:00
|
|
|
if let Some(fullscreen) = fullscreen {
|
2022-11-16 18:08:03 +00:00
|
|
|
window.set_fullscreen(fullscreen.then_some(winit::window::Fullscreen::Borderless(None)));
|
2022-07-29 12:21:23 +00:00
|
|
|
}
|
|
|
|
|
2021-10-22 22:03:17 +00:00
|
|
|
if let Some(window_title) = window_title {
|
|
|
|
window.set_title(&window_title);
|
|
|
|
}
|
|
|
|
|
2022-04-16 20:27:22 +00:00
|
|
|
if let Some(window_pos) = window_pos {
|
|
|
|
window.set_outer_position(winit::dpi::PhysicalPosition {
|
|
|
|
x: window_pos.x as f64,
|
|
|
|
y: window_pos.y as f64,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-10-19 19:40:55 +00:00
|
|
|
if drag_window {
|
|
|
|
let _ = window.drag_window();
|
|
|
|
}
|
2022-07-21 18:16:56 +00:00
|
|
|
|
2022-09-17 09:20:40 +00:00
|
|
|
if let Some(always_on_top) = always_on_top {
|
2023-02-04 11:43:43 +00:00
|
|
|
use winit::window::WindowLevel;
|
|
|
|
window.set_window_level(if always_on_top {
|
|
|
|
WindowLevel::AlwaysOnTop
|
|
|
|
} else {
|
|
|
|
WindowLevel::Normal
|
|
|
|
});
|
2022-09-17 09:20:40 +00:00
|
|
|
}
|
2023-02-04 13:42:42 +00:00
|
|
|
|
|
|
|
if let Some(minimized) = minimized {
|
|
|
|
window.set_minimized(minimized);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(maximized) = maximized {
|
|
|
|
window.set_maximized(maximized);
|
|
|
|
}
|
2021-10-19 19:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/// For loading/saving app state and/or egui memory to disk.
|
2022-03-25 20:19:31 +00:00
|
|
|
pub fn create_storage(_app_name: &str) -> Option<Box<dyn epi::Storage>> {
|
2021-10-19 19:40:55 +00:00
|
|
|
#[cfg(feature = "persistence")]
|
2022-04-30 08:44:35 +00:00
|
|
|
if let Some(storage) = super::file_storage::FileStorage::from_app_name(_app_name) {
|
2022-03-25 20:19:31 +00:00
|
|
|
return Some(Box::new(storage));
|
2021-10-19 19:40:55 +00:00
|
|
|
}
|
2022-03-25 20:19:31 +00:00
|
|
|
None
|
2021-10-19 19:40:55 +00:00
|
|
|
}
|
2021-11-03 12:45:51 +00:00
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/// Everything needed to make a winit-based integration for [`epi`].
|
|
|
|
pub struct EpiIntegration {
|
2022-03-16 14:39:48 +00:00
|
|
|
pub frame: epi::Frame,
|
2022-04-29 06:17:49 +00:00
|
|
|
last_auto_save: std::time::Instant,
|
2022-01-10 22:13:10 +00:00
|
|
|
pub egui_ctx: egui::Context,
|
2022-02-22 16:13:53 +00:00
|
|
|
pending_full_output: egui::FullOutput,
|
2022-04-29 06:17:49 +00:00
|
|
|
egui_winit: egui_winit::State,
|
2022-08-20 14:08:59 +00:00
|
|
|
/// When set, it is time to close the native window.
|
|
|
|
close: bool,
|
2022-01-26 21:04:24 +00:00
|
|
|
can_drag_window: bool,
|
2021-11-03 12:45:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl EpiIntegration {
|
2022-05-22 18:24:41 +00:00
|
|
|
pub fn new<E>(
|
|
|
|
event_loop: &EventLoopWindowTarget<E>,
|
2022-01-24 13:32:36 +00:00
|
|
|
max_texture_side: usize,
|
2021-11-03 12:45:51 +00:00
|
|
|
window: &winit::window::Window,
|
2022-06-09 15:41:59 +00:00
|
|
|
system_theme: Option<Theme>,
|
2022-03-25 20:19:31 +00:00
|
|
|
storage: Option<Box<dyn epi::Storage>>,
|
2022-05-22 15:43:30 +00:00
|
|
|
#[cfg(feature = "glow")] gl: Option<std::sync::Arc<glow::Context>>,
|
2022-08-08 10:15:31 +00:00
|
|
|
#[cfg(feature = "wgpu")] wgpu_render_state: Option<egui_wgpu::RenderState>,
|
2021-11-03 12:45:51 +00:00
|
|
|
) -> Self {
|
2022-01-10 22:13:10 +00:00
|
|
|
let egui_ctx = egui::Context::default();
|
2021-11-03 12:45:51 +00:00
|
|
|
|
2023-01-25 09:24:23 +00:00
|
|
|
let memory = load_egui_memory(storage.as_deref()).unwrap_or_default();
|
|
|
|
egui_ctx.memory_mut(|mem| *mem = memory);
|
2021-11-03 12:45:51 +00:00
|
|
|
|
2022-11-07 11:36:17 +00:00
|
|
|
let native_pixels_per_point = window.scale_factor() as f32;
|
|
|
|
|
2022-03-25 20:19:31 +00:00
|
|
|
let frame = epi::Frame {
|
2021-12-26 20:21:28 +00:00
|
|
|
info: epi::IntegrationInfo {
|
2022-06-09 15:41:59 +00:00
|
|
|
system_theme,
|
2021-12-26 20:21:28 +00:00
|
|
|
cpu_usage: None,
|
2022-11-07 11:36:17 +00:00
|
|
|
native_pixels_per_point: Some(native_pixels_per_point),
|
2022-05-13 08:15:43 +00:00
|
|
|
window_info: read_window_info(window, egui_ctx.pixels_per_point()),
|
2021-12-26 20:21:28 +00:00
|
|
|
},
|
2022-11-13 19:30:52 +00:00
|
|
|
output: epi::backend::AppOutput {
|
|
|
|
visible: Some(true),
|
|
|
|
..Default::default()
|
|
|
|
},
|
2022-03-25 20:19:31 +00:00
|
|
|
storage,
|
2022-05-12 07:02:28 +00:00
|
|
|
#[cfg(feature = "glow")]
|
2022-03-27 13:20:45 +00:00
|
|
|
gl,
|
2022-05-28 15:52:36 +00:00
|
|
|
#[cfg(feature = "wgpu")]
|
2022-08-08 10:15:31 +00:00
|
|
|
wgpu_render_state,
|
2022-03-25 20:19:31 +00:00
|
|
|
};
|
2021-12-26 20:21:28 +00:00
|
|
|
|
2022-05-22 18:24:41 +00:00
|
|
|
let mut egui_winit = egui_winit::State::new(event_loop);
|
|
|
|
egui_winit.set_max_texture_side(max_texture_side);
|
2022-11-07 11:36:17 +00:00
|
|
|
egui_winit.set_pixels_per_point(native_pixels_per_point);
|
2022-05-22 18:24:41 +00:00
|
|
|
|
2022-03-16 14:39:48 +00:00
|
|
|
Self {
|
2021-12-26 20:21:28 +00:00
|
|
|
frame,
|
2022-04-29 06:17:49 +00:00
|
|
|
last_auto_save: std::time::Instant::now(),
|
2021-11-03 12:45:51 +00:00
|
|
|
egui_ctx,
|
2022-05-22 18:24:41 +00:00
|
|
|
egui_winit,
|
2022-02-22 16:13:53 +00:00
|
|
|
pending_full_output: Default::default(),
|
2022-08-20 14:08:59 +00:00
|
|
|
close: false,
|
2022-01-26 21:04:24 +00:00
|
|
|
can_drag_window: false,
|
2022-01-17 17:45:09 +00:00
|
|
|
}
|
2021-11-03 12:45:51 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:12 +00:00
|
|
|
#[cfg(feature = "accesskit")]
|
|
|
|
pub fn init_accesskit<E: From<accesskit_winit::ActionRequestEvent> + Send>(
|
|
|
|
&mut self,
|
|
|
|
window: &winit::window::Window,
|
|
|
|
event_loop_proxy: winit::event_loop::EventLoopProxy<E>,
|
|
|
|
) {
|
|
|
|
let egui_ctx = self.egui_ctx.clone();
|
|
|
|
self.egui_winit
|
|
|
|
.init_accesskit(window, event_loop_proxy, move || {
|
|
|
|
// This function is called when an accessibility client
|
|
|
|
// (e.g. screen reader) makes its first request. If we got here,
|
|
|
|
// we know that an accessibility tree is actually wanted.
|
|
|
|
egui_ctx.enable_accesskit();
|
|
|
|
// Enqueue a repaint so we'll receive a full tree update soon.
|
|
|
|
egui_ctx.request_repaint();
|
|
|
|
egui::accesskit_placeholder_tree_update()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-16 14:39:48 +00:00
|
|
|
pub fn warm_up(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) {
|
2022-04-13 09:06:13 +00:00
|
|
|
crate::profile_function!();
|
2023-01-25 09:24:23 +00:00
|
|
|
let saved_memory: egui::Memory = self.egui_ctx.memory(|mem| mem.clone());
|
|
|
|
self.egui_ctx
|
|
|
|
.memory_mut(|mem| mem.set_everything_is_visible(true));
|
2022-03-16 14:39:48 +00:00
|
|
|
let full_output = self.update(app, window);
|
2022-02-22 16:13:53 +00:00
|
|
|
self.pending_full_output.append(full_output); // Handle it next frame
|
2023-01-25 09:24:23 +00:00
|
|
|
self.egui_ctx.memory_mut(|mem| *mem = saved_memory); // We don't want to remember that windows were huge.
|
2021-11-03 12:45:51 +00:00
|
|
|
self.egui_ctx.clear_animations();
|
|
|
|
}
|
|
|
|
|
2022-08-20 14:08:59 +00:00
|
|
|
/// If `true`, it is time to close the native window.
|
|
|
|
pub fn should_close(&self) -> bool {
|
|
|
|
self.close
|
2021-11-03 12:45:51 +00:00
|
|
|
}
|
|
|
|
|
2022-08-29 09:20:19 +00:00
|
|
|
pub fn on_event(
|
|
|
|
&mut self,
|
|
|
|
app: &mut dyn epi::App,
|
|
|
|
event: &winit::event::WindowEvent<'_>,
|
|
|
|
) -> EventResponse {
|
2022-01-26 21:04:24 +00:00
|
|
|
use winit::event::{ElementState, MouseButton, WindowEvent};
|
|
|
|
|
|
|
|
match event {
|
2022-12-12 14:16:32 +00:00
|
|
|
WindowEvent::CloseRequested => {
|
|
|
|
tracing::debug!("Received WindowEvent::CloseRequested");
|
|
|
|
self.close = app.on_close_event();
|
|
|
|
tracing::debug!("App::on_close_event returned {}", self.close);
|
|
|
|
}
|
|
|
|
WindowEvent::Destroyed => {
|
|
|
|
tracing::debug!("Received WindowEvent::Destroyed");
|
|
|
|
self.close = true;
|
|
|
|
}
|
2022-01-26 21:04:24 +00:00
|
|
|
WindowEvent::MouseInput {
|
|
|
|
button: MouseButton::Left,
|
|
|
|
state: ElementState::Pressed,
|
|
|
|
..
|
|
|
|
} => self.can_drag_window = true,
|
2022-11-07 11:36:17 +00:00
|
|
|
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
|
|
|
|
self.frame.info.native_pixels_per_point = Some(*scale_factor as _);
|
|
|
|
}
|
2022-01-26 21:04:24 +00:00
|
|
|
_ => {}
|
2022-01-17 17:45:09 +00:00
|
|
|
}
|
|
|
|
|
2022-08-29 09:20:19 +00:00
|
|
|
self.egui_winit.on_event(&self.egui_ctx, event)
|
2021-11-03 12:45:51 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 18:17:12 +00:00
|
|
|
#[cfg(feature = "accesskit")]
|
|
|
|
pub fn on_accesskit_action_request(&mut self, request: accesskit::ActionRequest) {
|
|
|
|
self.egui_winit.on_accesskit_action_request(request);
|
|
|
|
}
|
|
|
|
|
2022-03-16 14:39:48 +00:00
|
|
|
pub fn update(
|
|
|
|
&mut self,
|
|
|
|
app: &mut dyn epi::App,
|
|
|
|
window: &winit::window::Window,
|
|
|
|
) -> egui::FullOutput {
|
2022-04-29 06:17:49 +00:00
|
|
|
let frame_start = std::time::Instant::now();
|
2021-11-03 12:45:51 +00:00
|
|
|
|
2022-05-13 08:15:43 +00:00
|
|
|
self.frame.info.window_info = read_window_info(window, self.egui_ctx.pixels_per_point());
|
2021-11-03 12:45:51 +00:00
|
|
|
let raw_input = self.egui_winit.take_egui_input(window);
|
2022-02-22 16:13:53 +00:00
|
|
|
let full_output = self.egui_ctx.run(raw_input, |egui_ctx| {
|
2022-04-13 09:06:13 +00:00
|
|
|
crate::profile_scope!("App::update");
|
2022-03-25 20:19:31 +00:00
|
|
|
app.update(egui_ctx, &mut self.frame);
|
2021-11-03 19:11:25 +00:00
|
|
|
});
|
2022-02-22 16:13:53 +00:00
|
|
|
self.pending_full_output.append(full_output);
|
|
|
|
let full_output = std::mem::take(&mut self.pending_full_output);
|
|
|
|
|
|
|
|
{
|
|
|
|
let mut app_output = self.frame.take_app_output();
|
|
|
|
app_output.drag_window &= self.can_drag_window; // Necessary on Windows; see https://github.com/emilk/egui/pull/1108
|
|
|
|
self.can_drag_window = false;
|
2022-08-20 14:08:59 +00:00
|
|
|
if app_output.close {
|
|
|
|
self.close = app.on_close_event();
|
2022-12-12 14:16:32 +00:00
|
|
|
tracing::debug!("App::on_close_event returned {}", self.close);
|
2022-02-22 16:13:53 +00:00
|
|
|
}
|
2022-11-13 19:30:52 +00:00
|
|
|
self.frame.output.visible = app_output.visible; // this is handled by post_present
|
2022-04-29 06:17:49 +00:00
|
|
|
handle_app_output(window, self.egui_ctx.pixels_per_point(), app_output);
|
2022-01-17 17:45:09 +00:00
|
|
|
}
|
2022-01-15 12:59:52 +00:00
|
|
|
|
2022-11-16 18:08:03 +00:00
|
|
|
let frame_time = frame_start.elapsed().as_secs_f64() as f32;
|
2022-03-25 20:19:31 +00:00
|
|
|
self.frame.info.cpu_usage = Some(frame_time);
|
2021-11-03 12:45:51 +00:00
|
|
|
|
2022-02-22 16:13:53 +00:00
|
|
|
full_output
|
|
|
|
}
|
|
|
|
|
2022-05-29 18:33:04 +00:00
|
|
|
pub fn post_rendering(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) {
|
|
|
|
let inner_size = window.inner_size();
|
|
|
|
let window_size_px = [inner_size.width, inner_size.height];
|
|
|
|
|
|
|
|
app.post_rendering(window_size_px, &self.frame);
|
|
|
|
}
|
|
|
|
|
2022-11-13 19:30:52 +00:00
|
|
|
pub fn post_present(&mut self, window: &winit::window::Window) {
|
|
|
|
if let Some(visible) = self.frame.output.visible.take() {
|
|
|
|
window.set_visible(visible);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-22 16:13:53 +00:00
|
|
|
pub fn handle_platform_output(
|
|
|
|
&mut self,
|
|
|
|
window: &winit::window::Window,
|
|
|
|
platform_output: egui::PlatformOutput,
|
|
|
|
) {
|
|
|
|
self.egui_winit
|
|
|
|
.handle_platform_output(window, &self.egui_ctx, platform_output);
|
2021-11-03 12:45:51 +00:00
|
|
|
}
|
|
|
|
|
2022-03-25 20:19:31 +00:00
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
// Persistance stuff:
|
|
|
|
|
2022-03-16 14:39:48 +00:00
|
|
|
pub fn maybe_autosave(&mut self, app: &mut dyn epi::App, window: &winit::window::Window) {
|
2022-04-29 06:17:49 +00:00
|
|
|
let now = std::time::Instant::now();
|
2022-03-25 20:19:31 +00:00
|
|
|
if now - self.last_auto_save > app.auto_save_interval() {
|
|
|
|
self.save(app, window);
|
|
|
|
self.last_auto_save = now;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn save(&mut self, _app: &mut dyn epi::App, _window: &winit::window::Window) {
|
|
|
|
#[cfg(feature = "persistence")]
|
|
|
|
if let Some(storage) = self.frame.storage_mut() {
|
2022-04-13 09:06:13 +00:00
|
|
|
crate::profile_function!();
|
|
|
|
|
2022-03-25 20:19:31 +00:00
|
|
|
if _app.persist_native_window() {
|
2022-04-13 09:06:13 +00:00
|
|
|
crate::profile_scope!("native_window");
|
2022-03-25 20:19:31 +00:00
|
|
|
epi::set_value(
|
|
|
|
storage,
|
|
|
|
STORAGE_WINDOW_KEY,
|
2022-04-29 06:17:49 +00:00
|
|
|
&WindowSettings::from_display(_window),
|
2022-03-25 20:19:31 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
if _app.persist_egui_memory() {
|
2022-04-13 09:06:13 +00:00
|
|
|
crate::profile_scope!("egui_memory");
|
2023-01-25 09:24:23 +00:00
|
|
|
self.egui_ctx
|
|
|
|
.memory(|mem| epi::set_value(storage, STORAGE_EGUI_MEMORY_KEY, mem));
|
2022-03-25 20:19:31 +00:00
|
|
|
}
|
2022-04-13 09:06:13 +00:00
|
|
|
{
|
|
|
|
crate::profile_scope!("App::save");
|
|
|
|
_app.save(storage);
|
|
|
|
}
|
|
|
|
|
|
|
|
crate::profile_scope!("Storage::flush");
|
2022-03-25 20:19:31 +00:00
|
|
|
storage.flush();
|
|
|
|
}
|
2021-11-03 12:45:51 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-02 16:09:36 +00:00
|
|
|
|
2022-03-25 20:19:31 +00:00
|
|
|
#[cfg(feature = "persistence")]
|
|
|
|
const STORAGE_EGUI_MEMORY_KEY: &str = "egui";
|
2022-08-02 15:26:33 +00:00
|
|
|
|
2022-03-25 20:19:31 +00:00
|
|
|
#[cfg(feature = "persistence")]
|
|
|
|
const STORAGE_WINDOW_KEY: &str = "window";
|
|
|
|
|
2022-04-29 06:17:49 +00:00
|
|
|
pub fn load_window_settings(_storage: Option<&dyn epi::Storage>) -> Option<WindowSettings> {
|
2022-03-25 20:19:31 +00:00
|
|
|
#[cfg(feature = "persistence")]
|
|
|
|
{
|
2022-12-13 08:09:36 +00:00
|
|
|
epi::get_value(_storage?, STORAGE_WINDOW_KEY)
|
2022-03-25 20:19:31 +00:00
|
|
|
}
|
|
|
|
#[cfg(not(feature = "persistence"))]
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_egui_memory(_storage: Option<&dyn epi::Storage>) -> Option<egui::Memory> {
|
|
|
|
#[cfg(feature = "persistence")]
|
|
|
|
{
|
|
|
|
epi::get_value(_storage?, STORAGE_EGUI_MEMORY_KEY)
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "persistence"))]
|
|
|
|
None
|
|
|
|
}
|