1use crate::Val;
2use bevy_derive::Deref;
3use bevy_ecs::component::Component;
4use bevy_ecs::prelude::ReflectComponent;
5use bevy_math::Affine2;
6use bevy_math::Rot2;
7use bevy_math::Vec2;
8use bevy_reflect::prelude::*;
9
10#[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)]
18pub struct Val2 {
19 pub x: Val,
23 pub y: Val,
27}
28
29impl Val2 {
30 pub const ZERO: Self = Self {
31 x: Val::ZERO,
32 y: Val::ZERO,
33 };
34
35 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 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 pub const fn new(x: Val, y: Val) -> Self {
53 Self { x, y }
54 }
55
56 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
72impl Default for Val2 {
73 fn default() -> Self {
74 Self::ZERO
75 }
76}
77
78#[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)]
89pub struct UiTransform {
90 pub translation: Val2,
92 pub scale: Vec2,
94 pub rotation: Rot2,
96}
97
98impl UiTransform {
99 pub const IDENTITY: Self = Self {
100 translation: Val2::ZERO,
101 scale: Vec2::ONE,
102 rotation: Rot2::IDENTITY,
103 };
104
105 pub const fn from_rotation(rotation: Rot2) -> Self {
107 Self {
108 rotation,
109 ..Self::IDENTITY
110 }
111 }
112
113 pub const fn from_translation(translation: Val2) -> Self {
115 Self {
116 translation,
117 ..Self::IDENTITY
118 }
119 }
120
121 pub const fn from_scale(scale: Vec2) -> Self {
123 Self {
124 scale,
125 ..Self::IDENTITY
126 }
127 }
128
129 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
141impl Default for UiTransform {
142 fn default() -> Self {
143 Self::IDENTITY
144 }
145}
146
147#[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)]
158pub struct UiGlobalTransform(Affine2);
159
160impl Default for UiGlobalTransform {
161 fn default() -> Self {
162 Self(Affine2::IDENTITY)
163 }
164}
165
166impl UiGlobalTransform {
167 #[inline]
170 pub fn try_inverse(&self) -> Option<Affine2> {
171 (self.matrix2.determinant() != 0.).then_some(self.inverse())
172 }
173}
174
175impl From<Affine2> for UiGlobalTransform {
176 fn from(value: Affine2) -> Self {
177 Self(value)
178 }
179}
180
181impl From<UiGlobalTransform> for Affine2 {
182 fn from(value: UiGlobalTransform) -> Self {
183 value.0
184 }
185}
186
187impl From<&UiGlobalTransform> for Affine2 {
188 fn from(value: &UiGlobalTransform) -> Self {
189 value.0
190 }
191}