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