From f0b7737bdf5bf875876cb44550ad54fe48150a20 Mon Sep 17 00:00:00 2001 From: rustbasic <127506429+rustbasic@users.noreply.github.com> Date: Sat, 23 Mar 2024 15:37:56 +0900 Subject: [PATCH 01/15] Update memory.rs --- crates/egui/src/memory.rs | 1233 ++++++++++--------------------------- 1 file changed, 321 insertions(+), 912 deletions(-) diff --git a/crates/egui/src/memory.rs b/crates/egui/src/memory.rs index 068347b5697..1fa349b2a05 100644 --- a/crates/egui/src/memory.rs +++ b/crates/egui/src/memory.rs @@ -1,1003 +1,412 @@ -#![warn(missing_docs)] // Let's keep this file well-documented.` to memory.rs +//! Common tools used by [`super::glow_integration`] and [`super::wgpu_integration`]. -use ahash::HashMap; -use epaint::emath::TSTransform; +use web_time::Instant; +use winit::event_loop::EventLoopWindowTarget; -use crate::{ - area, vec2, EventFilter, Id, IdMap, LayerId, Order, Pos2, Rangef, RawInput, Rect, Style, Vec2, - ViewportId, ViewportIdMap, ViewportIdSet, -}; +use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _}; -// ---------------------------------------------------------------------------- +use egui::{DeferredViewportUiCallback, NumExt as _, ViewportBuilder, ViewportId}; +use egui_winit::{EventResponse, WindowSettings}; -/// The data that egui persists between frames. -/// -/// This includes window positions and sizes, -/// how far the user has scrolled in a [`ScrollArea`](crate::ScrollArea) etc. -/// -/// If you want this to persist when closing your app you should serialize [`Memory`] and store it. -/// For this you need to enable the `persistence`. -/// -/// If you want to store data for your widgets, you should look at [`Memory::data`] -#[derive(Clone, Debug)] -#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "persistence", serde(default))] -pub struct Memory { - /// Global egui options. - pub options: Options, - - /// This map stores some superficial state for all widgets with custom [`Id`]s. - /// - /// This includes storing if a [`crate::CollapsingHeader`] is open, how far scrolled a - /// [`crate::ScrollArea`] is, where the cursor in a [`crate::TextEdit`] is, etc. - /// - /// This is NOT meant to store any important data. Store that in your own structures! - /// - /// Each read clones the data, so keep your values cheap to clone. - /// If you want to store a lot of data you should wrap it in `Arc>` so it is cheap to clone. - /// - /// This will be saved between different program runs if you use the `persistence` feature. - /// - /// To store a state common for all your widgets (a singleton), use [`Id::NULL`] as the key. - pub data: crate::util::IdTypeMap, +use crate::{epi, Theme}; - // ------------------------------------------ - /// Can be used to cache computations from one frame to another. - /// - /// This is for saving CPU when you have something that may take 1-100ms to compute. - /// Things that are very slow (>100ms) should instead be done async (i.e. in another thread) - /// so as not to lock the UI thread. - /// - /// ``` - /// use egui::util::cache::{ComputerMut, FrameCache}; - /// - /// #[derive(Default)] - /// struct CharCounter {} - /// impl ComputerMut<&str, usize> for CharCounter { - /// fn compute(&mut self, s: &str) -> usize { - /// s.chars().count() // you probably want to cache something more expensive than this - /// } - /// } - /// type CharCountCache<'a> = FrameCache; - /// - /// # let mut ctx = egui::Context::default(); - /// ctx.memory_mut(|mem| { - /// let cache = mem.caches.cache::>(); - /// assert_eq!(cache.get("hello"), 5); - /// }); - /// ``` - #[cfg_attr(feature = "persistence", serde(skip))] - pub caches: crate::util::cache::CacheStorage, - - // ------------------------------------------ - /// new fonts that will be applied at the start of the next frame - #[cfg_attr(feature = "persistence", serde(skip))] - pub(crate) new_font_definitions: Option, - - // Current active viewport - #[cfg_attr(feature = "persistence", serde(skip))] - pub(crate) viewport_id: ViewportId, - - /// Which popup-window is open (if any)? - /// Could be a combo box, color picker, menu etc. - #[cfg_attr(feature = "persistence", serde(skip))] - popup: Option, - - #[cfg_attr(feature = "persistence", serde(skip))] - everything_is_visible: bool, - - /// Transforms per layer - pub layer_transforms: HashMap, - - // ------------------------------------------------- - // Per-viewport: - areas: ViewportIdMap, - - #[cfg_attr(feature = "persistence", serde(skip))] - pub(crate) interactions: ViewportIdMap, - - #[cfg_attr(feature = "persistence", serde(skip))] - pub(crate) focus: ViewportIdMap, -} +pub fn viewport_builder( + egui_zoom_factor: f32, + event_loop: &EventLoopWindowTarget, + native_options: &mut epi::NativeOptions, + window_settings: Option, +) -> ViewportBuilder { + crate::profile_function!(); -impl Default for Memory { - fn default() -> Self { - let mut slf = Self { - options: Default::default(), - data: Default::default(), - caches: Default::default(), - new_font_definitions: Default::default(), - interactions: Default::default(), - focus: Default::default(), - viewport_id: Default::default(), - areas: Default::default(), - layer_transforms: Default::default(), - popup: Default::default(), - everything_is_visible: Default::default(), - }; - slf.interactions.entry(slf.viewport_id).or_default(); - slf.areas.entry(slf.viewport_id).or_default(); - slf - } -} + let mut viewport_builder = native_options.viewport.clone(); -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -enum FocusDirection { - /// Select the widget closest above the current focused widget. - Up, + // Always use the default window size / position on iOS. Trying to restore the previous position + // causes the window to be shown too small. + #[cfg(not(target_os = "ios"))] + let inner_size_points = if let Some(mut window_settings) = window_settings { + // Restore pos/size from previous session - /// Select the widget to the right of the current focused widget. - Right, + window_settings + .clamp_size_to_sane_values(largest_monitor_point_size(egui_zoom_factor, event_loop)); + window_settings.clamp_position_to_monitors(egui_zoom_factor, event_loop); - /// Select the widget below the current focused widget. - Down, - - /// Select the widget to the left of the the current focused widget. - Left, + viewport_builder = window_settings.initialize_viewport_builder(viewport_builder); + window_settings.inner_size_points() + } else { + if let Some(pos) = viewport_builder.position { + viewport_builder = viewport_builder.with_position(pos); + } - /// Select the previous widget that had focus. - Previous, + if let Some(initial_window_size) = viewport_builder.inner_size { + let initial_window_size = initial_window_size + .at_most(largest_monitor_point_size(egui_zoom_factor, event_loop)); + viewport_builder = viewport_builder.with_inner_size(initial_window_size); + } - /// Select the next widget that wants focus. - Next, + viewport_builder.inner_size + }; + + #[cfg(not(target_os = "ios"))] + if native_options.centered { + crate::profile_scope!("center"); + if let Some(monitor) = event_loop.available_monitors().next() { + let monitor_size = monitor + .size() + .to_logical::(egui_zoom_factor as f64 * monitor.scale_factor()); + let inner_size = inner_size_points.unwrap_or(egui::Vec2 { x: 800.0, y: 600.0 }); + if 0.0 < monitor_size.width && 0.0 < monitor_size.height { + let x = (monitor_size.width - inner_size.x) / 2.0; + let y = (monitor_size.height - inner_size.y) / 2.0; + viewport_builder = viewport_builder.with_position([x, y]); + } + } + } - /// Don't change focus. - #[default] - None, + match std::mem::take(&mut native_options.window_builder) { + Some(hook) => hook(viewport_builder), + None => viewport_builder, + } } -impl FocusDirection { - fn is_cardinal(&self) -> bool { - match self { - Self::Up | Self::Right | Self::Down | Self::Left => true, +pub fn apply_window_settings( + window: &winit::window::Window, + window_settings: Option, +) { + crate::profile_function!(); - Self::Previous | Self::Next | Self::None => false, - } + if let Some(window_settings) = window_settings { + window_settings.initialize_window(window); } } -// ---------------------------------------------------------------------------- - -/// Some global options that you can read and write. -/// -/// See also [`crate::style::DebugOptions`]. -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "serde", serde(default))] -pub struct Options { - /// The default style for new [`Ui`](crate::Ui):s. - #[cfg_attr(feature = "serde", serde(skip))] - pub(crate) style: std::sync::Arc