1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use bevy::prelude::*;
use super::{Group, Interactable, InteractionState};
pub struct Dragged {
pub group: Group,
pub translation: Vec2,
pub origin: Vec2,
pub just_dropped: bool,
pub just_dragged: bool,
}
impl Dragged {
pub fn just_dropped(&self) -> bool {
self.just_dropped
}
pub fn just_dragged(&self) -> bool {
self.just_dragged
}
}
pub struct DragPlugin;
impl Plugin for DragPlugin {
fn build(&self, app: &mut AppBuilder) {
app
.init_resource::<InteractionState>()
.add_system(mouse_press_start_drag_system.system())
.add_system(mouse_release_stop_drag_system.system())
.add_system(drag_system.system());
}
}
pub fn drag_system(
interaction_state: Res<InteractionState>,
mut draggables: Query<(&mut Transform, &mut Dragged, &GlobalTransform)>,
) {
for (mut transform, mut dragged, global_transform) in draggables.iter_mut() {
if dragged.just_dragged {
dragged.just_dragged = false;
}
if let Some(cursor_position) = interaction_state.cursor_positions.get(&dragged.group) {
let parent_matrix = global_transform
.compute_matrix()
.mul_mat4(&transform.compute_matrix().inverse());
let global_hook_translation =
(*cursor_position + dragged.translation).extend(transform.translation.z);
transform.translation = parent_matrix
.inverse()
.transform_point3(global_hook_translation);
}
}
}
pub enum DropStrategy {
Reset,
Leave,
}
pub struct Draggable {
pub hook: Option<Vec2>,
pub groups: Vec<Group>,
pub drop_strategy: DropStrategy,
}
impl Default for Draggable {
fn default() -> Self {
Self {
hook: None,
groups: vec![Group::default()],
drop_strategy: DropStrategy::Leave,
}
}
}
pub fn mouse_press_start_drag_system(
interaction_state: Res<InteractionState>,
mouse_button_input: Res<Input<MouseButton>>,
draggables: Query<(Entity, &Draggable, &GlobalTransform), With<Interactable>>,
mut commands: Commands,
) {
if !mouse_button_input.just_pressed(MouseButton::Left) {
return;
}
for (entity, draggable, global_transform) in draggables.iter() {
for group in draggable.groups.iter() {
if let Some(list) = interaction_state.ordered_interact_list_map.get(group) {
if let Some((_, position)) = list.iter().find(|(e, _)| e == &entity) {
let translation = draggable
.hook
.unwrap_or(global_transform.translation.truncate() - *position);
commands.entity(entity).insert(Dragged {
group: group.clone(),
translation,
origin: global_transform.translation.truncate(),
just_dropped: false,
just_dragged: true,
});
break;
}
}
}
}
}
pub fn mouse_release_stop_drag_system(
mouse_button_input: Res<Input<MouseButton>>,
mut draggables: Query<(Entity, &Draggable, &mut Dragged, &mut Transform), With<Interactable>>,
mut commands: Commands,
) {
if !mouse_button_input.just_released(MouseButton::Left) {
return;
}
for (entity, draggable, mut dragged, mut transform) in draggables.iter_mut() {
if dragged.just_dropped {
if let DropStrategy::Reset = draggable.drop_strategy {
transform.translation = dragged.origin.extend(transform.translation.z);
}
commands.entity(entity).remove::<Dragged>();
} else {
dragged.just_dropped = true;
}
}
}