Skip to content

Commit 68dc3e1

Browse files
committed
Add button repeat functionality
- Track last pressed button and press time in a resource - Add system to trigger button actions at a repeat interval when held - Improves UX for increment/decrement and shape navigation buttons
1 parent a87a028 commit 68dc3e1

File tree

1 file changed

+89
-35
lines changed

1 file changed

+89
-35
lines changed

examples/ui/box_shadow.rs

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! This example shows how to create a node with a shadow and adjust its settings interactively.
22
3+
use bevy::time::Time;
34
use bevy::{color::palettes::css::*, prelude::*, winit::WinitSettings};
45

56
const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
@@ -61,7 +62,7 @@ struct ShadowSettings {
6162
#[derive(Component)]
6263
struct ShadowNode;
6364

64-
#[derive(Component)]
65+
#[derive(Component, PartialEq, Clone, Copy)]
6566
enum SettingsButton {
6667
XOffsetInc,
6768
XOffsetDec,
@@ -81,12 +82,20 @@ enum SettingsButton {
8182
#[derive(Component)]
8283
struct ValueLabel(String);
8384

85+
#[derive(Resource, Default)]
86+
struct HeldButton {
87+
button: Option<SettingsButton>,
88+
pressed_at: Option<f64>,
89+
last_repeat: Option<f64>,
90+
}
91+
8492
fn main() {
8593
App::new()
8694
.add_plugins(DefaultPlugins)
87-
.insert_resource(WinitSettings::desktop_app())
95+
.insert_resource(WinitSettings::default())
8896
.insert_resource(SHADOW_DEFAULT_SETTINGS)
8997
.insert_resource(SHAPE_DEFAULT_SETTINGS)
98+
.insert_resource(HeldButton::default())
9099
.add_systems(Startup, setup)
91100
.add_systems(
92101
Update,
@@ -95,6 +104,7 @@ fn main() {
95104
button_color_system,
96105
update_shape,
97106
update_shadow,
107+
button_repeat_system,
98108
),
99109
)
100110
.run();
@@ -501,47 +511,91 @@ fn button_system(
501511
>,
502512
mut shadow: ResMut<ShadowSettings>,
503513
mut shape: ResMut<ShapeSettings>,
514+
mut held: ResMut<HeldButton>,
515+
time: Res<Time>,
504516
) {
517+
let now = time.elapsed_secs_f64();
505518
for (interaction, btn) in &mut interaction_query {
506-
if *interaction == Interaction::Pressed {
507-
match btn {
508-
SettingsButton::XOffsetInc => shadow.x_offset += 1.0,
509-
SettingsButton::XOffsetDec => shadow.x_offset -= 1.0,
510-
SettingsButton::YOffsetInc => shadow.y_offset += 1.0,
511-
SettingsButton::YOffsetDec => shadow.y_offset -= 1.0,
512-
SettingsButton::BlurInc => shadow.blur = (shadow.blur + 1.0).max(0.0),
513-
SettingsButton::BlurDec => shadow.blur = (shadow.blur - 1.0).max(0.0),
514-
SettingsButton::SpreadInc => shadow.spread += 1.0,
515-
SettingsButton::SpreadDec => shadow.spread -= 1.0,
516-
SettingsButton::CountInc => {
517-
if shadow.count < 3 {
518-
shadow.count += 1;
519-
}
520-
}
521-
SettingsButton::CountDec => {
522-
if shadow.count > 1 {
523-
shadow.count -= 1;
524-
}
525-
}
526-
SettingsButton::ShapePrev => {
527-
if shape.index == 0 {
528-
shape.index = SHAPES.len() - 1;
529-
} else {
530-
shape.index -= 1;
531-
}
532-
}
533-
SettingsButton::ShapeNext => {
534-
shape.index = (shape.index + 1) % SHAPES.len();
535-
}
536-
SettingsButton::Reset => {
537-
*shape = SHAPE_DEFAULT_SETTINGS;
538-
*shadow = SHADOW_DEFAULT_SETTINGS;
519+
match *interaction {
520+
Interaction::Pressed => {
521+
trigger_button_action(btn, &mut *shadow, &mut *shape);
522+
held.button = Some(*btn);
523+
held.pressed_at = Some(now);
524+
held.last_repeat = Some(now);
525+
}
526+
Interaction::None | Interaction::Hovered => {
527+
if held.button == Some(*btn) {
528+
held.button = None;
529+
held.pressed_at = None;
530+
held.last_repeat = None;
539531
}
540532
}
541533
}
542534
}
543535
}
544536

537+
fn trigger_button_action(
538+
btn: &SettingsButton,
539+
shadow: &mut ShadowSettings,
540+
shape: &mut ShapeSettings,
541+
) {
542+
match btn {
543+
SettingsButton::XOffsetInc => shadow.x_offset += 1.0,
544+
SettingsButton::XOffsetDec => shadow.x_offset -= 1.0,
545+
SettingsButton::YOffsetInc => shadow.y_offset += 1.0,
546+
SettingsButton::YOffsetDec => shadow.y_offset -= 1.0,
547+
SettingsButton::BlurInc => shadow.blur = (shadow.blur + 1.0).max(0.0),
548+
SettingsButton::BlurDec => shadow.blur = (shadow.blur - 1.0).max(0.0),
549+
SettingsButton::SpreadInc => shadow.spread += 1.0,
550+
SettingsButton::SpreadDec => shadow.spread -= 1.0,
551+
SettingsButton::CountInc => {
552+
if shadow.count < 3 {
553+
shadow.count += 1;
554+
}
555+
}
556+
SettingsButton::CountDec => {
557+
if shadow.count > 1 {
558+
shadow.count -= 1;
559+
}
560+
}
561+
SettingsButton::ShapePrev => {
562+
if shape.index == 0 {
563+
shape.index = SHAPES.len() - 1;
564+
} else {
565+
shape.index -= 1;
566+
}
567+
}
568+
SettingsButton::ShapeNext => {
569+
shape.index = (shape.index + 1) % SHAPES.len();
570+
}
571+
SettingsButton::Reset => {
572+
*shape = SHAPE_DEFAULT_SETTINGS;
573+
*shadow = SHADOW_DEFAULT_SETTINGS;
574+
}
575+
}
576+
}
577+
578+
// System to repeat button action while held
579+
fn button_repeat_system(
580+
time: Res<Time>,
581+
mut held: ResMut<HeldButton>,
582+
mut shadow: ResMut<ShadowSettings>,
583+
mut shape: ResMut<ShapeSettings>,
584+
) {
585+
const INITIAL_DELAY: f64 = 0.15;
586+
const REPEAT_RATE: f64 = 0.08;
587+
if let (Some(btn), Some(pressed_at)) = (held.button, held.pressed_at) {
588+
let now = time.elapsed_secs_f64();
589+
let since_pressed = now - pressed_at;
590+
let last_repeat = held.last_repeat.unwrap_or(pressed_at);
591+
let since_last = now - last_repeat;
592+
if since_pressed > INITIAL_DELAY && since_last > REPEAT_RATE {
593+
trigger_button_action(&btn, &mut *shadow, &mut *shape);
594+
held.last_repeat = Some(now);
595+
}
596+
}
597+
}
598+
545599
// Changes color of button on hover and on pressed
546600
fn button_color_system(
547601
mut query: Query<

0 commit comments

Comments
 (0)