hui/element/builtin/
transformer.rs

1//! wrapper that allows applying various transformations to an element, such as translation, rotation, or scaling
2
3use glam::{Affine2, Vec2};
4use crate::{
5  draw::UiDrawCommand, element::{MeasureContext, ProcessContext, UiElement}, measure::Response
6};
7
8pub struct Transformer {
9  pub transform: Affine2,
10  pub element: Box<dyn UiElement>,
11}
12
13/// Wrapper that allows applying various transformations to an element, such as translation, rotation, or scaling\
14/// Use sparingly, as this is an experimental feature and may not work as expected\
15impl Transformer {
16  pub fn new(element: Box<dyn UiElement>) -> Self {
17    Self {
18      transform: Affine2::IDENTITY,
19      element,
20    }
21  }
22
23  pub fn translate(mut self, v: impl Into<Vec2>) -> Self {
24    self.transform *= Affine2::from_translation(v.into());
25    self
26  }
27
28  pub fn scale(mut self, v: impl Into<Vec2>) -> Self {
29    self.transform *= Affine2::from_scale(v.into());
30    self
31  }
32
33  pub fn rotate(mut self, radians: f32) -> Self {
34    self.transform *= Affine2::from_angle(radians);
35    self
36  }
37}
38
39impl UiElement for Transformer {
40  fn name(&self) -> &'static str {
41    "transformer"
42  }
43
44  fn measure(&self, ctx: MeasureContext) -> Response {
45    self.element.measure(ctx)
46  }
47
48  fn process(&self, ctx: ProcessContext) {
49    ctx.draw.add(UiDrawCommand::PushTransform(self.transform));
50    //This is stupid:
51    self.element.process(ProcessContext {
52      measure: ctx.measure,
53      state: ctx.state,
54      layout: ctx.layout,
55      draw: ctx.draw,
56      text_measure: ctx.text_measure,
57      current_font: ctx.current_font,
58      images: ctx.images,
59      input: ctx.input,
60      signal: ctx.signal,
61    });
62    ctx.draw.add(UiDrawCommand::PopTransform);
63  }
64}
65
66/// Extension trait for [`UiElement`] that adds the [`transform`] method
67pub trait ElementTransformExt {
68  /// Wrap the element in a [`Transformer`]
69  ///
70  /// This allows you to apply various transformations to the element, such as translation, rotation, or scaling\
71  /// Use sparingly, as this is an experimental feature and may not work as expected\
72  /// Transform is applied around the center of the element's bounding box.
73  fn transform(self) -> Transformer;
74}
75
76impl<T: UiElement + 'static> ElementTransformExt for T {
77  fn transform(self) -> Transformer {
78    Transformer::new(Box::new(self))
79  }
80}