vizia_core/views/
rating.rs1use crate::{icons::ICON_STAR_FILLED, prelude::*};
2
3pub struct Rating {
5 rating: Signal<u32>,
6 max_rating: u32,
7 on_change: Option<Box<dyn Fn(&mut EventContext, u32)>>,
8}
9
10pub(crate) enum RatingEvent {
11 SetRating(u32),
12 EmitRating,
13 Increment,
14 Decrement,
15}
16
17impl Rating {
18 pub fn new(
20 cx: &mut Context,
21 max_rating: u32,
22 rating: impl Res<u32> + SignalGet<u32> + SignalMap<u32>,
23 ) -> Handle<Self> {
24 let local_rating = Signal::new(rating.get());
25 Self { rating: local_rating, max_rating, on_change: None }
26 .build(cx, |cx| {
27 for i in 1..max_rating + 1 {
28 Svg::new(cx, ICON_STAR_FILLED)
29 .checkable(true)
31 .numeric_value(1)
32 .role(Role::RadioButton)
33 .checked(rating.map(move |r| *r >= i))
34 .toggle_class("foo", local_rating.map(move |r| *r >= i))
35 .on_hover(move |ex| ex.emit(RatingEvent::SetRating(i)))
36 .on_press(|ex| ex.emit(RatingEvent::EmitRating));
37 }
38 })
39 .numeric_value(rating)
40 .navigable(true)
41 .role(Role::RadioGroup)
42 .bind(rating, move |handle| {
43 let val = rating.get();
44 handle.modify(|rating| rating.rating.set(val));
45 })
46 }
47}
48
49impl View for Rating {
50 fn element(&self) -> Option<&'static str> {
51 Some("rating")
52 }
53
54 fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
55 event.map(|rating_event, _| match rating_event {
56 RatingEvent::SetRating(val) => self.rating.set(*val),
57 RatingEvent::EmitRating => {
58 if let Some(callback) = &self.on_change {
59 (callback)(cx, self.rating.get());
60 }
61 }
62 RatingEvent::Increment => {
63 self.rating.set((self.rating.get() + 1) % (self.max_rating + 1));
64 cx.emit(RatingEvent::EmitRating);
65 }
66 RatingEvent::Decrement => {
67 self.rating.set(if self.rating.get() == 0 {
68 self.max_rating
69 } else {
70 self.rating.get().saturating_sub(1)
71 });
72 cx.emit(RatingEvent::EmitRating);
73 }
74 });
75
76 event.map(|window_event, _| match window_event {
77 WindowEvent::KeyDown(code, _) => match code {
78 Code::ArrowLeft => {
79 cx.emit(RatingEvent::Decrement);
80 }
81
82 Code::ArrowRight => {
83 cx.emit(RatingEvent::Increment);
84 }
85
86 _ => {}
87 },
88
89 _ => {}
90 });
91 }
92}
93
94impl Handle<'_, Rating> {
95 pub fn on_change<F>(self, callback: F) -> Self
97 where
98 F: 'static + Fn(&mut EventContext, u32),
99 {
100 self.modify(|rating| rating.on_change = Some(Box::new(callback)))
101 }
102}