streamduck_core/modules/
core_module.rs

1//! Core module
2
3use std::collections::HashMap;
4use std::sync::Arc;
5use serde::{Deserialize, Serialize};
6use crate::config::PluginConfig;
7use crate::core::button::{Button, Component};
8use crate::core::{check_feature_list_for_feature, CoreHandle};
9use crate::core::manager::CoreManager;
10use crate::modules::components::{ComponentDefinition, map_ui_values, UIFieldType, UIFieldValue, UIValue};
11use crate::modules::{PluginMetadata, SDModule};
12use crate::modules::events::{core_event_to_global, SDCoreEvent, SDGlobalEvent};
13use crate::socket::send_event_to_socket;
14use crate::SocketManager;
15use crate::thread::rendering::{RendererComponent, RendererSettings};
16use crate::thread::rendering::component_values::{get_renderer_component_values, set_renderer_component_values};
17use crate::util::straight_copy;
18use crate::versions::{CORE, MODULE_MANAGER};
19
20/// The core module, for exposing renderer component to requests and such
21pub struct CoreModule {
22    pub(crate) socket_manager: Arc<SocketManager>
23}
24
25#[async_trait]
26impl SDModule for CoreModule {
27    fn name(&self) -> String {
28        "core".to_string()
29    }
30
31    fn components(&self) -> HashMap<String, ComponentDefinition> {
32        let mut map = HashMap::new();
33
34        map.insert("renderer".to_string(), ComponentDefinition {
35            display_name: "Renderer".to_string(),
36            description: "The only thing that makes a button render an image on streamdeck".to_string(),
37            default_looks: Default::default()
38        });
39
40        map
41    }
42
43    async fn add_component(&self, _: CoreHandle, button: &mut Button, name: &str) {
44        match name {
45            "renderer" => {
46                button.insert_component(RendererComponent::default()).ok();
47            }
48            _ => {}
49        }
50    }
51
52    async fn remove_component(&self, _: CoreHandle, button: &mut Button, name: &str) {
53        match name {
54            "renderer" => {
55                button.remove_component::<RendererComponent>();
56            }
57            _ => {}
58        }
59    }
60
61    async fn paste_component(&self, _: CoreHandle, reference_button: &Button, new_button: &mut Button) {
62        straight_copy(reference_button, new_button, RendererComponent::NAME);
63    }
64
65    async fn component_values(&self, core: CoreHandle, button: &Button, name: &str) -> Vec<UIValue> {
66        match name {
67            "renderer" => {
68                get_renderer_component_values(&core, button).await
69            }
70
71            _ => vec![],
72        }
73    }
74
75    async fn set_component_value(&self, core: CoreHandle, button: &mut Button, name: &str, value: Vec<UIValue>) {
76        match name {
77            "renderer" => {
78                set_renderer_component_values(&core, button, value).await
79            }
80
81            _ => {}
82        }
83    }
84
85    fn listening_for(&self) -> Vec<String> {
86        vec![RendererComponent::NAME.to_string()]
87    }
88
89    async fn settings(&self, core_manager: Arc<CoreManager>) -> Vec<UIValue> {
90        let settings: CoreSettings = core_manager.config.get_plugin_settings().await.unwrap_or_default();
91
92        let mut fields = vec![];
93
94        fields.push(
95            UIValue {
96                name: "rendering".to_string(),
97                display_name: "Rendering Settings".to_string(),
98                description: "Settings related to rendering of buttons".to_string(),
99                ty: UIFieldType::Collapsable,
100                value: UIFieldValue::Collapsable({
101                    let mut fields = vec![];
102
103                    fields.push(
104                        UIValue {
105                            name: "plugin_blacklist".to_string(),
106                            display_name: "Allowed plugins to render".to_string(),
107                            description: "Disabled plugins will not appear on buttons".to_string(),
108                            ty: UIFieldType::Collapsable,
109                            value: UIFieldValue::Collapsable({
110                                core_manager.module_manager.get_modules().await
111                                    .into_values()
112                                    .filter_map(|x| if check_feature_list_for_feature(&x.metadata().used_features, "rendering") {
113                                        let name = x.name();
114                                        Some(UIValue {
115                                            name: name.clone(),
116                                            display_name: name.clone(),
117                                            description: "".to_string(),
118                                            ty: UIFieldType::Checkbox { disabled: false },
119                                            value: UIFieldValue::Checkbox(!settings.renderer.plugin_blacklist.contains(&name))
120                                        })
121                                    } else { None })
122                                    .collect()
123                            })
124                        }
125                    );
126
127                    fields
128                })
129            }
130        );
131
132        fields
133    }
134
135    async fn set_setting(&self, core_manager: Arc<CoreManager>, value: Vec<UIValue>) {
136        let mut settings: CoreSettings = core_manager.config.get_plugin_settings().await.unwrap_or_default();
137
138        let change_map = map_ui_values(value);
139
140        if let Some(value) = change_map.get("rendering") {
141            if let UIFieldValue::Collapsable(value) = &value.value {
142                let change_map = map_ui_values(value.clone());
143
144                if let Some(value) = change_map.get("plugin_blacklist") {
145                    if let UIFieldValue::Collapsable(value) = &value.value {
146                        let change_map = map_ui_values(value.clone());
147
148                        for (name, value) in change_map {
149                            if let UIFieldValue::Checkbox(state) = value.value {
150                                if state {
151                                    settings.renderer.plugin_blacklist.retain(|x| *x != name);
152                                } else {
153                                    settings.renderer.plugin_blacklist.push(name);
154                                }
155                            }
156                        }
157                    }
158                }
159            }
160        }
161
162        // Calling redraw for all devices
163        for device in core_manager.list_added_devices().await.into_values() {
164            device.core.mark_for_redraw().await;
165        }
166
167        core_manager.config.set_plugin_settings(settings).await;
168    }
169
170    async fn global_event(&self, event: SDGlobalEvent) {
171        send_event_to_socket(&self.socket_manager, event).await;
172    }
173
174    async fn event(&self, core: CoreHandle, event: SDCoreEvent) {
175        let global_event = core_event_to_global(event, &core.core.serial_number().await).await;
176        send_event_to_socket(&self.socket_manager, global_event).await;
177    }
178
179    fn metadata(&self) -> PluginMetadata {
180        PluginMetadata::from_literals(
181            "core",
182            "TheJebForge",
183            "Core of the software, provides essential components",
184            "0.1",
185            &[
186                CORE,
187                MODULE_MANAGER
188            ]
189        )
190    }
191}
192
193/// Settings related to various things around the core
194#[derive(Serialize, Deserialize, Default)]
195pub struct CoreSettings {
196    /// Renderer settings
197    pub renderer: RendererSettings
198}
199
200impl PluginConfig for CoreSettings {
201    const NAME: &'static str = "core";
202}
203