vizia_core/views/
spinbox.rs1use crate::icons::{
2 ICON_CHEVRON_DOWN, ICON_CHEVRON_LEFT, ICON_CHEVRON_RIGHT, ICON_CHEVRON_UP, ICON_MINUS,
3 ICON_PLUS,
4};
5use crate::prelude::*;
6
7pub(crate) enum SpinboxEvent {
8 Increment,
9 Decrement,
10}
11
12pub struct Spinbox {
14 orientation: Signal<Orientation>,
15 icons: Signal<SpinboxIcons>,
16
17 on_decrement: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
18 on_increment: Option<Box<dyn Fn(&mut EventContext) + Send + Sync>>,
19}
20
21#[derive(Clone, Copy, Debug, PartialEq)]
23pub enum SpinboxIcons {
24 PlusMinus,
26 Chevrons,
28}
29
30impl_res_simple!(SpinboxIcons);
31
32impl Spinbox {
33 pub fn new<L, T>(cx: &mut Context, signal: L) -> Handle<Spinbox>
35 where
36 L: Copy + SignalGet<T> + Res<T> + 'static,
37 T: Clone + ToStringLocalized,
38 {
39 Self::custom(cx, move |cx| Label::new(cx, signal))
40 }
41
42 pub fn custom<F, V>(cx: &mut Context, content: F) -> Handle<Spinbox>
44 where
45 F: Fn(&mut Context) -> Handle<V>,
46 V: 'static + View,
47 {
48 let orientation = Signal::new(Orientation::Horizontal);
49 let icons = Signal::new(SpinboxIcons::Chevrons);
50
51 Self { orientation, icons, on_decrement: None, on_increment: None }
52 .build(cx, move |cx| {
53 Binding::new(cx, orientation, move |cx| match orientation.get() {
54 Orientation::Horizontal => {
55 Button::new(cx, |cx| {
56 Svg::new(
57 cx,
58 icons.map(|icons| match icons {
59 SpinboxIcons::PlusMinus => ICON_MINUS,
60 SpinboxIcons::Chevrons => ICON_CHEVRON_LEFT,
61 }),
62 )
63 })
64 .on_press(|ex| ex.emit(SpinboxEvent::Decrement))
65 .navigable(true)
66 .class("spinbox-button");
67 }
68
69 Orientation::Vertical => {
70 Button::new(cx, |cx| {
71 Svg::new(
72 cx,
73 icons.map(|icons| match icons {
74 SpinboxIcons::PlusMinus => ICON_PLUS,
75 SpinboxIcons::Chevrons => ICON_CHEVRON_UP,
76 }),
77 )
78 })
79 .on_press(|ex| ex.emit(SpinboxEvent::Increment))
80 .navigable(true)
81 .class("spinbox-button");
82 }
83 });
84 (content)(cx).class("spinbox-value");
85 Binding::new(cx, orientation, move |cx| match orientation.get() {
86 Orientation::Horizontal => {
87 Button::new(cx, |cx| {
88 Svg::new(
89 cx,
90 icons.map(|icons| match icons {
91 SpinboxIcons::PlusMinus => ICON_PLUS,
92 SpinboxIcons::Chevrons => ICON_CHEVRON_RIGHT,
93 }),
94 )
95 })
96 .on_press(|ex| ex.emit(SpinboxEvent::Increment))
97 .navigable(true)
98 .class("spinbox-button");
99 }
100
101 Orientation::Vertical => {
102 Button::new(cx, |cx| {
103 Svg::new(
104 cx,
105 icons.map(|icons| match icons {
106 SpinboxIcons::PlusMinus => ICON_MINUS,
107 SpinboxIcons::Chevrons => ICON_CHEVRON_DOWN,
108 }),
109 )
110 })
111 .on_press(|ex| ex.emit(SpinboxEvent::Decrement))
112 .navigable(true)
113 .class("spinbox-button");
114 }
115 });
116 })
117 .toggle_class("horizontal", orientation.map(|o| o == &Orientation::Horizontal))
118 .toggle_class("vertical", orientation.map(|o| o == &Orientation::Vertical))
119 .navigable(true)
120 }
121}
122
123impl Handle<'_, Spinbox> {
124 pub fn on_increment<F>(self, callback: F) -> Self
126 where
127 F: 'static + Fn(&mut EventContext) + Send + Sync,
128 {
129 self.modify(|spinbox: &mut Spinbox| spinbox.on_increment = Some(Box::new(callback)))
130 }
131
132 pub fn on_decrement<F>(self, callback: F) -> Self
134 where
135 F: 'static + Fn(&mut EventContext) + Send + Sync,
136 {
137 self.modify(|spinbox: &mut Spinbox| spinbox.on_decrement = Some(Box::new(callback)))
138 }
139
140 pub fn orientation(self, orientation: impl Res<Orientation> + 'static) -> Self {
142 let orientation = orientation.to_signal(self.cx);
143 self.bind(orientation, move |handle| {
144 let orientation = orientation.get();
145 handle.modify(move |spinbox| spinbox.orientation.set(orientation));
146 })
147 }
148
149 pub fn icons(self, icons: impl Res<SpinboxIcons> + 'static) -> Self {
151 let icons = icons.to_signal(self.cx);
152 self.bind(icons, move |handle| {
153 let icons = icons.get();
154 handle.modify(move |spinbox| spinbox.icons.set(icons));
155 })
156 }
157}
158
159impl View for Spinbox {
160 fn element(&self) -> Option<&'static str> {
161 Some("spinbox")
162 }
163
164 fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
165 event.map(|spinbox_event, _| match spinbox_event {
166 SpinboxEvent::Increment => {
167 if let Some(callback) = &self.on_increment {
168 (callback)(cx)
169 }
170 }
171
172 SpinboxEvent::Decrement => {
173 if let Some(callback) = &self.on_decrement {
174 (callback)(cx)
175 }
176 }
177 });
178 }
179}