saorsa_core/compositor/
layer.rs1use crate::geometry::Rect;
4use crate::segment::Segment;
5
6#[derive(Debug, Clone)]
11pub struct Layer {
12 pub widget_id: u64,
14 pub region: Rect,
16 pub z_index: i32,
18 pub lines: Vec<Vec<Segment>>,
20}
21
22impl Layer {
23 pub fn new(widget_id: u64, region: Rect, z_index: i32, lines: Vec<Vec<Segment>>) -> Self {
25 Self {
26 widget_id,
27 region,
28 z_index,
29 lines,
30 }
31 }
32
33 pub fn contains_row(&self, row: u16) -> bool {
35 row >= self.region.position.y && row < self.region.position.y + self.region.size.height
36 }
37
38 pub fn line_for_row(&self, row: u16) -> Option<&Vec<Segment>> {
42 if !self.contains_row(row) {
43 return None;
44 }
45 let local_idx = (row - self.region.position.y) as usize;
46 self.lines.get(local_idx)
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct CompositorRegion {
56 pub x: u16,
58 pub width: u16,
60 pub source_layer_idx: Option<usize>,
62}
63
64impl CompositorRegion {
65 pub fn new(x: u16, width: u16, source_layer_idx: Option<usize>) -> Self {
67 Self {
68 x,
69 width,
70 source_layer_idx,
71 }
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
77pub enum CompositorError {
78 InvalidLayer(String),
80 BufferTooSmall,
82}
83
84impl std::fmt::Display for CompositorError {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 match self {
87 CompositorError::InvalidLayer(msg) => write!(f, "Invalid layer: {}", msg),
88 CompositorError::BufferTooSmall => write!(f, "Compositor buffer too small"),
89 }
90 }
91}
92
93impl std::error::Error for CompositorError {}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn layer_construction() {
101 let region = Rect::new(10, 20, 30, 40);
102 let lines = vec![vec![Segment::new("hello")], vec![Segment::new("world")]];
103 let layer = Layer::new(123, region, 5, lines.clone());
104
105 assert!(layer.widget_id == 123);
106 assert!(layer.region == region);
107 assert!(layer.z_index == 5);
108 assert!(layer.lines.len() == 2);
109 }
110
111 #[test]
112 fn layer_empty_lines() {
113 let region = Rect::new(0, 0, 10, 5);
114 let layer = Layer::new(1, region, 0, vec![]);
115
116 assert!(layer.lines.is_empty());
117 }
118
119 #[test]
120 fn layer_contains_row() {
121 let region = Rect::new(0, 10, 20, 5); let layer = Layer::new(1, region, 0, vec![]);
123
124 assert!(layer.contains_row(10)); assert!(layer.contains_row(14)); assert!(!layer.contains_row(9)); assert!(!layer.contains_row(15)); }
129
130 #[test]
131 fn layer_line_for_row() {
132 let region = Rect::new(0, 10, 20, 3);
133 let lines = vec![
134 vec![Segment::new("line0")],
135 vec![Segment::new("line1")],
136 vec![Segment::new("line2")],
137 ];
138 let layer = Layer::new(1, region, 0, lines);
139
140 let result0 = layer.line_for_row(10);
141 assert!(result0.is_some());
142 let segs0 = match result0 {
143 Some(s) => s,
144 None => unreachable!(),
145 };
146 assert!(segs0.len() == 1);
147 assert!(segs0[0].text == "line0");
148
149 let result1 = layer.line_for_row(11);
150 assert!(result1.is_some());
151 let segs1 = match result1 {
152 Some(s) => s,
153 None => unreachable!(),
154 };
155 assert!(segs1[0].text == "line1");
156
157 let result2 = layer.line_for_row(12);
158 assert!(result2.is_some());
159 let segs2 = match result2 {
160 Some(s) => s,
161 None => unreachable!(),
162 };
163 assert!(segs2[0].text == "line2");
164 }
165
166 #[test]
167 fn layer_line_for_row_outside() {
168 let region = Rect::new(0, 10, 20, 2);
169 let lines = vec![vec![Segment::new("a")], vec![Segment::new("b")]];
170 let layer = Layer::new(1, region, 0, lines);
171
172 assert!(layer.line_for_row(9).is_none()); assert!(layer.line_for_row(12).is_none()); }
175
176 #[test]
177 fn region_construction() {
178 let region = CompositorRegion::new(5, 10, Some(3));
179
180 assert!(region.x == 5);
181 assert!(region.width == 10);
182 assert!(region.source_layer_idx == Some(3));
183 }
184
185 #[test]
186 fn region_with_no_source() {
187 let region = CompositorRegion::new(0, 20, None);
188
189 assert!(region.x == 0);
190 assert!(region.width == 20);
191 assert!(region.source_layer_idx.is_none());
192 }
193
194 #[test]
195 fn compositor_error_display() {
196 let err1 = CompositorError::InvalidLayer("bad widget".to_string());
197 let display1 = format!("{}", err1);
198 assert!(display1.contains("Invalid layer"));
199 assert!(display1.contains("bad widget"));
200
201 let err2 = CompositorError::BufferTooSmall;
202 let display2 = format!("{}", err2);
203 assert!(display2.contains("Compositor buffer too small"));
204 }
205}