PC Music Generator - a Virtual Modular Synthesizer
1use egui::{
2 InnerResponse,
3 Sense,
4 Ui,
5};
6use emath::{
7 Pos2,
8 Vec2,
9};
10
11use crate::{
12 module_description::{
13 ToggleKind,
14 WidgetKind,
15 },
16 visuals::{
17 templates::WidgetTemplate,
18 VisualComponent,
19 VisualTheme,
20 },
21};
22
23use super::WidgetResponse;
24
25pub struct Toggle {
26 pub(crate) name: String,
27 pub(crate) pos: Pos2,
28 pub(crate) size: Vec2,
29
30 on: f32,
31 off: f32,
32 state: bool,
33
34 visuals: Vec<VisualComponent>,
35}
36
37impl Toggle {
38 pub fn new(
39 name: String,
40 pos: Pos2,
41 size: Vec2,
42 on: f32,
43 off: f32,
44 visuals: Vec<VisualComponent>,
45 ) -> Self {
46 Self {
47 name,
48 pos,
49 size,
50 on,
51 off,
52 state: false,
53 visuals,
54 }
55 }
56
57 pub fn value(&self) -> f32 {
58 if self.state {
59 self.on
60 } else {
61 self.off
62 }
63 }
64
65 pub fn show(&mut self, ui: &mut Ui, theme: VisualTheme) -> InnerResponse<WidgetResponse> {
66 let old_state = self.state;
67 let mut res = ui.allocate_response(self.size, Sense::click());
68
69 if res.clicked() {
70 self.state = !self.state;
71 }
72
73 let rect = res.rect;
74 let center = rect.center();
75 if ui.is_rect_visible(rect) {
76 for visual in &self.visuals {
77 let value = if self.state { 1. } else { 0. };
78 visual.show_with_value(ui, center, theme, value);
79 }
80 }
81
82 let wr = if old_state == self.state {
83 res.changed = false;
84 WidgetResponse::None
85 } else {
86 res.changed = true;
87 WidgetResponse::Changed
88 };
89
90 InnerResponse::new(wr, res)
91 }
92
93 pub(crate) fn from_template(template: WidgetTemplate) -> Option<Self> {
94 let WidgetTemplate {
95 kind: WidgetKind::Toggle(ToggleKind { on, off }),
96 uuid: _,
97 name,
98 position: pos,
99 size,
100 components: visuals,
101 } = template
102 else {
103 return None;
104 };
105
106 let visuals = visuals
107 .into_values()
108 .filter_map(|v| v.try_into().ok())
109 .collect();
110 Some(Self::new(name, pos, size, on, off, visuals))
111 }
112}