ui_drag_and_drop/
ui_drag_and_drop.rs

1//! Demonstrates dragging and dropping UI nodes
2
3use bevy::prelude::*;
4
5fn main() {
6    App::new()
7        .add_plugins(DefaultPlugins)
8        .add_systems(Startup, setup)
9        .run();
10}
11
12const COLUMNS: i16 = 10;
13const ROWS: i16 = 10;
14const TILE_SIZE: f32 = 40.;
15
16fn setup(mut commands: Commands) {
17    commands.spawn(Camera2d);
18    commands
19        .spawn((Node {
20            display: Display::Grid,
21            align_self: AlignSelf::Center,
22            justify_self: JustifySelf::Center,
23            ..Default::default()
24        }, Pickable::IGNORE, BackgroundColor(Color::srgb(0.4, 0.4, 0.4))))
25        .with_children(|parent| {
26            let tile_colors = [
27                Color::srgb(0.2, 0.2, 0.8),
28                Color::srgb(0.8, 0.2, 0.2)
29            ];
30            for column in 0..COLUMNS {
31                for row in 0..ROWS {
32                    let i = column + row * COLUMNS;
33                    let tile_color = tile_colors[((row % 2) + column) as usize % tile_colors.len()];
34                    let tile_border_color = tile_color.darker(0.025);
35                    parent
36                        .spawn((
37                            Node {
38                                width: Val::Px(TILE_SIZE),
39                                height: Val::Px(TILE_SIZE),
40                                border: UiRect::all(Val::Px(4.)),
41                                grid_row: GridPlacement::start(row + 1),
42                                grid_column: GridPlacement::start(column + 1),
43                                align_items: AlignItems::Center,
44                                justify_content: JustifyContent::Center,
45                                ..Default::default()
46                            },
47                            BorderColor::all(tile_border_color),
48                            BackgroundColor(tile_color),
49                            Outline {
50                                width: Val::Px(2.),
51                                offset: Val::ZERO,
52                                color: Color::NONE,
53                            },
54                            Pickable {
55                                should_block_lower: false,
56                                is_hoverable: true,
57                            },
58                            GlobalZIndex::default()
59                        ))
60                        .observe(move |on_over: On<Pointer<Over>>, mut query: Query<(&mut BackgroundColor, &mut BorderColor)>| {
61                            if let Ok((mut background_color, mut border_color)) = query.get_mut(on_over.event_target()) {
62                                background_color.0 = tile_color.lighter(0.1);
63                                border_color.set_all(tile_border_color.lighter(0.1));
64                            }
65                        })
66                        .observe(move |on_out: On<Pointer<Out>>, mut query: Query<(&mut BackgroundColor, &mut BorderColor)>| {
67                            if let Ok((mut background_color, mut border_color)) = query.get_mut(on_out.event_target()) {
68                                background_color.0 = tile_color;
69                                border_color.set_all(tile_border_color);
70                            }
71                        })
72                        .observe(|on_drag_start: On<Pointer<DragStart>>, mut query: Query<(&mut Outline, &mut GlobalZIndex)>| {
73                            if let Ok((mut outline, mut global_zindex, )) = query.get_mut(on_drag_start.event_target()) {
74                                outline.color = Color::WHITE;
75                                global_zindex.0 = 1;
76                            }
77                        })
78                        .observe(|on_drag: On<Pointer<Drag>>, mut query: Query<&mut UiTransform>| {
79                            if let Ok(mut transform) = query.get_mut(on_drag.event_target()) {
80                                transform.translation = Val2::px(on_drag.distance.x, on_drag.distance.y);
81                            }
82                        })
83                        .observe(move |on_drag_end: On<Pointer<DragEnd>>, mut query: Query<(&mut UiTransform, &mut Outline, &mut GlobalZIndex)>| {
84                            if let Ok((mut transform, mut outline, mut global_zindex)) = query.get_mut(on_drag_end.event_target()) {
85                                transform.translation = Val2::ZERO;
86                                outline.color = Color::NONE;
87                                global_zindex.0 = 0;
88                            }
89                        })
90                        .observe(|on_drag_drop: On<Pointer<DragDrop>>, mut query: Query<&mut Node>| {
91                            if let Ok([mut a, mut b]) = query.get_many_mut([on_drag_drop.event_target(), on_drag_drop.dropped]) {
92                                core::mem::swap(&mut a.grid_row, &mut b.grid_row);
93                                core::mem::swap(&mut a.grid_column, &mut b.grid_column);
94                            }
95                        })
96                        .with_child((Text::new(format!("{i}")), Pickable::IGNORE));
97                }
98            }
99        });
100}