Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI Slider Widget #7116

Open
wants to merge 44 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
71056a3
made resource_scope work for non-send resources
Pietrek14 Sep 27, 2022
d607e6b
Merge branch 'bevyengine:main' into main
Pietrek14 Sep 27, 2022
83f2417
fixed the non-send resource scope tests
Pietrek14 Sep 27, 2022
6da0e41
formatting
Pietrek14 Sep 27, 2022
3500039
simplified panic in a non-send resource scope test
Pietrek14 Sep 28, 2022
d823b1b
Merge branch 'bevyengine:main' into main
Pietrek14 Sep 28, 2022
f68eb33
changed the name of non-send struct used for testing
Pietrek14 Sep 28, 2022
6ed303e
Merge branch 'bevyengine:main' into main
Pietrek14 Oct 6, 2022
23a22ae
Merge branch 'bevyengine:main' into main
Pietrek14 Jan 7, 2023
ac8f4dc
made the slider again
Pietrek14 Jan 7, 2023
c19e507
formatting
Pietrek14 Jan 7, 2023
2c432bf
added slider example to readme
Pietrek14 Jan 7, 2023
a038156
fixed slider system ordering
Pietrek14 Jan 7, 2023
13aff11
clarification for relativecursorposition component
Pietrek14 Jan 7, 2023
52bfd93
made slider range always be between 0. and 1.
Pietrek14 Jan 7, 2023
7b5c9be
updated comments
Pietrek14 Jan 7, 2023
ae51b05
Merge branch 'bevyengine:main' into new-slider
Pietrek14 Jan 8, 2023
4616e76
brought back the old design
Pietrek14 Jan 9, 2023
3957bff
Merge branch 'new-slider' of https://github.com/Pietrek14/bevy into n…
Pietrek14 Jan 9, 2023
7394000
formatting
Pietrek14 Jan 9, 2023
e5ad68e
added slider tests
Pietrek14 Jan 11, 2023
b208c9f
bugfix
Pietrek14 Jan 11, 2023
c35da65
bugfix and comment correction
Pietrek14 Jan 11, 2023
0a013ac
Merge branch 'main' of https://github.com/bevyengine/bevy into new-sl…
Pietrek14 Jan 12, 2023
625673f
organised widget systems into plugins
Pietrek14 Jan 13, 2023
841350f
formatting
Pietrek14 Jan 13, 2023
8837a50
centered the cursor on the slider handle
Pietrek14 Jan 13, 2023
65bb68c
added a stepped slider to the example
Pietrek14 Jan 13, 2023
acb99e3
clarification of range checks
Pietrek14 Jan 13, 2023
1d2bb26
Merge branch 'bevyengine:main' into new-slider
Pietrek14 Jan 14, 2023
db1564b
Merge branch 'bevyengine:main' into new-slider
Pietrek14 Jan 14, 2023
95506a2
Merge branch 'bevyengine:main' into new-slider
Pietrek14 Jan 15, 2023
e98d5a7
Merge branch 'main' of https://github.com/bevyengine/bevy into new-sl…
Pietrek14 Jan 16, 2023
48986d1
Merge branch 'new-slider' of https://github.com/Pietrek14/bevy into n…
Pietrek14 Jan 16, 2023
92ff4f2
adjusted slider code to use the new RelativeCursorPosition
Pietrek14 Jan 16, 2023
8084661
made the slider handle change color when dragged in the example
Pietrek14 Jan 17, 2023
5e51efa
formatting
Pietrek14 Jan 17, 2023
3cc3743
example pages
Pietrek14 Jan 17, 2023
af5f7e7
replaced SliderDragged with simple Interaction
Pietrek14 Jan 18, 2023
f47bcfc
formatting
Pietrek14 Jan 20, 2023
d35a9b5
deleted unused imports
Pietrek14 Jan 20, 2023
5f6c73f
Merge branch 'main' of https://github.com/bevyengine/bevy into new-sl…
Pietrek14 Jan 20, 2023
dd7371b
formatting
Pietrek14 Jan 22, 2023
8d13a1a
removed unnecessary intos
Pietrek14 Jan 22, 2023
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
10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,16 @@ description = "Illustrates creating and updating a button"
category = "UI (User Interface)"
wasm = true

[[example]]
name = "slider"
path = "examples/ui/slider.rs"

