1use std::cell::RefCell;
5use std::ops::BitOr;
6use std::rc::Rc;
7
8use crabshell_reactive::{Owner, untrack};
9
10use crate::cx::{Anchor, Cx};
11use crate::geometry::{Rect, Size};
12use crate::prop::{IntoProp, Prop};
13use crate::style::Style;
14use crate::text::TextSystem;
15use crate::tree::{Tree, borrow};
16use crate::view::WindowView;
17use crate::widgets::Widget;
18
19#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct Output {
22 name: String,
23}
24
25impl Output {
26 pub fn new(name: impl Into<String>) -> Output {
29 Output { name: name.into() }
30 }
31
32 pub fn name(&self) -> String {
35 self.name.clone()
36 }
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub enum Edge {
42 Top,
44 Bottom,
46 Left,
48 Right,
50}
51
52impl Edge {
53 const fn bit(self) -> u8 {
54 match self {
55 Edge::Top => 1,
56 Edge::Bottom => 2,
57 Edge::Left => 4,
58 Edge::Right => 8,
59 }
60 }
61}
62
63#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
66pub struct Anchors(u8);
67
68impl Anchors {
69 pub const NONE: Anchors = Anchors(0);
71
72 pub const fn contains(self, edge: Edge) -> bool {
74 self.0 & edge.bit() != 0
75 }
76
77 pub fn edge(self) -> Option<Edge> {
81 let [top, bottom, left, right] =
82 [Edge::Top, Edge::Bottom, Edge::Left, Edge::Right].map(|edge| self.contains(edge));
83 match (top, bottom, left, right) {
84 (true, false, false, false) | (true, false, true, true) => Some(Edge::Top),
85 (false, true, false, false) | (false, true, true, true) => Some(Edge::Bottom),
86 (false, false, true, false) | (true, true, true, false) => Some(Edge::Left),
87 (false, false, false, true) | (true, true, false, true) => Some(Edge::Right),
88 _ => None,
89 }
90 }
91}
92
93impl From<Edge> for Anchors {
94 fn from(edge: Edge) -> Anchors {
95 Anchors(edge.bit())
96 }
97}
98
99impl BitOr for Edge {
100 type Output = Anchors;
101
102 fn bitor(self, other: Edge) -> Anchors {
103 Anchors(self.bit() | other.bit())
104 }
105}
106
107impl BitOr<Edge> for Anchors {
108 type Output = Anchors;
109
110 fn bitor(self, edge: Edge) -> Anchors {
111 Anchors(self.0 | edge.bit())
112 }
113}
114
115#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
117pub enum Layer {
118 Background,
120 Bottom,
122 #[default]
124 Top,
125 Overlay,
127}
128
129pub struct PanelWindow {
144 pub(crate) output: Output,
145 pub(crate) anchors: Option<Prop<Anchors>>,
146 pub(crate) width: Option<Prop<u32>>,
147 pub(crate) height: Option<Prop<u32>>,
148 pub(crate) exclusive_zone: Option<Prop<i32>>,
149 pub(crate) layer: Option<Prop<Layer>>,
150 pub(crate) style: Option<Prop<Style>>,
151 pub(crate) child: Option<Box<dyn Widget>>,
152}
153
154impl PanelWindow {
155 pub fn new(output: &Output) -> PanelWindow {
157 PanelWindow {
158 output: output.clone(),
159 anchors: None,
160 width: None,
161 height: None,
162 exclusive_zone: None,
163 layer: None,
164 style: None,
165 child: None,
166 }
167 }
168
169 pub fn anchors(mut self, anchors: impl IntoProp<Anchors>) -> PanelWindow {
171 self.anchors = Some(anchors.into_prop());
172 self
173 }
174
175 pub fn width(mut self, width: impl IntoProp<u32>) -> PanelWindow {
178 self.width = Some(width.into_prop());
179 self
180 }
181
182 pub fn height(mut self, height: impl IntoProp<u32>) -> PanelWindow {
186 self.height = Some(height.into_prop());
187 self
188 }
189
190 pub fn exclusive_zone(mut self, zone: impl IntoProp<i32>) -> PanelWindow {
194 self.exclusive_zone = Some(zone.into_prop());
195 self
196 }
197
198 pub fn layer(mut self, layer: impl IntoProp<Layer>) -> PanelWindow {
200 self.layer = Some(layer.into_prop());
201 self
202 }
203
204 pub fn style(mut self, style: impl IntoProp<Style>) -> PanelWindow {
207 self.style = Some(style.into_prop());
208 self
209 }
210
211 pub fn child(mut self, child: impl Widget) -> PanelWindow {
213 self.child = Some(Box::new(child));
214 self
215 }
216}
217
218#[derive(Clone, Copy, Debug, PartialEq, Eq)]
220pub struct SurfaceConfig {
221 pub anchors: Anchors,
223 pub width: u32,
225 pub height: u32,
227 pub exclusive_zone: i32,
229 pub layer: Layer,
231}
232
233pub struct Window {
244 pub(crate) tree: Rc<RefCell<Tree>>,
245 pub(crate) owner: Owner,
246}
247
248impl Window {
249 pub fn new(cx: &Cx, mut panel: PanelWindow) -> Window {
257 let child = untrack(|| panel.child.take().map(|child| child.into_element()));
261 let path: Rc<str> = format!("PanelWindow[{}]", panel.output.name).into();
262 let cx = cx
263 .child()
264 .named(path.to_string())
265 .at(Rc::new(Anchor::default()));
266 let owner = cx.owner();
267 let output = panel.output.clone();
268 let tree =
269 Rc::new_cyclic(|this| RefCell::new(Tree::new(this.clone(), "PanelWindow", output, cx, path)));
270 borrow(&tree).mount_panel(panel, child);
271 Window { tree, owner }
272 }
273
274 pub fn output(&self) -> Output {
276 self.tree.borrow().output.clone()
277 }
278
279 pub fn surface(&self) -> SurfaceConfig {
285 let tree = self.tree.borrow();
286 let surface = &tree.surface;
287 let exclusive_zone = surface.exclusive_zone.unwrap_or_else(|| {
288 let thickness = match surface.anchors.edge() {
289 Some(Edge::Top | Edge::Bottom) => surface.height,
290 Some(Edge::Left | Edge::Right) => surface.width,
291 None => 0,
292 };
293 i32::try_from(thickness).unwrap_or(i32::MAX)
294 });
295 SurfaceConfig {
296 anchors: surface.anchors,
297 width: surface.width,
298 height: surface.height,
299 exclusive_zone,
300 layer: surface.layer,
301 }
302 }
303
304 pub fn take_surface_changed(&self) -> bool {
308 std::mem::take(&mut borrow(&self.tree).surface.changed)
309 }
310
311 pub fn size(&self) -> Size {
314 self.tree.borrow().size
315 }
316
317 pub fn set_size(&self, size: Size) {
320 let mut tree = borrow(&self.tree);
321 if tree.size != size {
322 tree.size = size;
323 tree.needs_layout = true;
324 }
325 }
326
327 pub fn needs_layout(&self) -> bool {
329 self.tree.borrow().needs_layout
330 }
331
332 pub fn layout(&self, text: &mut TextSystem) {
335 borrow(&self.tree).layout(text);
336 }
337
338 pub fn has_damage(&self) -> bool {
340 !self.tree.borrow().damage.is_empty()
341 }
342
343 pub fn take_damage(&self) -> Vec<Rect> {
346 std::mem::take(&mut borrow(&self.tree).damage)
347 }
348
349 pub fn view(&self) -> WindowView<'_> {
352 WindowView::new(self.tree.borrow())
353 }
354}
355
356impl Drop for Window {
357 fn drop(&mut self) {
358 self.owner.dispose();
359 }
360}