Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 71 additions & 21 deletions crates/bevy_feathers/src/controls/slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ use bevy_ecs::{
system::{Commands, Query, Res},
};
use bevy_input_focus::tab_navigation::TabIndex;
use bevy_picking::PickingSystems;
use bevy_picking::{hover::Hovered, PickingSystems};
use bevy_reflect::{prelude::ReflectDefault, Reflect};
use bevy_scene::prelude::*;
use bevy_text::FontWeight;
use bevy_ui::{
widget::Text, AlignItems, BackgroundGradient, ColorStop, Display, FlexDirection, Gradient,
InteractionDisabled, InterpolationColorSpace, JustifyContent, LinearGradient, Node,
PositionType, UiRect, Val,
PositionType, Pressed, UiRect, Val,
};
use bevy_ui_widgets::{
Slider, SliderOrientation, SliderPrecision, SliderRange, SliderValue, TrackClick,
Expand Down Expand Up @@ -90,6 +90,7 @@ pub fn slider(props: SliderProps) -> impl Scene {
flex_grow: 1.0,
border_radius: {RoundedCorners::All.to_border_radius(6.0)},
}
Hovered
Slider {
track_click: TrackClick::Drag,
orientation: SliderOrientation::Horizontal,
Expand Down Expand Up @@ -155,6 +156,7 @@ pub fn slider_bundle<B: Bundle>(props: SliderProps, overrides: B) -> impl Bundle
border_radius: RoundedCorners::All.to_border_radius(6.0),
..Default::default()
},
Hovered::default(),
Slider {
track_click: TrackClick::Drag,
orientation: SliderOrientation::Horizontal,
Expand Down Expand Up @@ -200,55 +202,103 @@ pub fn slider_bundle<B: Bundle>(props: SliderProps, overrides: B) -> impl Bundle

fn update_slider_styles(
mut q_sliders: Query<
(Entity, Has<InteractionDisabled>, &mut BackgroundGradient),
(With<SliderStyle>, Or<(Spawned, Added<InteractionDisabled>)>),
(
Entity,
Has<InteractionDisabled>,
Has<Pressed>,
&Hovered,
&mut BackgroundGradient,
),
(
With<SliderStyle>,
Or<(
Spawned,
Added<InteractionDisabled>,
Changed<Hovered>,
Added<Pressed>,
)>,
),
>,
theme: Res<UiTheme>,
mut commands: Commands,
) {
for (slider_ent, disabled, mut gradient) in q_sliders.iter_mut() {
for (slider_ent, disabled, pressed, hovered, mut gradient) in q_sliders.iter_mut() {
set_slider_styles(
slider_ent,
&theme,
disabled,
pressed,
hovered.0,
gradient.as_mut(),
&mut commands,
);
}
}

fn update_slider_styles_remove(
mut q_sliders: Query<(Entity, Has<InteractionDisabled>, &mut BackgroundGradient)>,
mut q_sliders: Query<
(
Entity,
Has<InteractionDisabled>,
Has<Pressed>,
&Hovered,
&mut BackgroundGradient,
),
With<SliderStyle>,
>,
mut removed_disabled: RemovedComponents<InteractionDisabled>,
mut remove_pressed: RemovedComponents<Pressed>,
theme: Res<UiTheme>,
mut commands: Commands,
) {
removed_disabled.read().for_each(|ent| {
if let Ok((slider_ent, disabled, mut gradient)) = q_sliders.get_mut(ent) {
set_slider_styles(
slider_ent,
&theme,
disabled,
gradient.as_mut(),
&mut commands,
);
}
});
removed_disabled
.read()
.chain(remove_pressed.read())
.for_each(|ent| {
if let Ok((slider_ent, disabled, pressed, hovered, mut gradient)) =
q_sliders.get_mut(ent)
{
set_slider_styles(
slider_ent,
&theme,
disabled,
pressed,
hovered.0,
gradient.as_mut(),
&mut commands,
);
}
});
}

fn set_slider_styles(
slider_ent: Entity,
theme: &Res<'_, UiTheme>,
disabled: bool,
pressed: bool,
hovered: bool,
gradient: &mut BackgroundGradient,
commands: &mut Commands,
) {
let bar_color = theme.color(&match disabled {
true => tokens::SLIDER_BAR_DISABLED,
false => tokens::SLIDER_BAR,
let bar_color = theme.color(&if disabled {
tokens::SLIDER_BAR_DISABLED
} else if pressed {
tokens::SLIDER_BAR_PRESSED
} else if hovered {
tokens::SLIDER_BAR_HOVER
} else {
tokens::SLIDER_BAR
});

let bg_color = theme.color(&tokens::SLIDER_BG);
let bg_color = theme.color(&if disabled {
tokens::SLIDER_BG_DISABLED
} else if pressed {
tokens::SLIDER_BG_PRESSED
} else if hovered {
tokens::SLIDER_BG_HOVER
} else {
tokens::SLIDER_BG
});

let cursor_shape = match disabled {
true => bevy_window::SystemCursorIcon::NotAllowed,
Expand Down
5 changes: 5 additions & 0 deletions crates/bevy_feathers/src/dark_theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ pub fn create_dark_theme() -> ThemeProps {
),
// Slider
(tokens::SLIDER_BG, palette::GRAY_1),
(tokens::SLIDER_BG_HOVER, palette::GRAY_1.lighter(0.05)),
(tokens::SLIDER_BG_PRESSED, palette::GRAY_1.lighter(0.1)),
(tokens::SLIDER_BG_DISABLED, palette::GRAY_1),
(tokens::SLIDER_BAR, palette::ACCENT),
(tokens::SLIDER_BAR_HOVER, palette::ACCENT.lighter(0.05)),
(tokens::SLIDER_BAR_PRESSED, palette::ACCENT.lighter(0.1)),
(tokens::SLIDER_BAR_DISABLED, palette::GRAY_2),
(tokens::SLIDER_TEXT, palette::WHITE),
(tokens::SLIDER_TEXT_DISABLED, palette::WHITE.with_alpha(0.5)),
Expand Down
14 changes: 12 additions & 2 deletions crates/bevy_feathers/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,19 @@ pub const BUTTON_PLAIN_BG_PRESSED: ThemeToken =

/// Background for slider
pub const SLIDER_BG: ThemeToken = ThemeToken::new_static("feathers.slider.bg");
/// Background for slider moving bar
/// Background for slider (hovered)
pub const SLIDER_BG_HOVER: ThemeToken = ThemeToken::new_static("feathers.slider.bg.hover");
/// Background for slider (pressed)
pub const SLIDER_BG_PRESSED: ThemeToken = ThemeToken::new_static("feathers.slider.bg.pressed");
/// Background for slider (disabled)
pub const SLIDER_BG_DISABLED: ThemeToken = ThemeToken::new_static("feathers.slider.bg.disabled");
/// Fill color for slider
pub const SLIDER_BAR: ThemeToken = ThemeToken::new_static("feathers.slider.bar");
/// Background for slider moving bar (disabled)
/// Fill color for slider (hovered)
pub const SLIDER_BAR_HOVER: ThemeToken = ThemeToken::new_static("feathers.slider.bar.hover");
/// Fill color for slider (pressed)
pub const SLIDER_BAR_PRESSED: ThemeToken = ThemeToken::new_static("feathers.slider.bar.pressed");
/// Fill color for slider (disabled)
pub const SLIDER_BAR_DISABLED: ThemeToken = ThemeToken::new_static("feathers.slider.bar.disabled");
/// Background for slider text
pub const SLIDER_TEXT: ThemeToken = ThemeToken::new_static("feathers.slider.text");
Expand Down
43 changes: 39 additions & 4 deletions crates/bevy_ui_widgets/src/slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ use bevy_input::ButtonState;
use bevy_input_focus::FocusedInput;
use bevy_log::warn_once;
use bevy_math::ops;
use bevy_picking::events::{Drag, DragEnd, DragStart, Pointer, Press};
use bevy_picking::events::{Cancel, Drag, DragEnd, DragStart, Pointer, Press, Release};
use bevy_reflect::{prelude::ReflectDefault, Reflect};
use bevy_ui::{
ComputedNode, ComputedUiRenderTargetInfo, InteractionDisabled, UiGlobalTransform, UiScale,
ComputedNode, ComputedUiRenderTargetInfo, InteractionDisabled, Pressed, UiGlobalTransform,
UiScale,
};

use crate::ValueChange;
Expand Down Expand Up @@ -247,6 +248,7 @@ pub struct CoreSliderDragState {
pub(crate) fn slider_on_pointer_down(
mut press: On<Pointer<Press>>,
q_slider: Query<(
Entity,
&Slider,
&SliderValue,
&SliderRange,
Expand All @@ -266,6 +268,7 @@ pub(crate) fn slider_on_pointer_down(
// Thumb click, stop propagation to prevent track click.
press.propagate(false);
} else if let Ok((
slider_ent,
slider,
value,
range,
Expand All @@ -284,6 +287,8 @@ pub(crate) fn slider_on_pointer_down(
return;
}

commands.entity(slider_ent).insert(Pressed);

let is_vertical = slider.orientation.is_vertical(node);

// Find thumb size by searching descendants for the first entity with SliderThumb
Expand Down Expand Up @@ -446,16 +451,44 @@ pub(crate) fn slider_on_drag(

pub(crate) fn slider_on_drag_end(
mut drag_end: On<Pointer<DragEnd>>,
mut q_slider: Query<(&Slider, &mut CoreSliderDragState)>,
mut q_slider: Query<(Entity, &Slider, &mut CoreSliderDragState)>,
mut commands: Commands,
) {
if let Ok((_slider, mut drag)) = q_slider.get_mut(drag_end.entity) {
if let Ok((slider_ent, _slider, mut drag)) = q_slider.get_mut(drag_end.entity) {
drag_end.propagate(false);
commands.entity(slider_ent).remove::<Pressed>();
if drag.dragging {
drag.dragging = false;
}
}
}

fn slider_on_pointer_up(
mut release: On<Pointer<Release>>,
mut q_slider: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<Slider>>,
mut commands: Commands,
) {
if let Ok((slider, disabled, pressed)) = q_slider.get_mut(release.entity) {
release.propagate(false);
if !disabled && pressed {
commands.entity(slider).remove::<Pressed>();
}
}
}

fn slider_on_pointer_cancel(
mut release: On<Pointer<Cancel>>,
mut q_slider: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<Slider>>,
mut commands: Commands,
) {
if let Ok((slider, disabled, pressed)) = q_slider.get_mut(release.entity) {
release.propagate(false);
if !disabled && pressed {
commands.entity(slider).remove::<Pressed>();
}
}
}

fn slider_on_key_input(
mut focused_input: On<FocusedInput<KeyboardInput>>,
q_slider: Query<
Expand Down Expand Up @@ -616,6 +649,8 @@ pub struct SliderPlugin;
impl Plugin for SliderPlugin {
fn build(&self, app: &mut App) {
app.add_observer(slider_on_pointer_down)
.add_observer(slider_on_pointer_up)
.add_observer(slider_on_pointer_cancel)
.add_observer(slider_on_drag_start)
.add_observer(slider_on_drag_end)
.add_observer(slider_on_drag)
Expand Down