fltk_extras/
button.rs

1use crate::styles::colors::*;
2use fltk::{enums::*, prelude::*, *};
3use std::cell::RefCell;
4use std::rc::Rc;
5
6#[derive(Clone)]
7pub struct Toggle {
8    p: group::Pack,
9    btn: button::ToggleButton,
10}
11
12impl Default for Toggle {
13    fn default() -> Self {
14        Toggle::new(0, 0, 0, 0, "")
15    }
16}
17
18impl Toggle {
19    pub fn new(x: i32, y: i32, w: i32, h: i32, label: &str) -> Self {
20        let p = group::Pack::new(x, y, w, h, None)
21            .with_label(label)
22            .with_align(Align::Left);
23        frame::Frame::default().with_size(w, 7);
24        let mut btn = button::ToggleButton::new(x, y, w, 14, "@+6square")
25            .with_align(Align::Left | Align::Inside);
26        btn.set_frame(FrameType::FlatBox);
27        btn.set_down_frame(FrameType::FlatBox);
28        btn.set_label_color(Color::White);
29        btn.set_color(RED);
30        btn.set_selection_color(GREEN);
31        btn.clear_visible_focus();
32        btn.handle(|b, ev| match ev {
33            Event::Push => {
34                if b.value() {
35                    b.set_align(Align::Left | Align::Inside);
36                } else {
37                    b.set_align(Align::Right | Align::Inside);
38                }
39                app::redraw();
40                true
41            }
42            _ => false,
43        });
44        p.end();
45        Self { btn, p }
46    }
47    pub fn set_value(&mut self, val: bool) {
48        self.btn.set_value(val);
49        if self.btn.value() {
50            self.btn.set_align(Align::Right | Align::Inside);
51        } else {
52            self.btn.set_align(Align::Left | Align::Inside);
53        }
54        app::redraw();
55    }
56    pub fn value(&self) -> bool {
57        self.btn.value()
58    }
59    pub fn set_callback<F: 'static + FnMut(&mut Self)>(&mut self, mut cb: F) {
60        let mut s = self.clone();
61        self.btn.set_callback(move |_| {
62            cb(&mut s);
63            app::redraw();
64        });
65    }
66}
67
68fltk::widget_extends!(Toggle, group::Pack, p);
69
70#[derive(Clone)]
71pub struct RoundToggle {
72    p: group::Pack,
73    btn: button::ToggleButton,
74}
75
76impl Default for RoundToggle {
77    fn default() -> Self {
78        RoundToggle::new(0, 0, 0, 0, "")
79    }
80}
81
82impl RoundToggle {
83    pub fn new(x: i32, y: i32, w: i32, h: i32, label: &str) -> Self {
84        let p = group::Pack::new(x, y, w, h, None)
85            .with_label(label)
86            .with_align(Align::Left);
87        let mut btn = button::ToggleButton::new(x, y, w, 30, "@+6circle")
88            .with_align(Align::Left | Align::Inside);
89        btn.set_frame(FrameType::RFlatBox);
90        btn.set_down_frame(FrameType::RFlatBox);
91        btn.set_label_color(Color::White);
92        btn.set_color(RED);
93        btn.set_selection_color(GREEN);
94        btn.clear_visible_focus();
95        btn.handle(|b, ev| match ev {
96            Event::Push => {
97                if b.value() {
98                    b.set_align(Align::Left | Align::Inside);
99                } else {
100                    b.set_align(Align::Right | Align::Inside);
101                }
102                app::redraw();
103                true
104            }
105            _ => false,
106        });
107        p.end();
108        Self { btn, p }
109    }
110    pub fn set_value(&mut self, val: bool) {
111        self.btn.set_value(val);
112        if self.btn.value() {
113            self.btn.set_align(Align::Right | Align::Inside);
114        } else {
115            self.btn.set_align(Align::Left | Align::Inside);
116        }
117        app::redraw();
118    }
119    pub fn value(&self) -> bool {
120        self.btn.value()
121    }
122    pub fn set_callback<F: 'static + FnMut(&mut Self)>(&mut self, mut cb: F) {
123        let mut s = self.clone();
124        self.btn.set_callback(move |_| {
125            cb(&mut s);
126            app::redraw();
127        });
128    }
129}
130
131fltk::widget_extends!(RoundToggle, group::Pack, p);
132
133#[derive(Clone)]
134pub struct HollowRoundToggle {
135    btn: button::ToggleButton,
136}
137
138impl Default for HollowRoundToggle {
139    fn default() -> Self {
140        HollowRoundToggle::new(0, 0, 0, 0, "")
141    }
142}
143
144impl HollowRoundToggle {
145    pub fn new(x: i32, y: i32, w: i32, h: i32, label: &str) -> Self {
146        let mut btn = button::ToggleButton::new(x, y, w, h, None)
147            .with_label(label)
148            .with_align(Align::Left);
149        btn.set_frame(FrameType::NoBox);
150        btn.set_down_frame(FrameType::NoBox);
151        btn.set_selection_color(GREEN);
152        btn.set_color(RED);
153        btn.clear_visible_focus();
154        btn.draw(|b| {
155            let col = if b.value() {
156                b.selection_color().to_rgb()
157            } else {
158                b.color().to_rgb()
159            };
160            let svg = format!(
161                "<svg viewBox='0 0 {} {}'>
162            <rect x='1%' y='1%' rx='15' width='95%' height='95%' fill='none' stroke='rgb({},{},{})'/>
163            </svg>",
164                b.w(),
165                b.h(),
166                col.0,
167                col.1,
168                col.2
169            );
170            let mut image = image::SvgImage::from_data(&svg).unwrap();
171            image.scale(b.w(), b.h(), false, true);
172            image.draw(b.x(), b.y(), b.w(), b.h());
173            let svg = format!(
174                "<svg viewBox='0 0 100 100'>
175            <circle cx='50' cy='50' r='50' fill='rgb({},{},{})'/>
176            </svg>",
177                col.0, col.1, col.2
178            );
179            let mut image = image::SvgImage::from_data(&svg).unwrap();
180            image.scale(18, 18, false, true);
181            if b.value() {
182                image.draw(b.x() + b.w() - 6 - 18, b.y() + ((b.h() - 18)/2), 18, 18);
183            } else {
184                image.draw(b.x() + 3, b.y() + ((b.h() - 18)/2), 18, 18);
185            }
186        });
187        Self { btn }
188    }
189}
190
191fltk::widget_extends!(HollowRoundToggle, button::ToggleButton, btn);
192
193// const ON_COLOR: Color = Color::from_u32(0x33aa33);
194// const OFF_COLOR: Color = Color::from_u32(0x444444);
195
196pub struct RoundToggle2 {
197    toggle: button::ToggleButton,
198}
199
200impl RoundToggle2 {
201    pub fn new(x: i32, y: i32, w: i32, h: i32, label: &str) -> Self {
202        let p = group::Pack::new(x, y, w, h, None)
203            .with_label(label)
204            .with_align(Align::Left);
205        let mut toggle = button::ToggleButton::new(x, y, w, 30, "");
206        toggle.draw(|t| {
207            draw::set_draw_color(Color::from_u32(0xeeeeee));
208            draw::draw_pie(
209                t.x() - 10 + (t.w() - t.h() + 20) * t.value() as i32,
210                t.y(),
211                t.h(),
212                t.h(),
213                0.,
214                360.,
215            );
216        });
217        toggle.set_callback(|_t| app::redraw());
218        toggle.set_frame(FrameType::RFlatBox);
219        toggle.set_color(RED);
220        toggle.set_selection_color(GREEN);
221        toggle.clear_visible_focus();
222        p.end();
223
224        RoundToggle2 { toggle }
225    }
226
227    pub fn set_callback<F: FnMut(&mut button::ToggleButton) + 'static>(&mut self, mut cb: F) {
228        self.toggle.set_callback(move |t| {
229            if t.is_set() {
230                t.set_align(Align::Inside | Align::Right);
231                t.set_label_color(Color::from_u32(0xeeeeee));
232            } else {
233                t.set_align(Align::Inside | Align::Left);
234                t.set_label_color(Color::from_u32(0xeeeeee));
235            }
236            app::redraw();
237            cb(t);
238        });
239    }
240}
241
242impl Default for RoundToggle2 {
243    fn default() -> Self {
244        RoundToggle2::new(0, 0, 0, 0, "")
245    }
246}
247
248widget_extends!(RoundToggle2, button::ToggleButton, toggle);
249
250#[derive(Clone)]
251pub struct CheckButton {
252    btn: button::ToggleButton,
253}
254
255impl Default for CheckButton {
256    fn default() -> Self {
257        CheckButton::new(0, 0, 0, 0, "")
258    }
259}
260
261impl CheckButton {
262    pub fn new(x: i32, y: i32, w: i32, _h: i32, label: &str) -> Self {
263        let mut btn = button::ToggleButton::new(x, y, w, 14, None)
264            .with_label(label)
265            .with_align(Align::Right | Align::Inside);
266        btn.set_frame(FrameType::NoBox);
267        btn.set_down_frame(FrameType::NoBox);
268        btn.clear_visible_focus();
269        btn.draw(|b| {
270            draw::set_line_style(draw::LineStyle::Solid, 2);
271            draw::draw_box(
272                FrameType::RoundedFrame,
273                b.x(),
274                b.y() - 10 + b.h() / 2,
275                20,
276                20,
277                GREEN,
278            );
279            if b.value() {
280                draw::draw_check(b.x() + 1, b.y() - 9 + b.h() / 2, 18, 18, GREEN);
281            }
282        });
283        Self { btn }
284    }
285    pub fn set_value(&mut self, val: bool) {
286        self.btn.set_value(val);
287        app::redraw();
288    }
289    pub fn value(&self) -> bool {
290        self.btn.value()
291    }
292    pub fn set_callback<F: 'static + FnMut(&mut Self)>(&mut self, mut cb: F) {
293        let mut s = self.clone();
294        self.btn.set_callback(move |_| {
295            cb(&mut s);
296            app::redraw();
297        });
298    }
299}
300
301fltk::widget_extends!(CheckButton, button::ToggleButton, btn);
302
303#[derive(Clone)]
304pub struct RadioButton {
305    btn: button::RadioButton,
306}
307
308impl Default for RadioButton {
309    fn default() -> Self {
310        RadioButton::new(0, 0, 0, 0, "")
311    }
312}
313
314impl RadioButton {
315    pub fn new(x: i32, y: i32, w: i32, _h: i32, label: &str) -> Self {
316        let mut btn = button::RadioButton::new(x, y, w, 14, None)
317            .with_label(label)
318            .with_align(Align::Right | Align::Inside);
319        btn.set_frame(FrameType::NoBox);
320        btn.set_down_frame(FrameType::NoBox);
321        btn.clear_visible_focus();
322        btn.draw(|b| {
323            draw::set_line_style(draw::LineStyle::Solid, 2);
324            draw::set_draw_color(GREEN);
325            draw::draw_arc(b.x(), b.y() - 10 + b.h() / 2, 20, 20, 0., 360.);
326            if b.value() {
327                draw::draw_pie(b.x() + 5, b.y() - 5 + b.h() / 2, 10, 10, 0., 360.);
328            }
329        });
330        Self { btn }
331    }
332    pub fn set_value(&mut self, val: bool) {
333        self.btn.set_value(val);
334        app::redraw();
335    }
336    pub fn value(&self) -> bool {
337        self.btn.value()
338    }
339    pub fn set_callback<F: 'static + FnMut(&mut Self)>(&mut self, mut cb: F) {
340        let mut s = self.clone();
341        self.btn.set_callback(move |_| {
342            cb(&mut s);
343            app::redraw();
344        });
345    }
346}
347
348fltk::widget_extends!(RadioButton, button::RadioButton, btn);
349
350#[derive(Clone)]
351pub struct HoverButton {
352    btn: button::Button,
353    col: Rc<RefCell<Color>>,
354}
355
356impl Default for HoverButton {
357    fn default() -> Self {
358        HoverButton::new(0, 0, 0, 0, "")
359    }
360}
361
362impl HoverButton {
363    pub fn new(x: i32, y: i32, w: i32, h: i32, label: &str) -> Self {
364        let mut btn = button::Button::new(x, y, w, h, None).with_label(label);
365        btn.set_color(SEL_BLUE);
366        btn.super_draw(false);
367        btn.draw(|b| {
368            draw::set_draw_color(b.color());
369            draw::draw_rectf(b.x(), b.y(), b.w(), b.h());
370            draw::set_draw_color(b.label_color());
371            draw::draw_text2(&b.label(), b.x(), b.y(), b.w(), b.h(), Align::Center);
372        });
373        let col = Rc::new(RefCell::new(SEL_BLUE));
374        btn.handle({
375            let col = col.clone();
376            move |b, ev| match ev {
377                Event::Enter | Event::Released => {
378                    b.set_color(col.borrow().lighter());
379                    b.redraw();
380                    true
381                }
382                Event::Leave | Event::Push => {
383                    b.set_color(*col.borrow());
384                    b.redraw();
385                    true
386                }
387                _ => false,
388            }
389        });
390        Self { btn, col }
391    }
392    pub fn set_color(&mut self, col: Color) {
393        *self.col.borrow_mut() = col;
394        self.btn.set_color(col);
395    }
396}
397
398fltk::widget_extends!(HoverButton, button::Button, btn);