Skip to content

Commit 79cfdd0

Browse files
authored
Fix widgets to not stroke outside the paint_rects. (#861)
Fixes #628.
1 parent d8b6e14 commit 79cfdd0

File tree

8 files changed

+54
-36
lines changed

8 files changed

+54
-36
lines changed

druid/src/widget/button.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,10 @@ impl<T: Data> Widget<T> for Button<T> {
114114
let is_active = ctx.is_active();
115115
let is_hot = ctx.is_hot();
116116
let size = ctx.size();
117+
let stroke_width = env.get(theme::BUTTON_BORDER_WIDTH);
117118

118119
let rounded_rect = Rect::from_origin_size(Point::ORIGIN, size)
120+
.inset(-stroke_width / 2.0)
119121
.to_rounded_rect(env.get(theme::BUTTON_BORDER_RADIUS));
120122

121123
let bg_gradient = if is_active {
@@ -138,11 +140,7 @@ impl<T: Data> Widget<T> for Button<T> {
138140
env.get(theme::BORDER_DARK)
139141
};
140142

141-
ctx.stroke(
142-
rounded_rect,
143-
&border_color,
144-
env.get(theme::BUTTON_BORDER_WIDTH),
145-
);
143+
ctx.stroke(rounded_rect, &border_color, stroke_width);
146144

147145
ctx.fill(rounded_rect, &bg_gradient);
148146

druid/src/widget/checkbox.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
//! A checkbox widget.
1616
17-
use crate::kurbo::{BezPath, Point, Rect, RoundedRect, Size};
17+
use crate::kurbo::{BezPath, Point, Rect, Size};
1818
use crate::piet::{LineCap, LineJoin, LinearGradient, RenderContext, StrokeStyle, UnitPoint};
1919
use crate::theme;
2020
use crate::widget::{Label, LabelText};
@@ -94,9 +94,12 @@ impl Widget<bool> for Checkbox {
9494

9595
fn paint(&mut self, ctx: &mut PaintCtx, data: &bool, env: &Env) {
9696
let size = env.get(theme::BASIC_WIDGET_HEIGHT);
97+
let border_width = 1.;
9798

98-
let rect =
99-
RoundedRect::from_origin_size(Point::ORIGIN, Size::new(size, size).to_vec2(), 2.);
99+
let rect = Size::new(size, size)
100+
.to_rect()
101+
.inset(-border_width / 2.)
102+
.to_rounded_rect(2.);
100103

101104
//Paint the background
102105
let background_gradient = LinearGradient::new(
@@ -116,7 +119,7 @@ impl Widget<bool> for Checkbox {
116119
env.get(theme::BORDER_DARK)
117120
};
118121

119-
ctx.stroke(rect, &border_color, 1.);
122+
ctx.stroke(rect, &border_color, border_width);
120123

121124
if *data {
122125
// Paint the checkmark

druid/src/widget/painter.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ use crate::{
6464
/// const STROKE_WIDTH: f64 = 2.0;
6565
///
6666
/// let colorwell: Painter<Color> = Painter::new(|ctx, data: &Color, env| {
67-
/// let bounds = ctx.size().to_rect();
67+
/// // Shrink the bounds a little, to ensure that our stroke remains within
68+
/// // the paint bounds.
69+
/// let bounds = ctx.size().to_rect().inset(-STROKE_WIDTH / 2.0);
6870
/// let rounded = bounds.to_rounded_rect(CORNER_RADIUS);
6971
/// ctx.fill(rounded, data);
7072
/// ctx.stroke(rounded, &env.get(druid::theme::PRIMARY_DARK), STROKE_WIDTH);

druid/src/widget/progress_bar.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
//! A progress bar widget.
1616
17-
use crate::kurbo::{Point, RoundedRect, Size};
17+
use crate::kurbo::{Point, Rect, Size};
1818
use crate::theme;
1919
use crate::{
2020
BoxConstraints, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, LinearGradient,
@@ -59,19 +59,21 @@ impl Widget<f64> for ProgressBar {
5959

6060
fn paint(&mut self, ctx: &mut PaintCtx, data: &f64, env: &Env) {
6161
let clamped = data.max(0.0).min(1.0);
62+
let stroke_width = 2.0;
6263

63-
let rounded_rect = RoundedRect::from_origin_size(
64+
let rounded_rect = Rect::from_origin_size(
6465
Point::ORIGIN,
6566
(Size {
6667
width: ctx.size().width,
6768
height: env.get(theme::BASIC_WIDGET_HEIGHT),
6869
})
6970
.to_vec2(),
70-
4.,
71-
);
71+
)
72+
.inset(-stroke_width / 2.0)
73+
.to_rounded_rect(4.0);
7274

7375
//Paint the border
74-
ctx.stroke(rounded_rect, &env.get(theme::BORDER_DARK), 2.0);
76+
ctx.stroke(rounded_rect, &env.get(theme::BORDER_DARK), stroke_width);
7577

7678
//Paint the background
7779
let background_gradient = LinearGradient::new(
@@ -86,15 +88,16 @@ impl Widget<f64> for ProgressBar {
8688

8789
//Paint the bar
8890
let calculated_bar_width = clamped * rounded_rect.width();
89-
let rounded_rect = RoundedRect::from_origin_size(
91+
let rounded_rect = Rect::from_origin_size(
9092
Point::ORIGIN,
9193
(Size {
9294
width: calculated_bar_width,
9395
height: env.get(theme::BASIC_WIDGET_HEIGHT),
9496
})
9597
.to_vec2(),
96-
env.get(theme::PROGRESS_BAR_RADIUS),
97-
);
98+
)
99+
.inset(-stroke_width / 2.0)
100+
.to_rounded_rect(env.get(theme::PROGRESS_BAR_RADIUS));
98101
let bar_gradient = LinearGradient::new(
99102
UnitPoint::TOP,
100103
UnitPoint::BOTTOM,

druid/src/widget/scroll.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,15 +253,19 @@ impl<T, W: Widget<T>> Scroll<T, W> {
253253

254254
// Vertical bar
255255
if viewport.height() < self.child_size.height {
256-
let bounds = self.calc_vertical_bar_bounds(viewport, env);
256+
let bounds = self
257+
.calc_vertical_bar_bounds(viewport, env)
258+
.inset(-edge_width / 2.0);
257259
let rect = RoundedRect::from_rect(bounds, radius);
258260
ctx.render_ctx.fill(rect, &brush);
259261
ctx.render_ctx.stroke(rect, &border_brush, edge_width);
260262
}
261263

262264
// Horizontal bar
263265
if viewport.width() < self.child_size.width {
264-
let bounds = self.calc_horizontal_bar_bounds(viewport, env);
266+
let bounds = self
267+
.calc_horizontal_bar_bounds(viewport, env)
268+
.inset(-edge_width / 2.0);
265269
let rect = RoundedRect::from_rect(bounds, radius);
266270
ctx.render_ctx.fill(rect, &brush);
267271
ctx.render_ctx.stroke(rect, &border_brush, edge_width);

druid/src/widget/slider.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
//! A slider widget.
1616
17-
use crate::kurbo::{Circle, Point, Rect, RoundedRect, Shape, Size};
17+
use crate::kurbo::{Circle, Point, Rect, Shape, Size};
1818
use crate::theme;
1919
use crate::{
2020
BoxConstraints, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, LinearGradient,
@@ -138,13 +138,16 @@ impl Widget<f64> for Slider {
138138
let rect = Rect::from_origin_size(Point::ORIGIN, ctx.size());
139139
let knob_size = env.get(theme::BASIC_WIDGET_HEIGHT);
140140
let track_thickness = 4.;
141+
let border_width = 2.;
142+
let knob_stroke_width = 2.;
141143

142144
//Paint the background
143145
let background_width = rect.width() - knob_size;
144146
let background_origin = Point::new(knob_size / 2., (knob_size - track_thickness) / 2.);
145147
let background_size = Size::new(background_width, track_thickness);
146-
let background_rect =
147-
RoundedRect::from_origin_size(background_origin, background_size.to_vec2(), 2.);
148+
let background_rect = Rect::from_origin_size(background_origin, background_size)
149+
.inset(-border_width / 2.)
150+
.to_rounded_rect(2.);
148151

149152
let background_gradient = LinearGradient::new(
150153
UnitPoint::TOP,
@@ -155,7 +158,7 @@ impl Widget<f64> for Slider {
155158
),
156159
);
157160

158-
ctx.stroke(background_rect, &env.get(theme::BORDER_DARK), 2.0);
161+
ctx.stroke(background_rect, &env.get(theme::BORDER_DARK), border_width);
159162

160163
ctx.fill(background_rect, &background_gradient);
161164

@@ -165,7 +168,7 @@ impl Widget<f64> for Slider {
165168

166169
let knob_position = (rect.width() - knob_size) * clamped + knob_size / 2.;
167170
self.knob_pos = Point::new(knob_position, knob_size / 2.);
168-
let knob_circle = Circle::new(self.knob_pos, knob_size / 2.);
171+
let knob_circle = Circle::new(self.knob_pos, (knob_size - knob_stroke_width) / 2.);
169172

170173
let normal_knob_gradient = LinearGradient::new(
171174
UnitPoint::TOP,
@@ -197,7 +200,7 @@ impl Widget<f64> for Slider {
197200
env.get(theme::FOREGROUND_DARK)
198201
};
199202

200-
ctx.stroke(knob_circle, &border_color, 2.);
203+
ctx.stroke(knob_circle, &border_color, knob_stroke_width);
201204

202205
//Actually paint the knob
203206
ctx.fill(knob_circle, &knob_gradient);

druid/src/widget/stepper.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use std::f64::EPSILON;
1818
use std::time::Duration;
1919

20-
use crate::kurbo::{BezPath, Rect, RoundedRect};
20+
use crate::kurbo::{BezPath, Rect};
2121
use crate::piet::{LinearGradient, RenderContext, UnitPoint};
2222
use crate::{
2323
BoxConstraints, Env, Event, EventCtx, LayoutCtx, LifeCycle, LifeCycleCtx, PaintCtx, Size,
@@ -120,13 +120,18 @@ impl Default for Stepper {
120120

121121
impl Widget<f64> for Stepper {
122122
fn paint(&mut self, ctx: &mut PaintCtx, _data: &f64, env: &Env) {
123-
let rounded_rect = RoundedRect::from_origin_size(Point::ORIGIN, ctx.size().to_vec2(), 4.);
123+
let stroke_width = 2.0;
124+
let rounded_rect = ctx
125+
.size()
126+
.to_rect()
127+
.inset(-stroke_width / 2.0)
128+
.to_rounded_rect(4.0);
124129

125130
let height = ctx.size().height;
126131
let width = env.get(theme::BASIC_WIDGET_HEIGHT);
127132
let button_size = Size::new(width, height / 2.);
128133

129-
ctx.stroke(rounded_rect, &env.get(theme::BORDER_DARK), 2.0);
134+
ctx.stroke(rounded_rect, &env.get(theme::BORDER_DARK), stroke_width);
130135
ctx.clip(rounded_rect);
131136

132137
// draw buttons for increase/decrease

druid/src/widget/switch.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
//! A toggle switch widget.
1616
17-
use crate::kurbo::{Circle, Point, Rect, RoundedRect, Shape, Size};
17+
use crate::kurbo::{Circle, Point, Rect, Shape, Size};
1818
use crate::piet::{
1919
FontBuilder, LinearGradient, RenderContext, Text, TextLayout, TextLayoutBuilder, UnitPoint,
2020
};
@@ -201,12 +201,12 @@ impl Widget<bool> for Switch {
201201
let knob_size = switch_height - 2. * SWITCH_PADDING;
202202
let on_pos = switch_width - knob_size / 2. - SWITCH_PADDING;
203203
let off_pos = knob_size / 2. + SWITCH_PADDING;
204+
let stroke_width = 2.0;
204205

205-
let background_rect = RoundedRect::from_origin_size(
206-
Point::ORIGIN,
207-
Size::new(switch_width, switch_height).to_vec2(),
208-
switch_height / 2.,
209-
);
206+
let background_rect = Size::new(switch_width, switch_height)
207+
.to_rect()
208+
.inset(-stroke_width / 2.0)
209+
.to_rounded_rect(switch_height / 2.);
210210

211211
// position knob
212212
if !self.animation_in_progress && !self.knob_dragged {
@@ -242,7 +242,7 @@ impl Widget<bool> for Switch {
242242
),
243243
);
244244

245-
ctx.stroke(background_rect, &env.get(theme::BORDER_DARK), 2.0);
245+
ctx.stroke(background_rect, &env.get(theme::BORDER_DARK), stroke_width);
246246
ctx.fill(background_rect, &background_gradient_on_state);
247247
ctx.fill(background_rect, &background_gradient_off_state);
248248
ctx.clip(background_rect);

0 commit comments

Comments
 (0)