use crate::{
env::VideoState, registry::AnimationPropertyId, Env, GlobalState, LayoutRect, LayoutSize,
LayoutSnapshot, RuntimeState, ViewHandle,
};
use fission_i18n::I18nRegistry;
use fission_ir::WidgetId;
use fission_layout::BoxConstraints;
use fission_theme::Theme;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{BuildHasher, Hash};
pub struct View<'a, S: GlobalState> {
pub state: &'a S,
pub runtime: &'a RuntimeState,
pub env: &'a Env,
pub layout: Option<&'a LayoutSnapshot>,
}
impl<'a, S: GlobalState> View<'a, S> {
pub fn new(
state: &'a S,
runtime: &'a RuntimeState,
env: &'a Env,
layout: Option<&'a LayoutSnapshot>,
) -> Self {
Self {
state,
runtime,
env,
layout,
}
}
pub fn state(&self) -> &S {
self.state
}
pub fn runtime(&self) -> &RuntimeState {
self.runtime
}
pub fn env(&self) -> &Env {
self.env
}
pub fn layout(&self) -> Option<&LayoutSnapshot> {
self.layout
}
pub fn theme(&self) -> &Theme {
&self.env.theme
}
pub fn i18n(&self) -> &I18nRegistry {
&self.env.i18n
}
pub fn get_rect(&self, id: WidgetId) -> Option<LayoutRect> {
let node_id: WidgetId = id.into();
self.layout.and_then(|l| l.get_node_rect(node_id))
}
pub fn get_constraints(&self, id: WidgetId) -> Option<BoxConstraints> {
let node_id: WidgetId = id.into();
self.layout.and_then(|l| l.get_node_constraints(node_id))
}
pub fn viewport_size(&self) -> LayoutSize {
self.env.viewport_size
}
pub fn select<R>(&self, selector: impl FnOnce(&S) -> R) -> R {
selector(self.state)
}
pub fn animation_value(&self, widget_id: WidgetId, property: &AnimationPropertyId) -> f32 {
self.runtime
.animation
.values
.get(&(widget_id, property.clone()))
.copied()
.unwrap_or_else(|| property.default_value())
}
pub fn video_state(&self, widget_id: WidgetId) -> Option<&VideoState> {
self.runtime.video.states.get(&widget_id)
}
}
#[derive(Clone, Copy, Debug)]
pub struct ValueView<'a, T> {
value: &'a T,
}
impl<'a, T> ValueView<'a, T> {
pub fn new(value: &'a T) -> Self {
Self { value }
}
pub fn borrow(&self) -> &'a T {
self.value
}
pub fn map<R>(&self, selector: impl FnOnce(&T) -> R) -> ComputedView<R> {
ComputedView::new(selector(self.value))
}
}
impl<T: Clone> ValueView<'_, T> {
pub fn get(&self) -> T {
self.value.clone()
}
}
impl<'a, T> ValueView<'a, Vec<T>> {
pub fn len(&self) -> usize {
self.value.len()
}
pub fn is_empty(&self) -> bool {
self.value.is_empty()
}
pub fn iter(&self) -> std::slice::Iter<'a, T> {
self.value.iter()
}
}
impl<'a, T> IntoIterator for ValueView<'a, Vec<T>> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.value.iter()
}
}
#[derive(Clone, Debug)]
pub struct ComputedView<T> {
value: T,
}
impl<T> ComputedView<T> {
pub fn new(value: T) -> Self {
Self { value }
}
pub fn borrow(&self) -> &T {
&self.value
}
pub fn get(self) -> T {
self.value
}
pub fn map<R>(self, selector: impl FnOnce(&T) -> R) -> ComputedView<R> {
ComputedView::new(selector(&self.value))
}
}
pub trait FissionViewField {
type View<'a>
where
Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a>;
}
macro_rules! scalar_view_field {
($($ty:ty),* $(,)?) => {
$(
impl FissionViewField for $ty {
type View<'a> = ValueView<'a, Self> where Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
ValueView::new(value)
}
}
)*
};
}
scalar_view_field!(
bool, char, String, usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64
);
impl<T> FissionViewField for Vec<T> {
type View<'a>
= ValueView<'a, Self>
where
Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
ValueView::new(value)
}
}
impl<T> FissionViewField for Option<T> {
type View<'a>
= ValueView<'a, Self>
where
Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
ValueView::new(value)
}
}
impl<T, const N: usize> FissionViewField for [T; N] {
type View<'a>
= ValueView<'a, Self>
where
Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
ValueView::new(value)
}
}
impl<T: Ord> FissionViewField for BTreeSet<T> {
type View<'a>
= ValueView<'a, Self>
where
Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
ValueView::new(value)
}
}
impl<K: Ord, V> FissionViewField for BTreeMap<K, V> {
type View<'a>
= ValueView<'a, Self>
where
Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
ValueView::new(value)
}
}
impl<T: Eq + Hash, S: BuildHasher> FissionViewField for HashSet<T, S> {
type View<'a>
= ValueView<'a, Self>
where
Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
ValueView::new(value)
}
}
impl<K: Eq + Hash, V, S: BuildHasher> FissionViewField for HashMap<K, V, S> {
type View<'a>
= ValueView<'a, Self>
where
Self: 'a;
fn view_field<'a>(value: &'a Self) -> Self::View<'a> {
ValueView::new(value)
}
}
pub trait Selector<S: GlobalState> {
type Output;
fn select(view: ViewHandle<S>) -> Self::Output;
}