From 209cbeb03046d8b690232ba6d6fc980cd32f2669 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 4 Sep 2023 09:37:35 +0200 Subject: [PATCH 1/4] Replace instant with web_time (#3296) --- Cargo.lock | 13 ++++++++++++- crates/egui-winit/Cargo.toml | 12 ++---------- crates/egui-winit/src/lib.rs | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54812aff9..c2ca14a83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1206,12 +1206,12 @@ dependencies = [ "arboard", "document-features", "egui", - "instant", "log", "puffin", "raw-window-handle", "serde", "smithay-clipboard", + "web-time", "webbrowser", "winit", ] @@ -4052,6 +4052,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa75ec260dcf59cc310827bae1d7f629809b173dbfe808a633e19754dd4282a5" +dependencies = [ + "js-sys", + "once_cell", + "wasm-bindgen", +] + [[package]] name = "webbrowser" version = "0.8.10" diff --git a/crates/egui-winit/Cargo.toml b/crates/egui-winit/Cargo.toml index 2d6833d91..30e206306 100644 --- a/crates/egui-winit/Cargo.toml +++ b/crates/egui-winit/Cargo.toml @@ -60,8 +60,9 @@ egui = { version = "0.22.0", path = "../egui", default-features = false, feature "log", ] } log = { version = "0.4", features = ["std"] } -winit = { version = "0.28", default-features = false } raw-window-handle = "0.5.0" +web-time = { version = "0.1" } # We use web-time so we can (maybe) compile for web +winit = { version = "0.28", default-features = false } #! ### Optional dependencies @@ -73,17 +74,8 @@ document-features = { version = "0.2", optional = true } puffin = { version = "0.16", optional = true } serde = { version = "1.0", optional = true, features = ["derive"] } - webbrowser = { version = "0.8.3", optional = true } -[target.'cfg(not(target_arch="wasm32"))'.dependencies] -instant = { version = "0.1" } - -[target.'cfg(target_arch="wasm32")'.dependencies] -instant = { version = "0.1", features = [ - "wasm-bindgen", -] } # We use instant so we can (maybe) compile for web - [target.'cfg(any(target_os="linux", target_os="dragonfly", target_os="freebsd", target_os="netbsd", target_os="openbsd"))'.dependencies] smithay-clipboard = { version = "0.6.3", optional = true } diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index edc51b9b6..62888588b 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -53,7 +53,7 @@ pub struct EventResponse { /// Handles the integration between egui and winit. pub struct State { - start_time: instant::Instant, + start_time: web_time::Instant, egui_input: egui::RawInput, pointer_pos_in_points: Option, any_pointer_button_down: bool, @@ -95,7 +95,7 @@ impl State { }; Self { - start_time: instant::Instant::now(), + start_time: web_time::Instant::now(), egui_input, pointer_pos_in_points: None, any_pointer_button_down: false, From 5f742b9abac37dbdfe9e64e388f8d7d5669696e0 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 4 Sep 2023 09:55:47 +0200 Subject: [PATCH 2/4] Improve documentation of `eframe`, especially for wasm32 (#3295) * Improve documentation of `eframe`, especially for wasm32 * remove dead code * fix --- crates/eframe/src/epi/mod.rs | 2 +- crates/eframe/src/lib.rs | 13 ++++++-- crates/eframe/src/native/run.rs | 4 +++ crates/eframe/src/web/app_runner.rs | 8 ++--- crates/eframe/src/web/backend.rs | 27 +++------------- crates/eframe/src/web/events.rs | 10 +++--- crates/eframe/src/web/mod.rs | 43 ++++++++++++++------------ crates/eframe/src/web/panic_handler.rs | 3 ++ crates/eframe/src/web/screen_reader.rs | 3 ++ crates/eframe/src/web/storage.rs | 10 +++--- crates/eframe/src/web/web_logger.rs | 4 ++- crates/eframe/src/web/web_runner.rs | 3 +- 12 files changed, 69 insertions(+), 61 deletions(-) diff --git a/crates/eframe/src/epi/mod.rs b/crates/eframe/src/epi/mod.rs index 6172bf42e..85433e7a3 100644 --- a/crates/eframe/src/epi/mod.rs +++ b/crates/eframe/src/epi/mod.rs @@ -118,7 +118,7 @@ pub trait App { /// /// Can be used from web to interact or other external context. /// - /// You need to implement this if you want to be able to access the application from JS using [`crate::web::backend::AppRunner`]. + /// You need to implement this if you want to be able to access the application from JS using [`crate::WebRunner::app_mut`]. /// /// This is needed because downcasting `Box` -> `Box` to get &`ConcreteApp` is not simple in current rust. /// diff --git a/crates/eframe/src/lib.rs b/crates/eframe/src/lib.rs index 63c7cdeeb..2972d6727 100644 --- a/crates/eframe/src/lib.rs +++ b/crates/eframe/src/lib.rs @@ -50,7 +50,7 @@ //! #[derive(Clone)] //! #[wasm_bindgen] //! pub struct WebHandle { -//! runner: WebRunner, +//! runner: eframe::WebRunner, //! } //! //! # #[cfg(target_arch = "wasm32")] @@ -64,7 +64,7 @@ //! eframe::WebLogger::init(log::LevelFilter::Debug).ok(); //! //! Self { -//! runner: WebRunner::new(), +//! runner: eframe::WebRunner::new(), //! } //! } //! @@ -82,6 +82,7 @@ //! //! // The following are optional: //! +//! /// Shut down eframe and clean up resources. //! #[wasm_bindgen] //! pub fn destroy(&self) { //! self.runner.destroy(); @@ -121,6 +122,7 @@ #![cfg_attr(feature = "document-features", doc = document_features::document_features!())] //! +#![warn(missing_docs)] // let's keep eframe well-documented #![allow(clippy::needless_doctest_main)] // Re-export all useful libraries: @@ -296,23 +298,28 @@ pub fn run_simple_native( /// The different problems that can occur when trying to run `eframe`. #[derive(thiserror::Error, Debug)] pub enum Error { + /// An error from [`winit`]. #[cfg(not(target_arch = "wasm32"))] #[error("winit error: {0}")] Winit(#[from] winit::error::OsError), + /// An error from [`glutin`] when using [`glow`]. #[cfg(all(feature = "glow", not(target_arch = "wasm32")))] #[error("glutin error: {0}")] Glutin(#[from] glutin::error::Error), + /// An error from [`glutin`] when using [`glow`]. #[cfg(all(feature = "glow", not(target_arch = "wasm32")))] - #[error("Found no glutin configs matching the template: {0:?}. error: {1:?}")] + #[error("Found no glutin configs matching the template: {0:?}. Error: {1:?}")] NoGlutinConfigs(glutin::config::ConfigTemplate, Box), + /// An error from [`wgpu`]. #[cfg(feature = "wgpu")] #[error("WGPU error: {0}")] Wgpu(#[from] egui_wgpu::WgpuError), } +/// Short for `Result`. pub type Result = std::result::Result; // --------------------------------------------------------------------------- diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 4a508db9b..c1db4492b 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -18,15 +18,19 @@ use super::epi_integration::{self, EpiIntegration}; // ---------------------------------------------------------------------------- +/// The custom even `eframe` uses with the [`winit`] event loop. #[derive(Debug)] pub enum UserEvent { + /// A repaint is requested. RequestRepaint { + /// When to repaint. when: Instant, /// What the frame number was when the repaint was _requested_. frame_nr: u64, }, + /// A request related to [`accesskit`](https://accesskit.dev/). #[cfg(feature = "accesskit")] AccessKitActionRequest(accesskit_winit::ActionRequestEvent), } diff --git a/crates/eframe/src/web/app_runner.rs b/crates/eframe/src/web/app_runner.rs index 4da93c521..6f4579b66 100644 --- a/crates/eframe/src/web/app_runner.rs +++ b/crates/eframe/src/web/app_runner.rs @@ -56,7 +56,7 @@ impl AppRunner { egui_ctx.set_os(egui::os::OperatingSystem::from_user_agent( &super::user_agent().unwrap_or_default(), )); - super::load_memory(&egui_ctx); + super::storage::load_memory(&egui_ctx); let theme = system_theme.unwrap_or(web_options.default_theme); egui_ctx.set_visuals(theme.egui_visuals()); @@ -140,7 +140,7 @@ impl AppRunner { pub fn save(&mut self) { if self.app.persist_egui_memory() { - super::save_memory(&self.egui_ctx); + super::storage::save_memory(&self.egui_ctx); } if let Some(storage) = self.frame.storage_mut() { self.app.save(storage); @@ -262,11 +262,11 @@ struct LocalStorage {} impl epi::Storage for LocalStorage { fn get_string(&self, key: &str) -> Option { - super::local_storage_get(key) + super::storage::local_storage_get(key) } fn set_string(&mut self, key: &str, value: String) { - super::local_storage_set(key, &value); + super::storage::local_storage_set(key, &value); } fn flush(&mut self) {} diff --git a/crates/eframe/src/web/backend.rs b/crates/eframe/src/web/backend.rs index dde1d8976..8c5edec14 100644 --- a/crates/eframe/src/web/backend.rs +++ b/crates/eframe/src/web/backend.rs @@ -10,13 +10,14 @@ use super::percent_decode; /// Data gathered between frames. #[derive(Default)] -pub struct WebInput { +pub(crate) struct WebInput { /// Required because we don't get a position on touched pub latest_touch_pos: Option, /// Required to maintain a stable touch position for multi-touch gestures. pub latest_touch_pos_id: Option, + /// The raw input to `egui`. pub raw: egui::RawInput, } @@ -41,10 +42,8 @@ impl WebInput { // ---------------------------------------------------------------------------- -use std::sync::atomic::Ordering::SeqCst; - /// Stores when to do the next repaint. -pub struct NeedRepaint(Mutex); +pub(crate) struct NeedRepaint(Mutex); impl Default for NeedRepaint { fn default() -> Self { @@ -74,30 +73,14 @@ impl NeedRepaint { } } -pub struct IsDestroyed(std::sync::atomic::AtomicBool); - -impl Default for IsDestroyed { - fn default() -> Self { - Self(false.into()) - } -} - -impl IsDestroyed { - pub fn fetch(&self) -> bool { - self.0.load(SeqCst) - } - - pub fn set_true(&self) { - self.0.store(true, SeqCst); - } -} - // ---------------------------------------------------------------------------- +/// The User-Agent of the user's browser. pub fn user_agent() -> Option { web_sys::window()?.navigator().user_agent().ok() } +/// Get the [`epi::Location`] from the browser. pub fn web_location() -> epi::Location { let location = web_sys::window().unwrap().location(); diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index cbfa11a68..ea5a5bf08 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -29,7 +29,7 @@ fn paint_if_needed(runner: &mut AppRunner) -> Result<(), JsValue> { Ok(()) } -pub fn request_animation_frame(runner_ref: WebRunner) -> Result<(), JsValue> { +pub(crate) fn request_animation_frame(runner_ref: WebRunner) -> Result<(), JsValue> { let window = web_sys::window().unwrap(); let closure = Closure::once(move || paint_and_schedule(&runner_ref)); window.request_animation_frame(closure.as_ref().unchecked_ref())?; @@ -39,7 +39,7 @@ pub fn request_animation_frame(runner_ref: WebRunner) -> Result<(), JsValue> { // ------------------------------------------------------------------------ -pub fn install_document_events(runner_ref: &WebRunner) -> Result<(), JsValue> { +pub(crate) fn install_document_events(runner_ref: &WebRunner) -> Result<(), JsValue> { let document = web_sys::window().unwrap().document().unwrap(); { @@ -189,7 +189,7 @@ pub fn install_document_events(runner_ref: &WebRunner) -> Result<(), JsValue> { Ok(()) } -pub fn install_window_events(runner_ref: &WebRunner) -> Result<(), JsValue> { +pub(crate) fn install_window_events(runner_ref: &WebRunner) -> Result<(), JsValue> { let window = web_sys::window().unwrap(); // Save-on-close @@ -211,7 +211,7 @@ pub fn install_window_events(runner_ref: &WebRunner) -> Result<(), JsValue> { Ok(()) } -pub fn install_color_scheme_change_event(runner_ref: &WebRunner) -> Result<(), JsValue> { +pub(crate) fn install_color_scheme_change_event(runner_ref: &WebRunner) -> Result<(), JsValue> { let window = web_sys::window().unwrap(); if let Some(media_query_list) = prefers_color_scheme_dark(&window)? { @@ -230,7 +230,7 @@ pub fn install_color_scheme_change_event(runner_ref: &WebRunner) -> Result<(), J Ok(()) } -pub fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValue> { +pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValue> { let canvas = canvas_element(runner_ref.try_lock().unwrap().canvas_id()).unwrap(); { diff --git a/crates/eframe/src/web/mod.rs b/crates/eframe/src/web/mod.rs index 9c3920a50..252dddd30 100644 --- a/crates/eframe/src/web/mod.rs +++ b/crates/eframe/src/web/mod.rs @@ -3,16 +3,20 @@ #![allow(clippy::missing_errors_doc)] // So many `-> Result<_, JsValue>` mod app_runner; -pub mod backend; +mod backend; mod events; mod input; mod panic_handler; -pub mod screen_reader; -pub mod storage; mod text_agent; mod web_logger; mod web_runner; +/// Access to the browser screen reader. +pub mod screen_reader; + +/// Access to local browser storage. +pub mod storage; + pub(crate) use app_runner::AppRunner; pub use panic_handler::{PanicHandler, PanicSummary}; pub use web_logger::WebLogger; @@ -34,8 +38,6 @@ mod web_painter_wgpu; pub(crate) type ActiveWebPainter = web_painter_wgpu::WebPainterWgpu; pub use backend::*; -pub use events::*; -pub use storage::*; use egui::Vec2; use wasm_bindgen::prelude::*; @@ -59,15 +61,9 @@ pub fn now_sec() -> f64 { / 1000.0 } -#[allow(dead_code)] -pub fn screen_size_in_native_points() -> Option { - let window = web_sys::window()?; - Some(egui::vec2( - window.inner_width().ok()?.as_f64()? as f32, - window.inner_height().ok()?.as_f64()? as f32, - )) -} - +/// The native GUI scale factor, taking into account the browser zoom. +/// +/// Corresponds to [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) in JavaScript. pub fn native_pixels_per_point() -> f32 { let pixels_per_point = web_sys::window().unwrap().device_pixel_ratio() as f32; if pixels_per_point > 0.0 && pixels_per_point.is_finite() { @@ -77,6 +73,9 @@ pub fn native_pixels_per_point() -> f32 { } } +/// Ask the browser about the preferred system theme. +/// +/// `None` means unknown. pub fn system_theme() -> Option { let dark_mode = prefers_color_scheme_dark(&web_sys::window()?) .ok()?? @@ -96,13 +95,13 @@ fn theme_from_dark_mode(dark_mode: bool) -> Theme { } } -pub fn canvas_element(canvas_id: &str) -> Option { +fn canvas_element(canvas_id: &str) -> Option { let document = web_sys::window()?.document()?; let canvas = document.get_element_by_id(canvas_id)?; canvas.dyn_into::().ok() } -pub fn canvas_element_or_die(canvas_id: &str) -> web_sys::HtmlCanvasElement { +fn canvas_element_or_die(canvas_id: &str) -> web_sys::HtmlCanvasElement { canvas_element(canvas_id) .unwrap_or_else(|| panic!("Failed to find canvas with id {canvas_id:?}")) } @@ -114,7 +113,7 @@ fn canvas_origin(canvas_id: &str) -> egui::Pos2 { egui::pos2(rect.left() as f32, rect.top() as f32) } -pub fn canvas_size_in_points(canvas_id: &str) -> egui::Vec2 { +fn canvas_size_in_points(canvas_id: &str) -> egui::Vec2 { let canvas = canvas_element(canvas_id).unwrap(); let pixels_per_point = native_pixels_per_point(); egui::vec2( @@ -123,7 +122,7 @@ pub fn canvas_size_in_points(canvas_id: &str) -> egui::Vec2 { ) } -pub fn resize_canvas_to_screen_size(canvas_id: &str, max_size_points: egui::Vec2) -> Option<()> { +fn resize_canvas_to_screen_size(canvas_id: &str, max_size_points: egui::Vec2) -> Option<()> { let canvas = canvas_element(canvas_id)?; let parent = canvas.parent_element()?; @@ -178,7 +177,8 @@ pub fn resize_canvas_to_screen_size(canvas_id: &str, max_size_points: egui::Vec2 // ---------------------------------------------------------------------------- -pub fn set_cursor_icon(cursor: egui::CursorIcon) -> Option<()> { +/// Set the cursor icon. +fn set_cursor_icon(cursor: egui::CursorIcon) -> Option<()> { let document = web_sys::window()?.document()?; document .body()? @@ -187,8 +187,9 @@ pub fn set_cursor_icon(cursor: egui::CursorIcon) -> Option<()> { .ok() } +/// Set the clipboard text. #[cfg(web_sys_unstable_apis)] -pub fn set_clipboard_text(s: &str) { +fn set_clipboard_text(s: &str) { if let Some(window) = web_sys::window() { if let Some(clipboard) = window.navigator().clipboard() { let promise = clipboard.write_text(s); @@ -245,6 +246,7 @@ fn cursor_web_name(cursor: egui::CursorIcon) -> &'static str { } } +/// Open the given url in the browser. pub fn open_url(url: &str, new_tab: bool) -> Option<()> { let name = if new_tab { "_blank" } else { "_self" }; @@ -267,6 +269,7 @@ pub fn location_hash() -> String { ) } +/// Percent-decodes a string. pub fn percent_decode(s: &str) -> String { percent_encoding::percent_decode_str(s) .decode_utf8_lossy() diff --git a/crates/eframe/src/web/panic_handler.rs b/crates/eframe/src/web/panic_handler.rs index a22bca9de..b379f775d 100644 --- a/crates/eframe/src/web/panic_handler.rs +++ b/crates/eframe/src/web/panic_handler.rs @@ -65,16 +65,19 @@ pub struct PanicSummary { } impl PanicSummary { + /// Construct a summary from a panic. pub fn new(info: &std::panic::PanicInfo<'_>) -> Self { let message = info.to_string(); let callstack = Error::new().stack(); Self { message, callstack } } + /// The panic message. pub fn message(&self) -> String { self.message.clone() } + /// The backtrace. pub fn callstack(&self) -> String { self.callstack.clone() } diff --git a/crates/eframe/src/web/screen_reader.rs b/crates/eframe/src/web/screen_reader.rs index 308957233..f4b37f200 100644 --- a/crates/eframe/src/web/screen_reader.rs +++ b/crates/eframe/src/web/screen_reader.rs @@ -1,3 +1,4 @@ +/// Screen reader support. pub struct ScreenReader { #[cfg(feature = "tts")] tts: Option, @@ -29,10 +30,12 @@ impl Default for ScreenReader { } impl ScreenReader { + /// Speak the given text out loud. #[cfg(not(feature = "tts"))] #[allow(clippy::unused_self)] pub fn speak(&mut self, _text: &str) {} + /// Speak the given text out loud. #[cfg(feature = "tts")] pub fn speak(&mut self, text: &str) { if text.is_empty() { diff --git a/crates/eframe/src/web/storage.rs b/crates/eframe/src/web/storage.rs index 9ab8b0426..4a2a53326 100644 --- a/crates/eframe/src/web/storage.rs +++ b/crates/eframe/src/web/storage.rs @@ -2,16 +2,18 @@ fn local_storage() -> Option { web_sys::window()?.local_storage().ok()? } +/// Read data from local storage. pub fn local_storage_get(key: &str) -> Option { local_storage().map(|storage| storage.get_item(key).ok())?? } +/// Write data to local storage. pub fn local_storage_set(key: &str, value: &str) { local_storage().map(|storage| storage.set_item(key, value)); } #[cfg(feature = "persistence")] -pub fn load_memory(ctx: &egui::Context) { +pub(crate) fn load_memory(ctx: &egui::Context) { if let Some(memory_string) = local_storage_get("egui_memory_ron") { match ron::from_str(&memory_string) { Ok(memory) => { @@ -25,10 +27,10 @@ pub fn load_memory(ctx: &egui::Context) { } #[cfg(not(feature = "persistence"))] -pub fn load_memory(_: &egui::Context) {} +pub(crate) fn load_memory(_: &egui::Context) {} #[cfg(feature = "persistence")] -pub fn save_memory(ctx: &egui::Context) { +pub(crate) fn save_memory(ctx: &egui::Context) { match ctx.memory(|mem| ron::to_string(mem)) { Ok(ron) => { local_storage_set("egui_memory_ron", &ron); @@ -40,4 +42,4 @@ pub fn save_memory(ctx: &egui::Context) { } #[cfg(not(feature = "persistence"))] -pub fn save_memory(_: &egui::Context) {} +pub(crate) fn save_memory(_: &egui::Context) {} diff --git a/crates/eframe/src/web/web_logger.rs b/crates/eframe/src/web/web_logger.rs index 09f731065..90dfc1b31 100644 --- a/crates/eframe/src/web/web_logger.rs +++ b/crates/eframe/src/web/web_logger.rs @@ -4,12 +4,14 @@ pub struct WebLogger { } impl WebLogger { - /// Pipe all [`log`] events to the web console. + /// Install a new `WebLogger`, piping all [`log`] events to the web console. pub fn init(filter: log::LevelFilter) -> Result<(), log::SetLoggerError> { log::set_max_level(filter); log::set_boxed_logger(Box::new(WebLogger::new(filter))) } + /// Create a new [`WebLogger`] with the given filter, + /// but don't install it. pub fn new(filter: log::LevelFilter) -> Self { Self { filter } } diff --git a/crates/eframe/src/web/web_runner.rs b/crates/eframe/src/web/web_runner.rs index 2c0395445..ff7ae377a 100644 --- a/crates/eframe/src/web/web_runner.rs +++ b/crates/eframe/src/web/web_runner.rs @@ -27,7 +27,7 @@ pub struct WebRunner { } impl WebRunner { - // Will install a panic handler that will catch and log any panics + /// Will install a panic handler that will catch and log any panics #[allow(clippy::new_without_default)] pub fn new() -> Self { #[cfg(not(web_sys_unstable_apis))] @@ -102,6 +102,7 @@ impl WebRunner { } } + /// Shut down eframe and clean up resources. pub fn destroy(&self) { self.unsubscribe_from_all_events(); From 59235ff01cce1e25293be6680396085fc888d66f Mon Sep 17 00:00:00 2001 From: v-kat <1297926+v-kat@users.noreply.github.com> Date: Mon, 4 Sep 2023 02:12:43 -0700 Subject: [PATCH 3/4] Changing menu_image_button to use ImageButton builder (#3288) Co-authored-by: Ivy --- crates/egui/src/menu.rs | 10 ++++------ crates/egui/src/ui.rs | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/egui/src/menu.rs b/crates/egui/src/menu.rs index 0364cf468..6c8d8f9b8 100644 --- a/crates/egui/src/menu.rs +++ b/crates/egui/src/menu.rs @@ -111,11 +111,10 @@ pub fn menu_button( /// Returns `None` if the menu is not open. pub fn menu_image_button( ui: &mut Ui, - texture_id: TextureId, - image_size: impl Into, + image_button: ImageButton, add_contents: impl FnOnce(&mut Ui) -> R, ) -> InnerResponse> { - stationary_menu_image_impl(ui, texture_id, image_size, Box::new(add_contents)) + stationary_menu_image_impl(ui, image_button, Box::new(add_contents)) } /// Construct a nested sub menu in another menu. @@ -202,14 +201,13 @@ fn stationary_menu_impl<'c, R>( /// Responds to primary clicks. fn stationary_menu_image_impl<'c, R>( ui: &mut Ui, - texture_id: TextureId, - image_size: impl Into, + image_button: ImageButton, add_contents: Box R + 'c>, ) -> InnerResponse> { let bar_id = ui.id(); let mut bar_state = BarState::load(ui.ctx(), bar_id); - let button_response = ui.add(ImageButton::new(texture_id, image_size)); + let button_response = ui.add(image_button); let inner = bar_state.bar_menu(&button_response, add_contents); bar_state.store(ui.ctx(), bar_id); diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 9f4135025..686d7a66e 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -2222,7 +2222,7 @@ impl Ui { if let Some(menu_state) = self.menu_state.clone() { menu::submenu_button(self, menu_state, String::new(), add_contents) } else { - menu::menu_image_button(self, texture_id, image_size, add_contents) + menu::menu_image_button(self, ImageButton::new(texture_id, image_size), add_contents) } } } From 72adf3bde38118bb3ac2559969b4a648f239d47a Mon Sep 17 00:00:00 2001 From: Barugon <16503728+Barugon@users.noreply.github.com> Date: Mon, 4 Sep 2023 02:43:24 -0700 Subject: [PATCH 4/4] Remove unnecessary code (#2860) --- crates/egui/src/containers/scroll_area.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index 8bd8142cf..5f7a9a035 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -445,7 +445,6 @@ impl ScrollArea { { // Clip the content, but only when we really need to: let clip_rect_margin = ui.visuals().clip_rect_margin; - let scroll_bar_inner_margin = ui.spacing().scroll_bar_inner_margin; let mut content_clip_rect = ui.clip_rect(); for d in 0..2 { if has_bar[d] { @@ -453,13 +452,6 @@ impl ScrollArea { content_clip_rect.min[d] = inner_rect.min[d] - clip_rect_margin; content_clip_rect.max[d] = inner_rect.max[d] + clip_rect_margin; } - - if state.show_scroll[d] { - // Make sure content doesn't cover scroll bars - let tiny_gap = 1.0; - content_clip_rect.max[1 - d] = - inner_rect.max[1 - d] + scroll_bar_inner_margin - tiny_gap; - } } else { // Nice handling of forced resizing beyond the possible: content_clip_rect.max[d] = ui.clip_rect().max[d] - current_bar_use[d];