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)]
78pub struct Responsive {
79 pub id: Option<WidgetId>,
81 pub query: ResponsiveQuery,
83 pub cases: Vec<ResponsiveCase>,
85 pub fallback: Widget,
87}
88
89impl Responsive {
90 pub fn new(fallback: impl Into<Widget>) -> Self {
92 Self {
93 id: None,
94 query: ResponsiveQuery::Viewport,
95 cases: Vec::new(),
96 fallback: fallback.into(),
97 }
98 }
99
100 pub fn id(mut self, id: WidgetId) -> Self {
102 self.id = Some(id);
103 self
104 }
105
106 pub fn case(mut self, case: ResponsiveCase) -> Self {
108 self.cases.push(case);
109 self
110 }
111
112 pub fn query(mut self, query: ResponsiveQuery) -> Self {
114 self.query = query;
115 self
116 }
117
118 pub fn container_query(self) -> Self {
120 self.query(ResponsiveQuery::Container)
121 }
122}
123
124impl InternalLower for Responsive {
125 fn lower(&self, cx: &mut InternalLoweringCx) -> WidgetId {
126 let id = self.id.unwrap_or_else(|| cx.next_node_id());
127 cx.push_scope(id);
128 let mut children = Vec::with_capacity(self.cases.len() + 1);
129 for case in &self.cases {
130 children.push(case.child.lower(cx));
131 }
132 children.push(self.fallback.lower(cx));
133 cx.pop_scope();
134
135 let mut builder = InternalIrBuilder::new(
136 id,
137 Op::Layout(LayoutOp::Responsive {
138 query: self.query,
139 cases: self.cases.iter().map(ResponsiveCase::condition).collect(),
140 }),
141 );
142 for child in children {
143 builder.add_child(child);
144 }
145 builder.build(cx)
146 }
147}