1use std::cell::Ref;
4
5use cosmic_text::{Buffer, LayoutRun};
6use taffy::TraversePartialTree;
7
8use crate::geometry::{Point, Rect, Size};
9use crate::style::{Color, Style};
10use crate::text::TextNode;
11use crate::tree::{Node, NodeId, NodeKind, Tree, icon_rect};
12use crate::widgets::IconSource;
13
14const DEFAULT_TEXT_COLOR: Color = Color::rgb(0, 0, 0);
16
17pub struct WindowView<'w> {
20 tree: Ref<'w, Tree>,
21}
22
23impl<'w> WindowView<'w> {
24 pub(crate) fn new(tree: Ref<'w, Tree>) -> WindowView<'w> {
25 WindowView { tree }
26 }
27
28 pub fn size(&self) -> Size {
30 self.tree.size
31 }
32
33 pub fn root(&self) -> NodeView<'_> {
35 NodeView::new(&self.tree, self.tree.root)
36 .expect("invariant: the root node exists while the tree does")
37 }
38}
39
40#[derive(Clone, Copy)]
43pub struct NodeView<'a> {
44 tree: &'a Tree,
45 id: NodeId,
46 node: &'a Node,
47}
48
49impl<'a> NodeView<'a> {
50 fn new(tree: &'a Tree, id: NodeId) -> Option<NodeView<'a>> {
51 let node = tree.node(id)?;
52 Some(NodeView { tree, id, node })
53 }
54
55 pub fn name(&self) -> &'static str {
57 self.node.name
58 }
59
60 pub fn path(&self) -> &'a str {
62 &self.node.path
63 }
64
65 pub fn rect(&self) -> Rect {
68 self.node.rect.unwrap_or_default()
69 }
70
71 pub fn bounds(&self) -> Rect {
75 self.node.bounds
76 }
77
78 pub fn style(&self) -> Style {
82 self.node.effective_style()
83 }
84
85 pub fn children(&self) -> impl Iterator<Item = NodeView<'a>> + 'a {
87 let tree = self.tree;
88 tree
89 .taffy
90 .child_ids(self.id)
91 .filter_map(move |id| NodeView::new(tree, id))
92 }
93
94 pub fn content(&self) -> Content<'a> {
96 match &self.node.kind {
97 NodeKind::Text(text) => Content::Text(TextView {
98 text,
99 color: self.inherited_color(),
100 }),
101 NodeKind::Icon(icon) => match &icon.source {
102 Some(source) => Content::Icon(IconView {
103 source,
104 rect: icon_rect(self.node.content, icon.size),
105 }),
106 None => Content::None,
107 },
108 _ => Content::None,
109 }
110 }
111
112 fn inherited_color(&self) -> Color {
115 let mut id = Some(self.id);
116 while let Some(current) = id {
117 if let Some(color) = self
118 .tree
119 .node(current)
120 .and_then(|node| node.effective_style().color)
121 {
122 return color;
123 }
124 id = self.tree.taffy.parent(current);
125 }
126 DEFAULT_TEXT_COLOR
127 }
128}
129
130pub enum Content<'a> {
132 None,
134 Text(TextView<'a>),
136 Icon(IconView<'a>),
138}
139
140pub struct TextView<'a> {
144 text: &'a TextNode,
145 color: Color,
146}
147
148impl<'a> TextView<'a> {
149 pub fn content(&self) -> &'a str {
151 &self.text.content
152 }
153
154 pub fn buffer(&self) -> &'a Buffer {
156 &self.text.buffer
157 }
158
159 pub fn runs(&self) -> impl Iterator<Item = LayoutRun<'a>> + 'a {
162 self.text.runs()
163 }
164
165 pub fn origin(&self) -> Point {
167 self.text.origin
168 }
169
170 pub fn color(&self) -> Color {
173 self.color
174 }
175}
176
177pub struct IconView<'a> {
179 pub source: &'a IconSource,
181 pub rect: Rect,
183}