1use crate::{
24 check_box::{CheckBoxBuilder, CheckBoxMessage},
25 core::{
26 num_traits::{NumCast, One, Zero},
27 pool::Handle,
28 reflect::prelude::*,
29 type_traits::prelude::*,
30 uuid::uuid,
31 visitor::prelude::*,
32 },
33 define_constructor,
34 message::UiMessage,
35 widget::{Widget, WidgetBuilder},
36 wrap_panel::WrapPanelBuilder,
37 BuildContext, Control, MessageDirection, MouseButton, Orientation, Thickness, UiNode,
38 UserInterface, WidgetMessage,
39};
40use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
41use fyrox_graph::BaseSceneGraph;
42use std::{
43 fmt::Debug,
44 mem,
45 ops::{BitAnd, BitOr, Deref, DerefMut, Not, Shl},
46};
47
48pub trait BitContainer:
49 BitAnd<Output = Self>
50 + BitOr<Output = Self>
51 + Clone
52 + Copy
53 + Default
54 + One
55 + Shl<Output = Self>
56 + NumCast
57 + Not<Output = Self>
58 + Zero
59 + PartialEq
60 + Debug
61 + Reflect
62 + Visit
63 + Send
64 + TypeUuidProvider
65 + 'static
66{
67}
68
69impl<T> BitContainer for T where
70 T: BitAnd<Output = Self>
71 + BitOr<Output = Self>
72 + Clone
73 + Copy
74 + Default
75 + One
76 + Shl<Output = Self>
77 + NumCast
78 + Not<Output = Self>
79 + Zero
80 + PartialEq
81 + Debug
82 + Reflect
83 + Visit
84 + Send
85 + TypeUuidProvider
86 + 'static
87{
88}
89
90#[derive(Debug, Clone, PartialEq, Eq)]
91pub enum BitFieldMessage<T: BitContainer> {
92 Value(T),
93}
94
95impl<T: BitContainer> BitFieldMessage<T> {
96 define_constructor!(BitFieldMessage:Value => fn value(T), layout: false);
97}
98
99impl<T: BitContainer> ConstructorProvider<UiNode, UserInterface> for BitField<T> {
100 fn constructor() -> GraphNodeConstructor<UiNode, UserInterface> {
101 GraphNodeConstructor::new::<Self>()
102 .with_variant(format!("Bit Field<{}>", std::any::type_name::<T>()), |ui| {
103 BitFieldBuilder::<T>::new(WidgetBuilder::new())
104 .build(&mut ui.build_ctx())
105 .into()
106 })
107 .with_group("Bit")
108 }
109}
110
111#[derive(Default, Clone, Reflect, Visit, Debug, ComponentProvider)]
112pub struct BitField<T>
113where
114 T: BitContainer,
115{
116 pub widget: Widget,
117 pub value: T,
118 pub bit_switches: Vec<Handle<UiNode>>,
119}
120
121impl<T> Deref for BitField<T>
122where
123 T: BitContainer,
124{
125 type Target = Widget;
126
127 fn deref(&self) -> &Self::Target {
128 &self.widget
129 }
130}
131
132impl<T> DerefMut for BitField<T>
133where
134 T: BitContainer,
135{
136 fn deref_mut(&mut self) -> &mut Self::Target {
137 &mut self.widget
138 }
139}
140
141#[must_use]
142fn set_bit<T: BitContainer>(value: T, index: usize) -> T {
143 value | (T::one() << T::from(index).unwrap_or_default())
144}
145
146#[must_use]
147fn reset_bit<T: BitContainer>(value: T, index: usize) -> T {
148 value & !(T::one() << T::from(index).unwrap_or_default())
149}
150
151#[must_use]
152fn is_bit_set<T: BitContainer>(value: T, index: usize) -> bool {
153 value & (T::one() << T::from(index).unwrap_or_default()) != T::zero()
154}
155
156impl<T> TypeUuidProvider for BitField<T>
157where
158 T: BitContainer,
159{
160 fn type_uuid() -> Uuid {
161 combine_uuids(
162 uuid!("6c19b266-18be-46d2-bfd3-f1dc9cb3f36c"),
163 T::type_uuid(),
164 )
165 }
166}
167
168impl<T> Control for BitField<T>
169where
170 T: BitContainer,
171{
172 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
173 self.widget.handle_routed_message(ui, message);
174
175 if let Some(CheckBoxMessage::Check(Some(value))) = message.data() {
176 if message.direction() == MessageDirection::FromWidget {
177 if let Some(bit_index) = self
178 .bit_switches
179 .iter()
180 .position(|s| *s == message.destination())
181 {
182 let new_value = if *value {
183 set_bit(self.value, bit_index)
184 } else {
185 reset_bit(self.value, bit_index)
186 };
187
188 ui.send_message(BitFieldMessage::value(
189 self.handle,
190 MessageDirection::ToWidget,
191 new_value,
192 ));
193 }
194 }
195 } else if let Some(BitFieldMessage::Value(value)) = message.data() {
196 if message.destination() == self.handle
197 && message.direction() == MessageDirection::ToWidget
198 && *value != self.value
199 {
200 self.value = *value;
201 self.sync_switches(ui);
202 ui.send_message(message.reverse());
203 }
204 } else if let Some(WidgetMessage::MouseDown { button, .. }) = message.data() {
205 if *button == MouseButton::Right {
206 for (index, bit) in self.bit_switches.iter().cloned().enumerate() {
207 if ui.node(bit).has_descendant(message.destination(), ui) {
208 let new_value = if is_bit_set(self.value, index) {
209 !(T::one() << T::from(index).unwrap_or_default())
210 } else {
211 T::one() << T::from(index).unwrap_or_default()
212 };
213
214 ui.send_message(BitFieldMessage::value(
215 self.handle,
216 MessageDirection::ToWidget,
217 new_value,
218 ));
219 }
220 }
221 }
222 }
223 }
224}
225
226impl<T> BitField<T>
227where
228 T: BitContainer,
229{
230 fn sync_switches(&self, ui: &UserInterface) {
231 for (i, handle) in self.bit_switches.iter().cloned().enumerate() {
232 ui.send_message(CheckBoxMessage::checked(
233 handle,
234 MessageDirection::ToWidget,
235 Some(is_bit_set(self.value, i)),
236 ));
237 }
238 }
239}
240
241pub struct BitFieldBuilder<T>
242where
243 T: BitContainer,
244{
245 widget_builder: WidgetBuilder,
246 value: T,
247}
248
249impl<T> BitFieldBuilder<T>
250where
251 T: BitContainer,
252{
253 pub fn new(widget_builder: WidgetBuilder) -> Self {
254 Self {
255 widget_builder,
256 value: T::default(),
257 }
258 }
259
260 pub fn with_value(mut self, value: T) -> Self {
261 self.value = value;
262 self
263 }
264
265 pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
266 let bit_switches = (0..(mem::size_of::<T>() * 8))
267 .map(|i| {
268 CheckBoxBuilder::new(WidgetBuilder::new().with_margin(Thickness::uniform(1.0)))
269 .checked(Some(is_bit_set(self.value, i)))
270 .build(ctx)
271 })
272 .collect::<Vec<_>>();
273
274 let panel =
275 WrapPanelBuilder::new(WidgetBuilder::new().with_children(bit_switches.iter().cloned()))
276 .with_orientation(Orientation::Horizontal)
277 .build(ctx);
278
279 let canvas = BitField {
280 widget: self.widget_builder.with_child(panel).build(ctx),
281 value: self.value,
282 bit_switches,
283 };
284 ctx.add_node(UiNode::new(canvas))
285 }
286}
287
288#[cfg(test)]
289mod test {
290 use crate::bit::BitFieldBuilder;
291 use crate::{test::test_widget_deletion, widget::WidgetBuilder};
292
293 #[test]
294 fn test_deletion() {
295 test_widget_deletion(|ctx| BitFieldBuilder::<usize>::new(WidgetBuilder::new()).build(ctx));
296 }
297}