ferroui_base/rendering/composition/generated/
ambient_light.rs1use bitflags::bitflags;
8use crate::media::Color;
9use crate::rendering::composition::animations::AnimationInstanceFactory;
10use crate::rendering::composition::animations::ICompositionAnimation;
11use crate::rendering::composition::expressions::ExpressionVariant;
12use crate::rendering::composition::server::CompositionProperty;
13use crate::rendering::composition::server::CompositionPropertyOf;
14use crate::rendering::composition::server::ServerPropertyValue;
15use crate::rendering::composition::server::props_of;
16use crate::rendering::composition::transport::BatchStreamReader;
17use crate::rendering::composition::transport::BatchStreamWriter;
18use crate::rendering::composition::transport::BatchValue;
19use crate::rendering::composition::transport::BatchValueReader;
20use std::any::Any;
21use std::any::TypeId;
22use std::cell::Cell;
23use std::sync::OnceLock;
24use std::time::Duration;
25use super::CompositionLightHooks;
26use super::CompositionLightProps;
27use super::ServerCompositionLightHooks;
28use super::ServerCompositionLightProps;
29
30bitflags! {
31 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
33 pub struct AmbientLightChangedFields: u8 {
34 const COLOR = 1;
35 const COLOR_ANIMATED = 2;
36 const INTENSITY = 4;
37 const INTENSITY_ANIMATED = 8;
38 }
39}
40
41impl BatchValue for AmbientLightChangedFields {
42 #[inline]
43 fn write_to(&self, out: &mut Vec<u8>) {
44 self.bits().write_to(out);
45 }
46
47 #[inline]
48 fn read_from(input: &mut BatchValueReader<'_>) -> Self {
49 AmbientLightChangedFields::from_bits_retain(u8::read_from(input))
50 }
51}
52
53pub trait AmbientLightHooks: CompositionLightHooks {
56 fn initialize_defaults_extra(&self) {}
57
58 fn validate_color_change(&self, _old_value: Color, _new_value: Color) {}
59 fn on_color_changed(&self) {}
60 fn on_color_changing(&self) {}
61
62 fn validate_intensity_change(&self, _old_value: f32, _new_value: f32) {}
63 fn on_intensity_changed(&self) {}
64 fn on_intensity_changing(&self) {}
65}
66
67pub struct AmbientLightProps {
69 base: CompositionLightProps,
70 changed_fields_of_ambient_light: Cell<AmbientLightChangedFields>,
71 color: Cell<Color>,
72 intensity: Cell<f32>,
73}
74
75impl Default for AmbientLightProps {
76 fn default() -> Self {
77 Self::new()
78 }
79}
80
81impl AmbientLightProps {
82 pub fn new() -> Self {
86 Self {
87 base: CompositionLightProps::new(),
88 changed_fields_of_ambient_light: Cell::new(AmbientLightChangedFields::empty()),
89 color: Cell::new(Default::default()),
90 intensity: Cell::new(Default::default()),
91 }
92 }
93
94 pub fn base(&self) -> &CompositionLightProps {
96 &self.base
97 }
98
99 pub fn initialize_defaults(&self, host: &dyn AmbientLightHooks) {
102 self.base.initialize_defaults(host);
103 self.initialize_own_defaults(host);
104 }
105
106 pub fn initialize_own_defaults(&self, host: &dyn AmbientLightHooks) {
108 AmbientLightHooks::initialize_defaults_extra(host);
109 self.set_color(host, crate::media::Colors::WHITE);
110 self.set_intensity(host, 1.0);
111 }
112
113 pub fn color(&self) -> Color {
115 self.color.get()
116 }
117
118 pub fn set_color(&self, host: &dyn AmbientLightHooks, value: Color) {
120 let mut changed = false;
121 let old_value = self.color.get();
122 if old_value.differs(&value) {
123 AmbientLightHooks::validate_color_change(host, old_value, value);
124 AmbientLightHooks::on_color_changing(host);
125 changed = true;
126 self.color.set(value);
128 self.changed_fields_of_ambient_light.set(self.changed_fields_of_ambient_light.get() | AmbientLightChangedFields::COLOR);
130 host.register_for_serialization();
131 host.pending_animations().remove(ServerAmbientLightProps::id_of_color_property().base());
133 self.changed_fields_of_ambient_light.set(self.changed_fields_of_ambient_light.get() & !AmbientLightChangedFields::COLOR_ANIMATED);
134 if let Some(animation) = host.implicit_animation("Color") {
136 if let Some(a) = animation.as_composition_animation() {
138 self.changed_fields_of_ambient_light.set(self.changed_fields_of_ambient_light.get() | AmbientLightChangedFields::COLOR_ANIMATED);
139 host.pending_animations().set(
140 ServerAmbientLightProps::id_of_color_property().base(),
141 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
142 );
143 }
144 host.start_animation_group(&animation, "Color", ExpressionVariant::create(value));
146 }
147 }
148 self.color.set(value);
149 if changed {
150 AmbientLightHooks::on_color_changed(host);
151 }
152 }
153
154 pub fn intensity(&self) -> f32 {
156 self.intensity.get()
157 }
158
159 pub fn set_intensity(&self, host: &dyn AmbientLightHooks, value: f32) {
161 let mut changed = false;
162 let old_value = self.intensity.get();
163 if old_value.differs(&value) {
164 AmbientLightHooks::validate_intensity_change(host, old_value, value);
165 AmbientLightHooks::on_intensity_changing(host);
166 changed = true;
167 self.intensity.set(value);
169 self.changed_fields_of_ambient_light.set(self.changed_fields_of_ambient_light.get() | AmbientLightChangedFields::INTENSITY);
171 host.register_for_serialization();
172 host.pending_animations().remove(ServerAmbientLightProps::id_of_intensity_property().base());
174 self.changed_fields_of_ambient_light.set(self.changed_fields_of_ambient_light.get() & !AmbientLightChangedFields::INTENSITY_ANIMATED);
175 if let Some(animation) = host.implicit_animation("Intensity") {
177 if let Some(a) = animation.as_composition_animation() {
179 self.changed_fields_of_ambient_light.set(self.changed_fields_of_ambient_light.get() | AmbientLightChangedFields::INTENSITY_ANIMATED);
180 host.pending_animations().set(
181 ServerAmbientLightProps::id_of_intensity_property().base(),
182 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
183 );
184 }
185 host.start_animation_group(&animation, "Intensity", ExpressionVariant::create(value));
187 }
188 }
189 self.intensity.set(value);
190 if changed {
191 AmbientLightHooks::on_intensity_changed(host);
192 }
193 }
194
195 pub fn start_animation(
199 &self,
200 host: &dyn AmbientLightHooks,
201 property_name: &str,
202 animation: &dyn ICompositionAnimation,
203 final_value: Option<ExpressionVariant>,
204 ) -> bool {
205 if property_name == "Color" {
206 let server = animation.create_instance(host.server(), final_value);
207 host.pending_animations().set(ServerAmbientLightProps::id_of_color_property().base(), server);
208 self.changed_fields_of_ambient_light.set(self.changed_fields_of_ambient_light.get() | AmbientLightChangedFields::COLOR_ANIMATED);
209 host.register_for_serialization();
210 return true;
211 }
212 if property_name == "Intensity" {
213 let server = animation.create_instance(host.server(), final_value);
214 host.pending_animations().set(ServerAmbientLightProps::id_of_intensity_property().base(), server);
215 self.changed_fields_of_ambient_light.set(self.changed_fields_of_ambient_light.get() | AmbientLightChangedFields::INTENSITY_ANIMATED);
216 host.register_for_serialization();
217 return true;
218 }
219 false
220 }
221
222 pub fn serialize_changes_core(&self, host: &dyn AmbientLightHooks, writer: &mut BatchStreamWriter<'_>) {
225 self.base.serialize_changes_core(host, writer);
226 let changed = self.changed_fields_of_ambient_light.get();
227 writer.write(changed);
228 if changed.contains(AmbientLightChangedFields::COLOR_ANIMATED) {
229 writer.write_value(host.pending_animations().get_and_remove(ServerAmbientLightProps::id_of_color_property().base()));
230 } else if changed.contains(AmbientLightChangedFields::COLOR) {
231 writer.write(self.color.get());
232 }
233 if changed.contains(AmbientLightChangedFields::INTENSITY_ANIMATED) {
234 writer.write_value(host.pending_animations().get_and_remove(ServerAmbientLightProps::id_of_intensity_property().base()));
235 } else if changed.contains(AmbientLightChangedFields::INTENSITY) {
236 writer.write(self.intensity.get());
237 }
238 self.changed_fields_of_ambient_light.set(AmbientLightChangedFields::empty());
239 }
240}
241
242pub trait ServerAmbientLightHooks: ServerCompositionLightHooks {
245 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
246 fn on_fields_deserialized(&self, _changed: AmbientLightChangedFields) {}
247}
248
249pub struct ServerAmbientLightProps {
251 base: ServerCompositionLightProps,
252 color: Cell<Color>,
253 intensity: Cell<f32>,
254}
255
256impl Default for ServerAmbientLightProps {
257 fn default() -> Self {
258 Self::new()
259 }
260}
261
262impl ServerAmbientLightProps {
263 pub fn new() -> Self {
266 Self {
267 base: ServerCompositionLightProps::new(),
268 color: Cell::new(Default::default()),
269 intensity: Cell::new(Default::default()),
270 }
271 }
272
273 pub fn base(&self) -> &ServerCompositionLightProps {
275 &self.base
276 }
277
278 pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
281 if type_id == TypeId::of::<Self>() {
282 return Some(self);
283 }
284 self.base.find_props(type_id)
285 }
286
287 pub fn id_of_color_property() -> &'static CompositionPropertyOf<Color> {
289 static PROPERTY: OnceLock<CompositionPropertyOf<Color>> = OnceLock::new();
290 PROPERTY.get_or_init(|| {
291 CompositionProperty::register::<ServerAmbientLightProps, Color>(
292 "Color",
293 "ServerAmbientLight",
294 |obj| props_of::<ServerAmbientLightProps>(obj).color.get(),
295 |obj, v| props_of::<ServerAmbientLightProps>(obj).color.set(v),
296 Some(|obj| ExpressionVariant::create(props_of::<ServerAmbientLightProps>(obj).color.get())),
297 Some(|obj, v: ExpressionVariant| props_of::<ServerAmbientLightProps>(obj).color.set(v.cast_or_default::<Color>())),
298 )
299 })
300 }
301
302 pub fn color(&self) -> Color {
304 self.color.get()
305 }
306
307 pub fn set_color(&self, host: &dyn ServerAmbientLightHooks, value: Color) {
308 self.color.set(value);
309 host.remove_animation_for_property(Self::id_of_color_property().base());
310 }
311
312 pub fn id_of_intensity_property() -> &'static CompositionPropertyOf<f32> {
314 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
315 PROPERTY.get_or_init(|| {
316 CompositionProperty::register::<ServerAmbientLightProps, f32>(
317 "Intensity",
318 "ServerAmbientLight",
319 |obj| props_of::<ServerAmbientLightProps>(obj).intensity.get(),
320 |obj, v| props_of::<ServerAmbientLightProps>(obj).intensity.set(v),
321 Some(|obj| ExpressionVariant::create(props_of::<ServerAmbientLightProps>(obj).intensity.get())),
322 Some(|obj, v: ExpressionVariant| props_of::<ServerAmbientLightProps>(obj).intensity.set(v.cast_or_default::<f32>())),
323 )
324 })
325 }
326
327 pub fn intensity(&self) -> f32 {
329 self.intensity.get()
330 }
331
332 pub fn set_intensity(&self, host: &dyn ServerAmbientLightHooks, value: f32) {
333 self.intensity.set(value);
334 host.remove_animation_for_property(Self::id_of_intensity_property().base());
335 }
336
337 pub fn deserialize_changes_core(
340 &self,
341 host: &dyn ServerAmbientLightHooks,
342 reader: &mut BatchStreamReader<'_>,
343 committed_at: Duration,
344 ) {
345 self.base.deserialize_changes_core(host, reader, committed_at);
346 ServerAmbientLightHooks::deserialize_changes_extra(host, reader);
347 let changed = reader.read::<AmbientLightChangedFields>();
348 if changed.contains(AmbientLightChangedFields::COLOR_ANIMATED) {
349 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
350 panic!("a batch starts an animation of `Color` without an animation instance");
351 };
352 host.set_animated_value(
353 Self::id_of_color_property().base(),
354 ExpressionVariant::create(self.color.get()),
355 committed_at,
356 animation,
357 );
358 } else if changed.contains(AmbientLightChangedFields::COLOR) {
359 let value = reader.read::<Color>();
360 self.set_color(host, value);
361 }
362 if changed.contains(AmbientLightChangedFields::INTENSITY_ANIMATED) {
363 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
364 panic!("a batch starts an animation of `Intensity` without an animation instance");
365 };
366 host.set_animated_value(
367 Self::id_of_intensity_property().base(),
368 ExpressionVariant::create(self.intensity.get()),
369 committed_at,
370 animation,
371 );
372 } else if changed.contains(AmbientLightChangedFields::INTENSITY) {
373 let value = reader.read::<f32>();
374 self.set_intensity(host, value);
375 }
376 ServerAmbientLightHooks::on_fields_deserialized(host, changed);
377 }
378
379 pub fn get_composition_property(name: &str) -> Option<&'static CompositionProperty> {
382 if name == "Color" {
383 return Some(Self::id_of_color_property().base());
384 }
385 if name == "Intensity" {
386 return Some(Self::id_of_intensity_property().base());
387 }
388 ServerCompositionLightProps::get_composition_property(name)
389 }
390}