Add descriptions, touch basic support

This commit is contained in:
Piotr Siuszko 2024-02-29 16:23:30 +01:00
parent eff6b3b06f
commit a2643d1cae
7 changed files with 115 additions and 4339 deletions

5
CHANGELOG.md Normal file
View File

@ -0,0 +1,5 @@
# CHANGELOG
## [0.1.0]
- Initial version

4303
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,11 @@
name = "bevy_simple_scroll_view" name = "bevy_simple_scroll_view"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
exclude = [".github/","wasm/"] exclude = [".github/","wasm/", "record.gif"]
categories = ["game-development", "gui"] categories = ["game-development", "gui"]
keywords = ["bevy","ui"] keywords = ["bevy","ui"]
repository = "https://github.com/Leinnan/bevy_simple_scroll_view"
homepage = "https://github.com/Leinnan/bevy_simple_scroll_view"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -12,12 +14,9 @@ license = "MIT OR Apache-2.0"
[dependencies.bevy] [dependencies.bevy]
version = "0.13" version = "0.13"
default-features = false default-features = false
features = ["bevy_ui", "bevy_asset", "bevy_text"] features = ["bevy_ui", "bevy_asset", "bevy_text", "bevy_winit"]
[dev-dependencies.bevy] [dev-dependencies.bevy]
version = "0.13" version = "0.13"
default-features = true default-features = false
features = ["bevy_ui", "bevy_asset", "bevy_text", "bevy_winit", "default_font"]
[dev-dependencies]
bevy_egui = "0.25"
bevy-inspector-egui = "0.23"

View File

