1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 23:00:04 -04:00

fix features

This commit is contained in:
adrien
2025-11-12 10:05:30 +01:00
parent c3ce6bf11f
commit 34bf318782
4 changed files with 59 additions and 52 deletions

View File

@@ -30,7 +30,7 @@ pub struct WidgetStyle {
pub struct ButtonStyle { pub struct ButtonStyle {
pub frame: Frame, pub frame: Frame,
pub text: TextVisuals, pub text_style: TextVisuals,
} }
pub struct CheckboxStyle { pub struct CheckboxStyle {
@@ -38,10 +38,10 @@ pub struct CheckboxStyle {
pub frame: Frame, pub frame: Frame,
/// Text next to it /// Text next to it
pub text: TextVisuals, pub text_style: TextVisuals,
/// Checkbox size /// Checkbox size
pub size: f32, pub checkbox_size: f32,
/// Checkmark size /// Checkmark size
pub check_size: f32, pub check_size: f32,
@@ -50,7 +50,7 @@ pub struct CheckboxStyle {
pub checkbox_frame: Frame, pub checkbox_frame: Frame,
/// Checkmark stroke /// Checkmark stroke
pub stroke: Stroke, pub check_stroke: Stroke,
} }
pub struct LabelStyle { pub struct LabelStyle {
@@ -148,7 +148,7 @@ impl Style {
.into(), .into(),
..Default::default() ..Default::default()
}, },
text: ws.text, text_style: ws.text,
} }
} }
@@ -157,16 +157,16 @@ impl Style {
let ws = self.widget_style(state); let ws = self.widget_style(state);
CheckboxStyle { CheckboxStyle {
frame: Frame::new(), frame: Frame::new(),
size: self.spacing.icon_width, checkbox_size: self.spacing.icon_width,
check_size: self.spacing.icon_width_inner, check_size: self.spacing.icon_width_inner,
checkbox_frame: Frame { checkbox_frame: Frame {
fill: visuals.weak_bg_fill, fill: visuals.bg_fill,
corner_radius: visuals.corner_radius, corner_radius: visuals.corner_radius,
stroke: visuals.bg_stroke, stroke: visuals.bg_stroke,
..Default::default() ..Default::default()
}, },
text: ws.text, text_style: ws.text,
stroke: ws.stroke, check_stroke: ws.stroke,
} }
} }

View File

