Skip to content

Commit 8b74155

Browse files
committed
Update toggle switch example and fix sizing
1 parent aa0b53b commit 8b74155

File tree

2 files changed

+85
-72
lines changed

2 files changed

+85
-72
lines changed

examples/switch.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,22 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use druid::widget::{
16-
Align, Button, Checkbox, Column, DynLabel, Label, Padding, ProgressBar, Row, Switch,
17-
};
15+
use druid::widget::{Column, Label, Padding, Row, Switch};
1816
use druid::{AppLauncher, Data, Lens, LensWrap, Widget, WindowDesc};
1917

2018
#[derive(Clone, Data, Lens)]
2119
struct DemoState {
22-
value: bool
20+
value: bool,
2321
}
2422

2523
fn build_widget() -> impl Widget<DemoState> {
2624
let mut col = Column::new();
27-
let label = DynLabel::new(|data: &DemoState, _env| {
28-
format!("value: {}", data.value)
29-
});
3025
let mut row = Row::new();
3126
let switch = LensWrap::new(Switch::new(), lenses::demo_state::value);
32-
let switch_label = Label::new("Enable");
27+
let switch_label = Label::new("Setting label");
3328

3429
row.add_child(Padding::uniform(5.0, switch_label), 0.0);
35-
row.add_child(Padding::uniform(5.0, switch), 1.0);
30+
row.add_child(Padding::uniform(5.0, switch), 0.0);
3631

3732
col.add_child(Padding::uniform(5.0, row), 1.0);
3833
col
@@ -42,8 +37,6 @@ fn main() {
4237
let window = WindowDesc::new(build_widget);
4338
AppLauncher::with_window(window)
4439
.use_simple_logger()
45-
.launch(DemoState {
46-
value: true
47-
})
40+
.launch(DemoState { value: true })
4841
.expect("launch failed");
4942
}

src/widget/switch.rs

Lines changed: 80 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@
1515
//! A toggle switch widget.
1616
1717
use crate::kurbo::{Circle, Point, Rect, RoundedRect, Size};
18+
use crate::piet::{FontBuilder, Text, TextLayout, TextLayoutBuilder};
1819
use crate::piet::{LinearGradient, RenderContext, UnitPoint};
1920
use crate::theme;
2021
use crate::widget::Align;
2122
use crate::{
2223
BaseState, BoxConstraints, Env, Event, EventCtx, LayoutCtx, PaintCtx, UpdateCtx, Widget,
2324
};
24-
use crate::piet::{
25-
FontBuilder, PietText, PietTextLayout, Text, TextLayout, TextLayoutBuilder,
26-
};
2725

2826
#[derive(Debug, Clone)]
2927
pub struct Switch;
3028

3129
impl Switch {
32-
pub fn new() -> impl Widget<bool> { Align::vertical(UnitPoint::CENTER, SwitchRaw::default()) }
30+
pub fn new() -> impl Widget<bool> {
31+
Align::vertical(UnitPoint::CENTER, SwitchRaw::default())
32+
}
3333
}
3434

3535
#[derive(Debug, Clone, Default)]
@@ -46,56 +46,34 @@ impl SwitchRaw {
4646
}
4747
false
4848
}
49-
}
5049

