Skip to content

Commit

Permalink
Hold down a modifier key when clicking a link to open it in a new tab
Browse files Browse the repository at this point in the history
  • Loading branch information
emilk committed Mar 8, 2021
1 parent c1ef816 commit 1c06622
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 15 deletions.
10 changes: 10 additions & 0 deletions egui/src/data/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand Down
39 changes: 35 additions & 4 deletions egui/src/data/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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).
///
Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
6 changes: 5 additions & 1 deletion egui/src/widgets/hyperlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions egui_demo_lib/src/wrap_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
}
Expand All @@ -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");
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions egui_glium/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
4 changes: 4 additions & 0 deletions egui_web/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 6 additions & 4 deletions egui_web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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(())
}
Expand Down

0 comments on commit 1c06622

Please sign in to comment.