Add `OutputCommand` for copying text and opening URL:s (#5532)
Add `OutputCommand` for copying text and opening URL:s * Part of https://github.com/emilk/egui/issues/5424 * Adds `egui::OutputComm * Part of https://github.com/emilk/egui/issues/5424and` * Adds `PlatformOutput::commands` * Deprecates `PlatformOutput::open_url` * Deprecates `PlatformOutput::copied_text`
This commit is contained in:
parent
1e0f3a5e2d
commit
e2c7e9e733
|
|
@ -292,12 +292,15 @@ impl AppRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_platform_output(&self, platform_output: egui::PlatformOutput) {
|
fn handle_platform_output(&self, platform_output: egui::PlatformOutput) {
|
||||||
|
#![allow(deprecated)]
|
||||||
|
|
||||||
#[cfg(feature = "web_screen_reader")]
|
#[cfg(feature = "web_screen_reader")]
|
||||||
if self.egui_ctx.options(|o| o.screen_reader) {
|
if self.egui_ctx.options(|o| o.screen_reader) {
|
||||||
super::screen_reader::speak(&platform_output.events_description());
|
super::screen_reader::speak(&platform_output.events_description());
|
||||||
}
|
}
|
||||||
|
|
||||||
let egui::PlatformOutput {
|
let egui::PlatformOutput {
|
||||||
|
commands,
|
||||||
cursor_icon,
|
cursor_icon,
|
||||||
open_url,
|
open_url,
|
||||||
copied_text,
|
copied_text,
|
||||||
|
|
@ -310,7 +313,19 @@ impl AppRunner {
|
||||||
request_discard_reasons: _, // handled by `Context::run`
|
request_discard_reasons: _, // handled by `Context::run`
|
||||||
} = platform_output;
|
} = platform_output;
|
||||||
|
|
||||||
|
for command in commands {
|
||||||
|
match command {
|
||||||
|
egui::OutputCommand::CopyText(text) => {
|
||||||
|
super::set_clipboard_text(&text);
|
||||||
|
}
|
||||||
|
egui::OutputCommand::OpenUrl(open_url) => {
|
||||||
|
super::open_url(&open_url.url, open_url.new_tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super::set_cursor_icon(cursor_icon);
|
super::set_cursor_icon(cursor_icon);
|
||||||
|
|
||||||
if let Some(open) = open_url {
|
if let Some(open) = open_url {
|
||||||
super::open_url(&open.url, open.new_tab);
|
super::open_url(&open.url, open.new_tab);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -820,9 +820,11 @@ impl State {
|
||||||
window: &Window,
|
window: &Window,
|
||||||
platform_output: egui::PlatformOutput,
|
platform_output: egui::PlatformOutput,
|
||||||
) {
|
) {
|
||||||
|
#![allow(deprecated)]
|
||||||
profiling::function_scope!();
|
profiling::function_scope!();
|
||||||
|
|
||||||
let egui::PlatformOutput {
|
let egui::PlatformOutput {
|
||||||
|
commands,
|
||||||
cursor_icon,
|
cursor_icon,
|
||||||
open_url,
|
open_url,
|
||||||
copied_text,
|
copied_text,
|
||||||
|
|
@ -835,6 +837,17 @@ impl State {
|
||||||
request_discard_reasons: _, // `egui::Context::run` handles this
|
request_discard_reasons: _, // `egui::Context::run` handles this
|
||||||
} = platform_output;
|
} = platform_output;
|
||||||
|
|
||||||
|
for command in commands {
|
||||||
|
match command {
|
||||||
|
egui::OutputCommand::CopyText(text) => {
|
||||||
|
self.clipboard.set(text);
|
||||||
|
}
|
||||||
|
egui::OutputCommand::OpenUrl(open_url) => {
|
||||||
|
open_url_in_browser(&open_url.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.set_cursor_icon(window, cursor_icon);
|
self.set_cursor_icon(window, cursor_icon);
|
||||||
|
|
||||||
if let Some(open_url) = open_url {
|
if let Some(open_url) = open_url {
|
||||||
|
|
|
||||||
|
|
@ -1419,6 +1419,12 @@ impl Context {
|
||||||
self.output_mut(|o| o.cursor_icon = cursor_icon);
|
self.output_mut(|o| o.cursor_icon = cursor_icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a command to [`PlatformOutput::commands`],
|
||||||
|
/// for the integration to execute at the end of the frame.
|
||||||
|
pub fn send_cmd(&self, cmd: crate::OutputCommand) {
|
||||||
|
self.output_mut(|o| o.commands.push(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
/// Open an URL in a browser.
|
/// Open an URL in a browser.
|
||||||
///
|
///
|
||||||
/// Equivalent to:
|
/// Equivalent to:
|
||||||
|
|
@ -1428,24 +1434,16 @@ impl Context {
|
||||||
/// ctx.output_mut(|o| o.open_url = Some(open_url));
|
/// ctx.output_mut(|o| o.open_url = Some(open_url));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn open_url(&self, open_url: crate::OpenUrl) {
|
pub fn open_url(&self, open_url: crate::OpenUrl) {
|
||||||
self.output_mut(|o| o.open_url = Some(open_url));
|
self.send_cmd(crate::OutputCommand::OpenUrl(open_url));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy the given text to the system clipboard.
|
/// Copy the given text to the system clipboard.
|
||||||
///
|
///
|
||||||
/// Empty strings are ignored.
|
|
||||||
///
|
|
||||||
/// Note that in wasm applications, the clipboard is only accessible in secure contexts (e.g.,
|
/// Note that in wasm applications, the clipboard is only accessible in secure contexts (e.g.,
|
||||||
/// HTTPS or localhost). If this method is used outside of a secure context, it will log an
|
/// HTTPS or localhost). If this method is used outside of a secure context, it will log an
|
||||||
/// error and do nothing. See <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts>.
|
/// error and do nothing. See <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts>.
|
||||||
///
|
|
||||||
/// Equivalent to:
|
|
||||||
/// ```
|
|
||||||
/// # let ctx = egui::Context::default();
|
|
||||||
/// ctx.output_mut(|o| o.copied_text = "Copy this".to_owned());
|
|
||||||
/// ```
|
|
||||||
pub fn copy_text(&self, text: String) {
|
pub fn copy_text(&self, text: String) {
|
||||||
self.output_mut(|o| o.copied_text = text);
|
self.send_cmd(crate::OutputCommand::CopyText(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format the given shortcut in a human-readable way (e.g. `Ctrl+Shift+X`).
|
/// Format the given shortcut in a human-readable way (e.g. `Ctrl+Shift+X`).
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,21 @@ pub struct IMEOutput {
|
||||||
pub cursor_rect: crate::Rect,
|
pub cursor_rect: crate::Rect,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Commands that the egui integration should execute at the end of a frame.
|
||||||
|
///
|
||||||
|
/// Commands that are specific to a viewport should be put in [`crate::ViewportCommand`] instead.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
pub enum OutputCommand {
|
||||||
|
/// Put this text in the system clipboard.
|
||||||
|
///
|
||||||
|
/// This is often a response to [`crate::Event::Copy`] or [`crate::Event::Cut`].
|
||||||
|
CopyText(String),
|
||||||
|
|
||||||
|
/// Open this url in a browser.
|
||||||
|
OpenUrl(OpenUrl),
|
||||||
|
}
|
||||||
|
|
||||||
/// The non-rendering part of what egui emits each frame.
|
/// The non-rendering part of what egui emits each frame.
|
||||||
///
|
///
|
||||||
/// You can access (and modify) this with [`crate::Context::output`].
|
/// You can access (and modify) this with [`crate::Context::output`].
|
||||||
|
|
@ -87,10 +102,14 @@ pub struct IMEOutput {
|
||||||
#[derive(Default, Clone, PartialEq)]
|
#[derive(Default, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct PlatformOutput {
|
pub struct PlatformOutput {
|
||||||
|
/// Commands that the egui integration should execute at the end of a frame.
|
||||||
|
pub commands: Vec<OutputCommand>,
|
||||||
|
|
||||||
/// Set the cursor to this icon.
|
/// Set the cursor to this icon.
|
||||||
pub cursor_icon: CursorIcon,
|
pub cursor_icon: CursorIcon,
|
||||||
|
|
||||||
/// If set, open this url.
|
/// If set, open this url.
|
||||||
|
#[deprecated = "Use `Context::open_url` instead"]
|
||||||
pub open_url: Option<OpenUrl>,
|
pub open_url: Option<OpenUrl>,
|
||||||
|
|
||||||
/// If set, put this text in the system clipboard. Ignore if empty.
|
/// If set, put this text in the system clipboard. Ignore if empty.
|
||||||
|
|
@ -104,6 +123,7 @@ pub struct PlatformOutput {
|
||||||
/// }
|
/// }
|
||||||
/// # });
|
/// # });
|
||||||
/// ```
|
/// ```
|
||||||
|
#[deprecated = "Use `Context::copy_text` instead"]
|
||||||
pub copied_text: String,
|
pub copied_text: String,
|
||||||
|
|
||||||
/// Events that may be useful to e.g. a screen reader.
|
/// Events that may be useful to e.g. a screen reader.
|
||||||
|
|
@ -162,7 +182,10 @@ impl PlatformOutput {
|
||||||
|
|
||||||
/// Add on new output.
|
/// Add on new output.
|
||||||
pub fn append(&mut self, newer: Self) {
|
pub fn append(&mut self, newer: Self) {
|
||||||
|
#![allow(deprecated)]
|
||||||
|
|
||||||
let Self {
|
let Self {
|
||||||
|
mut commands,
|
||||||
cursor_icon,
|
cursor_icon,
|
||||||
open_url,
|
open_url,
|
||||||
copied_text,
|
copied_text,
|
||||||
|
|
@ -175,6 +198,7 @@ impl PlatformOutput {
|
||||||
mut request_discard_reasons,
|
mut request_discard_reasons,
|
||||||
} = newer;
|
} = newer;
|
||||||
|
|
||||||
|
self.commands.append(&mut commands);
|
||||||
self.cursor_icon = cursor_icon;
|
self.cursor_icon = cursor_icon;
|
||||||
if open_url.is_some() {
|
if open_url.is_some() {
|
||||||
self.open_url = open_url;
|
self.open_url = open_url;
|
||||||
|
|
@ -213,7 +237,7 @@ impl PlatformOutput {
|
||||||
/// What URL to open, and how.
|
/// What URL to open, and how.
|
||||||
///
|
///
|
||||||
/// Use with [`crate::Context::open_url`].
|
/// Use with [`crate::Context::open_url`].
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct OpenUrl {
|
pub struct OpenUrl {
|
||||||
pub url: String,
|
pub url: String,
|
||||||
|
|
|
||||||
|
|
@ -482,7 +482,8 @@ pub use self::{
|
||||||
data::{
|
data::{
|
||||||
input::*,
|
input::*,
|
||||||
output::{
|
output::{
|
||||||
self, CursorIcon, FullOutput, OpenUrl, PlatformOutput, UserAttentionType, WidgetInfo,
|
self, CursorIcon, FullOutput, OpenUrl, OutputCommand, PlatformOutput,
|
||||||
|
UserAttentionType, WidgetInfo,
|
||||||
},
|
},
|
||||||
Key, UserData,
|
Key, UserData,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -936,13 +936,16 @@ pub enum ResizeDirection {
|
||||||
|
|
||||||
/// An output [viewport](crate::viewport)-command from egui to the backend, e.g. to change the window title or size.
|
/// An output [viewport](crate::viewport)-command from egui to the backend, e.g. to change the window title or size.
|
||||||
///
|
///
|
||||||
/// You can send a [`ViewportCommand`] to the viewport with [`Context::send_viewport_cmd`].
|
/// You can send a [`ViewportCommand`] to the viewport with [`Context::send_viewport_cmd`].
|
||||||
///
|
///
|
||||||
/// See [`crate::viewport`] for how to build new viewports (native windows).
|
/// See [`crate::viewport`] for how to build new viewports (native windows).
|
||||||
///
|
///
|
||||||
/// All coordinates are in logical points.
|
/// All coordinates are in logical points.
|
||||||
///
|
///
|
||||||
/// This is essentially a way to diff [`ViewportBuilder`].
|
/// [`ViewportCommand`] is essentially a way to diff [`ViewportBuilder`]s.
|
||||||
|
///
|
||||||
|
/// Only commands specific to a viewport are part of [`ViewportCommand`].
|
||||||
|
/// Other commands should be put in [`crate::OutputCommand`].
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub enum ViewportCommand {
|
pub enum ViewportCommand {
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,6 @@ set -x
|
||||||
rustup target add wasm32-unknown-unknown
|
rustup target add wasm32-unknown-unknown
|
||||||
|
|
||||||
# For generating JS bindings:
|
# For generating JS bindings:
|
||||||
cargo install --force --quiet wasm-bindgen-cli --version 0.2.95
|
if ! cargo install --list | grep -q 'wasm-bindgen-cli v0.2.95'; then
|
||||||
|
cargo install --force --quiet wasm-bindgen-cli --version 0.2.95
|
||||||
|
fi
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue