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

Add ViewportCommand::RequestCut, RequestCopy and RequestPaste to trigger clipboard actions #4035

Merged
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
55 changes: 39 additions & 16 deletions crates/eframe/src/native/glow_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use std::{cell::RefCell, num::NonZeroU32, rc::Rc, sync::Arc, time::Instant};

use egui_winit::ActionRequested;
use glutin::{
config::GlConfig,
context::NotCurrentGlContext,
Expand All @@ -22,8 +23,9 @@ use winit::{
};

use egui::{
epaint::ahash::HashMap, DeferredViewportUiCallback, ImmediateViewport, ViewportBuilder,
ViewportClass, ViewportId, ViewportIdMap, ViewportIdPair, ViewportInfo, ViewportOutput,
ahash::HashSet, epaint::ahash::HashMap, DeferredViewportUiCallback, ImmediateViewport,
ViewportBuilder, ViewportClass, ViewportId, ViewportIdMap, ViewportIdPair, ViewportInfo,
ViewportOutput,
};
#[cfg(feature = "accesskit")]
use egui_winit::accesskit_winit;
Expand Down Expand Up @@ -104,7 +106,7 @@ struct Viewport {
builder: ViewportBuilder,
deferred_commands: Vec<egui::viewport::ViewportCommand>,
info: ViewportInfo,
screenshot_requested: bool,
actions_requested: HashSet<egui_winit::ActionRequested>,

/// The user-callback that shows the ui.
/// None for immediate viewports.
Expand Down Expand Up @@ -682,17 +684,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);
}

Expand Down Expand Up @@ -1020,7 +1043,7 @@ impl GlutinWindowContext {
builder: viewport_builder,
deferred_commands: vec![],
info,
screenshot_requested: false,
actions_requested: Default::default(),
viewport_ui_cb: None,
gl_surface: None,
window: window.map(Arc::new),
Expand Down Expand Up @@ -1277,7 +1300,7 @@ impl GlutinWindowContext {
std::mem::take(&mut viewport.deferred_commands),
window,
is_viewport_focused,
&mut viewport.screenshot_requested,
&mut viewport.actions_requested,
);

// For Wayland : https://github.com/emilk/egui/issues/4196
Expand Down Expand Up @@ -1323,7 +1346,7 @@ fn initialize_or_update_viewport(
builder,
deferred_commands: vec![],
info: Default::default(),
screenshot_requested: false,
actions_requested: Default::default(),
viewport_ui_cb,
window: None,
egui_winit: None,
Expand Down
45 changes: 37 additions & 8 deletions crates/eframe/src/native/wgpu_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use std::{cell::RefCell, num::NonZeroU32, rc::Rc, sync::Arc, time::Instant};

use egui_winit::ActionRequested;
use parking_lot::Mutex;
use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _};
use winit::{
Expand All @@ -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;
Expand Down Expand Up @@ -78,7 +79,7 @@ pub struct Viewport {
builder: ViewportBuilder,
deferred_commands: Vec<egui::viewport::ViewportCommand>,
info: ViewportInfo,
screenshot_requested: bool,
actions_requested: HashSet<ActionRequested>,

/// `None` for sync viewports.
viewport_ui_cb: Option<Arc<DeferredViewportUiCallback>>,
Expand Down Expand Up @@ -289,7 +290,7 @@ impl WgpuWinitApp {
builder,
deferred_commands: vec![],
info,
screenshot_requested: false,
actions_requested: Default::default(),
viewport_ui_cb: None,
window: Some(window),
egui_winit: Some(egui_winit),
Expand Down Expand Up @@ -676,7 +677,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,
Expand All @@ -695,6 +699,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();
Expand Down Expand Up @@ -1073,7 +1102,7 @@ fn handle_viewport_output(
std::mem::take(&mut viewport.deferred_commands),
window,
is_viewport_focused,
&mut viewport.screenshot_requested,
&mut viewport.actions_requested,
);

// For Wayland : https://github.com/emilk/egui/issues/4196
Expand Down Expand Up @@ -1120,7 +1149,7 @@ fn initialize_or_update_viewport(
builder,
deferred_commands: vec![],
info: Default::default(),
screenshot_requested: false,
actions_requested: HashSet::new(),
viewport_ui_cb,
window: None,
egui_winit: None,
Expand Down
28 changes: 23 additions & 5 deletions crates/egui-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1254,14 +1256,21 @@ fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option<winit::window::Curs

// Helpers for egui Viewports
// ---------------------------------------------------------------------------
#[derive(PartialEq, Eq, Hash, Debug)]
pub enum ActionRequested {
Screenshot,
Cut,
Copy,
Paste,
}

pub fn process_viewport_commands(
egui_ctx: &egui::Context,
info: &mut ViewportInfo,
commands: impl IntoIterator<Item = ViewportCommand>,
window: &Window,
is_viewport_focused: bool,
screenshot_requested: &mut bool,
actions_requested: &mut HashSet<ActionRequested>,
) {
for command in commands {
process_viewport_command(
Expand All @@ -1270,7 +1279,7 @@ pub fn process_viewport_commands(
command,
info,
is_viewport_focused,
screenshot_requested,
actions_requested,
);
}
}
Expand All @@ -1281,7 +1290,7 @@ fn process_viewport_command(
command: ViewportCommand,
info: &mut ViewportInfo,
is_viewport_focused: bool,
screenshot_requested: &mut bool,
actions_requested: &mut HashSet<ActionRequested>,
) {
crate::profile_function!();

Expand Down Expand Up @@ -1478,7 +1487,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);
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions crates/egui/src/viewport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,21 @@ pub enum ViewportCommand {
///
/// The results are returned in `crate::Event::Screenshot`.
Screenshot,

/// Request cut of the current selection
///
/// 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).
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).
RequestPaste,
}

impl ViewportCommand {
Expand Down
10 changes: 5 additions & 5 deletions crates/egui_glow/src/winit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub use egui_winit;
pub use egui_winit::EventResponse;

use egui::{ViewportId, ViewportOutput};
use egui::{ahash::HashSet, ViewportId, ViewportOutput};
use egui_winit::winit;

use crate::shader_version::ShaderVersion;
Expand Down Expand Up @@ -79,17 +79,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<egui_winit::ActionRequested> = Default::default();
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);
}
}

Expand Down
Loading