Hold down a modifier key when clicking a link to open it in a new tab
This commit is contained in:
parent
c1ef81628b
commit
1c06622dbc
8 changed files with 69 additions and 15 deletions
|
@ -152,6 +152,16 @@ pub struct Modifiers {
|
|||
pub command: bool,
|
||||
}
|
||||
|
||||
impl Modifiers {
|
||||
pub fn is_none(&self) -> bool {
|
||||
self == &Self::default()
|
||||
}
|
||||
|
||||
pub fn any(&self) -> bool {
|
||||
!self.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Keyboard keys.
|
||||
///
|
||||
/// Includes all keys egui is interested in (such as `Home` and `End`)
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
/// What egui emits each frame.
|
||||
/// The backend should use this.
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Clone, Default, PartialEq)]
|
||||
pub struct Output {
|
||||
/// Set the cursor to this icon.
|
||||
pub cursor_icon: CursorIcon,
|
||||
|
||||
/// If set, open this url.
|
||||
pub open_url: Option<String>,
|
||||
pub open_url: Option<OpenUrl>,
|
||||
|
||||
/// Response to [`crate::Event::Copy`] or [`crate::Event::Cut`]. Ignore if empty.
|
||||
pub copied_text: String,
|
||||
|
@ -25,10 +25,35 @@ pub struct Output {
|
|||
pub events: Vec<OutputEvent>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct OpenUrl {
|
||||
pub url: String,
|
||||
/// If `true`, open the url in a new tab.
|
||||
/// If `false` open it in the same tab.
|
||||
/// Only matters when in a web browser.
|
||||
pub new_tab: bool,
|
||||
}
|
||||
|
||||
impl OpenUrl {
|
||||
pub fn same_tab(url: impl Into<String>) -> Self {
|
||||
Self {
|
||||
url: url.into(),
|
||||
new_tab: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_tab(url: impl Into<String>) -> Self {
|
||||
Self {
|
||||
url: url.into(),
|
||||
new_tab: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A mouse cursor icon.
|
||||
///
|
||||
/// egui emits a [`CursorIcon`] in [`Output`] each frame as a request to the integration.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum CursorIcon {
|
||||
Default,
|
||||
/// Pointing hand, used for e.g. web links
|
||||
|
@ -52,7 +77,7 @@ impl Default for CursorIcon {
|
|||
/// Things that happened during this frame that the integration may be interested in.
|
||||
///
|
||||
/// In particular, these events may be useful for accessability, i.e. for screen readers.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum OutputEvent {
|
||||
/// A widget gained keyboard focus (by tab key).
|
||||
///
|
||||
|
@ -81,6 +106,12 @@ pub enum WidgetType {
|
|||
}
|
||||
|
||||
impl Output {
|
||||
/// Open the given url in a web browser.
|
||||
/// If egui is running in a browser, the same tab will be reused.
|
||||
pub fn open_url(&mut self, url: impl Into<String>) {
|
||||
self.open_url = Some(OpenUrl::new_tab(url))
|
||||
}
|
||||
|
||||
/// Inform the backend integration that a widget gained focus
|
||||
pub fn push_gained_focus_event(&mut self, widget_type: WidgetType, text: impl Into<String>) {
|
||||
self.events
|
||||
|
|
|
@ -307,7 +307,10 @@ pub use epaint::{
|
|||
pub use {
|
||||
containers::*,
|
||||
context::{Context, CtxRef},
|
||||
data::{input::*, output::*},
|
||||
data::{
|
||||
input::*,
|
||||
output::{self, CursorIcon, Output, WidgetType},
|
||||
},
|
||||
grid::Grid,
|
||||
id::Id,
|
||||
input_state::{InputState, PointerState},
|
||||
|
|
|
@ -62,7 +62,11 @@ impl Widget for Hyperlink {
|
|||
ui.ctx().output().cursor_icon = CursorIcon::PointingHand;
|
||||
}
|
||||
if response.clicked() {
|
||||
ui.ctx().output().open_url = Some(url.clone());
|
||||
let modifiers = ui.ctx().input().modifiers;
|
||||
ui.ctx().output().open_url = Some(crate::output::OpenUrl {
|
||||
url: url.clone(),
|
||||
new_tab: modifiers.any(),
|
||||
});
|
||||
}
|
||||
|
||||
let color = ui.visuals().hyperlink_color;
|
||||
|
|
|
@ -93,7 +93,7 @@ impl epi::App for WrapApp {
|
|||
{
|
||||
self.selected_anchor = anchor.to_owned();
|
||||
if frame.is_web() {
|
||||
ui.output().open_url = Some(format!("#{}", anchor));
|
||||
ui.output().open_url(format!("#{}", anchor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ impl epi::App for WrapApp {
|
|||
if clock_button(ui, seconds_since_midnight).clicked() {
|
||||
self.selected_anchor = "clock".to_owned();
|
||||
if frame.is_web() {
|
||||
ui.output().open_url = Some("#clock".to_owned());
|
||||
ui.output().open_url("#clock");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ struct BackendPanel {
|
|||
frame_history: crate::frame_history::FrameHistory,
|
||||
|
||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||
output_event_history: std::collections::VecDeque<egui::OutputEvent>,
|
||||
output_event_history: std::collections::VecDeque<egui::output::OutputEvent>,
|
||||
}
|
||||
|
||||
impl Default for BackendPanel {
|
||||
|
|
|
@ -281,8 +281,8 @@ pub fn handle_output(
|
|||
display: &glium::backend::glutin::Display,
|
||||
clipboard: Option<&mut ClipboardContext>,
|
||||
) {
|
||||
if let Some(url) = output.open_url {
|
||||
if let Err(err) = webbrowser::open(&url) {
|
||||
if let Some(open) = output.open_url {
|
||||
if let Err(err) = webbrowser::open(&open.url) {
|
||||
eprintln!("Failed to open url: {}", err);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
|
||||
## Unreleased
|
||||
|
||||
### Added ⭐
|
||||
|
||||
* Hold down a modifier key when clicking a link to open it in a new tab.
|
||||
|
||||
|
||||
## 0.10.0 - 2021-02-28
|
||||
|
||||
|
|
|
@ -237,8 +237,8 @@ pub fn handle_output(output: &egui::Output) {
|
|||
} = output;
|
||||
|
||||
set_cursor_icon(*cursor_icon);
|
||||
if let Some(url) = open_url {
|
||||
crate::open_url(url);
|
||||
if let Some(open) = open_url {
|
||||
crate::open_url(&open.url, open.new_tab);
|
||||
}
|
||||
|
||||
#[cfg(web_sys_unstable_apis)]
|
||||
|
@ -299,9 +299,11 @@ fn cursor_web_name(cursor: egui::CursorIcon) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn open_url(url: &str) -> Option<()> {
|
||||
pub fn open_url(url: &str, new_tab: bool) -> Option<()> {
|
||||
let name = if new_tab { "_blank" } else { "_self" };
|
||||
|
||||
web_sys::window()?
|
||||
.open_with_url_and_target(url, "_self")
|
||||
.open_with_url_and_target(url, name)
|
||||
.ok()?;
|
||||
Some(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue