Skip to content

Commit 8081542

Browse files
Feathers HardLimit and SoftLimit now accept a RangeInclusive (#25237)
# Objective - Fixes #25107 ## Solution - After talking with @viridia , it makes sense just to update the `Range` to be a `RangeInclusive` so that the user understands it is an inclusive range for `HardLimit` and `SoftLimit`. There’s no need to accommodate exclusive ranges at this point so we can park #25236 for now. The changes are now very straightforward because of it. ## Testing - `cargo run --example clustered_decals --features="pbr_clustered_decals bevy_feathers”` has good behavior with number inputs - `cargo run --example box_shadow --features=“bevy_feathers”` works as expected - `cargo run --example feathers_gallery --features=“bevy_feathers”` works as expected --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
1 parent 1f2feb6 commit 8081542

11 files changed

Lines changed: 65 additions & 63 deletions

File tree

crates/bevy_feathers/src/controls/number_input.rs

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{f32::consts::PI, ops::Range};
1+
use std::{f32::consts::PI, ops::RangeInclusive};
22

33
use bevy_app::{Plugin, PreUpdate, PropagateOver};
44
use bevy_color::Color;
@@ -342,30 +342,30 @@ impl Default for NumberInputValue {
342342
#[derive(Debug, PartialEq, Clone, Reflect)]
343343
pub enum NumberInputRange {
344344
/// An 'f32' range.
345-
F32(Range<f32>),
345+
F32(RangeInclusive<f32>),
346346
/// An 'f64' range.
347-
F64(Range<f64>),
347+
F64(RangeInclusive<f64>),
348348
/// An 'i32' range.
349-
I32(Range<i32>),
349+
I32(RangeInclusive<i32>),
350350
/// An 'i64' range.
351-
I64(Range<i64>),
351+
I64(RangeInclusive<i64>),
352352
}
353353

354354
impl NumberInputRange {
355355
/// Clamp a numeric value of varying type to be within this range.
356356
pub fn clamp(&self, n: NumberInputValue) -> NumberInputValue {
357357
match (self, n) {
358358
(Self::F32(r), NumberInputValue::F32(v)) => {
359-
NumberInputValue::F32(v.clamp(r.start, r.end))
359+
NumberInputValue::F32(v.clamp(*r.start(), *r.end()))
360360
}
361361
(Self::F64(r), NumberInputValue::F64(v)) => {
362-
NumberInputValue::F64(v.clamp(r.start, r.end))
362+
NumberInputValue::F64(v.clamp(*r.start(), *r.end()))
363363
}
364364
(Self::I32(r), NumberInputValue::I32(v)) => {
365-
NumberInputValue::I32(v.clamp(r.start, r.end))
365+
NumberInputValue::I32(v.clamp(*r.start(), *r.end()))
366366
}
367367
(Self::I64(r), NumberInputValue::I64(v)) => {
368-
NumberInputValue::I64(v.clamp(r.start, r.end))
368+
NumberInputValue::I64(v.clamp(*r.start(), *r.end()))
369369
}
370370
(range, value) => {
371371
warn_once!("Number input range type mismatch: {range:?} {value:?}");
@@ -378,20 +378,20 @@ impl NumberInputRange {
378378
pub fn wrap(&self, n: NumberInputValue) -> NumberInputValue {
379379
match (self, n) {
380380
(Self::F32(r), NumberInputValue::F32(v)) => {
381-
let range = r.end - r.start;
382-
NumberInputValue::F32(r.start + (v - r.start).rem_euclid(range))
381+
let range = r.end() - r.start();
382+
NumberInputValue::F32(r.start() + (v - r.start()).rem_euclid(range))
383383
}
384384
(Self::F64(r), NumberInputValue::F64(v)) => {
385-
let range = r.end - r.start;
386-
NumberInputValue::F64(r.start + (v - r.start).rem_euclid(range))
385+
let range = r.end() - r.start();
386+
NumberInputValue::F64(r.start() + (v - r.start()).rem_euclid(range))
387387
}
388388
(Self::I32(r), NumberInputValue::I32(v)) => {
389-
let range = r.end - r.start;
390-
NumberInputValue::I32(r.start + (v - r.start).rem_euclid(range))
389+
let range = r.end() - r.start();
390+
NumberInputValue::I32(r.start() + (v - r.start()).rem_euclid(range))
391391
}
392392
(Self::I64(r), NumberInputValue::I64(v)) => {
393-
let range = r.end - r.start;
394-
NumberInputValue::I64(r.start + (v - r.start).rem_euclid(range))
393+
let range = r.end() - r.start();
394+
NumberInputValue::I64(r.start() + (v - r.start()).rem_euclid(range))
395395
}
396396
(range, value) => {
397397
warn_once!("Number input range type mismatch: {range:?} {value:?}");
@@ -405,32 +405,32 @@ impl NumberInputRange {
405405
pub fn thumb_position(&self, value: NumberInputValue) -> f32 {
406406
match (self, value) {
407407
(Self::F32(range), NumberInputValue::F32(n)) => {
408-
if range.end > range.start {
409-
(n - range.start) / (range.end - range.start)
408+
if range.end() > range.start() {
409+
(n - range.start()) / (range.end() - range.start())
410410
} else {
411411
0.5
412412
}
413413
}
414414

415415
(Self::F64(range), NumberInputValue::F64(n)) => {
416-
if range.end > range.start {
417-
((n - range.start) / (range.end - range.start)) as f32
416+
if range.end() > range.start() {
417+
((n - range.start()) / (range.end() - range.start())) as f32
418418
} else {
419419
0.5
420420
}
421421
}
422422

423423
(Self::I32(range), NumberInputValue::I32(n)) => {
424-
if range.end > range.start {
425-
(n - range.start) as f32 / (range.end - range.start) as f32
424+
if range.end() > range.start() {
425+
(n - range.start()) as f32 / (range.end() - range.start()) as f32
426426
} else {
427427
0.5
428428
}
429429
}
430430

431431
(Self::I64(range), NumberInputValue::I64(n)) => {
432-
if range.end > range.start {
433-
(n - range.start) as f32 / (range.end - range.start) as f32
432+
if range.end() > range.start() {
433+
(n - range.start()) as f32 / (range.end() - range.start()) as f32
434434
} else {
435435
0.5
436436
}
@@ -446,7 +446,7 @@ impl NumberInputRange {
446446

447447
impl Default for NumberInputRange {
448448
fn default() -> Self {
449-
Self::F32(0.0..0.0)
449+
Self::F32(0.0..=0.0)
450450
}
451451
}
452452

@@ -457,22 +457,22 @@ pub struct SoftLimit(pub NumberInputRange);
457457

458458
impl SoftLimit {
459459
/// Create a [`SoftLimit`] for `f32` values.
460-
pub fn f32(range: Range<f32>) -> Self {
460+
pub fn f32(range: RangeInclusive<f32>) -> Self {
461461
Self(NumberInputRange::F32(range))
462462
}
463463

464464
/// Create a [`SoftLimit`] for `f64` values.
465-
pub fn f64(range: Range<f64>) -> Self {
465+
pub fn f64(range: RangeInclusive<f64>) -> Self {
466466
Self(NumberInputRange::F64(range))
467467
}
468468

469469
/// Create a [`SoftLimit`] for `i32` values.
470-
pub fn i32(range: Range<i32>) -> Self {
470+
pub fn i32(range: RangeInclusive<i32>) -> Self {
471471
Self(NumberInputRange::I32(range))
472472
}
473473

474474
/// Create a [`SoftLimit`] for `i64` values.
475-
pub fn i64(range: Range<i64>) -> Self {
475+
pub fn i64(range: RangeInclusive<i64>) -> Self {
476476
Self(NumberInputRange::I64(range))
477477
}
478478
}
@@ -485,22 +485,22 @@ pub struct HardLimit(pub NumberInputRange);
485485

486486
impl HardLimit {
487487
/// Create a [`HardLimit`] for `f32` values.
488-
pub fn f32(range: Range<f32>) -> Self {
488+
pub fn f32(range: RangeInclusive<f32>) -> Self {
489489
Self(NumberInputRange::F32(range))
490490
}
491491

492492
/// Create a [`HardLimit`] for `f64` values.
493-
pub fn f64(range: Range<f64>) -> Self {
493+
pub fn f64(range: RangeInclusive<f64>) -> Self {
494494
Self(NumberInputRange::F64(range))
495495
}
496496

497497
/// Create a [`HardLimit`] for `i32` values.
498-
pub fn i32(range: Range<i32>) -> Self {
498+
pub fn i32(range: RangeInclusive<i32>) -> Self {
499499
Self(NumberInputRange::I32(range))
500500
}
501501

502502
/// Create a [`HardLimit`] for `i64` values.
503-
pub fn i64(range: Range<i64>) -> Self {
503+
pub fn i64(range: RangeInclusive<i64>) -> Self {
504504
Self(NumberInputRange::I64(range))
505505
}
506506
}
@@ -1003,10 +1003,10 @@ fn scrubber_on_drag_start(
10031003
// Use various heuristics to determine drag speed based on which components are present.
10041004
drag.drag_speed = if let Some(SoftLimit(nrange)) = soft_limit {
10051005
match nrange {
1006-
NumberInputRange::F32(range) => (range.end - range.start) as f64 / slider_size,
1007-
NumberInputRange::F64(range) => (range.end - range.start) / slider_size,
1008-
NumberInputRange::I32(range) => (range.end - range.start) as f64 / slider_size,
1009-
NumberInputRange::I64(range) => (range.end - range.start) as f64 / slider_size,
1006+
NumberInputRange::F32(range) => (range.end() - range.start()) as f64 / slider_size,
1007+
NumberInputRange::F64(range) => (range.end() - range.start()) / slider_size,
1008+
NumberInputRange::I32(range) => (range.end() - range.start()) as f64 / slider_size,
1009+
NumberInputRange::I64(range) => (range.end() - range.start()) as f64 / slider_size,
10101010
}
10111011
} else if let Some(NumberInputStep(step)) = step {
10121012
*step * BASE_DRAG_SPEED

examples/3d/clustered_decals.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,12 @@ fn spawn_buttons(commands: &mut Commands) {
242242

243243
// The number inputs start off hidden because Camera is selected first.
244244
Visibility::Hidden
245-
number_input_f32("Scale Multiplier", Some(AppNumberInput::Scale), 1.0, NumberInputPrecision(2), 0.05..10.)
245+
number_input_f32("Scale Multiplier", Some(AppNumberInput::Scale), 1.0, NumberInputPrecision(2), 0.05..=10.)
246246
,
247247

248248
Visibility::Hidden
249-
number_input_f32("Roll (-π to π)", Some(AppNumberInput::Roll), 0.0, NumberInputPrecision(2), -PI..PI)
249+
// + epsilon and next_down are used since roll recalculation likes to switch between -PI and PI upon recalculating roll.
250+
number_input_f32("Roll (-π to π)", Some(AppNumberInput::Roll), 0.0, NumberInputPrecision(2), -PI + f32::EPSILON ..=PI.next_down())
250251
,
251252
]
252253
});

examples/3d/color_grading.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ fn number_input_for_value(
225225
template_value(NumberInputValue::F32(setting.get(color_grading)))
226226
template_value(setting)
227227
NumberInputPrecision(2)
228-
HardLimit::f32(0. ..10.)
228+
HardLimit::f32(0. ..=10.)
229229
]
230230
}
231231
}

examples/3d/light_textures.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,12 @@ fn spawn_buttons(commands: &mut Commands) {
299299

300300
// The number inputs start off hidden because Camera is selected first.
301301
Visibility::Hidden
302-
number_input_f32("Scale Multiplier", Some(AppNumberInput::Scale), 1.0, NumberInputPrecision(2), 0.01..5.)
302+
number_input_f32("Scale Multiplier", Some(AppNumberInput::Scale), 1.0, NumberInputPrecision(2), 0.01..=5.)
303303
,
304304

305305
Visibility::Hidden
306-
number_input_f32("Roll (-π to π)", Some(AppNumberInput::Roll), 0.0, NumberInputPrecision(2), -PI..PI)
306+
// + epsilon and next_down are used since roll recalculation likes to switch between -PI and PI upon recalculating roll.
307+
number_input_f32("Roll (-π to π)", Some(AppNumberInput::Roll), 0.0, NumberInputPrecision(2), -PI + f32::EPSILON ..=PI.next_down())
307308
,
308309
]
309310
});

examples/3d/ssr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ fn range_controls(value: f32, app_number_input: AppNumberInput) -> impl Scene {
560560
template_value(NumberInputValue::F32(value))
561561
template_value(app_number_input)
562562
NumberInputPrecision(3)
563-
HardLimit::f32(0.0..1.0)
563+
HardLimit::f32(0.0..=1.0)
564564
Node {
565565
align_items: AlignItems::Center,
566566
}

examples/animation/animation_graph.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ fn setup_node_rects(commands: &mut Commands) {
310310
Children [
311311
ZIndex(1)
312312
number_input_f32(clip.text, Some(clip.clone()),
313-
ExampleAnimationWeights::default().weights[clip.index], NumberInputPrecision(2), 0. ..1.),
313+
ExampleAnimationWeights::default().weights[clip.index], NumberInputPrecision(2), 0. ..=1.),
314314

315315
// The background node that fills up based on the number input value.
316316
WeightBackground

examples/helpers/number_input_f32.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn number_input_f32<T>(
2222
number_input_identifier: Option<T>,
2323
value: f32,
2424
precision: NumberInputPrecision,
25-
limits: core::ops::Range<f32>,
25+
limits: core::ops::RangeInclusive<f32>,
2626
) -> Box<dyn Scene>
2727
where
2828
T: Template<Output: Component> + Send + Sync + Unpin + 'static,

examples/helpers/number_input_i32.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub fn number_input_i32<T>(
2222
number_input_identifier: Option<T>,
2323
value: i32,
2424
precision: NumberInputPrecision,
25-
limits: core::ops::Range<i32>,
25+
limits: core::ops::RangeInclusive<i32>,
2626
) -> Box<dyn Scene>
2727
where
2828
T: Template<Output: Component> + Send + Sync + Unpin + 'static,

examples/ui/styling/box_shadow.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,42 +247,42 @@ fn settings_panel_scene(app_settings: &AppSettings) -> impl Scene {
247247
Some(AppNumberInputF32::XOffset),
248248
app_settings.x_offset,
249249
NumberInputPrecision(0),
250-
-200. ..200.
250+
-200. ..=200.
251251
),
252252
number_input_f32(
253253
AppNumberInputF32::YOffset.label(),
254254
Some(AppNumberInputF32::YOffset),
255255
app_settings.y_offset,
256256
NumberInputPrecision(0),
257-
-200. ..200.
257+
-200. ..=200.
258258
),
259259
number_input_f32(
260260
AppNumberInputF32::Blur.label(),
261261
Some(AppNumberInputF32::Blur),
262262
app_settings.blur,
263263
NumberInputPrecision(0),
264-
0. ..100.
264+
0. ..=100.
265265
),
266266
number_input_f32(
267267
AppNumberInputF32::Spread.label(),
268268
Some(AppNumberInputF32::Spread),
269269
app_settings.spread,
270270
NumberInputPrecision(0),
271-
-200. ..200.
271+
-200. ..=200.
272272
),
273273
number_input_i32(
274274
AppNumberInputI32::Count.label(),
275275
Some(AppNumberInputI32::Count),
276276
app_settings.count as i32,
277277
NumberInputPrecision(0),
278-
1..3
278+
1..=3
279279
),
280280
number_input_i32(
281281
AppNumberInputI32::Samples.label(),
282282
Some(AppNumberInputI32::Samples),
283283
app_settings.samples as i32,
284284
NumberInputPrecision(0),
285-
0..15
285+
0..=15
286286
),
287287
// Reset button
288288
@FeathersButton {

examples/ui/widgets/feathers_gallery.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ fn demo_column_2() -> impl Scene {
812812
@FeathersNumberInput
813813
DemoScalarField
814814
NumberInputPrecision(2)
815-
HardLimit::f32(0.0..100.0)
815+
HardLimit::f32(0.0..=100.0)
816816
Node {
817817
flex_grow: 1.0,
818818
max_width: px(100),

0 commit comments

Comments
 (0)