Skip to content

Commit

Permalink
Require a StrokeKind when painting rectangles with strokes (#5648)
Browse files Browse the repository at this point in the history
This is a breaking change, requiring users to think about wether the
stroke is inside/centered/outside the rect.

When in doubt, add `egui::StrokeKind::Inside` to the function call.
  • Loading branch information
emilk authored Jan 29, 2025
1 parent 8d2c8c2 commit 525d435
Show file tree
Hide file tree
Showing 35 changed files with 184 additions and 73 deletions.
12 changes: 9 additions & 3 deletions crates/egui/src/containers/collapsing_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
Response, Sense, Stroke, TextStyle, TextWrapMode, Ui, Vec2, WidgetInfo, WidgetText, WidgetType,
};
use emath::GuiRounding as _;
use epaint::Shape;
use epaint::{Shape, StrokeKind};

#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
Expand Down Expand Up @@ -576,15 +576,21 @@ impl CollapsingHeader {
visuals.rounding,
visuals.weak_bg_fill,
visuals.bg_stroke,
StrokeKind::Inside,
));
}

if selected || selectable && (header_response.hovered() || header_response.has_focus())
{
let rect = rect.expand(visuals.expansion);

ui.painter()
.rect(rect, visuals.rounding, visuals.bg_fill, visuals.bg_stroke);
ui.painter().rect(
rect,
visuals.rounding,
visuals.bg_fill,
visuals.bg_stroke,
StrokeKind::Inside,
);
}

{
Expand Down
1 change: 1 addition & 0 deletions crates/egui/src/containers/combo_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ fn button_frame(
visuals.rounding,
visuals.weak_bg_fill,
visuals.bg_stroke,
epaint::StrokeKind::Inside,
),
);
}
Expand Down
11 changes: 7 additions & 4 deletions crates/egui/src/containers/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,13 @@ impl Frame {
let fill_rect = self.fill_rect(content_rect);
let widget_rect = self.widget_rect(content_rect);

let frame_shape = Shape::Rect(
epaint::RectShape::new(fill_rect, rounding, fill, stroke)
.with_stroke_kind(epaint::StrokeKind::Outside),
);
let frame_shape = Shape::Rect(epaint::RectShape::new(
fill_rect,
rounding,
fill,
stroke,
epaint::StrokeKind::Outside,
));

if shadow == Default::default() {
frame_shape
Expand Down
1 change: 1 addition & 0 deletions crates/egui/src/containers/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ impl Resize {
rect,
3.0,
ui.visuals().widgets.noninteractive.bg_stroke,
epaint::StrokeKind::Inside,
));
}

Expand Down
4 changes: 2 additions & 2 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use epaint::{
tessellator,
text::{FontInsert, FontPriority, Fonts},
util::OrderedFloat,
vec2, ClippedPrimitive, ClippedShape, Color32, ImageData, ImageDelta, Pos2, Rect,
vec2, ClippedPrimitive, ClippedShape, Color32, ImageData, ImageDelta, Pos2, Rect, StrokeKind,
TessellationOptions, TextureAtlas, TextureId, Vec2,
};