@ -1,11 +1,40 @@
# Bevy Simple Scroll View # Bevy Simple Scroll View
[![crates.io](https://img.shields.io/crates/v/bevy_simple_scroll_view.svg)](https://crates.io/crates/bevy_simple_scroll_view)
[![docs](https://docs.rs/bevy_simple_scroll_view/badge.svg)](https://docs.rs/bevy_simple_scroll_view)
[![license](https://img.shields.io/crates/l/bevy_simple_scroll_view)](https://github.com/Leinnan/bevy_simple_scroll_view#license)
[![Following released Bevy versions](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://bevyengine.org/learn/quick-start/plugin-development/#main-branch-tracking)
[![crates.io](https://img.shields.io/crates/d/bevy_simple_scroll_view.svg)](https://crates.io/crates/bevy_simple_scroll_view)
Simple to use plugin implementing ScrollView into Bevy engine. Supports scroll using dragging and scrolling. Simple to use plugin implementing ScrollView into Bevy engine. Supports scroll using dragging and scrolling.
![Gif with plugin in action](record.gif)
More details available in [simple.rs example](examples/simple.rs). More details available in [simple.rs example](examples/simple.rs).
## Installation ## Installation
```sh ```sh
cargo add --git https://github.com/Leinnan/bevy_simple_scroll_view.git cargo add bevy_simple_scroll_view
``` ```
## Contributing
Please feel free to open a PR, but keep in mind this project's goals. This is meant to be a simple scroll view widget.
The code should be simple enough for users to quickly understand and modify for their own purposes.
Please keep PRs small and scoped to a single feature or fix.
## Planned features
- one big thing missing is support for the [TouchInput events](https://docs.rs/bevy/latest/bevy/input/touch/struct.TouchInput.html) so the mobile platforms would work well.
- horizontal scroll, should be pretty simple.
- **DOCS**
- _optional_ if there would be simple enough implementation I would consider adding scrollbars.
## Bevy compatibility table
Bevy version | crate version
--- | ---
0.13 | 0.1

View File

@ -1,17 +1,14 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_inspector_egui::quick::WorldInspectorPlugin;
use bevy_simple_scroll_view::*; use bevy_simple_scroll_view::*;
const BORDER_COLOR_ACTIVE: Color = Color::rgb(0.75, 0.52, 0.99); const CLR_1: Color = Color::rgb(0.168, 0.168, 0.168);
const BACKGROUND_COLOR: Color = Color::rgb(0.15, 0.15, 0.15); const CLR_2: Color = Color::rgb(0.109, 0.109, 0.109);
const CLR_3: Color = Color::rgb(0.569, 0.592, 0.647);
const CLR_4: Color = Color::rgb(0.902, 0.4, 0.004);
fn main() { fn main() {
App::new() App::new()
.add_plugins(( .add_plugins((DefaultPlugins, ScrollViewPlugin))
DefaultPlugins,
ScrollViewPlugin,
WorldInspectorPlugin::new(),
))
.add_systems(Startup, prepare) .add_systems(Startup, prepare)
.add_systems(Update, reset_scroll) .add_systems(Update, reset_scroll)
.run(); .run();
@ -24,20 +21,24 @@ fn prepare(mut commands: Commands) {
style: Style { style: Style {
width: Val::Percent(100.0), width: Val::Percent(100.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
margin: UiRect::all(Val::Px(15.0)), padding: UiRect::all(Val::Px(15.0)),
..default() ..default()
}, },
background_color: Color::rgb(0.05, 0.05, 0.05).into(), background_color: CLR_1.into(),
..default() ..default()
}) })
.with_children(|p| { .with_children(|p| {
p.spawn(ButtonBundle { p.spawn(ButtonBundle {
style: Style { style: Style {
margin: UiRect::all(Val::Px(5.0)), margin: UiRect::all(Val::Px(15.0)),
padding: UiRect::all(Val::Px(5.0)), padding: UiRect::all(Val::Px(15.0)),
max_height: Val::Px(100.0),
border: UiRect::all(Val::Px(3.0)),
align_items: AlignItems::Center,
..default() ..default()
}, },
background_color: BORDER_COLOR_ACTIVE.into(), background_color: CLR_2.into(),
border_color: CLR_4.into(),
..default() ..default()
}) })
.with_children(|p| { .with_children(|p| {
@ -45,7 +46,7 @@ fn prepare(mut commands: Commands) {
"Reset scroll", "Reset scroll",
TextStyle { TextStyle {
font_size: 25.0, font_size: 25.0,
color: Color::ANTIQUE_WHITE, color: CLR_4,
..default() ..default()
}, },
)); ));
@ -54,11 +55,10 @@ fn prepare(mut commands: Commands) {
NodeBundle { NodeBundle {
style: Style { style: Style {
width: Val::Percent(80.0), width: Val::Percent(80.0),
height: Val::Percent(50.0),
margin: UiRect::all(Val::Px(15.0)), margin: UiRect::all(Val::Px(15.0)),
..default() ..default()
}, },
background_color: BACKGROUND_COLOR.into(), background_color: CLR_2.into(),
..default() ..default()
}, },
ScrollView::default(), ScrollView::default(),
@ -68,6 +68,7 @@ fn prepare(mut commands: Commands) {
NodeBundle { NodeBundle {
style: Style { style: Style {
flex_direction: bevy::ui::FlexDirection::Column, flex_direction: bevy::ui::FlexDirection::Column,
width: Val::Percent(100.0),
..default() ..default()
}, },
..default() ..default()
@ -75,18 +76,17 @@ fn prepare(mut commands: Commands) {
ScrollableContent::default(), ScrollableContent::default(),
)) ))
.with_children(|scroll_area| { .with_children(|scroll_area| {
for i in 0..10 { for i in 0..21 {
scroll_area scroll_area
.spawn(NodeBundle { .spawn(NodeBundle {
style: Style { style: Style {
width: Val::Percent(150.0), min_width: Val::Px(200.0),
margin: UiRect::all(Val::Px(5.0)), margin: UiRect::all(Val::Px(15.0)),
border: UiRect::all(Val::Px(3.0)), border: UiRect::all(Val::Px(5.0)),
padding: UiRect::all(Val::Px(25.0)), padding: UiRect::all(Val::Px(30.0)),
..default() ..default()
}, },
border_color: BORDER_COLOR_ACTIVE.into(), border_color: CLR_3.into(),
background_color: BACKGROUND_COLOR.into(),
..default() ..default()
}) })
.with_children(|p| { .with_children(|p| {
@ -95,7 +95,7 @@ fn prepare(mut commands: Commands) {
format!("Nr {}", i), format!("Nr {}", i),
TextStyle { TextStyle {
font_size: 25.0, font_size: 25.0,
color: Color::ANTIQUE_WHITE, color: CLR_3,
..default() ..default()
}, },
) )

BIN
record.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

View File

@ -1,9 +1,21 @@
#![doc = include_str!("../README.md")]
use bevy::{ use bevy::{
input::mouse::{MouseMotion, MouseWheel}, input::mouse::{MouseMotion, MouseWheel},
prelude::*, prelude::*,
}; };
/// A `Plugin` providing the systems and components required to make a ScrollView work. /// A `Plugin` providing the systems and components required to make a ScrollView work.
///
/// # Example
/// ```
/// use bevy::prelude::*;
/// use bevy_simple_scroll_view::;
///
/// App::new()
/// .add_plugins((DefaultPlugins,ScrollViewPlugin))
/// .run();
/// ```
pub struct ScrollViewPlugin; pub struct ScrollViewPlugin;
impl Plugin for ScrollViewPlugin { impl Plugin for ScrollViewPlugin {
@ -15,6 +27,7 @@ impl Plugin for ScrollViewPlugin {
( (
create_scroll_view, create_scroll_view,
input_mouse_pressed_move, input_mouse_pressed_move,
input_touch_pressed_move,
scroll_events, scroll_events,
scroll_update, scroll_update,
) )
@ -23,21 +36,27 @@ impl Plugin for ScrollViewPlugin {
} }
} }
/// Root component of scroll, it should have clipped style.
#[derive(Component, Debug, Reflect)] #[derive(Component, Debug, Reflect)]
pub struct ScrollView { pub struct ScrollView {
/// Field which control speed of the scrolling.
/// Could be negative number to implement invert scroll
pub scroll_speed: f32, pub scroll_speed: f32,
} }
impl Default for ScrollView { impl Default for ScrollView {
fn default() -> Self { fn default() -> Self {
Self { Self {
scroll_speed: 100.0, scroll_speed: 200.0,
} }
} }
} }
/// Component containing offset value of the scroll container to the parent.
/// It is possible to update the field `pos_y` manually to move scrollview to desired location.
#[derive(Component, Debug, Reflect, Default)] #[derive(Component, Debug, Reflect, Default)]
pub struct ScrollableContent { pub struct ScrollableContent {
/// Scroll container offset to the `ScrollView`.
pub pos_y: f32, pub pos_y: f32,
} }
@ -77,9 +96,30 @@ fn input_mouse_pressed_move(
} }
} }
fn scroll_update(mut q: Query<(&ScrollableContent, &mut Style), Changed<ScrollableContent>>) { fn input_touch_pressed_move(
for (scroll, mut style) in q.iter_mut() { touches: Res<Touches>,
style.top = Val::Px(scroll.pos_y); mut q: Query<(&Children, &Interaction, &Node), With<ScrollView>>,
mut content_q: Query<(&mut ScrollableContent, &Node)>,
) {
for t in touches.iter() {
let Some(touch) = touches.get_pressed(t.id()) else {
continue;
};
for (children, &interaction, node) in q.iter_mut() {
if interaction != Interaction::Pressed {
continue;
}
let container_height = node.size().y;
for &child in children.iter() {
if let Ok(item) = content_q.get_mut(child) {
let mut scroll = item.0;
let max_scroll = (item.1.size().y - container_height).max(0.0);
scroll.pos_y += touch.delta().y;
scroll.pos_y = scroll.pos_y.clamp(-max_scroll, 0.);
}
}
}
} }
} }
@ -115,3 +155,9 @@ fn scroll_events(
} }
} }
} }
fn scroll_update(mut q: Query<(&ScrollableContent, &mut Style), Changed<ScrollableContent>>) {
for (scroll, mut style) in q.iter_mut() {
style.top = Val::Px(scroll.pos_y);
}
}