Skip to main content

phoenixcord_sdk/
view.rs

1/*
2 * PhoenixCord, a Discord client mod
3 * Copyright (c) 2026 Leclowndu93150 and contributors
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7use crate::types::{Element, Icon, Node, NodeKind, Style};
8
9/// A UI tree that can nest freely.
10///
11/// WIT has no recursive types, so [`Element`] is a flat list of nodes. Build a `View` and call
12/// [`View::into_element`] to flatten it.
13pub struct View {
14    pub kind: NodeKind,
15    pub style: Style,
16    pub tooltip: Option<String>,
17    pub children: Vec<View>,
18}
19
20impl View {
21    pub fn new(kind: NodeKind) -> Self {
22        Self {
23            kind,
24            style: Style::default(),
25            tooltip: None,
26            children: Vec::new(),
27        }
28    }
29
30    pub fn stack(children: Vec<View>) -> Self {
31        Self {
32            children,
33            ..Self::new(NodeKind::Stack)
34        }
35    }
36
37    pub fn text(text: impl Into<String>) -> Self {
38        Self::new(NodeKind::Text(text.into()))
39    }
40
41    pub fn icon(icon: Icon) -> Self {
42        Self::new(NodeKind::Icon(icon))
43    }
44
45    pub fn style(mut self, style: Style) -> Self {
46        self.style = style;
47        self
48    }
49
50    pub fn tooltip(mut self, tooltip: impl Into<String>) -> Self {
51        self.tooltip = Some(tooltip.into());
52        self
53    }
54
55    /// Flattens the tree into an [`Element`] whose first node is the root.
56    pub fn into_element(self) -> Element {
57        let mut nodes = Vec::new();
58        push(self, &mut nodes);
59        Element { nodes }
60    }
61}
62
63fn push(view: View, nodes: &mut Vec<Node>) -> u32 {
64    let index = nodes.len();
65    nodes.push(Node {
66        kind: view.kind,
67        style: view.style,
68        tooltip: view.tooltip,
69        children: Vec::new(),
70    });
71    let children = view
72        .children
73        .into_iter()
74        .map(|child| push(child, nodes))
75        .collect();
76    nodes[index].children = children;
77    u32::try_from(index).expect("UI trees have fewer than 2^32 nodes")
78}