[package.metadata.example.slider]
name = "Slider"
description = "Illustrates creating and updating a slider"
category = "UI (User Interface)"
wasm = true

[[example]]
name = "window_fallthrough"
path = "examples/ui/window_fallthrough.rs"
Expand Down
48 changes: 42 additions & 6 deletions crates/bevy_ui/src/focus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{camera_config::UiCameraConfig, CalculatedClip, Node, UiStack};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
change_detection::DetectChanges,
entity::Entity,
Expand Down Expand Up @@ -52,6 +53,25 @@ impl Default for Interaction {
}
}

/// A component storing the position of the mouse relative to the node, (0., 0.) being the bottom-left corner and (1., 1.) being the upper-right
/// I can be used alongside interaction to get the position of the press.
/// If the mouse is not over the node, the value will go beyond the range of (0., 0.) to (1., 1.)
#[derive(
Component,
Deref,
DerefMut,
Copy,
Clone,
Default,
PartialEq,
Debug,
Reflect,
Serialize,
Deserialize,
)]
#[reflect(Component, Serialize, Deserialize, PartialEq)]
pub struct RelativeCursorPosition(Vec2);

/// Describes whether the node should block interactions with lower nodes
#[derive(Component, Copy, Clone, Eq, PartialEq, Debug, Reflect, Serialize, Deserialize)]
#[reflect(Component, Serialize, Deserialize, PartialEq)]
Expand Down Expand Up @@ -86,6 +106,7 @@ pub struct NodeQuery {
node: &'static Node,
global_transform: &'static GlobalTransform,
interaction: Option<&'static mut Interaction>,
relative_cursor_position: Option<&'static mut RelativeCursorPosition>,
focus_policy: Option<&'static FocusPolicy>,
calculated_clip: Option<&'static CalculatedClip>,
computed_visibility: Option<&'static ComputedVisibility>,
Expand Down Expand Up @@ -177,16 +198,31 @@ pub fn ui_focus_system(
let ui_position = position.truncate();
let extents = node.node.size() / 2.0;
let mut min = ui_position - extents;
let mut max = ui_position + extents;
if let Some(clip) = node.calculated_clip {
min = Vec2::max(min, clip.clip.min);
max = Vec2::min(max, clip.clip.max);
}
// if the current cursor position is within the bounds of the node, consider it for

// The mouse position relative to the node
// (0., 0.) is the bottom-left corner, (1., 1.) is the upper-right corner
Pietrek14 marked this conversation as resolved.
Show resolved Hide resolved
let relative_cursor_postition = cursor_position.map(|cursor_position| {
Vec2::new(
(cursor_position.x - min.x) / node.node.size().x,
(cursor_position.y - min.y) / node.node.size().y,
)
});

// If the current cursor position is within the bounds of the node, consider it for
// clicking
let contains_cursor = if let Some(cursor_position) = cursor_position {
(min.x..max.x).contains(&cursor_position.x)
&& (min.y..max.y).contains(&cursor_position.y)
let contains_cursor = if let Some(cursor_position) = relative_cursor_postition {
// Save the relative cursor position to the correct component
if let Some(mut relative_cursor_position_component) =
node.relative_cursor_position
{
relative_cursor_position_component.0 = cursor_position;
}

((0.)..1.).contains(&cursor_position.x)
&& ((0.)..1.).contains(&cursor_position.y)
Pietrek14 marked this conversation as resolved.
Show resolved Hide resolved
} else {
false
};
Expand Down
9 changes: 9 additions & 0 deletions crates/bevy_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl Plugin for UiPlugin {
.register_type::<FlexWrap>()
.register_type::<FocusPolicy>()
.register_type::<Interaction>()
.register_type::<RelativeCursorPosition>()
.register_type::<JustifyContent>()
.register_type::<Node>()
// NOTE: used by Style::aspect_ratio
Expand Down Expand Up @@ -135,6 +136,14 @@ impl Plugin for UiPlugin {
.ambiguous_with(bevy_text::update_text2d_layout)
.ambiguous_with(widget::text_system),
)
.add_system_to_stage(
CoreStage::PostUpdate,
widget::update_slider_value.label(widget::UpdateSliderValue),
)
.add_system_to_stage(
CoreStage::PostUpdate,
widget::update_slider_handle.after(widget::UpdateSliderValue),
)
Pietrek14 marked this conversation as resolved.
Show resolved Hide resolved
.add_system_to_stage(
CoreStage::PostUpdate,
flex_node_system
Expand Down
91 changes: 90 additions & 1 deletion crates/bevy_ui/src/node_bundles.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! This module contains basic node bundles used to build UIs

use crate::{
widget::Button, BackgroundColor, CalculatedSize, FocusPolicy, Interaction, Node, Style,
widget::{Button, Slider, SliderDragged, SliderHandle},
BackgroundColor, CalculatedSize, FocusPolicy, Interaction, Node, RelativeCursorPosition, Style,
UiImage, ZIndex,
};
use bevy_ecs::bundle::Bundle;
Expand Down Expand Up @@ -213,3 +214,91 @@ pub struct ButtonBundle {
/// Indicates the depth at which the node should appear in the UI
pub z_index: ZIndex,
}

/// A UI node that is a slider
#[derive(Bundle, Clone, Debug, Default)]
pub struct SliderBundle {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this over to the slider.rs and have everything be contained there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. Honestly think we should do the same with ButtonBundle, TextBundle and ImageBundle and just keep the core building blocks for UI in node_bundles.rs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda like having every bundles in a single file and not need to search around to find each bundle definition, but I understand that this won't scale super well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if I want to do this in this PR. It was originally supposed to be a simple slider widget, but it's slowly turning into a widget rework.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's a case of it being the first "somewhat" advanced widget and will define the structure for all widgets. But I do agree with @IceSentry that we should split it apart into 3 PRs:

  1. Widget restructuring with WidgetPlugin
  2. RelativeCursorPosition functionality that will be useful for multiple systems
  3. SliderWidget that depends on both of the previous PRs

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's continue the WidgetPlugin discussion over here, if necessary #7190

/// Describes the size of the node
pub node: Node,
/// Slider specific values
pub slider: Slider,
/// Describes the cursor position relative to the slider node
pub relative_cursor: RelativeCursorPosition,
/// Describes whether and how the slider has been interacted with by the input
pub interaction: Interaction,
/// Whether the slider is currently being dragged by the user
pub dragged: SliderDragged,
/// Describes the style including flexbox settings
pub style: Style,
/// The background color, which serves as a "fill" for this node
///
/// When combined with `UiImage`, tints the provided image.
pub background_color: BackgroundColor,
/// The image of the node
pub image: UiImage,
/// The transform of the node
///
/// This field is automatically managed by the UI layout system.
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
pub transform: Transform,
/// The global transform of the node
///
/// This field is automatically managed by the UI layout system.
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
pub global_transform: GlobalTransform,
/// Describes the visibility properties of the node
pub visibility: Visibility,
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
pub computed_visibility: ComputedVisibility,
}

/// A UI node that is a slider
#[derive(Bundle, Clone, Debug)]
pub struct SliderHandleBundle {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

/// Describes the size of the node
pub node: Node,
/// Marker component that signals this node is a slider handle
pub slider_handle: SliderHandle,
/// Describes the style including flexbox settings
/// The Slider parent is responsible for managing the position field, all user-made changes will be overwritten.
pub style: Style,
/// Whether this node should block interaction with lower nodes
pub focus_policy: FocusPolicy,
/// The background color, which serves as a "fill" for this node
///
/// When combined with `UiImage`, tints the provided image.
pub background_color: BackgroundColor,
/// The image of the node
pub image: UiImage,
/// The transform of the node
///
/// This field is automatically managed by the UI layout system.
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
pub transform: Transform,
/// The global transform of the node
///
/// This field is automatically managed by the UI layout system.
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
pub global_transform: GlobalTransform,
/// Describes the visibility properties of the node
pub visibility: Visibility,
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
pub computed_visibility: ComputedVisibility,
}

impl Default for SliderHandleBundle {
fn default() -> Self {
Self {
node: Node::default(),
slider_handle: SliderHandle,
style: Style::default(),
focus_policy: FocusPolicy::Pass,
background_color: BackgroundColor::default(),
image: UiImage::default(),
transform: Transform::default(),
global_transform: GlobalTransform::default(),
visibility: Visibility::default(),
computed_visibility: ComputedVisibility::default(),
}
}
}
2 changes: 2 additions & 0 deletions crates/bevy_ui/src/widget/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

mod button;
mod image;
mod slider;
mod text;

pub use button::*;
pub use image::*;
pub use slider::*;
pub use text::*;
Loading