1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
use crate::*;
/// Clickable text, that looks like a hyperlink.
///
/// To link to a web page, use [`Hyperlink`], [`Ui::hyperlink`] or [`Ui::hyperlink_to`].
///
/// See also [`Ui::link`].
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// // These are equivalent:
/// if ui.link("Documentation").clicked() {
/// // …
/// }
///
/// if ui.add(egui::Link::new("Documentation")).clicked() {
/// // …
/// }
/// # });
/// ```
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
pub struct Link {
text: WidgetText,
}
impl Link {
pub fn new(text: impl Into<WidgetText>) -> Self {
Self { text: text.into() }
}
}
impl Widget for Link {
fn ui(self, ui: &mut Ui) -> Response {
let Link { text } = self;
let label = Label::new(text).sense(Sense::click());
let (pos, text_galley, response) = label.layout_in_ui(ui);
response.widget_info(|| WidgetInfo::labeled(WidgetType::Link, text_galley.text()));
if response.hovered() {
ui.ctx().set_cursor_icon(CursorIcon::PointingHand);
}
if ui.is_rect_visible(response.rect) {
let color = ui.visuals().hyperlink_color;
let visuals = ui.style().interact(&response);
let underline = if response.hovered() || response.has_focus() {
Stroke::new(visuals.fg_stroke.width, color)
} else {
Stroke::NONE
};
ui.painter().add(epaint::TextShape {
pos,
galley: text_galley.galley,
override_text_color: Some(color),
underline,
angle: 0.0,
});
}
response
}
}
/// A clickable hyperlink, e.g. to `"https://github.com/emilk/egui"`.
///
/// See also [`Ui::hyperlink`] and [`Ui::hyperlink_to`].
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// // These are equivalent:
/// ui.hyperlink("https://github.com/emilk/egui");
/// ui.add(egui::Hyperlink::new("https://github.com/emilk/egui"));
///
/// // These are equivalent:
/// ui.hyperlink_to("My favorite repo", "https://github.com/emilk/egui");
/// ui.add(egui::Hyperlink::from_label_and_url("My favorite repo", "https://github.com/emilk/egui"));
/// # });
/// ```
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
pub struct Hyperlink {
url: String,
text: WidgetText,
}
impl Hyperlink {
#[allow(clippy::needless_pass_by_value)]
pub fn new(url: impl ToString) -> Self {
let url = url.to_string();
Self {
url: url.clone(),
text: url.into(),
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn from_label_and_url(text: impl Into<WidgetText>, url: impl ToString) -> Self {
Self {
url: url.to_string(),
text: text.into(),
}
}
}
impl Widget for Hyperlink {
fn ui(self, ui: &mut Ui) -> Response {
let Self { url, text } = self;
let response = ui.add(Link::new(text));
if response.clicked() {
let modifiers = ui.ctx().input(|i| i.modifiers);
ui.ctx().output_mut(|o| {
o.open_url = Some(crate::output::OpenUrl {
url: url.clone(),
new_tab: modifiers.any(),
});
});
}
if response.middle_clicked() {
ui.ctx().output_mut(|o| {
o.open_url = Some(crate::output::OpenUrl {
url: url.clone(),
new_tab: true,
});
});
}
response.on_hover_text(url)
}
}