drag_to_scroll/
drag_to_scroll.rs1use bevy::color::palettes::css::RED;
4use bevy::prelude::*;
5
6#[derive(Component)]
7struct ScrollableNode;
8
9#[derive(Component)]
10struct TileColor(Color);
11
12fn main() {
13 App::new()
14 .add_plugins(DefaultPlugins)
15 .add_systems(Startup, setup)
16 .run();
17}
18
19#[derive(Component)]
20struct ScrollStart(Vec2);
21
22fn setup(mut commands: Commands) {
23 let w = 60;
24 let h = 40;
25
26 commands.spawn(Camera2d);
27 commands.insert_resource(UiScale(0.5));
28
29 commands
30 .spawn((
31 Node {
32 width: percent(100),
33 height: percent(100),
34 overflow: Overflow::scroll(),
35 ..Default::default()
36 },
37 ScrollPosition(Vec2::ZERO),
38 ScrollableNode,
39 ScrollStart(Vec2::ZERO),
40 ))
41 .observe(
42 |drag: On<Pointer<Drag>>,
43 ui_scale: Res<UiScale>,
44 mut scroll_position_query: Query<
45 (&mut ScrollPosition, &ScrollStart),
46 With<ScrollableNode>,
47 >| {
48 if let Ok((mut scroll_position, start)) = scroll_position_query.single_mut() {
49 scroll_position.0 = (start.0 - drag.distance / ui_scale.0).max(Vec2::ZERO);
50 }
51 },
52 )
53 .observe(
54 |_: On<Pointer<DragStart>>,
55 mut scroll_position_query: Query<
56 (&ComputedNode, &mut ScrollStart),
57 With<ScrollableNode>,
58 >| {
59 if let Ok((computed_node, mut start)) = scroll_position_query.single_mut() {
60 start.0 = computed_node.scroll_position * computed_node.inverse_scale_factor;
61 }
62 },
63 )
64 .with_children(|commands| {
65 commands
66 .spawn((
67 Node {
68 display: Display::Grid,
69 grid_template_rows: RepeatedGridTrack::px(w as i32, 100.),
70 grid_template_columns: RepeatedGridTrack::px(h as i32, 100.),
71 ..default()
72 },
73 Pickable {
74 is_hoverable: false,
75 should_block_lower: true,
76 }
77 ))
78 .with_children(|commands| {
79 for y in 0..h {
80 for x in 0..w {
81 let tile_color = if (x + y) % 2 == 1 {
82 let hue = ((x as f32 / w as f32) * 270.0)
83 + ((y as f32 / h as f32) * 90.0);
84 Color::hsl(hue, 1., 0.5)
85 } else {
86 Color::BLACK
87 };
88 commands.spawn((
89 Node {
90 grid_row: GridPlacement::start(y + 1),
91 grid_column: GridPlacement::start(x + 1),
92 ..default()
93 },
94 Pickable {
95 should_block_lower: false,
96 is_hoverable: true,
97 },
98 TileColor(tile_color),
99 BackgroundColor(tile_color),
100 ))
101 .observe(|over: On<Pointer<Over>>, mut query: Query<&mut BackgroundColor>,| {
102 if let Ok(mut background_color) = query.get_mut(over.entity) {
103 background_color.0 = RED.into();
104 }
105 })
106 .observe(|out: On<Pointer<Out>>, mut query: Query<(&mut BackgroundColor, &TileColor)>| {
107 if let Ok((mut background_color, tile_color)) = query.get_mut(out.entity) {
108 background_color.0 = tile_color.0;
109 }
110 });
111 }
112 }
113 });
114 });
115}