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}