rg3d_ui/
rect.rs

1use crate::{
2    core::{algebra::Vector2, math::Rect, pool::Handle},
3    define_constructor,
4    grid::{Column, GridBuilder, Row},
5    message::{MessageDirection, UiMessage},
6    numeric::NumericType,
7    text::TextBuilder,
8    vec::vec2::{Vec2EditorBuilder, Vec2EditorMessage},
9    widget::{Widget, WidgetBuilder},
10    BuildContext, Control, Thickness, UiNode, UserInterface, VerticalAlignment,
11};
12use std::{
13    any::{Any, TypeId},
14    fmt::Debug,
15    ops::{Deref, DerefMut},
16};
17
18#[derive(Debug, Clone, PartialEq)]
19pub enum RectEditorMessage<T>
20where
21    T: NumericType,
22{
23    Value(Rect<T>),
24}
25
26impl<T: NumericType> RectEditorMessage<T> {
27    define_constructor!(RectEditorMessage:Value => fn value(Rect<T>), layout: false);
28}
29
30#[derive(Debug, Clone)]
31pub struct RectEditor<T>
32where
33    T: NumericType,
34{
35    widget: Widget,
36    position: Handle<UiNode>,
37    size: Handle<UiNode>,
38    value: Rect<T>,
39}
40
41impl<T> Deref for RectEditor<T>
42where
43    T: NumericType,
44{
45    type Target = Widget;
46
47    fn deref(&self) -> &Self::Target {
48        &self.widget
49    }
50}
51
52impl<T> DerefMut for RectEditor<T>
53where
54    T: NumericType,
55{
56    fn deref_mut(&mut self) -> &mut Self::Target {
57        &mut self.widget
58    }
59}
60
61impl<T> Control for RectEditor<T>
62where
63    T: NumericType,
64{
65    fn query_component(&self, type_id: TypeId) -> Option<&dyn Any> {
66        if type_id == TypeId::of::<Self>() {
67            Some(self)
68        } else {
69            None
70        }
71    }
72
73    fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
74        self.widget.handle_routed_message(ui, message);
75
76        if let Some(RectEditorMessage::Value(value)) = message.data::<RectEditorMessage<T>>() {
77            if message.destination() == self.handle
78                && message.direction() == MessageDirection::ToWidget
79                && *value != self.value
80            {
81                self.value = *value;
82
83                ui.send_message(message.reverse());
84            }
85        } else if let Some(Vec2EditorMessage::Value(value)) = message.data::<Vec2EditorMessage<T>>()
86        {
87            if message.direction() == MessageDirection::FromWidget {
88                if message.destination() == self.position {
89                    if self.value.position != *value {
90                        ui.send_message(RectEditorMessage::value(
91                            self.handle,
92                            MessageDirection::ToWidget,
93                            Rect::new(value.x, value.y, self.value.size.x, self.value.size.y),
94                        ));
95                    }
96                } else if message.destination() == self.size && self.value.size != *value {
97                    ui.send_message(RectEditorMessage::value(
98                        self.handle,
99                        MessageDirection::ToWidget,
100                        Rect::new(
101                            self.value.position.x,
102                            self.value.position.y,
103                            value.x,
104                            value.y,
105                        ),
106                    ));
107                }
108            }
109        }
110    }
111}
112
113pub struct RectEditorBuilder<T>
114where
115    T: NumericType,
116{
117    widget_builder: WidgetBuilder,
118    value: Rect<T>,
119}
120
121fn create_field<T: NumericType>(
122    ctx: &mut BuildContext,
123    name: &str,
124    value: Vector2<T>,
125    row: usize,
126) -> (Handle<UiNode>, Handle<UiNode>) {
127    let editor;
128    let grid = GridBuilder::new(
129        WidgetBuilder::new()
130            .with_margin(Thickness::left(10.0))
131            .on_row(row)
132            .with_child(
133                TextBuilder::new(WidgetBuilder::new())
134                    .with_text(name)
135                    .with_vertical_text_alignment(VerticalAlignment::Center)
136                    .build(ctx),
137            )
138            .with_child({
139                editor = Vec2EditorBuilder::new(WidgetBuilder::new().on_column(1))
140                    .with_value(value)
141                    .build(ctx);
142                editor
143            }),
144    )
145    .add_column(Column::strict(70.0))
146    .add_column(Column::stretch())
147    .add_row(Row::stretch())
148    .build(ctx);
149    (grid, editor)
150}
151
152impl<T> RectEditorBuilder<T>
153where
154    T: NumericType,
155{
156    pub fn new(widget_builder: WidgetBuilder) -> Self {
157        Self {
158            widget_builder,
159            value: Default::default(),
160        }
161    }
162
163    pub fn with_value(mut self, value: Rect<T>) -> Self {
164        self.value = value;
165        self
166    }
167
168    pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
169        let (position_grid, position) = create_field(ctx, "Position", self.value.position, 0);
170        let (size_grid, size) = create_field(ctx, "Size", self.value.size, 1);
171        let node = RectEditor {
172            widget: self
173                .widget_builder
174                .with_child(
175                    GridBuilder::new(
176                        WidgetBuilder::new()
177                            .with_child(position_grid)
178                            .with_child(size_grid),
179                    )
180                    .add_row(Row::stretch())
181                    .add_row(Row::stretch())
182                    .add_column(Column::stretch())
183                    .build(ctx),
184                )
185                .build(),
186            value: self.value,
187            position,
188            size,
189        };
190
191        ctx.add_node(UiNode::new(node))
192    }
193}