@@ -1,11 +1,12 @@
use std::sync::Arc; use std::{mem, sync::Arc};
use epaint::Margin; use epaint::Margin;
use crate::{ use crate::{
Atom, AtomExt as _, AtomKind, AtomLayout, AtomLayoutResponse, Color32, CornerRadius, Frame, Atom, AtomExt as _, AtomKind, AtomLayout, AtomLayoutResponse, Color32, CornerRadius, Frame,
Image, IntoAtoms, NumExt as _, Response, RichText, Sense, Stroke, TextStyle, TextWrapMode, Ui, Image, IntoAtoms, NumExt as _, Response, RichText, Sense, Stroke, TextStyle, TextWrapMode, Ui,
Vec2, Widget, WidgetInfo, WidgetText, WidgetType, style_trait::WidgetState, Vec2, Widget, WidgetInfo, WidgetText, WidgetType,
style_trait::{ButtonStyle, WidgetState},
}; };
/// Clickable button with text. /// Clickable button with text.
@@ -293,16 +294,16 @@ impl<'a> Button<'a> {
let text = layout.text().map(String::from); let text = layout.text().map(String::from);
let has_frame_margin = frame.unwrap_or_else(|| ui.visuals().button_frame);
let id = ui.next_auto_id(); let id = ui.next_auto_id();
let response: Option<Response> = ui.ctx().read_response(id); let response: Option<Response> = ui.ctx().read_response(id);
let state = response.map(|r| r.widget_state()).unwrap_or_default(); let state = response.map(|r| r.widget_state()).unwrap_or_default();
let style = ui.style().button_style(state, selected); let ButtonStyle { frame, text_style } = ui.style().button_style(state, selected);
let has_frame_margin = frame.unwrap_or_else(|| ui.visuals().button_frame);
let mut button_padding = if has_frame_margin { let mut button_padding = if has_frame_margin {
style.frame.inner_margin frame.inner_margin
} else { } else {
Margin::ZERO Margin::ZERO
}; };
@@ -313,7 +314,7 @@ impl<'a> Button<'a> {
} }
// Override global style by local style // Override global style by local style
let mut frame = style.frame; let mut frame = frame;
if let Some(fill) = fill { if let Some(fill) = fill {
frame = frame.fill(fill); frame = frame.fill(fill);
} }
@@ -331,31 +332,34 @@ impl<'a> Button<'a> {
layout.map_texts(|t| match t { layout.map_texts(|t| match t {
WidgetText::Text(text) => { WidgetText::Text(text) => {
let rich_text = RichText::new(text.clone()) let rich_text = RichText::new(text.clone())
.font(style.text.font_id.clone()) .font(text_style.font_id.clone())
.color(style.text.color); .color(text_style.color);
WidgetText::RichText(Arc::new(rich_text)) WidgetText::RichText(Arc::new(rich_text))
} }
WidgetText::RichText(mut text) => {
let text_mut = Arc::make_mut(&mut text);
*text_mut = mem::take(text_mut).font(text_style.font_id.clone());
WidgetText::RichText(text)
}
w => w, w => w,
}); });
// Retrocompatibility with button settings // Retrocompatibility with button settings
let mut prepared = layout = if has_frame_margin && (state != WidgetState::Inactive || frame_when_inactive) {
if has_frame_margin && (state != WidgetState::Inactive || frame_when_inactive) { layout.frame(frame)
layout.frame(frame).min_size(min_size).allocate(ui) } else {
} else { layout.frame(Frame::new().inner_margin(frame.inner_margin))
layout };
.frame(Frame::new().inner_margin(frame.inner_margin))
.min_size(min_size) let mut prepared = layout.min_size(min_size).allocate(ui);
.allocate(ui)
};
// Get AtomLayoutResponse, empty if not visible // Get AtomLayoutResponse, empty if not visible
let response = if ui.is_rect_visible(prepared.response.rect) { let response = if ui.is_rect_visible(prepared.response.rect) {
if image_tint_follows_text_color { if image_tint_follows_text_color {
prepared.map_images(|image| image.tint(style.text.color)); prepared.map_images(|image| image.tint(text_style.color));
} }
prepared.fallback_text_color = style.text.color; prepared.fallback_text_color = text_style.color;
prepared.paint(ui) prepared.paint(ui)
} else { } else {

View File

@@ -2,7 +2,7 @@ use emath::Rect;
use crate::{ use crate::{
Atom, AtomLayout, Atoms, Id, IntoAtoms, NumExt as _, Response, Sense, Shape, Ui, Vec2, Widget, Atom, AtomLayout, Atoms, Id, IntoAtoms, NumExt as _, Response, Sense, Shape, Ui, Vec2, Widget,
WidgetInfo, WidgetType, epaint, pos2, WidgetInfo, WidgetType, epaint, pos2, style_trait::CheckboxStyle,
}; };
// TODO(emilk): allow checkbox without a text label // TODO(emilk): allow checkbox without a text label
@@ -61,16 +61,22 @@ impl Widget for Checkbox<'_> {
let id = ui.next_auto_id(); let id = ui.next_auto_id();
let response: Option<Response> = ui.ctx().read_response(id); let response: Option<Response> = ui.ctx().read_response(id);
let state = response.map(|r| r.widget_state()).unwrap_or_default(); let state = response.map(|r| r.widget_state()).unwrap_or_default();
let style = ui.style().checkbox_style(state);
let icon_width = style.size; let CheckboxStyle {
check_size,
checkbox_frame,
checkbox_size,
frame,
check_stroke,
text_style,
} = ui.style().checkbox_style(state);
// interact_size or size ? // interact_size or size ?
let mut min_size = Vec2::splat(ui.spacing().interact_size.y); let mut min_size = Vec2::splat(ui.spacing().interact_size.y);
min_size.y = min_size.y.at_least(icon_width); min_size.y = min_size.y.at_least(checkbox_size);
// In order to center the checkbox based on min_size we set the icon height to at least min_size.y // In order to center the checkbox based on min_size we set the icon height to at least min_size.y
let mut icon_size = Vec2::splat(icon_width); let mut icon_size = Vec2::splat(checkbox_size);
icon_size.y = icon_size.y.at_least(min_size.y); icon_size.y = icon_size.y.at_least(min_size.y);
let rect_id = Id::new("egui::checkbox"); let rect_id = Id::new("egui::checkbox");
atoms.push_left(Atom::custom(rect_id, icon_size)); atoms.push_left(Atom::custom(rect_id, icon_size));
@@ -80,7 +86,7 @@ impl Widget for Checkbox<'_> {
let mut prepared = AtomLayout::new(atoms) let mut prepared = AtomLayout::new(atoms)
.sense(Sense::click()) .sense(Sense::click())
.min_size(min_size) .min_size(min_size)
.frame(style.frame) .frame(frame)
.allocate(ui); .allocate(ui);
if prepared.response.clicked() { if prepared.response.clicked() {
@@ -105,23 +111,22 @@ impl Widget for Checkbox<'_> {
}); });
if ui.is_rect_visible(prepared.response.rect) { if ui.is_rect_visible(prepared.response.rect) {
// let visuals = ui.style().interact_selectable(&response, *checked); // too colorful prepared.fallback_text_color = text_style.color;
prepared.fallback_text_color = style.text.color;
let response = prepared.paint(ui); let response = prepared.paint(ui);
if let Some(rect) = response.rect(rect_id) { if let Some(rect) = response.rect(rect_id) {
let big_icon_rect = Rect::from_center_size( let big_icon_rect = Rect::from_center_size(
pos2(rect.left() + icon_width / 2.0, rect.center().y), pos2(rect.left() + checkbox_size / 2.0, rect.center().y),
Vec2::splat(style.size), Vec2::splat(checkbox_size),
); );
let small_icon_rect = let small_icon_rect =
Rect::from_center_size(big_icon_rect.center(), Vec2::splat(style.check_size)); Rect::from_center_size(big_icon_rect.center(), Vec2::splat(check_size));
ui.painter().add(epaint::RectShape::new( ui.painter().add(epaint::RectShape::new(
big_icon_rect, big_icon_rect,
style.checkbox_frame.corner_radius, checkbox_frame.corner_radius,
style.checkbox_frame.fill, checkbox_frame.fill,
style.checkbox_frame.stroke, checkbox_frame.stroke,
epaint::StrokeKind::Inside, epaint::StrokeKind::Inside,
)); ));
@@ -130,7 +135,7 @@ impl Widget for Checkbox<'_> {
ui.painter().add(Shape::hline( ui.painter().add(Shape::hline(
small_icon_rect.x_range(), small_icon_rect.x_range(),
small_icon_rect.center().y, small_icon_rect.center().y,
style.stroke, check_stroke,
)); ));
} else if *checked { } else if *checked {
// Check mark: // Check mark:
@@ -140,7 +145,7 @@ impl Widget for Checkbox<'_> {
pos2(small_icon_rect.center().x, small_icon_rect.bottom()), pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
pos2(small_icon_rect.right(), small_icon_rect.top()), pos2(small_icon_rect.right(), small_icon_rect.top()),
], ],
style.stroke, check_stroke,
)); ));
} }
} }

