fission_core/ui/widgets/
responsive.rs1use crate::internal::InternalLower;
2use crate::lowering::{InternalIrBuilder, InternalLoweringCx};
3use crate::ui::Widget;
4use fission_ir::{
5 op::{ResponsiveCondition, ResponsiveQuery},
6 LayoutOp, Op, WidgetId,
7};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ResponsiveCase {
13 pub min_width: Option<f32>,
15 pub max_width: Option<f32>,
17 pub child: Widget,
19}
20
21impl ResponsiveCase {
22 pub fn min_width(min_width: f32, child: impl Into<Widget>) -> Self {
24 Self {
25 min_width: Some(min_width),
26 max_width: None,
27 child: child.into(),
28 }
29 }
30
31 pub fn max_width(max_width: f32, child: impl Into<Widget>) -> Self {
33 Self {
34 min_width: None,
35 max_width: Some(max_width),
36 child: child.into(),
37 }
38 }
39
40 pub fn between(min_width: f32, max_width: f32, child: impl Into<Widget>) -> Self {
42 Self {
43 min_width: Some(min_width),
44 max_width: Some(max_width),
45 child: child.into(),
46 }
47 }
48
49 fn condition(&self) -> ResponsiveCondition {
50 ResponsiveCondition {
51 min_width: self.min_width,
52 max_width: self.max_width,
53 }
54 }
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct Responsive {
60 pub id: Option<WidgetId>,
62 pub query: ResponsiveQuery,
64 pub cases: Vec<ResponsiveCase>,
66 pub fallback: Widget,
68}
69
70impl Responsive {
71 pub fn new(fallback: impl Into<Widget>) -> Self {
73 Self {
74 id: None,
75 query: ResponsiveQuery::Viewport,
76 cases: Vec::new(),
77 fallback: fallback.into(),
78 }
79 }
80
81 pub fn id(mut self, id: WidgetId) -> Self {
83 self.id = Some(id);
84 self
85 }
86
87 pub fn case(mut self, case: ResponsiveCase) -> Self {
89 self.cases.push(case);
90 self
91 }
92
93 pub fn query(mut self, query: ResponsiveQuery) -> Self {
95 self.query = query;
96 self
97 }
98
99 pub fn container_query(self) -> Self {
101 self.query(ResponsiveQuery::Container)
102 }
103}
104
105impl InternalLower for Responsive {
106 fn lower(&self, cx: &mut InternalLoweringCx) -> WidgetId {
107 let id = self.id.unwrap_or_else(|| cx.next_node_id());
108 cx.push_scope(id);
109 let mut children = Vec::with_capacity(self.cases.len() + 1);
110 for case in &self.cases {
111 children.push(case.child.lower(cx));
112 }
113 children.push(self.fallback.lower(cx));
114 cx.pop_scope();
115
116 let mut builder = InternalIrBuilder::new(
117 id,
118 Op::Layout(LayoutOp::Responsive {
119 query: self.query,
120 cases: self.cases.iter().map(ResponsiveCase::condition).collect(),
121 }),
122 );
123 for child in children {
124 builder.add_child(child);
125 }
126 builder.build(cx)
127 }
128}