1use crate::resources::BITS_ICON;
24use crate::{
25 brush::Brush,
26 core::{
27 algebra::Vector2,
28 color::Color,
29 math::Rect,
30 num_traits::{Euclid, NumCast, One, Zero},
31 pool::Handle,
32 reflect::prelude::*,
33 type_traits::prelude::*,
34 uuid::uuid,
35 visitor::prelude::*,
36 },
37 define_constructor,
38 draw::{CommandTexture, Draw, DrawingContext},
39 message::{ButtonState, UiMessage},
40 widget::{Widget, WidgetBuilder},
41 BuildContext, Control, MessageDirection, MouseButton, UiNode, UserInterface, WidgetMessage,
42};
43use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
44use std::{
45 fmt::Debug,
46 mem,
47 ops::{BitAnd, BitOr, Deref, DerefMut, Not, Shl},
48};
49
50const BIT_SIZE: f32 = 16.0;
51const BYTE_GAP: f32 = 8.0;
52const ROW_GAP: f32 = 4.0;
53
54const ON_NORMAL: Brush = Brush::Solid(Color::DARK_GRAY);
55const ON_HOVER: Brush = Brush::Solid(Color::LIGHT_BLUE);
56const OFF_HOVER: Brush = Brush::Solid(Color::DARK_SLATE_BLUE);
57
58pub trait BitContainer:
59 BitAnd<Output = Self>
60 + BitOr<Output = Self>
61 + Clone
62 + Copy
63 + Default
64 + One
65 + Shl<Output = Self>
66 + NumCast
67 + Not<Output = Self>
68 + Zero
69 + PartialEq
70 + Debug
71 + Reflect
72 + Visit
73 + Send
74 + TypeUuidProvider
75 + 'static
76{
77}
78
79impl<T> BitContainer for T where
80 T: BitAnd<Output = Self>
81 + BitOr<Output = Self>
82 + Clone
83 + Copy
84 + Default
85 + One
86 + Shl<Output = Self>
87 + NumCast
88 + Not<Output = Self>
89 + Zero
90 + PartialEq
91 + Debug
92 + Reflect
93 + Visit
94 + Send
95 + TypeUuidProvider
96 + 'static
97{
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
101pub enum BitFieldMessage<T: BitContainer> {
102 Value(T),
103}
104
105impl<T: BitContainer> BitFieldMessage<T> {
106 define_constructor!(BitFieldMessage:Value => fn value(T), layout: false);
107}
108
109impl<T: BitContainer> ConstructorProvider<UiNode, UserInterface> for BitField<T> {
110 fn constructor() -> GraphNodeConstructor<UiNode, UserInterface> {
111 GraphNodeConstructor::new::<Self>()
112 .with_variant(format!("Bit Field<{}>", std::any::type_name::<T>()), |ui| {
113 BitFieldBuilder::<T>::new(WidgetBuilder::new())
114 .build(&mut ui.build_ctx())
115 .into()
116 })
117 .with_group("Bit")
118 }
119}
120
121#[derive(Default, Clone, Reflect, Visit, Debug, ComponentProvider)]
122#[reflect(derived_type = "UiNode")]
123pub struct BitField<T>
124where
125 T: BitContainer,
126{
127 pub widget: Widget,
128 pub value: T,
129 #[visit(skip)]
130 #[reflect(hidden)]
131 current_bit: usize,
132 #[visit(skip)]
133 #[reflect(hidden)]
134 bit_state: BitState,
135 #[visit(skip)]
136 #[reflect(hidden)]
137 current_value: bool,
138}
139
140impl<T> Deref for BitField<T>
141where
142 T: BitContainer,
143{
144 type Target = Widget;
145
146 fn deref(&self) -> &Self::Target {
147 &self.widget
148 }
149}
150
151impl<T> DerefMut for BitField<T>
152where
153 T: BitContainer,
154{
155 fn deref_mut(&mut self) -> &mut Self::Target {
156 &mut self.widget
157 }
158}
159
160#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
161enum BitState {
162 #[default]
163 Normal,
164 Hovered,
165 Pressed,
166}
167
168#[must_use]
169fn set_bit_value<T: BitContainer>(value: T, index: usize, bit_value: bool) -> T {
170 if bit_value {
171 set_bit(value, index)
172 } else {
173 reset_bit(value, index)
174 }
175}
176
177#[must_use]
178fn set_bit<T: BitContainer>(value: T, index: usize) -> T {
179 value | (T::one() << T::from(index).unwrap_or_default())
180}
181
182#[must_use]
183fn reset_bit<T: BitContainer>(value: T, index: usize) -> T {
184 value & !(T::one() << T::from(index).unwrap_or_default())
185}
186
187#[must_use]
188fn is_bit_set<T: BitContainer>(value: T, index: usize) -> bool {
189 value & (T::one() << T::from(index).unwrap_or_default()) != T::zero()
190}
191
192fn byte_width(width: f32) -> usize {
193 let byte_size = BIT_SIZE * 8.0;
194 let col_stride = byte_size + BYTE_GAP;
195 ((width - byte_size) / col_stride).floor().max(0.0) as usize + 1
196}
197
198fn bit_to_rect(index: usize, width: usize) -> Rect<f32> {
199 let (byte_index, bit_index) = index.div_rem_euclid(&8);
200 let (byte_y, byte_x) = byte_index.div_rem_euclid(&width);
201 let row_stride = BIT_SIZE + ROW_GAP;
202 let col_stride = BIT_SIZE * 8.0 + BYTE_GAP;
203 let x = col_stride * byte_x as f32 + BIT_SIZE * bit_index as f32;
204 let y = row_stride * byte_y as f32;
205 Rect::new(x, y, BIT_SIZE, BIT_SIZE)
206}
207
208fn position_to_bit(position: Vector2<f32>, size: usize, width: f32) -> Option<usize> {
209 let byte_width = byte_width(width);
210 (0..size).find(|&i| bit_to_rect(i, byte_width).contains(position))
211}
212
213impl<T> TypeUuidProvider for BitField<T>
214where
215 T: BitContainer,
216{
217 fn type_uuid() -> Uuid {
218 combine_uuids(
219 uuid!("6c19b266-18be-46d2-bfd3-f1dc9cb3f36c"),
220 T::type_uuid(),
221 )
222 }
223}
224
225impl<T> Control for BitField<T>
226where
227 T: BitContainer,
228{
229 fn measure_override(&self, _ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
230 let size = mem::size_of::<T>();
231 let byte_size = BIT_SIZE * 8.0;
232 let width = available_size.x;
233 let byte_width = if width.is_finite() {
234 byte_width(width)
235 } else {
236 2
237 };
238 let (byte_height, rem) = size.div_rem_euclid(&byte_width);
239 let byte_height = byte_height + if rem > 0 { 1 } else { 0 };
240 let byte_height = byte_height.max(1);
241 let byte_width = byte_width.min(size);
242 let width = byte_width as f32 * byte_size + (byte_width - 1) as f32 * BYTE_GAP;
243 let height = byte_height as f32 * BIT_SIZE + (byte_height - 1) as f32 * ROW_GAP;
244 Vector2::new(width, height)
245 }
246 fn draw(&self, ctx: &mut DrawingContext) {
247 let value = self.value;
248 let width = self.actual_local_size().x;
249 let byte_width = byte_width(width);
250 let bit_count = mem::size_of::<T>() * 8;
251 for i in 0..bit_count {
252 if (self.current_bit != i || self.bit_state == BitState::Normal) && is_bit_set(value, i)
253 {
254 self.draw_bit_background(i, byte_width, ctx);
255 }
256 }
257 ctx.commit(
258 self.clip_bounds(),
259 ON_NORMAL,
260 CommandTexture::None,
261 &self.material,
262 None,
263 );
264 for i in 0..bit_count {
265 if (self.current_bit != i || self.bit_state == BitState::Normal)
266 && !is_bit_set(value, i)
267 {
268 self.draw_bit_background(i, byte_width, ctx);
269 }
270 }
271 ctx.commit(
272 self.clip_bounds(),
273 Brush::Solid(Color::TRANSPARENT),
274 CommandTexture::None,
275 &self.material,
276 None,
277 );
278 if self.bit_state != BitState::Normal {
279 let i = self.current_bit;
280 self.draw_bit_background(i, byte_width, ctx);
281 if is_bit_set(value, i) {
282 ctx.commit(
283 self.clip_bounds(),
284 ON_HOVER,
285 CommandTexture::None,
286 &self.material,
287 None,
288 );
289 } else {
290 ctx.commit(
291 self.clip_bounds(),
292 OFF_HOVER,
293 CommandTexture::None,
294 &self.material,
295 None,
296 );
297 }
298 }
299 for i in 0..bit_count {
300 if is_bit_set(value, i) {
301 self.draw_bit_foreground(i, byte_width, ctx);
302 }
303 }
304 ctx.commit(
305 self.clip_bounds(),
306 Brush::Solid(Color::WHITE),
307 CommandTexture::None,
308 &self.material,
309 None,
310 );
311 for i in 0..bit_count {
312 if is_bit_set(value, i) {
313 self.draw_bit_icon(i, byte_width, ctx);
314 }
315 }
316 ctx.commit(
317 self.clip_bounds(),
318 Brush::Solid(Color::BLACK),
319 CommandTexture::Texture(BITS_ICON.clone().unwrap()),
320 &self.material,
321 None,
322 );
323 for i in 0..bit_count {
324 if !is_bit_set(value, i) {
325 self.draw_bit_icon(i, byte_width, ctx);
326 }
327 }
328 ctx.commit(
329 self.clip_bounds(),
330 Brush::Solid(Color::GRAY),
331 CommandTexture::Texture(BITS_ICON.clone().unwrap()),
332 &self.material,
333 None,
334 );
335 }
336 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
337 self.widget.handle_routed_message(ui, message);
338
339 if let Some(WidgetMessage::MouseMove { pos, state }) = message.data() {
340 if message.destination() == self.handle()
341 && message.direction() == MessageDirection::FromWidget
342 {
343 let pos = self.screen_to_local(*pos);
344 let size = mem::size_of::<T>() * 8;
345 self.bit_state = BitState::Normal;
346 if let Some(bit_index) = position_to_bit(pos, size, self.actual_local_size().x) {
347 self.current_bit = bit_index;
348 let mut new_value = self.value;
349 match state.left {
350 ButtonState::Pressed => {
351 new_value = set_bit_value(new_value, bit_index, self.current_value);
352 self.bit_state = BitState::Pressed;
353 }
354 ButtonState::Released => {
355 self.bit_state = BitState::Hovered;
356 }
357 }
358
359 if new_value != self.value {
360 ui.send_message(BitFieldMessage::value(
361 self.handle,
362 MessageDirection::ToWidget,
363 new_value,
364 ));
365 }
366 }
367 }
368 } else if let Some(WidgetMessage::MouseDown { pos, button }) = message.data() {
369 if message.destination() == self.handle()
370 && message.direction() == MessageDirection::FromWidget
371 {
372 let pos = self.screen_to_local(*pos);
373 let size = mem::size_of::<T>() * 8;
374 self.bit_state = BitState::Normal;
375 if let Some(bit_index) = position_to_bit(pos, size, self.actual_local_size().x) {
376 self.current_bit = bit_index;
377 match button {
378 MouseButton::Left => {
379 message.set_handled(true);
380 self.bit_state = BitState::Pressed;
381 self.current_value = !is_bit_set(self.value, bit_index);
382 let new_value =
383 set_bit_value(self.value, bit_index, self.current_value);
384 self.bit_state = BitState::Pressed;
385
386 ui.send_message(BitFieldMessage::value(
387 self.handle,
388 MessageDirection::ToWidget,
389 new_value,
390 ));
391 }
392 MouseButton::Right => {
393 message.set_handled(true);
394 self.bit_state = BitState::Hovered;
395 let new_value = if is_bit_set(self.value, bit_index) {
396 !(T::one() << T::from(bit_index).unwrap_or_default())
397 } else {
398 T::one() << T::from(bit_index).unwrap_or_default()
399 };
400
401 ui.send_message(BitFieldMessage::value(
402 self.handle,
403 MessageDirection::ToWidget,
404 new_value,
405 ));
406 }
407 _ => (),
408 }
409 }
410 }
411 } else if let Some(WidgetMessage::MouseLeave)
412 | Some(WidgetMessage::MouseUp {
413 button: MouseButton::Left,
414 ..
415 }) = message.data()
416 {
417 if message.destination() == self.handle() {
418 self.bit_state = BitState::Normal;
419 }
420 } else if let Some(BitFieldMessage::Value(value)) = message.data() {
421 if message.destination() == self.handle
422 && message.direction() == MessageDirection::ToWidget
423 && *value != self.value
424 {
425 self.value = *value;
426 ui.send_message(message.reverse());
427 }
428 }
429 }
430}
431
432impl<T> BitField<T>
433where
434 T: BitContainer,
435{
436 fn screen_to_local(&self, position: Vector2<f32>) -> Vector2<f32> {
437 let trans = self.visual_transform();
438 let Some(trans) = trans.try_inverse() else {
439 return position;
440 };
441 trans.transform_point(&position.into()).coords
442 }
443 fn draw_bit_background(&self, index: usize, width: usize, ctx: &mut DrawingContext) {
444 let rect = bit_to_rect(index, width);
445 ctx.push_rect_filled(&rect, None);
446 }
447 fn draw_bit_foreground(&self, index: usize, width: usize, ctx: &mut DrawingContext) {
448 let rect = bit_to_rect(index, width);
449 ctx.push_rect(&rect, 1.0);
450 }
451 fn draw_bit_icon(&self, index: usize, width: usize, ctx: &mut DrawingContext) {
452 let rect = bit_to_rect(index, width);
453 let center = rect.center();
454 let rect = Rect::new(center.x - 4.0, center.y - 4.0, 8.0, 8.0);
455 let i = index % 32;
456 let u = i as f32 / 32.0;
457 let u1 = (i + 1) as f32 / 32.0;
458 let t0 = Vector2::new(u, 0.0);
459 let t1 = Vector2::new(u1, 0.0);
460 let t2 = Vector2::new(u1, 1.0);
461 let t3 = Vector2::new(u, 1.0);
462 ctx.push_rect_filled(&rect, Some(&[t0, t1, t2, t3]));
463 }
464}
465
466pub struct BitFieldBuilder<T>
467where
468 T: BitContainer,
469{
470 widget_builder: WidgetBuilder,
471 value: T,
472}
473
474impl<T> BitFieldBuilder<T>
475where
476 T: BitContainer,
477{
478 pub fn new(widget_builder: WidgetBuilder) -> Self {
479 Self {
480 widget_builder,
481 value: T::default(),
482 }
483 }
484
485 pub fn with_value(mut self, value: T) -> Self {
486 self.value = value;
487 self
488 }
489
490 pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
491 let canvas = BitField {
492 widget: self.widget_builder.build(ctx),
493 value: self.value,
494 current_bit: 0,
495 bit_state: BitState::Normal,
496 current_value: false,
497 };
498 ctx.add_node(UiNode::new(canvas))
499 }
500}
501
502#[cfg(test)]
503mod test {
504 use super::*;
505 use crate::bit::{byte_width, BitFieldBuilder};
506 use crate::{test::test_widget_deletion, widget::WidgetBuilder};
507
508 #[test]
509 fn test_deletion() {
510 test_widget_deletion(|ctx| BitFieldBuilder::<usize>::new(WidgetBuilder::new()).build(ctx));
511 }
512
513 #[test]
514 fn test_byte_width() {
515 assert_eq!(byte_width(0.0), 1);
516 assert_eq!(byte_width(8.0 * BIT_SIZE), 1);
517 assert_eq!(byte_width(16.0 * BIT_SIZE), 1);
518 assert_eq!(byte_width(16.0 * BIT_SIZE + BYTE_GAP), 2);
519 assert_eq!(byte_width(24.0 * BIT_SIZE + 2.0 * BYTE_GAP), 3);
520 assert_eq!(byte_width(32.0 * BIT_SIZE + 2.0 * BYTE_GAP), 3);
521 assert_eq!(byte_width(32.0 * BIT_SIZE + 3.0 * BYTE_GAP), 4);
522 assert_eq!(byte_width(40.0 * BIT_SIZE + 4.0 * BYTE_GAP), 5);
523 }
524}