Add Label::sense so you can make clickable labels
relates to https://github.com/emilk/egui/issues/292
This commit is contained in:
parent
3c0c729af8
commit
5d50fa1350
5 changed files with 60 additions and 9 deletions
|
@ -7,6 +7,8 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md) and [
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added ⭐
|
||||||
|
* Make labels interactive with `Label::sense(Sense::click())`.
|
||||||
|
|
||||||
## 0.11.0 - 2021-04-05 - Optimization, screen reader & new layout logic
|
## 0.11.0 - 2021-04-05 - Optimization, screen reader & new layout logic
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,11 @@ impl std::fmt::Debug for Response {
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
/// Returns true if this widget was clicked this frame by the primary button.
|
/// Returns true if this widget was clicked this frame by the primary button.
|
||||||
|
///
|
||||||
|
/// Note that the widget must be sensing clicks with [`Sense::click`].
|
||||||
|
/// [`crate::Button`] senses clicks; [`crate::Label`] does not (unless you call [`crate::Label::sense`]).
|
||||||
|
///
|
||||||
|
/// You can use [`Self::interact`] to sense more things *after* adding a widget.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn clicked(&self) -> bool {
|
pub fn clicked(&self) -> bool {
|
||||||
self.clicked[PointerButton::Primary as usize]
|
self.clicked[PointerButton::Primary as usize]
|
||||||
|
@ -198,6 +203,11 @@ impl Response {
|
||||||
///
|
///
|
||||||
/// To find out which button(s), query [`crate::PointerState::button_down`]
|
/// To find out which button(s), query [`crate::PointerState::button_down`]
|
||||||
/// (`ui.input().pointer.button_down(…)`).
|
/// (`ui.input().pointer.button_down(…)`).
|
||||||
|
///
|
||||||
|
/// Note that the widget must be sensing drags with [`Sense::drag`].
|
||||||
|
/// [`crate::DragValue`] senses drags; [`crate::Label`] does not (unless you call [`crate::Label::sense`]).
|
||||||
|
///
|
||||||
|
/// You can use [`Self::interact`] to sense more things *after* adding a widget.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dragged(&self) -> bool {
|
pub fn dragged(&self) -> bool {
|
||||||
self.dragged
|
self.dragged
|
||||||
|
@ -340,10 +350,13 @@ impl Response {
|
||||||
|
|
||||||
/// Check for more interactions (e.g. sense clicks on a `Response` returned from a label).
|
/// Check for more interactions (e.g. sense clicks on a `Response` returned from a label).
|
||||||
///
|
///
|
||||||
|
/// Note that this call will not add any hover-effects to the widget, so when possible
|
||||||
|
/// it is better to give the widget a `Sense` instead, e.g. using `[Label::sense]`.
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # let mut ui = egui::Ui::__test();
|
/// # let mut ui = egui::Ui::__test();
|
||||||
/// let response = ui.label("hello");
|
/// let response = ui.label("hello");
|
||||||
/// assert!(!response.clicked()); // labels don't sense clicks
|
/// assert!(!response.clicked()); // labels don't sense clicks by default
|
||||||
/// let response = response.interact(egui::Sense::click());
|
/// let response = response.interact(egui::Sense::click());
|
||||||
/// if response.clicked() { /* … */ }
|
/// if response.clicked() { /* … */ }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -75,4 +75,9 @@ impl Sense {
|
||||||
focusable: self.focusable | other.focusable,
|
focusable: self.focusable | other.focusable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if we sense either clicks or drags.
|
||||||
|
pub fn interactive(&self) -> bool {
|
||||||
|
self.click || self.drag
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,9 @@ pub struct Widgets {
|
||||||
|
|
||||||
impl Widgets {
|
impl Widgets {
|
||||||
pub fn style(&self, response: &Response) -> &WidgetVisuals {
|
pub fn style(&self, response: &Response) -> &WidgetVisuals {
|
||||||
if response.is_pointer_button_down_on() || response.has_focus() {
|
if !response.sense.interactive() {
|
||||||
|
&self.noninteractive
|
||||||
|
} else if response.is_pointer_button_down_on() || response.has_focus() {
|
||||||
&self.active
|
&self.active
|
||||||
} else if response.hovered() {
|
} else if response.hovered() {
|
||||||
&self.hovered
|
&self.hovered
|
||||||
|
|
|
@ -25,6 +25,7 @@ pub struct Label {
|
||||||
underline: bool,
|
underline: bool,
|
||||||
italics: bool,
|
italics: bool,
|
||||||
raised: bool,
|
raised: bool,
|
||||||
|
sense: Sense,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Label {
|
impl Label {
|
||||||
|
@ -42,6 +43,7 @@ impl Label {
|
||||||
underline: false,
|
underline: false,
|
||||||
italics: false,
|
italics: false,
|
||||||
raised: false,
|
raised: false,
|
||||||
|
sense: Sense::focusable_noninteractive(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +143,24 @@ impl Label {
|
||||||
self.text_color = Some(text_color.into());
|
self.text_color = Some(text_color.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Make the label response to clicks and/or drags.
|
||||||
|
///
|
||||||
|
/// By default, a label is inert and does not response to click or drags.
|
||||||
|
/// By calling this you can turn the label into a button of sorts.
|
||||||
|
/// This will also give the label the hover-effect of a button, but without the frame.
|
||||||
|
///
|
||||||
|
/// ``` rust
|
||||||
|
/// # use egui::{Label, Sense};
|
||||||
|
/// # let ui = &mut egui::Ui::__test();
|
||||||
|
/// if ui.add(Label::new("click me").sense(Sense::click())).clicked() {
|
||||||
|
/// /* … */
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn sense(mut self, sense: Sense) -> Self {
|
||||||
|
self.sense = sense;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Label {
|
impl Label {
|
||||||
|
@ -176,10 +196,17 @@ impl Label {
|
||||||
// This should be the easiest method of putting text anywhere.
|
// This should be the easiest method of putting text anywhere.
|
||||||
|
|
||||||
pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: Arc<Galley>) {
|
pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: Arc<Galley>) {
|
||||||
self.paint_galley_focus(ui, pos, galley, false)
|
self.paint_galley_impl(ui, pos, galley, false, ui.visuals().text_color())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_galley_focus(&self, ui: &mut Ui, pos: Pos2, galley: Arc<Galley>, focus: bool) {
|
fn paint_galley_impl(
|
||||||
|
&self,
|
||||||
|
ui: &mut Ui,
|
||||||
|
pos: Pos2,
|
||||||
|
galley: Arc<Galley>,
|
||||||
|
has_focus: bool,
|
||||||
|
response_color: Color32,
|
||||||
|
) {
|
||||||
let Self {
|
let Self {
|
||||||
mut background_color,
|
mut background_color,
|
||||||
code,
|
code,
|
||||||
|
@ -192,7 +219,7 @@ impl Label {
|
||||||
..
|
..
|
||||||
} = *self;
|
} = *self;
|
||||||
|
|
||||||
let underline = underline || focus;
|
let underline = underline || has_focus;
|
||||||
|
|
||||||
let text_color = if let Some(text_color) = self.text_color {
|
let text_color = if let Some(text_color) = self.text_color {
|
||||||
text_color
|
text_color
|
||||||
|
@ -201,7 +228,7 @@ impl Label {
|
||||||
} else if weak {
|
} else if weak {
|
||||||
ui.visuals().weak_text_color()
|
ui.visuals().weak_text_color()
|
||||||
} else {
|
} else {
|
||||||
ui.visuals().text_color()
|
response_color
|
||||||
};
|
};
|
||||||
|
|
||||||
if code {
|
if code {
|
||||||
|
@ -287,7 +314,7 @@ impl Label {
|
||||||
|
|
||||||
impl Widget for Label {
|
impl Widget for Label {
|
||||||
fn ui(self, ui: &mut Ui) -> Response {
|
fn ui(self, ui: &mut Ui) -> Response {
|
||||||
let sense = Sense::focusable_noninteractive();
|
let sense = self.sense;
|
||||||
|
|
||||||
if self.should_wrap(ui)
|
if self.should_wrap(ui)
|
||||||
&& ui.layout().main_dir() == Direction::LeftToRight
|
&& ui.layout().main_dir() == Direction::LeftToRight
|
||||||
|
@ -339,13 +366,15 @@ impl Widget for Label {
|
||||||
response |= ui.allocate_rect(rect, sense);
|
response |= ui.allocate_rect(rect, sense);
|
||||||
}
|
}
|
||||||
response.widget_info(|| WidgetInfo::labeled(WidgetType::Label, &galley.text));
|
response.widget_info(|| WidgetInfo::labeled(WidgetType::Label, &galley.text));
|
||||||
self.paint_galley_focus(ui, pos, galley, response.has_focus());
|
let response_color = ui.style().interact(&response).text_color();
|
||||||
|
self.paint_galley_impl(ui, pos, galley, response.has_focus(), response_color);
|
||||||
response
|
response
|
||||||
} else {
|
} else {
|
||||||
let galley = self.layout(ui);
|
let galley = self.layout(ui);
|
||||||
let (rect, response) = ui.allocate_exact_size(galley.size, sense);
|
let (rect, response) = ui.allocate_exact_size(galley.size, sense);
|
||||||
response.widget_info(|| WidgetInfo::labeled(WidgetType::Label, &galley.text));
|
response.widget_info(|| WidgetInfo::labeled(WidgetType::Label, &galley.text));
|
||||||
self.paint_galley_focus(ui, rect.min, galley, response.has_focus());
|
let response_color = ui.style().interact(&response).text_color();
|
||||||
|
self.paint_galley_impl(ui, rect.min, galley, response.has_focus(), response_color);
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue