1use cranpose_ui_graphics::{
5 Brush, Color, CornerRadii, DrawPrimitive, GraphicsLayer, Point, Rect, Size,
6};
7
8use crate::{
9 graph::{
10 CachePolicy, DrawPrimitiveNode, IsolationReasons, LayerNode, PrimitiveEntry, PrimitiveNode,
11 PrimitivePhase, ProjectiveTransform, RenderGraph, RenderNode, TextPrimitiveNode,
12 },
13 raster_cache::LayerRasterCacheHashes,
14};
15
16#[derive(Clone, PartialEq, Eq)]
19pub struct DevOverlayKey {
20 pub text: String,
21 pub viewport_width_bits: u32,
22 pub viewport_height_bits: u32,
23}
24
25impl DevOverlayKey {
26 pub fn new(text: &str, viewport: Size) -> Self {
27 Self {
28 text: text.to_string(),
29 viewport_width_bits: viewport.width.to_bits(),
30 viewport_height_bits: viewport.height.to_bits(),
31 }
32 }
33}
34
35pub fn build_dev_overlay_graph(
39 text: &str,
40 viewport: Size,
41 node_id: cranpose_core::NodeId,
42) -> RenderGraph {
43 let padding = 8.0;
44 let font_size = 14.0;
45 let char_width = 7.0;
46 let text_width = text.len() as f32 * char_width;
47 let text_height = font_size * 1.4;
48 let x = (viewport.width - text_width - padding * 2.0).max(padding);
49 let y = padding;
50
51 let mut overlay_layer = LayerNode {
52 node_id: Some(node_id),
53 local_bounds: Rect {
54 x: 0.0,
55 y: 0.0,
56 width: text_width + padding,
57 height: text_height + padding / 2.0,
58 },
59 transform_to_parent: ProjectiveTransform::translation(x, y),
60 content_offset: Point::default(),
61 motion_context_animated: false,
62 translated_content_context: false,
63 translated_content_offset: Point::default(),
64 scene_children_origin: Point::default(),
65 scene_children_layer_translation: Point::default(),
66 graphics_layer: GraphicsLayer::default(),
67 clip_to_bounds: false,
68 shadow_clip: None,
69 hit_test: None,
70 has_hit_targets: false,
71 has_origin_sinks: false,
72 isolation: IsolationReasons::default(),
73 cache_policy: CachePolicy::None,
74 cache_hashes: LayerRasterCacheHashes::default(),
75 cache_hashes_valid: false,
76 children: vec![
77 RenderNode::Primitive(PrimitiveEntry {
78 phase: PrimitivePhase::BeforeChildren,
79 node: PrimitiveNode::Draw(DrawPrimitiveNode {
80 primitive: DrawPrimitive::RoundRect {
81 rect: Rect {
82 x: 0.0,
83 y: 0.0,
84 width: text_width + padding,
85 height: text_height + padding / 2.0,
86 },
87 brush: Brush::Solid(Color(0.0, 0.0, 0.0, 0.7)),
88 radii: CornerRadii::uniform(4.0),
89 stroke: None,
90 },
91 clip: None,
92 }),
93 }),
94 RenderNode::Primitive(PrimitiveEntry {
95 phase: PrimitivePhase::AfterChildren,
96 node: PrimitiveNode::Text(Box::new(TextPrimitiveNode {
97 node_id,
98 rect: Rect {
99 x: padding / 2.0,
100 y: padding / 4.0,
101 width: text_width,
102 height: text_height,
103 },
104 text: std::rc::Rc::new(cranpose_ui::text::AnnotatedString::from(text)),
105 text_style: cranpose_ui::TextStyle::default(),
106 font_size,
107 layout_options: cranpose_ui::TextLayoutOptions::default(),
108 clip: None,
109 })),
110 }),
111 ],
112 };
113 overlay_layer.recompute_raster_cache_hashes();
114
115 let mut graph = RenderGraph::new(LayerNode {
116 node_id: None,
117 local_bounds: Rect::from_size(viewport),
118 transform_to_parent: ProjectiveTransform::identity(),
119 content_offset: Point::default(),
120 motion_context_animated: false,
121 translated_content_context: false,
122 translated_content_offset: Point::default(),
123 scene_children_origin: Point::default(),
124 scene_children_layer_translation: Point::default(),
125 graphics_layer: GraphicsLayer::default(),
126 clip_to_bounds: false,
127 shadow_clip: None,
128 hit_test: None,
129 has_hit_targets: false,
130 has_origin_sinks: false,
131 isolation: IsolationReasons::default(),
132 cache_policy: CachePolicy::None,
133 cache_hashes: LayerRasterCacheHashes::default(),
134 cache_hashes_valid: false,
135 children: vec![RenderNode::Layer(Box::new(overlay_layer))],
136 });
137 graph.root.recompute_raster_cache_hashes();
138 graph
139}