1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 04:40:03 -04:00

Atom link (wip)

This commit is contained in:
lucasmerlin
2025-06-30 13:21:51 +02:00
parent e8061684b9
commit e4d346d23c
3 changed files with 48 additions and 25 deletions

View File

@@ -1974,8 +1974,8 @@ impl Ui {
/// ///
/// See also [`Link`]. /// See also [`Link`].
#[must_use = "You should check if the user clicked this with `if ui.link(…).clicked() { … } "] #[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 { pub fn link<'a>(&mut self, atoms: impl IntoAtoms<'a>) -> Response {
Link::new(text).ui(self) Link::new(atoms).ui(self)
} }
/// Link to a web page. /// Link to a web page.

View File

@@ -1,6 +1,6 @@
use crate::{ use crate::{
epaint, text_selection, CursorIcon, Label, Response, Sense, Stroke, Ui, Widget, WidgetInfo, epaint, text_selection, AtomLayout, CursorIcon, IntoAtoms, Response, Sense, Stroke, Ui, Widget,
WidgetText, WidgetType, WidgetInfo, WidgetText, WidgetType,
}; };
use self::text_selection::LabelSelectionState; use self::text_selection::LabelSelectionState;
@@ -24,27 +24,38 @@ use self::text_selection::LabelSelectionState;
/// # }); /// # });
/// ``` /// ```
#[must_use = "You should put this widget in a ui with `ui.add(widget);`"] #[must_use = "You should put this widget in a ui with `ui.add(widget);`"]
pub struct Link { pub struct Link<'a> {
text: WidgetText, layout: AtomLayout<'a>,
} }
impl Link { impl<'a> Link<'a> {
pub fn new(text: impl Into<WidgetText>) -> Self { pub fn new(atoms: impl IntoAtoms<'a>) -> Self {
Self { text: text.into() } Self {
layout: AtomLayout::new(atoms).sense(Sense::click()),
}
} }
} }
impl Widget for Link { impl Widget for Link<'_> {
fn ui(self, ui: &mut Ui) -> Response { fn ui(self, ui: &mut Ui) -> Response {
let Self { text } = self; let Self { layout } = self;
let label = Label::new(text).sense(Sense::click());
let (galley_pos, galley, response) = label.layout_in_ui(ui); let color = ui.visuals().hyperlink_color;
response let text = layout.atoms.text().map(String::from);
.widget_info(|| WidgetInfo::labeled(WidgetType::Link, ui.is_enabled(), galley.text())); let layout_with_color = layout.fallback_text_color(color);
let allocated = layout_with_color.allocate(ui);
let response = allocated.response.clone();
response.widget_info(|| {
WidgetInfo::labeled(
WidgetType::Link,
ui.is_enabled(),
text.as_deref().unwrap_or(""),
)
});
if ui.is_rect_visible(response.rect) { if ui.is_rect_visible(response.rect) {
let color = ui.visuals().hyperlink_color;
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
let underline = if response.hovered() || response.has_focus() { let underline = if response.hovered() || response.has_focus() {
@@ -54,14 +65,25 @@ impl Widget for Link {
}; };
let selectable = ui.style().interaction.selectable_labels; let selectable = ui.style().interaction.selectable_labels;
if selectable {
LabelSelectionState::label_text_selection( for galley in allocated.iter_texts() {
ui, &response, galley_pos, galley, color, underline, let galley_pos = response.rect.min;
);
} else { if selectable {
ui.painter().add( LabelSelectionState::label_text_selection(
epaint::TextShape::new(galley_pos, galley, color).with_underline(underline), ui,
); &response,
galley_pos,
galley.clone(),
color,
underline,
);
} else {
ui.painter().add(
epaint::TextShape::new(galley_pos, galley.clone(), color)
.with_underline(underline),
);
}
} }
if response.hovered() { if response.hovered() {

View File

@@ -168,7 +168,8 @@ impl WidgetGallery {
ui.end_row(); ui.end_row();
ui.add(doc_link_label("Link", "link")); ui.add(doc_link_label("Link", "link"));
if ui.link("Click me!").clicked() { let egui_icon = egui::include_image!("../../data/icon.png");
if ui.link((egui_icon, "Click me!")).clicked() {
*boolean = !*boolean; *boolean = !*boolean;
} }
ui.end_row(); ui.end_row();