streamduck_core/thread/rendering/
custom.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3use image::DynamicImage;
4use streamdeck::{DeviceImage, StreamDeck};
5use tokio::sync::{RwLock, RwLockReadGuard};
6use crate::core::button::Button;
7use crate::core::{CoreHandle, UniqueButton};
8use crate::modules::components::UIValue;
9use crate::thread::rendering::RendererComponent;
10
11/// Reference to Stream Deck
12///
13/// This is used to restrain plugins from setting buttons that don't use their renderers, would be uncool if some plugin decided to draw to every button instead of button that user wanted
14pub struct DeviceReference<'a> {
15    streamdeck: &'a mut StreamDeck,
16    key: u8,
17}
18
19#[allow(dead_code)]
20impl<'a> DeviceReference<'a> {
21    pub(crate) fn new(streamdeck: &'a mut StreamDeck, key: u8) -> Self {
22        Self {
23            streamdeck,
24            key
25        }
26    }
27
28    /// Writes image to streamdeck directly on button currently processed by core
29    pub fn write_image(&mut self, image: &DeviceImage) -> Result<(), streamdeck::Error> {
30        self.streamdeck.write_button_image(self.key, image)
31    }
32}
33
34/// Custom renderer trait
35#[allow(unused_variables)]
36#[async_trait]
37pub trait CustomRenderer: Send + Sync {
38    /// Name of the renderer
39    fn name(&self) -> String;
40
41    /// Called whenever current screen changes, should be used for any things that shouldn't be called every tick
42    async fn refresh(&self, core_handle: &CoreHandle) {}
43
44    /// Called on every tick with device reference provided
45    async fn render(&self, key: u8, button: &UniqueButton, core_handle: &CoreHandle, streamdeck: &mut DeviceReference) {}
46
47    /// Called on get_button_images method, the returned image is what will be shown on GUI
48    async fn representation(&self, key: u8, button: &UniqueButton, core_handle: &CoreHandle) -> Option<DynamicImage> { None }
49
50    /// Called when renderer component has custom renderer selected, can be used to give custom fields to renderer component
51    async fn component_values(&self, button: &Button, component: &RendererComponent, core_handle: &CoreHandle) -> Vec<UIValue> { vec![] }
52
53    /// Called when renderer component has custom renderer selected, used to set custom fields to whatever structure plugin wishes
54    async fn set_component_value(&self, button: &mut Button, component: &mut RendererComponent, core_handle: &CoreHandle, value: Vec<UIValue>) { }
55}
56
57/// Reference counted renderer object
58pub type UniqueRenderer = Arc<dyn CustomRenderer>;
59
60/// Manager that keeps a bunch of related things to rendering thread
61#[derive(Default)]
62pub struct RenderingManager {
63    renderers: RwLock<HashMap<String, UniqueRenderer>>
64}
65
66impl RenderingManager {
67    /// Creates new rendering manager
68    pub fn new() -> Arc<Self> {
69        Arc::new(Self::default())
70    }
71
72    /// Adds renderer to the manager
73    pub async fn add_custom_renderer(&self, renderer: UniqueRenderer) {
74        let mut lock = self.renderers.write().await;
75        lock.insert(renderer.name(), renderer);
76    }
77
78    /// Returns all renderers managed by the manager
79    pub async fn get_renderers(&self) -> HashMap<String, UniqueRenderer> {
80        self.renderers.read().await.clone()
81    }
82
83    /// Returns read lock for renderers
84    pub async fn read_renderers(&self) -> RwLockReadGuard<'_, HashMap<String, UniqueRenderer>> {
85        self.renderers.read().await
86    }
87}