freya_devtools_app/
node.rs1use freya::prelude::*;
2use freya_core::integration::NodeId;
3
4use crate::hooks::use_node_info;
5
6#[derive(PartialEq)]
7pub struct NodeElement {
8 pub node_id: NodeId,
9 pub window_id: u64,
10 pub is_selected: bool,
11 pub is_open: Option<bool>,
12 pub on_selected: EventHandler<()>,
13 pub on_arrow: EventHandler<()>,
14}
15
16impl Render for NodeElement {
17 fn render_key(&self) -> DiffKey
18 where
19 Self: RenderKey,
20 {
21 DiffKey::from(&(self.node_id, self.window_id))
22 }
23 fn render(&self) -> impl IntoElement {
24 let Some(node) = use_node_info(self.node_id, self.window_id) else {
25 return rect().into_element();
26 };
27
28 let margin_left = ((node.height + 1) * 10) as f32 - 18.;
29 let id = self.node_id.0;
30
31 let role = node.state.accessibility.builder.role();
32
33 let on_select = {
34 let on_selected = self.on_selected.clone();
35 move |_| on_selected.call(())
36 };
37
38 let on_open = {
39 let handler = self.on_arrow.clone();
40 let is_open = self.is_open;
41 move |e: Event<PressEventData>| {
42 if is_open.is_some() {
43 handler.call(());
44 e.stop_propagation();
45 }
46 }
47 };
48
49 let arrow_button = self.is_open.map(|is_open| {
50 let arrow_degrees = if is_open { 0. } else { 270. };
51 Button::new()
52 .corner_radius(99.)
53 .border_fill(Color::TRANSPARENT)
54 .padding(Gaps::new_all(6.))
55 .background(Color::TRANSPARENT)
56 .on_press(on_open)
57 .child(ArrowIcon::new().rotate(arrow_degrees).fill(Color::WHITE))
58 });
59
60 Button::new()
61 .corner_radius(99.)
62 .width(Size::fill())
63 .height(Size::px(27.))
64 .border_fill(Color::TRANSPARENT)
65 .background(if self.is_selected {
66 (40, 40, 40).into()
67 } else {
68 Color::TRANSPARENT
69 })
70 .hover_background(if self.is_selected {
71 (40, 40, 40).into()
72 } else {
73 Color::from((45, 45, 45))
74 })
75 .on_press(on_select)
76 .child(
77 rect()
78 .offset_x(margin_left)
79 .direction(Direction::Horizontal)
80 .width(Size::fill())
81 .cross_align(Alignment::center())
82 .child(rect().width(Size::px(25.)).maybe_child(arrow_button))
83 .child(
84 paragraph()
85 .max_lines(1)
86 .font_size(14.)
87 .text_overflow(TextOverflow::Ellipsis)
89 .span(
90 Span::new(if node.is_window {
91 "Window".to_string()
92 } else if role == AccessibilityRole::GenericContainer {
93 "rect".to_string()
94 } else {
95 format!("{role:?}")
96 })
97 .color(Color::WHITE),
98 )
99 .span(
100 Span::new(if node.is_window {
101 format!(", id: {}", self.window_id)
102 } else {
103 format!(", id: {}", id)
104 })
105 .color(Color::from_rgb(200, 200, 200)),
106 ),
107 ),
108 )
109 .into()
110 }
111}