Expand Down Expand Up @@ -1087,7 +1087,7 @@ impl Context {
let text = format!("🔥 {text}");
let color = self.style().visuals.error_fg_color;
let painter = self.debug_painter();
painter.rect_stroke(widget_rect, 0.0, (1.0, color));
painter.rect_stroke(widget_rect, 0.0, (1.0, color), StrokeKind::Outside);

let below = widget_rect.bottom() + 32.0 < screen_rect.bottom();

Expand Down
7 changes: 6 additions & 1 deletion crates/egui/src/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,12 @@ impl GridLayout {

if (debug_expand_width && too_wide) || (debug_expand_height && too_high) {
let painter = self.ctx.debug_painter();
painter.rect_stroke(rect, 0.0, (1.0, Color32::LIGHT_BLUE));
painter.rect_stroke(
rect,
0.0,
(1.0, Color32::LIGHT_BLUE),
crate::StrokeKind::Inside,
);

let stroke = Stroke::new(2.5, Color32::from_rgb(200, 0, 0));
let paint_line_seg = |a, b| painter.line_segment([a, b], stroke);
Expand Down
2 changes: 1 addition & 1 deletion crates/egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ pub use epaint::{
text::{FontData, FontDefinitions, FontFamily, FontId, FontTweak},
textures::{TextureFilter, TextureOptions, TextureWrapMode, TexturesDelta},
ClippedPrimitive, ColorImage, FontImage, ImageData, Margin, Mesh, PaintCallback,
PaintCallbackInfo, Rounding, Shadow, Shape, Stroke, TextureHandle, TextureId,
PaintCallbackInfo, Rounding, Shadow, Shape, Stroke, StrokeKind, TextureHandle, TextureId,
};

pub mod text {
Expand Down
17 changes: 13 additions & 4 deletions crates/egui/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;
use emath::GuiRounding as _;
use epaint::{
text::{Fonts, Galley, LayoutJob},
CircleShape, ClippedShape, PathStroke, RectShape, Rounding, Shape, Stroke,
CircleShape, ClippedShape, PathStroke, RectShape, Rounding, Shape, Stroke, StrokeKind,
};

use crate::{
Expand Down Expand Up @@ -301,6 +301,7 @@ impl Painter {
0.0,
color.additive().linear_multiply(0.015),
(1.0, color),
StrokeKind::Outside,
);
self.text(
rect.min,
Expand Down Expand Up @@ -407,15 +408,22 @@ impl Painter {
})
}

/// The stroke extends _outside_ the [`Rect`].
/// See also [`Self::rect_filled`] and [`Self::rect_stroke`].
pub fn rect(
&self,
rect: Rect,
rounding: impl Into<Rounding>,
fill_color: impl Into<Color32>,
stroke: impl Into<Stroke>,
stroke_kind: StrokeKind,
) -> ShapeIdx {
self.add(RectShape::new(rect, rounding, fill_color, stroke))
self.add(RectShape::new(
rect,
rounding,
fill_color,
stroke,
stroke_kind,
))
}

pub fn rect_filled(
Expand All @@ -433,8 +441,9 @@ impl Painter {
rect: Rect,
rounding: impl Into<Rounding>,
stroke: impl Into<Stroke>,
stroke_kind: StrokeKind,
) -> ShapeIdx {
self.add(RectShape::stroke(rect, rounding, stroke))
self.add(RectShape::stroke(rect, rounding, stroke, stroke_kind))
}

/// Show an arrow starting at `origin` and going in the direction of `vec`, with the length `vec.length()`.
Expand Down
16 changes: 14 additions & 2 deletions crates/egui/src/pass_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,13 @@ impl DebugRect {
Color32::LIGHT_BLUE
};
let rect_bg_color = Color32::BLUE.gamma_multiply(0.5);
painter.rect(rect, 0.0, rect_bg_color, (1.0, rect_fg_color));
painter.rect(
rect,
0.0,
rect_bg_color,
(1.0, rect_fg_color),
crate::StrokeKind::Outside,
);
}

if !callstack.is_empty() {
Expand Down Expand Up @@ -157,7 +163,13 @@ impl DebugRect {
text_bg_color
};
let text_rect = Rect::from_min_size(text_pos, galley.size());
painter.rect(text_rect, 0.0, text_bg_color, (1.0, text_rect_stroke_color));
painter.rect(
text_rect,
0.0,
text_bg_color,
(1.0, text_rect_stroke_color),
crate::StrokeKind::Middle,
);
painter.galley(text_pos, galley, text_color);

if is_clicking {
Expand Down
2 changes: 1 addition & 1 deletion crates/egui/src/placer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ impl Placer {

if let Some(grid) = &self.grid {
let rect = grid.next_cell(self.cursor(), Vec2::splat(0.0));
painter.rect_stroke(rect, 1.0, stroke);
painter.rect_stroke(rect, 1.0, stroke, epaint::StrokeKind::Inside);
let align = Align2::CENTER_CENTER;
painter.debug_text(align.pos_in_rect(&rect), align, stroke.color, text);
} else {
Expand Down
10 changes: 7 additions & 3 deletions crates/egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1186,7 +1186,7 @@ impl Ui {
/// # egui::__run_test_ui(|ui| {
/// let response = ui.allocate_response(egui::vec2(100.0, 200.0), egui::Sense::click());
/// if response.clicked() { /* … */ }
/// ui.painter().rect_stroke(response.rect, 0.0, (1.0, egui::Color32::WHITE));
/// ui.painter().rect_stroke(response.rect, 0.0, (1.0, egui::Color32::WHITE), egui::StrokeKind::Inside);
/// # });
/// ```
pub fn allocate_response(&mut self, desired_size: Vec2, sense: Sense) -> Response {
Expand Down Expand Up @@ -1253,8 +1253,12 @@ impl Ui {
let debug_expand_height = self.style().debug.show_expand_height;

if (debug_expand_width && too_wide) || (debug_expand_height && too_high) {
self.painter
.rect_stroke(rect, 0.0, (1.0, Color32::LIGHT_BLUE));
self.painter.rect_stroke(
rect,
0.0,
(1.0, Color32::LIGHT_BLUE),
crate::StrokeKind::Inside,
);

let stroke = Stroke::new(2.5, Color32::from_rgb(200, 0, 0));
let paint_line_seg = |a, b| self.painter().line_segment([a, b], stroke);
Expand Down
1 change: 1 addition & 0 deletions crates/egui/src/widgets/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ impl Widget for Button<'_> {
frame_rounding,
frame_fill,
frame_stroke,
epaint::StrokeKind::Inside,
);

let mut cursor_x = rect.min.x + button_padding.x;
Expand Down
1 change: 1 addition & 0 deletions crates/egui/src/widgets/checkbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ impl Widget for Checkbox<'_> {
visuals.rounding,
visuals.bg_fill,
visuals.bg_stroke,
epaint::StrokeKind::Inside,
));

if indeterminate {
Expand Down
19 changes: 13 additions & 6 deletions crates/egui/src/widgets/color_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
};
use epaint::{
ecolor::{Color32, Hsva, HsvaGamma, Rgba},
pos2, vec2, Mesh, Rect, Shape, Stroke, Vec2,
pos2, vec2, Mesh, Rect, Shape, Stroke, StrokeKind, Vec2,
};

fn contrast_color(color: impl Into<Rgba>) -> Color32 {
Expand Down Expand Up @@ -97,11 +97,16 @@ fn color_button(ui: &mut Ui, color: Color32, open: bool) -> Response {
};
let rect = rect.expand(visuals.expansion);

show_color_at(ui.painter(), color, rect);
let stroke_width = 1.0;
show_color_at(ui.painter(), color, rect.shrink(stroke_width));

let rounding = visuals.rounding.at_most(2); // Can't do more rounding because the background grid doesn't do any rounding
ui.painter()
.rect_stroke(rect, rounding, (2.0, visuals.bg_fill)); // fill is intentional, because default style has no border
ui.painter().rect_stroke(
rect,
rounding,
(stroke_width, visuals.bg_fill), // Using fill for stroke is intentional, because default style has no border
StrokeKind::Inside,
);
}

response
Expand Down Expand Up @@ -139,7 +144,8 @@ fn color_slider_1d(ui: &mut Ui, value: &mut f32, color_at: impl Fn(f32) -> Color
ui.painter().add(Shape::mesh(mesh));
}

ui.painter().rect_stroke(rect, 0.0, visuals.bg_stroke); // outline
ui.painter()
.rect_stroke(rect, 0.0, visuals.bg_stroke, StrokeKind::Inside); // outline

{
// Show where the slider is at:
Expand Down Expand Up @@ -208,7 +214,8 @@ fn color_slider_2d(
}
ui.painter().add(Shape::mesh(mesh)); // fill

ui.painter().rect_stroke(rect, 0.0, visuals.bg_stroke); // outline
ui.painter()
.rect_stroke(rect, 0.0, visuals.bg_stroke, StrokeKind::Inside); // outline

// Show where the slider is at:
let x = lerp(rect.left()..=rect.right(), *x_value);
Expand Down
8 changes: 6 additions & 2 deletions crates/egui/src/widgets/image_button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,12 @@ impl Widget for ImageButton<'_> {
);

// Draw frame outline:
ui.painter()
.rect_stroke(rect.expand2(expansion), rounding, stroke);
ui.painter().rect_stroke(
rect.expand2(expansion),
rounding,
stroke,
epaint::StrokeKind::Inside,
);
}

widgets::image::texture_load_result_response(&self.image.source(ui.ctx()), &tlr, response)
Expand Down
5 changes: 2 additions & 3 deletions crates/egui/src/widgets/progress_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ impl Widget for ProgressBar {
let corner_radius = outer_rect.height() / 2.0;
let rounding = rounding.unwrap_or_else(|| corner_radius.into());
ui.painter()
.rect(outer_rect, rounding, visuals.extreme_bg_color, Stroke::NONE);
.rect_filled(outer_rect, rounding, visuals.extreme_bg_color);
let min_width =
2.0 * f32::max(rounding.sw as _, rounding.nw as _).at_most(corner_radius);
let filled_width = (outer_rect.width() * progress).at_least(min_width);
Expand All @@ -152,13 +152,12 @@ impl Widget for ProgressBar {
bright
};

ui.painter().rect(
ui.painter().rect_filled(
inner_rect,
rounding,
Color32::from(
Rgba::from(fill.unwrap_or(visuals.selection.bg_fill)) * color_factor as f32,
),
Stroke::NONE,
);

if animate && !is_custom_rounding {
Expand Down
1 change: 1 addition & 0 deletions crates/egui/src/widgets/selected_label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ impl Widget for SelectableLabel {
visuals.rounding,
visuals.weak_bg_fill,
visuals.bg_stroke,
epaint::StrokeKind::Inside,
);
}

Expand Down
9 changes: 7 additions & 2 deletions crates/egui/src/widgets/slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,8 +815,13 @@ impl Slider<'_> {
};
let v = v + Vec2::splat(visuals.expansion);
let rect = Rect::from_center_size(center, 2.0 * v);
ui.painter()
.rect(rect, visuals.rounding, visuals.bg_fill, visuals.fg_stroke);
ui.painter().rect(
rect,
visuals.rounding,
visuals.bg_fill,
visuals.fg_stroke,
epaint::StrokeKind::Inside,
);
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion crates/egui/src/widgets/text_edit/builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::sync::Arc;

use emath::{Rect, TSTransform};
use epaint::text::{cursor::CCursor, Galley, LayoutJob};
use epaint::{
text::{cursor::CCursor, Galley, LayoutJob},
StrokeKind,
};

use crate::{
epaint,
Expand Down Expand Up @@ -442,13 +445,15 @@ impl TextEdit<'_> {
visuals.rounding,
background_color,
ui.visuals().selection.stroke,
StrokeKind::Inside,
)
} else {
epaint::RectShape::new(
frame_rect,
visuals.rounding,
background_color,
visuals.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop".
StrokeKind::Inside,
)
}
} else {
Expand All @@ -457,6 +462,7 @@ impl TextEdit<'_> {
frame_rect,
visuals.rounding,
visuals.bg_stroke, // TODO(emilk): we want to show something here, or a text-edit field doesn't "pop".
StrokeKind::Inside,
)
};

Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_app/src/frame_history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ impl FrameHistory {
style.rounding,
ui.visuals().extreme_bg_color,
ui.style().noninteractive().bg_stroke,
egui::StrokeKind::Inside,
)));

let rect = rect.shrink(4.0);
Expand Down
Loading

0 comments on commit 525d435

Please sign in to comment.