Skip to main content

miracle_plugin/
workspace.rs

1use super::bindings;
2use super::container::*;
3use super::core::Rectangle;
4use super::host::*;
5use super::output::*;
6
7#[derive(Debug, Clone)]
8pub struct Workspace {
9    /// The workspace number (if set).
10    pub number: Option<u32>,
11    /// The workspace name (if set).
12    pub name: Option<String>,
13    /// The number of container trees in this workspace.
14    pub num_trees: u32,
15    /// The current area of the workspace.
16    pub rectangle: Rectangle,
17    internal: u64,
18}
19
20impl Workspace {
21    pub fn id(&self) -> u64 {
22        self.internal
23    }
24
25    /// Create from the C struct.
26    pub unsafe fn from_c_with_name(value: &bindings::miracle_workspace_t, name: String) -> Self {
27        Self {
28            number: if value.has_number != 0 {
29                Some(value.number)
30            } else {
31                None
32            },
33            name: if value.has_name != 0 {
34                Some(name)
35            } else {
36                None
37            },
38            num_trees: value.num_trees,
39            internal: value.internal,
40            rectangle: Rectangle {
41                x: value.position.x,
42                y: value.position.y,
43                width: value.size.w,
44                height: value.size.h,
45            },
46        }
47    }
48
49    /// Get the output that this workspace is on.
50    pub fn output(&self) -> Option<Output> {
51        const NAME_BUF_LEN: usize = 256;
52        let mut output = std::mem::MaybeUninit::<crate::bindings::miracle_output_t>::uninit();
53        let mut name_buf: [u8; NAME_BUF_LEN] = [0; NAME_BUF_LEN];
54
55        unsafe {
56            let result = miracle_workspace_get_output(
57                self.internal as i64,
58                output.as_mut_ptr() as i32,
59                name_buf.as_mut_ptr() as i32,
60                NAME_BUF_LEN as i32,
61            );
62
63            if result != 0 {
64                return None;
65            }
66
67            let output = output.assume_init();
68
69            // Find the null terminator to get the actual string length
70            let name_len = name_buf
71                .iter()
72                .position(|&c| c == 0)
73                .unwrap_or(NAME_BUF_LEN);
74            let name = String::from_utf8_lossy(&name_buf[..name_len]).into_owned();
75
76            Some(Output::from_c_with_name(&output, name))
77        }
78    }
79
80    /// Get a tree from the workspace by index.
81    ///
82    /// Returns `None` if the index is out of bounds.
83    pub fn tree_at(&self, index: u32) -> Option<Container> {
84        if index >= self.num_trees {
85            return None;
86        }
87
88        let mut container = std::mem::MaybeUninit::<crate::bindings::miracle_container_t>::uninit();
89        unsafe {
90            let result = miracle_workspace_get_tree(
91                self.internal as i64,
92                index,
93                container.as_mut_ptr() as i32,
94            );
95
96            if result != 0 {
97                return None;
98            }
99
100            let container = container.assume_init();
101            Some(Container::from(container))
102        }
103    }
104
105    /// Get all trees from the workspace.
106    pub fn trees(&self) -> Vec<Container> {
107        (0..self.num_trees)
108            .filter_map(|i| self.tree_at(i))
109            .collect()
110    }
111}