use crate::internal::InternalLower;
use crate::lowering::{InternalIrBuilder, InternalLoweringCx};
use crate::ui::Widget;
use fission_ir::{
op::{ResponsiveCondition, ResponsiveQuery},
LayoutOp, Op, WidgetId,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResponsiveCase {
pub min_width: Option<f32>,
pub max_width: Option<f32>,
pub child: Widget,
}
impl ResponsiveCase {
pub fn min_width(min_width: f32, child: impl Into<Widget>) -> Self {
Self {
min_width: Some(min_width),
max_width: None,
child: child.into(),
}
}
pub fn max_width(max_width: f32, child: impl Into<Widget>) -> Self {
Self {
min_width: None,
max_width: Some(max_width),
child: child.into(),
}
}
pub fn between(min_width: f32, max_width: f32, child: impl Into<Widget>) -> Self {
Self {
min_width: Some(min_width),
max_width: Some(max_width),
child: child.into(),
}
}
fn condition(&self) -> ResponsiveCondition {
ResponsiveCondition {
min_width: self.min_width,
max_width: self.max_width,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Responsive {
pub id: Option<WidgetId>,
pub query: ResponsiveQuery,
pub cases: Vec<ResponsiveCase>,
pub fallback: Widget,
}
impl Responsive {
pub fn new(fallback: impl Into<Widget>) -> Self {
Self {
id: None,
query: ResponsiveQuery::Viewport,
cases: Vec::new(),
fallback: fallback.into(),
}
}
pub fn id(mut self, id: WidgetId) -> Self {
self.id = Some(id);
self
}
pub fn case(mut self, case: ResponsiveCase) -> Self {
self.cases.push(case);
self
}
pub fn query(mut self, query: ResponsiveQuery) -> Self {
self.query = query;
self
}
pub fn container_query(self) -> Self {
self.query(ResponsiveQuery::Container)
}
}
impl InternalLower for Responsive {
fn lower(&self, cx: &mut InternalLoweringCx) -> WidgetId {
let id = self.id.unwrap_or_else(|| cx.next_node_id());
cx.push_scope(id);
let mut children = Vec::with_capacity(self.cases.len() + 1);
for case in &self.cases {
children.push(case.child.lower(cx));
}
children.push(self.fallback.lower(cx));
cx.pop_scope();
let mut builder = InternalIrBuilder::new(
id,
Op::Layout(LayoutOp::Responsive {
query: self.query,
cases: self.cases.iter().map(ResponsiveCase::condition).collect(),
}),
);
for child in children {
builder.add_child(child);
}
builder.build(cx)
}
}