egui/widgets/
hyperlink.rs1use crate::*;
2
3use self::text_selection::LabelSelectionState;
4
5#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
24pub struct Link {
25 text: WidgetText,
26}
27
28impl Link {
29 pub fn new(text: impl Into<WidgetText>) -> Self {
30 Self { text: text.into() }
31 }
32}
33
34impl Widget for Link {
35 fn ui(self, ui: &mut Ui) -> Response {
36 let Self { text } = self;
37 let label = Label::new(text).sense(Sense::click());
38
39 let (galley_pos, galley, response) = label.layout_in_ui(ui);
40 response
41 .widget_info(|| WidgetInfo::labeled(WidgetType::Link, ui.is_enabled(), galley.text()));
42
43 if ui.is_rect_visible(response.rect) {
44 let color = ui.visuals().hyperlink_color;
45 let visuals = ui.style().interact(&response);
46
47 let underline = if response.hovered() || response.has_focus() {
48 Stroke::new(visuals.fg_stroke.width, color)
49 } else {
50 Stroke::NONE
51 };
52
53 ui.painter().add(
54 epaint::TextShape::new(galley_pos, galley.clone(), color).with_underline(underline),
55 );
56
57 let selectable = ui.style().interaction.selectable_labels;
58 if selectable {
59 LabelSelectionState::label_text_selection(ui, &response, galley_pos, &galley);
60 }
61
62 if response.hovered() {
63 ui.ctx().set_cursor_icon(CursorIcon::PointingHand);
64 }
65 }
66
67 response
68 }
69}
70
71#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
87pub struct Hyperlink {
88 url: String,
89 text: WidgetText,
90 new_tab: bool,
91}
92
93impl Hyperlink {
94 #[allow(clippy::needless_pass_by_value)]
95 pub fn new(url: impl ToString) -> Self {
96 let url = url.to_string();
97 Self {
98 url: url.clone(),
99 text: url.into(),
100 new_tab: false,
101 }
102 }
103
104 #[allow(clippy::needless_pass_by_value)]
105 pub fn from_label_and_url(text: impl Into<WidgetText>, url: impl ToString) -> Self {
106 Self {
107 url: url.to_string(),
108 text: text.into(),
109 new_tab: false,
110 }
111 }
112
113 #[inline]
115 pub fn open_in_new_tab(mut self, new_tab: bool) -> Self {
116 self.new_tab = new_tab;
117 self
118 }
119}
120
121impl Widget for Hyperlink {
122 fn ui(self, ui: &mut Ui) -> Response {
123 let Self { url, text, new_tab } = self;
124
125 let response = ui.add(Link::new(text));
126
127 if response.clicked() {
128 let modifiers = ui.ctx().input(|i| i.modifiers);
129 ui.ctx().open_url(crate::OpenUrl {
130 url: url.clone(),
131 new_tab: new_tab || modifiers.any(),
132 });
133 }
134 if response.middle_clicked() {
135 ui.ctx().open_url(crate::OpenUrl {
136 url: url.clone(),
137 new_tab: true,
138 });
139 }
140
141 if ui.style().url_in_tooltip {
142 response.on_hover_text(url)
143 } else {
144 response
145 }
146 }
147}