View File

@@ -13,7 +13,7 @@ use crate::{Response, Sense, Ui, Vec2, Widget, vec2};
/// ``` /// ```
#[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 Separator { pub struct Separator {
spacing: f32, spacing: Option<f32>,
grow: f32, grow: f32,
is_horizontal_line: Option<bool>, is_horizontal_line: Option<bool>,
} }
@@ -21,7 +21,7 @@ pub struct Separator {
impl Default for Separator { impl Default for Separator {
fn default() -> Self { fn default() -> Self {
Self { Self {
spacing: 6.0, spacing: None,
grow: 0.0, grow: 0.0,
is_horizontal_line: None, is_horizontal_line: None,
} }
@@ -38,7 +38,7 @@ impl Separator {
/// this is the width of the separator widget. /// this is the width of the separator widget.
#[inline] #[inline]
pub fn spacing(mut self, spacing: f32) -> Self { pub fn spacing(mut self, spacing: f32) -> Self {
self.spacing = spacing; self.spacing = Some(spacing);
self self
} }
@@ -88,7 +88,7 @@ impl Separator {
impl Widget for Separator { impl Widget for Separator {
fn ui(self, ui: &mut Ui) -> Response { fn ui(self, ui: &mut Ui) -> Response {
let Self { let Self {
mut spacing, spacing,
grow, grow,
is_horizontal_line, is_horizontal_line,
} = self; } = self;
@@ -100,9 +100,7 @@ impl Widget for Separator {
let style = ui.style().separator_style(state); let style = ui.style().separator_style(state);
// override the spacing if not set // override the spacing if not set
if spacing == 0.0 && style.spacing != 0.0 { let spacing = spacing.unwrap_or(style.spacing);
spacing = style.spacing;
}
let is_horizontal_line = is_horizontal_line let is_horizontal_line = is_horizontal_line
.unwrap_or_else(|| ui.is_grid() || !ui.layout().main_dir().is_horizontal()); .unwrap_or_else(|| ui.is_grid() || !ui.layout().main_dir().is_horizontal());