Add Link widget (#1506)
This looks like a Hyperlink, but doesn't do anything when clicked. Or rather: it lets the user decide what happens on click. Closes https://github.com/emilk/egui/issues/1152
This commit is contained in:
parent
96335d5f45
commit
2d2022fb72
6 changed files with 105 additions and 33 deletions
|
@ -14,6 +14,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
|
|||
* Added `Ui::push_id` to resolve id clashes ([#1374](https://github.com/emilk/egui/pull/1374)).
|
||||
* Added `Frame::outer_margin`.
|
||||
* Added `Painter::hline` and `Painter::vline`.
|
||||
* Added `Link` and `ui.link` ([#1506](https://github.com/emilk/egui/pull/1506)).
|
||||
|
||||
### Changed 🔧
|
||||
* `ClippedMesh` has been replaced with `ClippedPrimitive` ([#1351](https://github.com/emilk/egui/pull/1351)).
|
||||
|
@ -27,7 +28,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
|
|||
* Renamed the feature `serialize` to `serde` ([#1467](https://github.com/emilk/egui/pull/1467)).
|
||||
|
||||
### Fixed 🐛
|
||||
* Fixed ComboBoxes always being rendered left-aligned ([#1304](https://github.com/emilk/egui/pull/1304)).
|
||||
* Fixed `ComboBox`:es always being rendered left-aligned ([#1304](https://github.com/emilk/egui/pull/1304)).
|
||||
* Fixed ui code that could lead to a deadlock ([#1380](https://github.com/emilk/egui/pull/1380)).
|
||||
* Text is darker and more readable in bright mode ([#1412](https://github.com/emilk/egui/pull/1412)).
|
||||
* Fixed `Ui::add_visible` sometimes leaving the `Ui` in a disabled state. ([#1436](https://github.com/emilk/egui/issues/1436)).
|
||||
|
|
|
@ -466,7 +466,7 @@ impl WidgetInfo {
|
|||
|
||||
// TODO: localization
|
||||
let widget_type = match typ {
|
||||
WidgetType::Hyperlink => "link",
|
||||
WidgetType::Link => "link",
|
||||
WidgetType::TextEdit => "text edit",
|
||||
WidgetType::Button => "button",
|
||||
WidgetType::Checkbox => "checkbox",
|
||||
|
|
|
@ -494,7 +494,8 @@ pub mod special_emojis {
|
|||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub enum WidgetType {
|
||||
Label, // TODO: emit Label events
|
||||
Hyperlink,
|
||||
/// e.g. a hyperlink
|
||||
Link,
|
||||
TextEdit,
|
||||
Button,
|
||||
Checkbox,
|
||||
|
|
|
@ -1227,14 +1227,40 @@ impl Ui {
|
|||
Label::new(text.into().weak()).ui(self)
|
||||
}
|
||||
|
||||
/// Shortcut for `add(Hyperlink::new(url))`
|
||||
/// Looks like a hyperlink.
|
||||
///
|
||||
/// Shortcut for `add(Link::new(text))`.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// if ui.link("Documentation").clicked() {
|
||||
/// // …
|
||||
/// }
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// See also [`Link`].
|
||||
#[must_use = "You should check if the user clicked this with `if ui.link(…).clicked() { … } "]
|
||||
pub fn link(&mut self, text: impl Into<WidgetText>) -> Response {
|
||||
Link::new(text).ui(self)
|
||||
}
|
||||
|
||||
/// Link to a web page.
|
||||
///
|
||||
/// Shortcut for `add(Hyperlink::new(url))`.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// ui.hyperlink("https://www.egui.rs/");
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// See also [`Hyperlink`].
|
||||
pub fn hyperlink(&mut self, url: impl ToString) -> Response {
|
||||
Hyperlink::new(url).ui(self)
|
||||
}
|
||||
|
||||
/// Shortcut for `add(Hyperlink::new(url).text(label))`
|
||||
/// Shortcut for `add(Hyperlink::new(url).text(label))`.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
|
|
|
@ -1,5 +1,69 @@
|
|||
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().output().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`].
|
||||
|
@ -42,15 +106,9 @@ impl Hyperlink {
|
|||
|
||||
impl Widget for Hyperlink {
|
||||
fn ui(self, ui: &mut Ui) -> Response {
|
||||
let Hyperlink { url, text } = self;
|
||||
let label = Label::new(text).sense(Sense::click());
|
||||
let Self { url, text } = self;
|
||||
|
||||
let (pos, text_galley, response) = label.layout_in_ui(ui);
|
||||
response.widget_info(|| WidgetInfo::labeled(WidgetType::Hyperlink, text_galley.text()));
|
||||
|
||||
if response.hovered() {
|
||||
ui.ctx().output().cursor_icon = CursorIcon::PointingHand;
|
||||
}
|
||||
let response = ui.add(Link::new(text));
|
||||
if response.clicked() {
|
||||
let modifiers = ui.ctx().input().modifiers;
|
||||
ui.ctx().output().open_url = Some(crate::output::OpenUrl {
|
||||
|
@ -64,26 +122,6 @@ impl Widget for Hyperlink {
|
|||
new_tab: true,
|
||||
});
|
||||
}
|
||||
|
||||
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.on_hover_text(url)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,6 +141,12 @@ impl WidgetGallery {
|
|||
}
|
||||
ui.end_row();
|
||||
|
||||
ui.add(doc_link_label("Link", "link"));
|
||||
if ui.link("Click me!").clicked() {
|
||||
*boolean = !*boolean;
|
||||
}
|
||||
ui.end_row();
|
||||
|
||||
ui.add(doc_link_label("Checkbox", "checkbox"));
|
||||
ui.checkbox(boolean, "Checkbox");
|
||||
ui.end_row();
|
||||
|
|
Loading…
Reference in a new issue