PC Music Generator - a Virtual Modular Synthesizer

Theming

+204 -54
+32
empty.yml
··· 1 + uuid: fb3e046d-c883-4c5f-b36e-3d5c6c8fbe26 2 + name: '' 3 + theme: 4 + highlight_color: 5 + - 255 6 + - 255 7 + - 255 8 + - 255 9 + midtone_color: 10 + - 160 11 + - 160 12 + - 160 13 + - 255 14 + lowlight_color: 15 + - 96 16 + - 96 17 + - 96 18 + - 255 19 + accent_color: 20 + - 255 21 + - 215 22 + - 0 23 + - 255 24 + text_color: 25 + - 160 26 + - 160 27 + - 160 28 + - 255 29 + size: U1 30 + visuals: {} 31 + devices: {} 32 + connections: {}
+27
prefab_modules/gigas1.yml
··· 1 1 size: Q1 2 2 uuid: 911f4d08-18ff-4f85-a7e7-70244fab87b4 3 + name: Gigas1 4 + theme: 5 + highlight_color: 6 + - 255 7 + - 255 8 + - 255 9 + - 255 10 + midtone_color: 11 + - 160 12 + - 160 13 + - 160 14 + - 255 15 + lowlight_color: 16 + - 96 17 + - 96 18 + - 96 19 + - 255 20 + accent_color: 21 + - 255 22 + - 215 23 + - 0 24 + - 255 25 + text_color: 26 + - 160 27 + - 160 28 + - 160 29 + - 255 3 30 visuals: 4 31 0: 5 32 uuid: 0f96dbae-aa7e-4316-a956-e1467ae07780
+27
prefab_modules/moogsimple.yml
··· 1 1 size: U1 2 2 uuid: 5066f806-2fb2-4cfe-b70d-dcd7d7c4ed38 3 + name: Moogsimple 4 + theme: 5 + highlight_color: 6 + - 255 7 + - 255 8 + - 255 9 + - 255 10 + midtone_color: 11 + - 160 12 + - 160 13 + - 160 14 + - 255 15 + lowlight_color: 16 + - 96 17 + - 96 18 + - 96 19 + - 255 20 + accent_color: 21 + - 255 22 + - 215 23 + - 0 24 + - 255 25 + text_color: 26 + - 160 27 + - 160 28 + - 160 29 + - 255 3 30 visuals: 4 31 0: 5 32 uuid: 8093ddaf-9403-48c8-98e7-a3595cd8080a
+27
prefab_modules/simpleout.yml
··· 1 1 size: U1 2 2 uuid: 4761ac0d-f7ce-4bb0-84ba-8f707e92962c 3 + name: simpleout 4 + theme: 5 + highlight_color: 6 + - 255 7 + - 255 8 + - 255 9 + - 255 10 + midtone_color: 11 + - 160 12 + - 160 13 + - 160 14 + - 255 15 + lowlight_color: 16 + - 96 17 + - 96 18 + - 96 19 + - 255 20 + accent_color: 21 + - 255 22 + - 215 23 + - 0 24 + - 255 25 + text_color: 26 + - 160 27 + - 160 28 + - 160 29 + - 255 3 30 visuals: 4 31 0: 5 32 uuid: 8093ddaf-9403-48c8-98e7-a3595cd8080a
+42 -11
rack-designer/src/app.rs
··· 30 30 devices::description::Param, 31 31 pos_drag_value, 32 32 two_drag_value, 33 - visuals::templates::WidgetTemplate, 33 + visuals::{ 34 + templates::WidgetTemplate, 35 + VisualTheme, 36 + }, 34 37 widget_description::{ 35 38 ModuleDescription, 36 39 WidgetKind, ··· 163 166 .resizable(false) 164 167 .min_width(256.) 165 168 .show(ctx, |ui| { 169 + ui.collapsing("Theme", |ui| { 170 + ui.horizontal(|ui| { 171 + ui.label("Accent"); 172 + ui.color_edit_button_srgba(&mut state.module.theme.accent_color); 173 + }); 174 + ui.horizontal(|ui| { 175 + ui.label("Highlight"); 176 + ui.color_edit_button_srgba(&mut state.module.theme.highlight_color); 177 + }); 178 + ui.horizontal(|ui| { 179 + ui.label("Lowlight"); 180 + ui.color_edit_button_srgba(&mut state.module.theme.lowlight_color); 181 + }); 182 + ui.horizontal(|ui| { 183 + ui.label("Midtone"); 184 + ui.color_edit_button_srgba(&mut state.module.theme.midtone_color); 185 + }); 186 + ui.horizontal(|ui| { 187 + ui.label("Text"); 188 + ui.color_edit_button_srgba(&mut state.module.theme.text_color); 189 + }); 190 + }); 191 + 166 192 ScrollArea::vertical().id_source("widgets").show(ui, |ui| { 167 193 widgets_editor(ui, &mut state, loader); 168 194 }); ··· 206 232 CentralPanel::default().show(ctx, |ui| { 207 233 let r = ui.available_rect_before_wrap(); 208 234 paint_module_bg(ui.painter(), r.center(), current.module.size); 209 - paint_module_widgets(ui, r.center(), &current.module.visuals); 235 + paint_module_widgets( 236 + ui, 237 + r.center(), 238 + &current.module.visuals, 239 + current.module.theme, 240 + ); 210 241 }); 211 242 next_state 212 243 } ··· 366 397 ); 367 398 } 368 399 369 - fn paint_module_widgets(ui: &mut Ui, center: Pos2, visuals: &BTreeMap<usize, WidgetTemplate>) { 370 - visuals.values().for_each(|visual| { 371 - visual.preview( 372 - ui, 373 - center + visual.position.to_vec2(), 374 - Default::default(), 375 - 0.0, 376 - ) 377 - }); 400 + fn paint_module_widgets( 401 + ui: &mut Ui, 402 + center: Pos2, 403 + visuals: &BTreeMap<usize, WidgetTemplate>, 404 + theme: VisualTheme, 405 + ) { 406 + visuals 407 + .values() 408 + .for_each(|visual| visual.preview(ui, center + visual.position.to_vec2(), theme, 0.0)); 378 409 }
+6 -1
rack-designer/src/app/state.rs
··· 1 - use rack::widget_description::ModuleDescription; 1 + use rack::{ 2 + visuals::VisualTheme, 3 + widget_description::ModuleDescription, 4 + }; 2 5 3 6 use rack::container::sizing::ModuleSize; 4 7 use uuid::Uuid; ··· 74 77 device_adder: None, 75 78 module: ModuleDescription { 76 79 uuid: Uuid::new_v4(), 80 + name: String::new(), 81 + theme: VisualTheme::default(), 77 82 size, 78 83 visuals: Default::default(), 79 84 devices: Default::default(),
+11 -3
rack/src/graph/modules.rs
··· 24 24 Param, 25 25 }, 26 26 graph::Graph, 27 - visuals::templates::WidgetTemplate, 27 + visuals::{ 28 + templates::WidgetTemplate, 29 + VisualTheme, 30 + }, 28 31 widget_description::ModuleDescription, 29 32 widgets::{ 30 33 SlotWidget, ··· 46 49 pub size: ModuleSize, 47 50 pub devices: Vec<DeviceId>, 48 51 pub visuals: SlotMap<VisualId, SlotWidget>, 52 + theme: VisualTheme, 49 53 pub values: SecondaryMap<VisualId, Connector>, 50 54 /// Maps inputs to their visuals 51 55 pub ins: SecondaryMap<InputId, VisualId>, ··· 71 75 graph: &mut Graph, 72 76 size: ModuleSize, 73 77 visual_descs: BTreeMap<usize, WidgetTemplate>, 78 + theme: VisualTheme, 74 79 devices: BTreeMap<usize, DeviceKind>, 75 80 mut connections: BTreeMap<(usize, usize), usize>, 76 81 ) -> ModuleId { ··· 120 125 size, 121 126 devices, 122 127 visuals, 128 + theme, 123 129 values, 124 130 ins, 125 131 outs, ··· 129 135 pub fn insert_from_description(graph: &mut Graph, description: ModuleDescription) -> ModuleId { 130 136 let ModuleDescription { 131 137 uuid: _, 138 + name: _, 139 + theme, 132 140 size, 133 141 visuals, 134 142 devices, 135 143 connections, 136 144 } = description; 137 - Self::insert_new(graph, size, visuals, devices, connections) 145 + Self::insert_new(graph, size, visuals, theme, devices, connections) 138 146 } 139 147 140 148 fn ui_for(&mut self, position: Pos2, ui: &mut Ui) -> ModuleResponse { ··· 143 151 for (vid, w) in visuals.iter_mut() { 144 152 let pos = w.pos() + position.to_vec2(); 145 153 ui.put(Rect::from_min_size(pos, w.size()), |ui: &mut Ui| { 146 - let InnerResponse { inner, response } = w.show(ui); 154 + let InnerResponse { inner, response } = w.show(ui, self.theme); 147 155 if let Some(connected_plug) = self.values.get(vid).copied() { 148 156 match inner { 149 157 WidgetResponse::None => {}
+6 -6
rack/src/visuals.rs
··· 210 210 Text(Pos2, String, FontFamily), 211 211 } 212 212 213 - #[derive(Serialize, Deserialize, Clone, Copy)] 213 + #[derive(Serialize, Deserialize, Clone, Copy, Debug)] 214 214 pub struct VisualTheme { 215 - highlight_color: Color32, 216 - midtone_color: Color32, 217 - lowlight_color: Color32, 218 - accent_color: Color32, 219 - text_color: Color32, 215 + pub highlight_color: Color32, 216 + pub midtone_color: Color32, 217 + pub lowlight_color: Color32, 218 + pub accent_color: Color32, 219 + pub text_color: Color32, 220 220 } 221 221 222 222 impl Default for VisualTheme {
+6 -1
rack/src/widget_description.rs
··· 9 9 use crate::{ 10 10 container::sizing::ModuleSize, 11 11 devices::description::DeviceKind, 12 - visuals::templates::WidgetTemplate, 12 + visuals::{ 13 + templates::WidgetTemplate, 14 + VisualTheme, 15 + }, 13 16 widgets::KnobRange, 14 17 Uuidentified, 15 18 }; ··· 17 20 #[derive(Debug, Serialize, Deserialize, Clone)] 18 21 pub struct ModuleDescription { 19 22 pub uuid: Uuid, 23 + pub name: String, 24 + pub theme: VisualTheme, 20 25 pub size: ModuleSize, 21 26 pub visuals: BTreeMap<usize, WidgetTemplate>, 22 27 pub devices: BTreeMap<usize, DeviceKind>,
+7 -4
rack/src/widgets.rs
··· 11 11 use std::ops::RangeInclusive; 12 12 13 13 use crate::{ 14 - visuals::templates::WidgetTemplate, 14 + visuals::{ 15 + templates::WidgetTemplate, 16 + VisualTheme, 17 + }, 15 18 Tooltipable, 16 19 }; 17 20 ··· 94 97 } 95 98 } 96 99 97 - pub fn show(&mut self, ui: &mut Ui) -> InnerResponse<WidgetResponse> { 100 + pub fn show(&mut self, ui: &mut Ui, theme: VisualTheme) -> InnerResponse<WidgetResponse> { 98 101 match self { 99 - SlotWidget::Knob(k) => k.show(ui), 102 + SlotWidget::Knob(k) => k.show(ui, theme), 100 103 SlotWidget::Fader(_f) => todo!(), 101 - SlotWidget::Port(p) => p.show(ui), 104 + SlotWidget::Port(p) => p.show(ui, theme), 102 105 } 103 106 } 104 107
+3 -2
rack/src/widgets/connector/ports.rs
··· 2 2 visuals::{ 3 3 templates::WidgetTemplate, 4 4 VisualComponent, 5 + VisualTheme, 5 6 }, 6 7 widget_description::WidgetKind, 7 8 widgets::WidgetResponse, ··· 24 25 } 25 26 26 27 impl Port { 27 - pub fn show(&mut self, ui: &mut Ui) -> InnerResponse<WidgetResponse> { 28 + pub fn show(&mut self, ui: &mut Ui, theme: VisualTheme) -> InnerResponse<WidgetResponse> { 28 29 let (rect, response) = ui.allocate_exact_size(self.size, Sense::click()); 29 30 30 31 ui.painter().debug_rect(rect, Color32::DEBUG_COLOR, ""); 31 32 let center = rect.center(); 32 33 if ui.is_rect_visible(rect) { 33 34 for visual in &self.visuals { 34 - visual.show(ui, center, Default::default()); 35 + visual.show(ui, center, theme); 35 36 } 36 37 } 37 38 let inner = if response.clicked_by(PointerButton::Primary) {
+7 -6
rack/src/widgets/knob.rs
··· 18 18 visuals::{ 19 19 templates::WidgetTemplate, 20 20 VisualComponent, 21 + VisualTheme, 21 22 }, 22 23 widget_description::{ 23 24 KnobKind, ··· 88 89 ui.allocate_response(self.size, Sense::click_and_drag()) 89 90 } 90 91 91 - fn update(&mut self, ui: &mut Ui) -> Response { 92 + fn update(&mut self, ui: &mut Ui, theme: VisualTheme) -> Response { 92 93 let old_value = self.value; 93 94 let old_angle = self.angle; 94 95 ··· 115 116 self.angle = angle; 116 117 } 117 118 118 - self.draw(ui, &res); 119 + self.draw(ui, &res, theme); 119 120 120 121 res.changed = self.value != old_value; 121 122 122 123 res 123 124 } 124 125 125 - fn draw(&mut self, ui: &mut Ui, res: &Response) { 126 + fn draw(&mut self, ui: &mut Ui, res: &Response, theme: VisualTheme) { 126 127 let rect = res.rect; 127 128 let center = rect.center(); 128 129 ui.painter().debug_rect(rect, Color32::GOLD, ""); 129 130 130 131 if ui.is_rect_visible(rect) { 131 132 for visual in &self.visuals { 132 - visual.show_with_value(ui, center, Default::default(), self.angle) 133 + visual.show_with_value(ui, center, theme, self.angle) 133 134 } 134 135 } 135 136 } 136 137 137 - pub fn show(&mut self, ui: &mut Ui) -> InnerResponse<WidgetResponse> { 138 - let response = self.update(ui); 138 + pub fn show(&mut self, ui: &mut Ui, theme: VisualTheme) -> InnerResponse<WidgetResponse> { 139 + let response = self.update(ui, theme); 139 140 let wr = if response.changed() { 140 141 WidgetResponse::Changed 141 142 } else {
+3 -20
src/pcmg_ui/module_adder.rs
··· 5 5 Sense, 6 6 Window, 7 7 }; 8 - use rack::{ 9 - visuals::VisualTheme, 10 - widget_description::ModuleDescription, 11 - }; 8 + use rack::widget_description::ModuleDescription; 12 9 use uuid::Uuid; 13 10 14 11 pub struct ModuleAdder { ··· 31 28 ui.horizontal(|ui| { 32 29 ui.vertical(|ui| { 33 30 for (uuid, module) in self.modules.iter() { 34 - ui.selectable_value(&mut self.selection, Some(*uuid), uuid.to_string()); 35 - let (r, _) = ui.allocate_exact_size(module.size.size(), Sense::hover()); 36 - for vis in module.visuals.values() { 37 - vis.preview( 38 - ui, 39 - r.center() + vis.position.to_vec2(), 40 - VisualTheme::default(), 41 - 0.0, 42 - ) 43 - } 31 + ui.selectable_value(&mut self.selection, Some(*uuid), &module.name); 44 32 } 45 33 closing = ui.button("Add").clicked(); 46 34 }); ··· 49 37 let m = &self.modules[&uuid]; 50 38 let (r, _) = ui.allocate_exact_size(m.size.size(), Sense::hover()); 51 39 for w in m.visuals.values() { 52 - w.preview( 53 - ui, 54 - r.center() + w.position.to_vec2(), 55 - Default::default(), 56 - 0.0, 57 - ); 40 + w.preview(ui, r.center() + w.position.to_vec2(), m.theme, 0.0); 58 41 } 59 42 } 60 43 });