Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ui/src/ui_transform.rs
6598 views
1
use crate::Val;
2
use bevy_derive::Deref;
3
use bevy_ecs::component::Component;
4
use bevy_ecs::prelude::ReflectComponent;
5
use bevy_math::Affine2;
6
use bevy_math::Rot2;
7
use bevy_math::Vec2;
8
use bevy_reflect::prelude::*;
9
10
/// A pair of [`Val`]s used to represent a 2-dimensional size or offset.
11
#[derive(Debug, PartialEq, Clone, Copy, Reflect)]
12
#[reflect(Default, PartialEq, Debug, Clone)]
13
#[cfg_attr(
14
feature = "serialize",
15
derive(serde::Serialize, serde::Deserialize),
16
reflect(Serialize, Deserialize)
17
)]
18
pub struct Val2 {
19
/// Translate the node along the x-axis.
20
/// `Val::Percent` values are resolved based on the computed width of the Ui Node.
21
/// `Val::Auto` is resolved to `0.`.
22
pub x: Val,
23
/// Translate the node along the y-axis.
24
/// `Val::Percent` values are resolved based on the computed height of the UI Node.
25
/// `Val::Auto` is resolved to `0.`.
26
pub y: Val,
27
}
28
29
impl Val2 {
30
pub const ZERO: Self = Self {
31
x: Val::ZERO,
32
y: Val::ZERO,
33
};
34
35
/// Creates a new [`Val2`] where both components are in logical pixels
36
pub const fn px(x: f32, y: f32) -> Self {
37
Self {
38
x: Val::Px(x),
39
y: Val::Px(y),
40
}
41
}
42
43
/// Creates a new [`Val2`] where both components are percentage values
44
pub const fn percent(x: f32, y: f32) -> Self {
45
Self {
46
x: Val::Percent(x),
47
y: Val::Percent(y),
48
}
49
}
50
51
/// Creates a new [`Val2`]
52
pub const fn new(x: Val, y: Val) -> Self {
53
Self { x, y }
54
}
55
56
/// Resolves this [`Val2`] from the given `scale_factor`, `parent_size`,
57
/// and `viewport_size`.
58
///
59
/// Component values of [`Val::Auto`] are resolved to 0.
60
pub fn resolve(&self, scale_factor: f32, base_size: Vec2, viewport_size: Vec2) -> Vec2 {
61
Vec2::new(
62
self.x
63
.resolve(scale_factor, base_size.x, viewport_size)
64
.unwrap_or(0.),
65
self.y
66
.resolve(scale_factor, base_size.y, viewport_size)
67
.unwrap_or(0.),
68
)
69
}
70
}
71
72
impl Default for Val2 {
73
fn default() -> Self {
74
Self::ZERO
75
}
76
}
77
78
/// Relative 2D transform for UI nodes
79
///
80
/// [`UiGlobalTransform`] is automatically inserted whenever [`UiTransform`] is inserted.
81
#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)]
82
#[reflect(Component, Default, PartialEq, Debug, Clone)]
83
#[cfg_attr(
84
feature = "serialize",
85
derive(serde::Serialize, serde::Deserialize),
86
reflect(Serialize, Deserialize)
87
)]
88
#[require(UiGlobalTransform)]
89
pub struct UiTransform {
90
/// Translate the node.
91
pub translation: Val2,
92
/// Scale the node. A negative value reflects the node in that axis.
93
pub scale: Vec2,
94
/// Rotate the node clockwise.
95
pub rotation: Rot2,
96
}
97
98
impl UiTransform {
99
pub const IDENTITY: Self = Self {
100
translation: Val2::ZERO,
101
scale: Vec2::ONE,
102
rotation: Rot2::IDENTITY,
103
};
104
105
/// Creates a UI transform representing a rotation.
106
pub const fn from_rotation(rotation: Rot2) -> Self {
107
Self {
108
rotation,
109
..Self::IDENTITY
110
}
111
}
112
113
/// Creates a UI transform representing a responsive translation.
114
pub const fn from_translation(translation: Val2) -> Self {
115
Self {
116
translation,
117
..Self::IDENTITY
118
}
119
}
120
121
/// Creates a UI transform representing a scaling.
122
pub const fn from_scale(scale: Vec2) -> Self {
123
Self {
124
scale,
125
..Self::IDENTITY
126
}
127
}
128
129
/// Resolves the translation from the given `scale_factor`, `base_value`, and `target_size`
130
/// and returns a 2d affine transform from the resolved translation, and the `UiTransform`'s rotation, and scale.
131
pub fn compute_affine(&self, scale_factor: f32, base_size: Vec2, target_size: Vec2) -> Affine2 {
132
Affine2::from_scale_angle_translation(
133
self.scale,
134
self.rotation.as_radians(),
135
self.translation
136
.resolve(scale_factor, base_size, target_size),
137
)
138
}
139
}
140
141
impl Default for UiTransform {
142
fn default() -> Self {
143
Self::IDENTITY
144
}
145
}
146
147
/// Absolute 2D transform for UI nodes
148
///
149
/// [`UiGlobalTransform`]s are updated from [`UiTransform`] and [`Node`](crate::ui_node::Node)
150
/// in [`ui_layout_system`](crate::layout::ui_layout_system)
151
#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect, Deref)]
152
#[reflect(Component, Default, PartialEq, Debug, Clone)]
153
#[cfg_attr(
154
feature = "serialize",
155
derive(serde::Serialize, serde::Deserialize),
156
reflect(Serialize, Deserialize)
157
)]
158
pub struct UiGlobalTransform(Affine2);
159
160
impl Default for UiGlobalTransform {
161
fn default() -> Self {
162
Self(Affine2::IDENTITY)
163
}
164
}
165
166
impl UiGlobalTransform {
167
/// If the transform is invertible returns its inverse.
168
/// Otherwise returns `None`.
169
#[inline]
170
pub fn try_inverse(&self) -> Option<Affine2> {
171
(self.matrix2.determinant() != 0.).then_some(self.inverse())
172
}
173
}
174
175
impl From<Affine2> for UiGlobalTransform {
176
fn from(value: Affine2) -> Self {
177
Self(value)
178
}
179
}
180
181
impl From<UiGlobalTransform> for Affine2 {
182
fn from(value: UiGlobalTransform) -> Self {
183
value.0
184
}
185
}
186
187
impl From<&UiGlobalTransform> for Affine2 {
188
fn from(value: &UiGlobalTransform) -> Self {
189
value.0
190
}
191
}
192
193