From 6d8a7666140ad5ff507999a645683bdfe00cdf55 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 12 Jan 2021 20:50:54 +0100 Subject: [PATCH] [style] Slightly expand buttons when hovering and interacting --- egui/src/containers/collapsing_header.rs | 14 +++++++++----- egui/src/containers/combo_box.rs | 4 ++-- egui/src/containers/window.rs | 6 +++--- egui/src/style.rs | 12 +++++++++++- egui/src/widgets/button.rs | 14 +++++++++----- egui/src/widgets/color_picker.rs | 1 + egui/src/widgets/selected_label.rs | 1 + egui/src/widgets/slider.rs | 9 ++++++--- egui/src/widgets/text_edit.rs | 2 +- egui_demo_lib/src/apps/demo/toggle_switch.rs | 2 ++ 10 files changed, 45 insertions(+), 20 deletions(-) diff --git a/egui/src/containers/collapsing_header.rs b/egui/src/containers/collapsing_header.rs index 987390f9..477dec69 100644 --- a/egui/src/containers/collapsing_header.rs +++ b/egui/src/containers/collapsing_header.rs @@ -106,12 +106,14 @@ impl State { /// Paint the arrow icon that indicated if the region is open or not pub(crate) fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) { - let stroke = ui.style().interact(response).fg_stroke; + let visuals = ui.style().interact(response); + let stroke = visuals.fg_stroke; let rect = response.rect; // Draw a pointy triangle arrow: let rect = Rect::from_center_size(rect.center(), vec2(rect.width(), rect.height()) * 0.75); + let rect = rect.expand(visuals.expansion); let mut points = vec![rect.left_top(), rect.right_top(), rect.center_bottom()]; use std::f32::consts::TAU; let rotation = math::Rot2::from_angle(remap(openness, 0.0..=1.0, -TAU / 4.0..=0.0)); @@ -203,10 +205,12 @@ impl CollapsingHeader { state.toggle(ui); } + let visuals = ui.style().interact(&header_response); + let text_color = visuals.text_color(); ui.painter().add(Shape::Rect { - rect: header_response.rect, - corner_radius: ui.style().interact(&header_response).corner_radius, - fill: ui.style().interact(&header_response).bg_fill, + rect: header_response.rect.expand(visuals.expansion), + corner_radius: visuals.corner_radius, + fill: visuals.bg_fill, stroke: Default::default(), }); @@ -228,7 +232,7 @@ impl CollapsingHeader { text_pos, galley, label.text_style_or_default(ui.style()), - ui.style().interact(&header_response).text_color(), + text_color, ); Prepared { diff --git a/egui/src/containers/combo_box.rs b/egui/src/containers/combo_box.rs index 1845e440..a4222c89 100644 --- a/egui/src/containers/combo_box.rs +++ b/egui/src/containers/combo_box.rs @@ -79,7 +79,7 @@ pub fn combo_box( let icon_rect = Align2::RIGHT_CENTER.align_size_within_rect(icon_size, rect); let visuals = ui.style().interact(&response); - paint_icon(ui.painter(), icon_rect, visuals); + paint_icon(ui.painter(), icon_rect.expand(visuals.expansion), visuals); let text_rect = Align2::LEFT_CENTER.align_size_within_rect(galley.size, rect); ui.painter() @@ -145,7 +145,7 @@ fn button_frame( ui.painter().set( where_to_put_background, Shape::Rect { - rect: outer_rect, + rect: outer_rect.expand(visuals.expansion), corner_radius: visuals.corner_radius, fill: visuals.bg_fill, stroke: visuals.bg_stroke, diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs index b00cf7f9..b160b918 100644 --- a/egui/src/containers/window.rs +++ b/egui/src/containers/window.rs @@ -767,9 +767,9 @@ fn close_button(ui: &mut Ui, rect: Rect) -> Response { let response = ui.interact(rect, close_id, Sense::click()); ui.expand_to_include_rect(response.rect); - let rect = rect.shrink(2.0); - - let stroke = ui.style().interact(&response).fg_stroke; + let visuals = ui.style().interact(&response); + let rect = rect.shrink(2.0).expand(visuals.expansion); + let stroke = visuals.fg_stroke; ui.painter() .line_segment([rect.left_top(), rect.right_bottom()], stroke); ui.painter() diff --git a/egui/src/style.rs b/egui/src/style.rs index 327e29ad..79714206 100644 --- a/egui/src/style.rs +++ b/egui/src/style.rs @@ -227,6 +227,9 @@ pub struct WidgetVisuals { /// Stroke and text color of the interactive part of a component (button text, slider grab, check-mark, ...) pub fg_stroke: Stroke, + + /// Make the frame this much larger + pub expansion: f32, } impl WidgetVisuals { @@ -287,7 +290,7 @@ impl Default for Visuals { window_shadow: Shadow::big(), resize_corner_size: 12.0, text_cursor_width: 2.0, - clip_rect_margin: 1.0, // should be half the size of the widest frame stroke + clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion debug_expand_width: false, debug_expand_height: false, debug_resize: false, @@ -316,6 +319,7 @@ impl Default for Widgets { corner_radius: 4.0, fg_fill: Color32::from_rgb(120, 120, 200), fg_stroke: Stroke::new(2.0, Color32::WHITE), + expansion: 2.0, }, hovered: WidgetVisuals { bg_fill: Rgba::from_luminance_alpha(0.06, 0.5).into(), @@ -323,6 +327,7 @@ impl Default for Widgets { corner_radius: 4.0, fg_fill: Color32::from_rgb(100, 100, 150), fg_stroke: Stroke::new(1.5, Color32::from_gray(240)), + expansion: 1.0, }, inactive: WidgetVisuals { bg_fill: Rgba::from_luminance_alpha(0.04, 0.5).into(), @@ -330,6 +335,7 @@ impl Default for Widgets { corner_radius: 4.0, fg_fill: Color32::from_rgb(60, 60, 80), fg_stroke: Stroke::new(1.0, Color32::from_gray(200)), // Should NOT look grayed out! + expansion: 0.0, }, disabled: WidgetVisuals { bg_fill: Rgba::from_luminance_alpha(0.02, 0.5).into(), @@ -337,6 +343,7 @@ impl Default for Widgets { corner_radius: 4.0, fg_fill: Color32::from_rgb(50, 50, 50), fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // Should look grayed out + expansion: 0.0, }, noninteractive: WidgetVisuals { bg_stroke: Stroke::new(1.0, Rgba::from_white_alpha(0.06)), @@ -344,6 +351,7 @@ impl Default for Widgets { corner_radius: 4.0, fg_fill: Default::default(), fg_stroke: Stroke::new(1.0, Color32::from_gray(160)), // text color + expansion: 0.0, }, } } @@ -460,6 +468,7 @@ impl WidgetVisuals { corner_radius, fg_fill, fg_stroke, + expansion, } = self; ui_color(ui, bg_fill, "bg_fill"); @@ -467,6 +476,7 @@ impl WidgetVisuals { ui.add(Slider::f32(corner_radius, 0.0..=10.0).text("corner_radius")); ui_color(ui, fg_fill, "fg_fill"); stroke_ui(ui, fg_stroke, "fg_stroke (text)"); + ui.add(Slider::f32(expansion, -5.0..=5.0).text("expansion")); } } diff --git a/egui/src/widgets/button.rs b/egui/src/widgets/button.rs index 5b7ce421..25d38c56 100644 --- a/egui/src/widgets/button.rs +++ b/egui/src/widgets/button.rs @@ -117,8 +117,12 @@ impl Widget for Button { if frame { let fill = fill.unwrap_or(visuals.bg_fill); - ui.painter() - .rect(rect, visuals.corner_radius, fill, visuals.bg_stroke); + ui.painter().rect( + rect.expand(visuals.expansion), + visuals.corner_radius, + fill, + visuals.bg_stroke, + ); } let text_color = text_color @@ -198,7 +202,7 @@ impl<'a> Widget for Checkbox<'a> { ); let (small_icon_rect, big_icon_rect) = ui.style().spacing.icon_rectangles(rect); ui.painter().add(Shape::Rect { - rect: big_icon_rect, + rect: big_icon_rect.expand(visuals.expansion), corner_radius: visuals.corner_radius, fill: visuals.bg_fill, stroke: visuals.bg_stroke, @@ -292,7 +296,7 @@ impl Widget for RadioButton { painter.add(Shape::Circle { center: big_icon_rect.center(), - radius: big_icon_rect.width() / 2.0, + radius: big_icon_rect.width() / 2.0 + visuals.expansion, fill: visuals.bg_fill, stroke: visuals.bg_stroke, }); @@ -392,7 +396,7 @@ impl Widget for ImageButton { .rect(rect, 0.0, selection.bg_fill, selection.stroke); } else if frame { ui.painter().rect( - rect, + rect.expand(visuals.expansion), visuals.corner_radius, visuals.bg_fill, visuals.bg_stroke, diff --git a/egui/src/widgets/color_picker.rs b/egui/src/widgets/color_picker.rs index c3726f32..9c1ab14e 100644 --- a/egui/src/widgets/color_picker.rs +++ b/egui/src/widgets/color_picker.rs @@ -60,6 +60,7 @@ fn color_button(ui: &mut Ui, color: Color32) -> Response { let desired_size = ui.style().spacing.interact_size; let (rect, response) = ui.allocate_at_least(desired_size, Sense::click()); let visuals = ui.style().interact(&response); + let rect = rect.expand(visuals.expansion); background_checkers(ui.painter(), rect); ui.painter().add(Shape::Rect { rect, diff --git a/egui/src/widgets/selected_label.rs b/egui/src/widgets/selected_label.rs index ebd734c8..e323bca1 100644 --- a/egui/src/widgets/selected_label.rs +++ b/egui/src/widgets/selected_label.rs @@ -43,6 +43,7 @@ impl Widget for SelectableLabel { let visuals = ui.style().interact(&response); if selected || response.hovered { + let rect = rect.expand(visuals.expansion); let bg_fill = if selected { ui.style().visuals.selection.bg_fill } else { diff --git a/egui/src/widgets/slider.rs b/egui/src/widgets/slider.rs index d3aae681..254b14e6 100644 --- a/egui/src/widgets/slider.rs +++ b/egui/src/widgets/slider.rs @@ -278,18 +278,21 @@ impl<'a> Slider<'a> { ); let marker_center_x = self.x_from_value(value, x_range); + let visuals = ui.style().interact(response); ui.painter().add(Shape::Rect { rect: rail_rect, corner_radius: rail_radius, + // fill: visuals.bg_fill, fill: ui.style().visuals.widgets.inactive.bg_fill, + // stroke: visuals.bg_stroke, stroke: ui.style().visuals.widgets.inactive.bg_stroke, }); ui.painter().add(Shape::Circle { center: pos2(marker_center_x, rail_rect.center().y), - radius: handle_radius(rect), - fill: ui.style().interact(response).fg_fill, - stroke: ui.style().interact(response).fg_stroke, + radius: handle_radius(rect) + visuals.expansion, + fill: visuals.fg_fill, + stroke: visuals.fg_stroke, }); } } diff --git a/egui/src/widgets/text_edit.rs b/egui/src/widgets/text_edit.rs index b90c2e2b..dc6ee9bf 100644 --- a/egui/src/widgets/text_edit.rs +++ b/egui/src/widgets/text_edit.rs @@ -228,7 +228,7 @@ impl<'t> Widget for TextEdit<'t> { let response = response | ui.allocate_response(frame_rect.size(), Sense::click()); let visuals = ui.style().interact(&response); - let frame_rect = response.rect; + let frame_rect = response.rect.expand(visuals.expansion); ui.painter().set( where_to_put_background, Shape::Rect { diff --git a/egui_demo_lib/src/apps/demo/toggle_switch.rs b/egui_demo_lib/src/apps/demo/toggle_switch.rs index f7951230..060235a4 100644 --- a/egui_demo_lib/src/apps/demo/toggle_switch.rs +++ b/egui_demo_lib/src/apps/demo/toggle_switch.rs @@ -44,6 +44,7 @@ pub fn toggle(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { let on_bg_fill = egui::Rgba::from_rgb(0.0, 0.5, 0.25); let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on); // All coordinates are in absolute screen coordinates so we use `rect` to place the elements. + let rect = rect.expand(visuals.expansion); let radius = 0.5 * rect.height(); ui.painter().rect(rect, radius, bg_fill, visuals.bg_stroke); // Paint the circle, animating it from left to right with `how_on`: @@ -69,6 +70,7 @@ fn toggle_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { let off_bg_fill = egui::Rgba::TRANSPARENT; let on_bg_fill = egui::Rgba::from_rgb(0.0, 0.5, 0.25); let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on); + let rect = rect.expand(visuals.expansion); let radius = 0.5 * rect.height(); ui.painter().rect(rect, radius, bg_fill, visuals.bg_stroke); let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on);