1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-31 13:50:04 -04:00

Remove SelectableLabel

This commit is contained in:
lucasmerlin
2025-06-30 12:03:21 +02:00
parent d770cd53a6
commit 4e8e5e08ff
5 changed files with 45 additions and 98 deletions

View File

@@ -23,7 +23,7 @@ use crate::{
vec2, widgets, vec2, widgets,
widgets::{ widgets::{
color_picker, Button, Checkbox, DragValue, Hyperlink, Image, ImageSource, Label, Link, color_picker, Button, Checkbox, DragValue, Hyperlink, Image, ImageSource, Label, Link,
RadioButton, SelectableLabel, Separator, Spinner, TextEdit, Widget, RadioButton, Separator, Spinner, TextEdit, Widget,
}, },
Align, Color32, Context, CursorIcon, DragAndDrop, Id, InnerResponse, InputState, IntoAtoms, Align, Color32, Context, CursorIcon, DragAndDrop, Id, InnerResponse, InputState, IntoAtoms,
LayerId, Memory, Order, Painter, PlatformOutput, Pos2, Rangef, Rect, Response, Rgba, RichText, LayerId, Memory, Order, Painter, PlatformOutput, Pos2, Rangef, Rect, Response, Rgba, RichText,
@@ -2136,8 +2136,8 @@ impl Ui {
/// ///
/// See also [`SelectableLabel`] and [`Self::toggle_value`]. /// See also [`SelectableLabel`] and [`Self::toggle_value`].
#[must_use = "You should check if the user clicked this with `if ui.selectable_label(…).clicked() { … } "] #[must_use = "You should check if the user clicked this with `if ui.selectable_label(…).clicked() { … } "]
pub fn selectable_label(&mut self, checked: bool, text: impl Into<WidgetText>) -> Response { pub fn selectable_label<'a>(&mut self, checked: bool, text: impl IntoAtoms<'a>) -> Response {
SelectableLabel::new(checked, text).ui(self) Button::selectable_value(checked, text).ui(self)
} }
/// Show selectable text. It is selected if `*current_value == selected_value`. /// Show selectable text. It is selected if `*current_value == selected_value`.
@@ -2146,11 +2146,11 @@ impl Ui {
/// Example: `ui.selectable_value(&mut my_enum, Enum::Alternative, "Alternative")`. /// Example: `ui.selectable_value(&mut my_enum, Enum::Alternative, "Alternative")`.
/// ///
/// See also [`SelectableLabel`] and [`Self::toggle_value`]. /// See also [`SelectableLabel`] and [`Self::toggle_value`].
pub fn selectable_value<Value: PartialEq>( pub fn selectable_value<'a, Value: PartialEq>(
&mut self, &mut self,
current_value: &mut Value, current_value: &mut Value,
selected_value: Value, selected_value: Value,
text: impl Into<WidgetText>, text: impl IntoAtoms<'a>,
) -> Response { ) -> Response {
let mut response = self.selectable_label(*current_value == selected_value, text); let mut response = self.selectable_label(*current_value == selected_value, text);
if response.clicked() && *current_value != selected_value { if response.clicked() && *current_value != selected_value {

View File

@@ -29,6 +29,7 @@ pub struct Button<'a> {
stroke: Option<Stroke>, stroke: Option<Stroke>,
small: bool, small: bool,
frame: Option<bool>, frame: Option<bool>,
frame_when_inactive: bool,
min_size: Vec2, min_size: Vec2,
corner_radius: Option<CornerRadius>, corner_radius: Option<CornerRadius>,
selected: bool, selected: bool,
@@ -44,6 +45,7 @@ impl<'a> Button<'a> {
stroke: None, stroke: None,
small: false, small: false,
frame: None, frame: None,
frame_when_inactive: true,
min_size: Vec2::ZERO, min_size: Vec2::ZERO,
corner_radius: None, corner_radius: None,
selected: false, selected: false,
@@ -52,6 +54,25 @@ impl<'a> Button<'a> {
} }
} }
/// Show a selectable button.
///
/// Equivalent to:
/// ```rust
/// # use egui::{Button, IntoAtoms};
/// let selected = true;
/// Button::new("toggle me").selected(selected).frame_when_inactive(!selected).frame(true)
/// ```
///
/// See also:
/// - [`Ui::selectable_value`]
/// - [`Ui::selectable_label`]
pub fn selectable_value(selected: bool, atoms: impl IntoAtoms<'a>) -> Self {
Self::new(atoms)
.selected(selected)
.frame_when_inactive(selected)
.frame(true)
}
/// Creates a button with an image. The size of the image as displayed is defined by the provided size. /// Creates a button with an image. The size of the image as displayed is defined by the provided size.
/// ///
/// Note: In contrast to [`Button::new`], this limits the image size to the default font height /// Note: In contrast to [`Button::new`], this limits the image size to the default font height
@@ -138,6 +159,15 @@ impl<'a> Button<'a> {
self self
} }
/// If `false`, the button will not have a frame when inactive.
///
/// Default: `true`.
#[inline]
pub fn frame_when_inactive(mut self, frame_when_inactive: bool) -> Self {
self.frame_when_inactive = frame_when_inactive;
self
}
/// By default, buttons senses clicks. /// By default, buttons senses clicks.
/// Change this to a drag-button with `Sense::drag()`. /// Change this to a drag-button with `Sense::drag()`.
#[inline] #[inline]
@@ -220,6 +250,7 @@ impl<'a> Button<'a> {
stroke, stroke,
small, small,
frame, frame,
frame_when_inactive,
mut min_size, mut min_size,
corner_radius, corner_radius,
selected, selected,
@@ -243,9 +274,9 @@ impl<'a> Button<'a> {
let text = layout.text().map(String::from); let text = layout.text().map(String::from);
let has_frame = frame.unwrap_or_else(|| ui.visuals().button_frame); let mut has_frame = frame.unwrap_or_else(|| ui.visuals().button_frame);
let mut button_padding = if has_frame { let mut button_padding = if has_frame || !frame_when_inactive {
ui.spacing().button_padding ui.spacing().button_padding
} else { } else {
Vec2::ZERO Vec2::ZERO
@@ -262,6 +293,12 @@ impl<'a> Button<'a> {
let response = if ui.is_rect_visible(prepared.response.rect) { let response = if ui.is_rect_visible(prepared.response.rect) {
let visuals = ui.style().interact_selectable(&prepared.response, selected); let visuals = ui.style().interact_selectable(&prepared.response, selected);
if !frame_when_inactive {
has_frame &= prepared.response.hovered()
|| prepared.response.is_pointer_button_down_on()
|| prepared.response.has_focus();
}
if image_tint_follows_text_color { if image_tint_follows_text_color {
prepared.map_images(|image| image.tint(visuals.text_color())); prepared.map_images(|image| image.tint(visuals.text_color()));
} }

View File

@@ -16,7 +16,6 @@ mod image_button;
mod label; mod label;
mod progress_bar; mod progress_bar;
mod radio_button; mod radio_button;
mod selected_label;
mod separator; mod separator;
mod slider; mod slider;
mod spinner; mod spinner;
@@ -35,7 +34,6 @@ pub use self::{
label::Label, label::Label,
progress_bar::ProgressBar, progress_bar::ProgressBar,
radio_button::RadioButton, radio_button::RadioButton,
selected_label::SelectableLabel,
separator::Separator, separator::Separator,
slider::{Slider, SliderClamping, SliderOrientation}, slider::{Slider, SliderClamping, SliderOrientation},
spinner::Spinner, spinner::Spinner,

View File

@@ -1,88 +0,0 @@
use crate::{
NumExt as _, Response, Sense, TextStyle, Ui, Widget, WidgetInfo, WidgetText, WidgetType,
};
/// One out of several alternatives, either selected or not.
/// Will mark selected items with a different background color.
/// An alternative to [`crate::RadioButton`] and [`crate::Checkbox`].
///
/// Usually you'd use [`Ui::selectable_value`] or [`Ui::selectable_label`] instead.
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// #[derive(PartialEq)]
/// enum Enum { First, Second, Third }
/// let mut my_enum = Enum::First;
///
/// ui.selectable_value(&mut my_enum, Enum::First, "First");
///
/// // is equivalent to:
///
/// if ui.add(egui::SelectableLabel::new(my_enum == Enum::First, "First")).clicked() {
/// my_enum = Enum::First
/// }
/// # });
/// ```
#[must_use = "You should put this widget in a ui with `ui.add(widget);`"]
pub struct SelectableLabel {
selected: bool,
text: WidgetText,
}
impl SelectableLabel {
pub fn new(selected: bool, text: impl Into<WidgetText>) -> Self {
Self {
selected,
text: text.into(),
}
}
}
impl Widget for SelectableLabel {
fn ui(self, ui: &mut Ui) -> Response {
let Self { selected, text } = self;
let button_padding = ui.spacing().button_padding;
let total_extra = button_padding + button_padding;
let wrap_width = ui.available_width() - total_extra.x;
let galley = text.into_galley(ui, None, wrap_width, TextStyle::Button);
let mut desired_size = total_extra + galley.size();
desired_size.y = desired_size.y.at_least(ui.spacing().interact_size.y);
let (rect, response) = ui.allocate_at_least(desired_size, Sense::click());
response.widget_info(|| {
WidgetInfo::selected(
WidgetType::SelectableLabel,
ui.is_enabled(),
selected,
galley.text(),
)
});
if ui.is_rect_visible(response.rect) {
let text_pos = ui
.layout()
.align_size_within_rect(galley.size(), rect.shrink2(button_padding))
.min;
let visuals = ui.style().interact_selectable(&response, selected);
if selected || response.hovered() || response.highlighted() || response.has_focus() {
let rect = rect.expand(visuals.expansion);
ui.painter().rect(
rect,
visuals.corner_radius,
visuals.weak_bg_fill,
visuals.bg_stroke,
epaint::StrokeKind::Inside,
);
}
ui.painter().galley(text_pos, galley, visuals.text_color());
}
response
}
}

View File

@@ -27,7 +27,7 @@ pub fn password_ui(ui: &mut egui::Ui, password: &mut String) -> egui::Response {
let result = ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { let result = ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
// Toggle the `show_plaintext` bool with a button: // Toggle the `show_plaintext` bool with a button:
let response = ui let response = ui
.add(egui::SelectableLabel::new(show_plaintext, "👁")) .selectable_label(show_plaintext, "👁")
.on_hover_text("Show/hide password"); .on_hover_text("Show/hide password");
if response.clicked() { if response.clicked() {