From a743f6c5eb62ef1e94d217799192cf59c79c23c0 Mon Sep 17 00:00:00 2001 From: Bu5hm4nn Date: Mon, 12 Feb 2024 11:51:23 -0600 Subject: [PATCH 1/4] Add `ViewportCommand::RequestCut`, `ViewportCommand::RequestCopy` and `ViewportCommand::RequestPaste` to allow application to request these events --- crates/eframe/src/native/glow_integration.rs | 58 ++++++++++++++------ crates/eframe/src/native/wgpu_integration.rs | 47 +++++++++++++--- crates/egui-winit/src/lib.rs | 28 ++++++++-- crates/egui/src/viewport.rs | 9 +++ crates/egui_glow/src/winit.rs | 13 +++-- 5 files changed, 118 insertions(+), 37 deletions(-) diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index be30d853ccf..f8cea43afd1 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -9,6 +9,7 @@ use std::{cell::RefCell, rc::Rc, sync::Arc, time::Instant}; +use egui_winit::ActionRequested; use glutin::{ config::GlConfig, context::NotCurrentGlContext, @@ -22,9 +23,9 @@ use winit::{ }; use egui::{ - epaint::ahash::HashMap, DeferredViewportUiCallback, ImmediateViewport, NumExt as _, - ViewportBuilder, ViewportClass, ViewportId, ViewportIdMap, ViewportIdPair, ViewportIdSet, - ViewportInfo, ViewportOutput, + ahash::{HashMap, HashSet, HashSetExt}, + DeferredViewportUiCallback, ImmediateViewport, NumExt as _, ViewportBuilder, ViewportClass, + ViewportId, ViewportIdMap, ViewportIdPair, ViewportIdSet, ViewportInfo, ViewportOutput, }; #[cfg(feature = "accesskit")] use egui_winit::accesskit_winit; @@ -104,7 +105,7 @@ struct Viewport { class: ViewportClass, builder: ViewportBuilder, info: ViewportInfo, - screenshot_requested: bool, + actions_requested: HashSet, /// The user-callback that shows the ui. /// None for immediate viewports. @@ -636,17 +637,38 @@ impl GlowWinitRunning { ); { - let screenshot_requested = std::mem::take(&mut viewport.screenshot_requested); - if screenshot_requested { - let screenshot = painter.read_screen_rgba(screen_size_in_pixels); - egui_winit - .egui_input_mut() - .events - .push(egui::Event::Screenshot { - viewport_id, - image: screenshot.into(), - }); + for action in viewport.actions_requested.drain() { + match action { + ActionRequested::Screenshot => { + let screenshot = painter.read_screen_rgba(screen_size_in_pixels); + egui_winit + .egui_input_mut() + .events + .push(egui::Event::Screenshot { + viewport_id, + image: screenshot.into(), + }); + } + ActionRequested::Cut => { + egui_winit.egui_input_mut().events.push(egui::Event::Cut); + } + ActionRequested::Copy => { + egui_winit.egui_input_mut().events.push(egui::Event::Copy); + } + ActionRequested::Paste => { + if let Some(contents) = egui_winit.clipboard_text() { + let contents = contents.replace("\r\n", "\n"); + if !contents.is_empty() { + egui_winit + .egui_input_mut() + .events + .push(egui::Event::Paste(contents)); + } + } + } + } } + integration.post_rendering(&window); } @@ -959,7 +981,7 @@ impl GlutinWindowContext { class: ViewportClass::Root, builder: viewport_builder, info, - screenshot_requested: false, + actions_requested: HashSetExt::new(), viewport_ui_cb: None, gl_surface: None, window: window.map(Arc::new), @@ -1211,7 +1233,7 @@ impl GlutinWindowContext { commands, window, is_viewport_focused, - &mut viewport.screenshot_requested, + &mut viewport.actions_requested, ); } } @@ -1256,7 +1278,7 @@ fn initialize_or_update_viewport<'vp>( class, builder, info: Default::default(), - screenshot_requested: false, + actions_requested: HashSet::new(), viewport_ui_cb, window: None, egui_winit: None, @@ -1290,7 +1312,7 @@ fn initialize_or_update_viewport<'vp>( delta_commands, window, is_viewport_focused, - &mut viewport.screenshot_requested, + &mut viewport.actions_requested, ); } diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index e8fe39f9064..068da3dc9b8 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -7,6 +7,7 @@ use std::{cell::RefCell, rc::Rc, sync::Arc, time::Instant}; +use egui_winit::ActionRequested; use parking_lot::Mutex; use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _}; use winit::{ @@ -15,9 +16,9 @@ use winit::{ }; use egui::{ - ahash::HashMap, DeferredViewportUiCallback, FullOutput, ImmediateViewport, ViewportBuilder, - ViewportClass, ViewportId, ViewportIdMap, ViewportIdPair, ViewportIdSet, ViewportInfo, - ViewportOutput, + ahash::{HashMap, HashSet, HashSetExt}, + DeferredViewportUiCallback, FullOutput, ImmediateViewport, ViewportBuilder, ViewportClass, + ViewportId, ViewportIdMap, ViewportIdPair, ViewportIdSet, ViewportInfo, ViewportOutput, }; #[cfg(feature = "accesskit")] use egui_winit::accesskit_winit; @@ -77,7 +78,7 @@ pub struct Viewport { class: ViewportClass, builder: ViewportBuilder, info: ViewportInfo, - screenshot_requested: bool, + actions_requested: HashSet, /// `None` for sync viewports. viewport_ui_cb: Option>, @@ -286,7 +287,7 @@ impl WgpuWinitApp { maximized: Some(window.is_maximized()), ..Default::default() }, - screenshot_requested: false, + actions_requested: HashSetExt::new(), viewport_ui_cb: None, window: Some(window), egui_winit: Some(egui_winit), @@ -643,7 +644,10 @@ impl WgpuWinitRunning { let clipped_primitives = egui_ctx.tessellate(shapes, pixels_per_point); - let screenshot_requested = std::mem::take(&mut viewport.screenshot_requested); + let screenshot_requested = viewport + .actions_requested + .take(&ActionRequested::Screenshot) + .is_some(); let (vsync_secs, screenshot) = painter.paint_and_update_textures( viewport_id, pixels_per_point, @@ -662,6 +666,31 @@ impl WgpuWinitRunning { }); } + for action in viewport.actions_requested.drain() { + match action { + ActionRequested::Screenshot => { + // already handled above + } + ActionRequested::Cut => { + egui_winit.egui_input_mut().events.push(egui::Event::Cut); + } + ActionRequested::Copy => { + egui_winit.egui_input_mut().events.push(egui::Event::Copy); + } + ActionRequested::Paste => { + if let Some(contents) = egui_winit.clipboard_text() { + let contents = contents.replace("\r\n", "\n"); + if !contents.is_empty() { + egui_winit + .egui_input_mut() + .events + .push(egui::Event::Paste(contents)); + } + } + } + } + } + integration.post_rendering(window); let active_viewports_ids: ViewportIdSet = viewport_output.keys().copied().collect(); @@ -1027,7 +1056,7 @@ fn handle_viewport_output( commands, window, is_viewport_focused, - &mut viewport.screenshot_requested, + &mut viewport.actions_requested, ); } } @@ -1060,7 +1089,7 @@ fn initialize_or_update_viewport<'vp>( class, builder, info: Default::default(), - screenshot_requested: false, + actions_requested: HashSet::new(), viewport_ui_cb, window: None, egui_winit: None, @@ -1093,7 +1122,7 @@ fn initialize_or_update_viewport<'vp>( delta_commands, window, is_viewport_focused, - &mut viewport.screenshot_requested, + &mut viewport.actions_requested, ); } diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 15b6663a7ba..07a449f9ba8 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -14,7 +14,9 @@ pub use accesskit_winit; pub use egui; #[cfg(feature = "accesskit")] use egui::accesskit; -use egui::{Pos2, Rect, Vec2, ViewportBuilder, ViewportCommand, ViewportId, ViewportInfo}; +use egui::{ + ahash::HashSet, Pos2, Rect, Vec2, ViewportBuilder, ViewportCommand, ViewportId, ViewportInfo, +}; pub use winit; pub mod clipboard; @@ -1244,6 +1246,13 @@ fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option, window: &Window, is_viewport_focused: bool, - screenshot_requested: &mut bool, + actions_requested: &mut HashSet, ) { for command in commands { process_viewport_command( @@ -1260,7 +1269,7 @@ pub fn process_viewport_commands( command, info, is_viewport_focused, - screenshot_requested, + actions_requested, ); } } @@ -1271,7 +1280,7 @@ fn process_viewport_command( command: ViewportCommand, info: &mut ViewportInfo, is_viewport_focused: bool, - screenshot_requested: &mut bool, + actions_requested: &mut HashSet, ) { crate::profile_function!(); @@ -1452,7 +1461,16 @@ fn process_viewport_command( } } ViewportCommand::Screenshot => { - *screenshot_requested = true; + actions_requested.insert(ActionRequested::Screenshot); + } + ViewportCommand::RequestCut => { + actions_requested.insert(ActionRequested::Cut); + } + ViewportCommand::RequestCopy => { + actions_requested.insert(ActionRequested::Copy); + } + ViewportCommand::RequestPaste => { + actions_requested.insert(ActionRequested::Paste); } } } diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index 4e88eab4b39..89c2eb7f3d7 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -965,6 +965,15 @@ pub enum ViewportCommand { /// /// The results are returned in `crate::Event::Screenshot`. Screenshot, + + /// Request a cut from the clipboard + RequestCut, + + /// Request a copy from the clipboard + RequestCopy, + + /// Request a paste from the clipboard + RequestPaste, } impl ViewportCommand { diff --git a/crates/egui_glow/src/winit.rs b/crates/egui_glow/src/winit.rs index 5d87d000416..f03969a2b09 100644 --- a/crates/egui_glow/src/winit.rs +++ b/crates/egui_glow/src/winit.rs @@ -1,7 +1,10 @@ pub use egui_winit; pub use egui_winit::EventResponse; -use egui::{ViewportId, ViewportOutput}; +use egui::{ + ahash::{HashSet, HashSetExt}, + ViewportId, ViewportOutput, +}; use egui_winit::winit; use crate::shader_version::ShaderVersion; @@ -79,17 +82,17 @@ impl EguiGlow { log::warn!("Multiple viewports not yet supported by EguiGlow"); } for (_, ViewportOutput { commands, .. }) in viewport_output { - let mut screenshot_requested = false; + let mut actions_requested: HashSet = HashSetExt::new(); egui_winit::process_viewport_commands( &self.egui_ctx, &mut self.viewport_info, commands, window, true, - &mut screenshot_requested, + &mut actions_requested, ); - if screenshot_requested { - log::warn!("Screenshot not yet supported by EguiGlow"); + for action in actions_requested { + log::warn!("{:?} not yet supported by EguiGlow", action); } } From 92a21f8f473ec0f779b5ae45c8a233dcfbecb26e Mon Sep 17 00:00:00 2001 From: Bu5hm4nn Date: Mon, 25 Mar 2024 22:28:33 -0600 Subject: [PATCH 2/4] Elaborate docstring for new Clipboard Viewport commands --- crates/egui/src/viewport.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index 89c2eb7f3d7..1782cbe2eee 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -966,13 +966,16 @@ pub enum ViewportCommand { /// The results are returned in `crate::Event::Screenshot`. Screenshot, - /// Request a cut from the clipboard + /// Request cut of the current selection + /// this is equivalent to the system keyboard shortcut for cut (e.g. CTRL + X) RequestCut, - /// Request a copy from the clipboard + /// Request a copy of the current selection + /// this is equivalent to the system keyboard shortcut for copy (e.g. CTRL + C) RequestCopy, - /// Request a paste from the clipboard + /// Request a paste from the clipboard to the current focused TextEdit if any + /// this is equivalent to the system keyboard shortcut for paste (e.g. CTRL + V) RequestPaste, } From 86631789641decaec714bad63a188f652f073f1f Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 21 Apr 2024 12:11:33 +0200 Subject: [PATCH 3/4] improve docstring --- crates/egui/src/viewport.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index 1782cbe2eee..4b18cb2d8c9 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -967,15 +967,18 @@ pub enum ViewportCommand { Screenshot, /// Request cut of the current selection - /// this is equivalent to the system keyboard shortcut for cut (e.g. CTRL + X) + /// + /// This is equivalent to the system keyboard shortcut for cut (e.g. CTRL + X). RequestCut, - /// Request a copy of the current selection - /// this is equivalent to the system keyboard shortcut for copy (e.g. CTRL + C) + /// Request a copy of the current selection. + /// + /// This is equivalent to the system keyboard shortcut for copy (e.g. CTRL + C). RequestCopy, - /// Request a paste from the clipboard to the current focused TextEdit if any - /// this is equivalent to the system keyboard shortcut for paste (e.g. CTRL + V) + /// Request a paste from the clipboard to the current focused TextEdit if any. + /// + /// This is equivalent to the system keyboard shortcut for paste (e.g. CTRL + V). RequestPaste, } From 24a0aac2772bcb7c8ba3e609f051044c04db339f Mon Sep 17 00:00:00 2001 From: bu5hm4nn Date: Sun, 21 Apr 2024 15:49:00 -0600 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Emil Ernerfeldt --- crates/eframe/src/native/wgpu_integration.rs | 2 +- crates/egui_glow/src/winit.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index 0cef8d7fa94..60a6addc5cc 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -287,7 +287,7 @@ impl WgpuWinitApp { maximized: Some(window.is_maximized()), ..Default::default() }, - actions_requested: HashSetExt::new(), + actions_requested: Default::default(), viewport_ui_cb: None, window: Some(window), egui_winit: Some(egui_winit), diff --git a/crates/egui_glow/src/winit.rs b/crates/egui_glow/src/winit.rs index f03969a2b09..dd377fcead1 100644 --- a/crates/egui_glow/src/winit.rs +++ b/crates/egui_glow/src/winit.rs @@ -82,7 +82,7 @@ impl EguiGlow { log::warn!("Multiple viewports not yet supported by EguiGlow"); } for (_, ViewportOutput { commands, .. }) in viewport_output { - let mut actions_requested: HashSet = HashSetExt::new(); + let mut actions_requested: HashSet = Default::default(); egui_winit::process_viewport_commands( &self.egui_ctx, &mut self.viewport_info,