51-
impl Widget<bool> for SwitchRaw {
52-
fn paint(&mut self, paint_ctx: &mut PaintCtx, base_state: &BaseState, data: &bool, env: &Env) {
53-
let knob_size = env.get(theme::BASIC_WIDGET_HEIGHT);
54-
let size = env.get(theme::BASIC_WIDGET_HEIGHT);
55-
let switch_thickness = 8. + knob_size;
50+
fn paint_label(
51+
&mut self,
52+
paint_ctx: &mut PaintCtx,
53+
base_state: &BaseState,
54+
data: &bool,
55+
env: &Env,
56+
switch_width: f64,
57+
switch_padding: f64,
58+
) {
5659
let font_name = env.get(theme::FONT_NAME);
5760
let font_size = env.get(theme::TEXT_SIZE_NORMAL);
5861

59-
let background_rect =
60-
RoundedRect::from_origin_size(Point::ORIGIN, Size::new(switch_thickness * 2.5, switch_thickness).to_vec2(), switch_thickness / 2.);
62+
let label = if *data { "ON" } else { "OFF" };
6163

62-
let background_gradient = if *data {
63-
LinearGradient::new(
64-
UnitPoint::TOP,
65-
UnitPoint::BOTTOM,
66-
(
67-
env.get(theme::PRIMARY_LIGHT),
68-
env.get(theme::PRIMARY_DARK),
69-
),
70-
)
71-
} else {
72-
LinearGradient::new(
73-
UnitPoint::TOP,
74-
UnitPoint::BOTTOM,
75-
(
76-
env.get(theme::BACKGROUND_LIGHT),
77-
env.get(theme::BACKGROUND_DARK),
78-
),
79-
)
80-
};
81-
82-
paint_ctx.stroke(background_rect, &env.get(theme::BORDER), 2.0);
83-
84-
paint_ctx.fill(background_rect, &background_gradient);
85-
86-
let label = if *data {
87-
"ON"
88-
} else {
89-
"OFF"
90-
};
91-
92-
let font = paint_ctx.text()
64+
let font = paint_ctx
65+
.text()
9366
.new_font_by_name(font_name, font_size)
9467
.unwrap()
9568
.build()
9669
.unwrap();
9770

98-
let text_layout = paint_ctx.text().new_text_layout(&font, label).unwrap().build().unwrap();
71+
let text_layout = paint_ctx
72+
.text()
73+
.new_text_layout(&font, label)
74+
.unwrap()
75+
.build()
76+
.unwrap();
9977

10078
let mut origin = UnitPoint::LEFT.resolve(Rect::from_origin_size(
10179
Point::ORIGIN,
@@ -105,28 +83,64 @@ impl Widget<bool> for SwitchRaw {
10583
),
10684
));
10785

108-
//Make sure we don't draw the text too low
109-
origin.y = origin.y.min(base_state.size().height) + 4.;
86+
// adjust label position
87+
origin.y = origin.y.min(base_state.size().height);
11088

11189
if *data {
112-
origin.x = 8.
90+
origin.x = switch_padding * 2.
11391
} else {
114-
origin.x = switch_thickness * 2.5 - text_layout.width() - 8.
92+
origin.x = switch_width - text_layout.width() - switch_padding * 2.
11593
}
11694

11795
paint_ctx.draw_text(&text_layout, origin, &env.get(theme::LABEL_COLOR));
96+
}
97+
}
98+
99+
impl Widget<bool> for SwitchRaw {
100+
fn paint(&mut self, paint_ctx: &mut PaintCtx, base_state: &BaseState, data: &bool, env: &Env) {
101+
let switch_padding = 3.;
102+
let switch_height = env.get(theme::BORDERED_WIDGET_HEIGHT);
103+
let switch_width = switch_height * 2.75;
104+
let knob_size = switch_height - 2. * switch_padding;
105+
106+
let background_rect = RoundedRect::from_origin_size(
107+
Point::ORIGIN,
108+
Size::new(switch_width, switch_height).to_vec2(),
109+
switch_height / 2.,
110+
);
111+
112+
// paint different background for on and off state
113+
let background_gradient = if *data {
114+
LinearGradient::new(
115+
UnitPoint::TOP,
116+
UnitPoint::BOTTOM,
117+
(env.get(theme::PRIMARY_LIGHT), env.get(theme::PRIMARY_DARK)),
118+
)
119+
} else {
120+
LinearGradient::new(
121+
UnitPoint::TOP,
122+
UnitPoint::BOTTOM,
123+
(
124+
env.get(theme::BACKGROUND_LIGHT),
125+
env.get(theme::BACKGROUND_DARK),
126+
),
127+
)
128+
};
118129

130+
paint_ctx.stroke(background_rect, &env.get(theme::BORDER), 2.0);
131+
paint_ctx.fill(background_rect, &background_gradient);
119132

133+
// paint the knob
120134
let is_active = base_state.is_active();
121135
let is_hovered = self.knob_hovered;
122136

123137
let knob_position = if *data {
124-
switch_thickness * 2.5 - knob_size / 2. - 4.
138+
switch_width - knob_size / 2. - switch_padding
125139
} else {
126140
knob_size / 2. + 4.
127141
};
128142

129-
self.knob_pos = Point::new(knob_position, knob_size / 2. + 4.);
143+
self.knob_pos = Point::new(knob_position, knob_size / 2. + switch_padding);
130144
let knob_circle = Circle::new(self.knob_pos, knob_size / 2.);
131145

132146
let normal_knob_gradient = LinearGradient::new(
@@ -152,16 +166,25 @@ impl Widget<bool> for SwitchRaw {
152166
normal_knob_gradient
153167
};
154168

155-
//Paint the border
169+
// paint the border
156170
let border_color = if is_hovered || is_active {
157171
env.get(theme::FOREGROUND_LIGHT)
158172
} else {
159173
env.get(theme::FOREGROUND_DARK)
160174
};
161175

162176
paint_ctx.stroke(knob_circle, &border_color, 2.);
163-
164177
paint_ctx.fill(knob_circle, &knob_gradient);
178+
179+
// paint on/off label
180+
self.paint_label(
181+
paint_ctx,
182+
base_state,
183+
data,
184+
env,
185+
switch_width,
186+
switch_padding,
187+
);
165188
}
166189

167190
fn layout(
@@ -171,15 +194,12 @@ impl Widget<bool> for SwitchRaw {
171194
_data: &bool,
172195
env: &Env,
173196
) -> Size {
174-
let width = (8. + env.get(theme::BASIC_WIDGET_HEIGHT)) * 2.5;
175-
bc.constrain(Size::new(
176-
width,
177-
env.get(theme::BASIC_WIDGET_HEIGHT),
178-
))
197+
let width = (6. + env.get(theme::BORDERED_WIDGET_HEIGHT)) * 2.75;
198+
bc.constrain(Size::new(width, env.get(theme::BORDERED_WIDGET_HEIGHT)))
179199
}
180200

181201
fn event(&mut self, event: &Event, ctx: &mut EventCtx, data: &mut bool, env: &Env) {
182-
let knob_size = env.get(theme::BASIC_WIDGET_HEIGHT);
202+
let knob_size = env.get(theme::BORDERED_WIDGET_HEIGHT);
183203

184204
match event {
185205
Event::MouseDown(_) => {
@@ -201,7 +221,7 @@ impl Widget<bool> for SwitchRaw {
201221
}
202222
Event::MouseMoved(mouse) => {
203223
if ctx.is_active() {
204-
// todo
224+
// todo: animate dragging of knob
205225
}
206226
if ctx.is_hot() {
207227
if self.knob_hit_test(knob_size, mouse.pos) {
@@ -219,4 +239,4 @@ impl Widget<bool> for SwitchRaw {
219239
fn update(&mut self, ctx: &mut UpdateCtx, _old_data: Option<&bool>, _data: &bool, _env: &Env) {
220240
ctx.invalidate();
221241
}
222-
}
242+
}

0 commit comments

Comments
 (0)