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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
//-------------------------------------------------------------------------------------------------------------------
/// Anchor point on a tooltip's parent where the tooltip should be positioned.
//-------------------------------------------------------------------------------------------------------------------
/// A tooltip's alignment on its edge facing the parent node. Without any offset, the anchor point and alignment
/// point will overlap.
//-------------------------------------------------------------------------------------------------------------------
/// Component/instruction for setting up a tooltip associated with the current entity.
///
/// The tooltip will spawn as a fresh UI scene when hovering the entity.
// Need WithTooltipReactor component to insert on reactor entities so they can be cleaned up on WithTooltip revert
// Reactor entities should be child-ed to the WithTooltip entity
// On tooltip spawn, make Animated<PropagateOpacity> to control the entry, and another tied to the Dying pseudostate
// for fade-out.
/*
Events:
- On tooltip activation (after delay).
- On tooltip deactivation (after delay).
- target entity: WithTooltip instruction
- on_pointer_enter, on_pressed: spawn tooltip, add HasTooltip component to hovered entity
- on_pointer_leave, on_released, on_press_canceled: remove HasTooltip component, add "Dying" pseudostate
(activates Animated<PropagateOpacity>), also add DespawnOnOpacityOut component which waits for PropagateOpacity to
reach zero then despawns
- DespawnOnOpacityOut checker system should be ordered in Last to make sure PropagateOpacity has a chance to be
inserted by the flux framework
- tooltip
- has TooltipParent component
- has WindowClamp component
- has CenterPosition component
- includes absolute offset
- includes left/right and top/bottom
- has Animated<PropagateOpacity> with delay for on_enter, and a second entry tied to "Dying" pseudostate
- system: update CenterPosition from TooltipParent, if parent is missing then despawn self
- system:
- demo
- make mock-draggable object with tooltip
- on trigger DragStart, insert ComputedCenteringDrag component with initial center position
- on trigger Drag, update ComputedCenteringDrag with distance traveled
- no need to remove ComputedCenteringDrag for the demo
- system: convert ComputedCenteringDrag to Transform
- use TargetCamera on current node to detect which window we are in? camera -> render target -> window entity
*/
/*
// Reference solution from discord user:
use bevy::{math::Vec3A, prelude::*, ui::UiSystem, window::PrimaryWindow};
pub fn plugin(app: &mut App) {
app.add_systems(
PostUpdate,
window_clamp.after(TransformSystem::TransformPropagate),
);
app.add_systems(
PostUpdate,
center_position
.after(UiSystem::Layout)
.before(TransformSystem::TransformPropagate),
);
}
/// UI nodes with this component will position their center at the specified position.
#[derive(Component)]
pub struct CenterPosition {
pub position: Vec2,
}
/// UI nodes with this component will be moved to fit within the window size.
#[derive(Component)]
pub struct WindowClamp;
pub fn center_position(mut nodes: Query<(&mut Transform, &CenterPosition)>) {
for (mut transform, center) in &mut nodes {
transform.translation.x = center.position.x;
transform.translation.y = center.position.y;
}
}
pub fn window_clamp(
mut nodes: Query<(&mut UiGlobalTransform, &ComputedNode), With<WindowClamp>>,
window: Single<&Window, With<PrimaryWindow>>,
) {
let size = window.size();
for (mut transform, node) in &mut nodes {
let mut affine = transform.affine();
let half_size = node.size() / 2.0;
let min = (affine.translation.xy() - half_size).min(Vec2::ZERO);
let max = size - (affine.translation.xy() + half_size).max(size);
affine.translation += Vec3A::from((min + max).extend(0.0));
*transform = UiGlobalTransform::from(affine);
}
}
*/
//-------------------------------------------------------------------------------------------------------------------
pub ;
//-------------------------------------------------------------------------------------------------------------------