use crate::view::any_element::AnyElement;
use crate::view::div::div;
use crate::view::element::IntoElement;
use crate::view::interactivity::{Effects, EventContext};
use crate::view::theme::Theme;
use crate::core::{Action, Animation, EntityContext, FocusHandle, Handle, Lerp, Size};
use std::ops::{Deref, DerefMut};
use std::time::Instant;
pub trait Render: Sized + 'static {
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement;
}
pub struct ViewContext<'a, 'b, T> {
pub theme: &'a Theme,
pub viewport: Size,
entity: &'a mut EntityContext<'b, T>,
}
impl<'a, 'b, T: 'static> ViewContext<'a, 'b, T> {
pub fn new(theme: &'a Theme, viewport: Size, entity: &'a mut EntityContext<'b, T>) -> Self {
Self { theme, viewport, entity }
}
pub fn listener<E>(
&self,
callback: impl Fn(&mut T, &E, &mut ListenerContext<T>) + 'static,
) -> impl Fn(&E, &mut EventContext) + 'static {
let handle = self.entity.handle();
move |event, context| {
let effects = &mut context.effects;
context.entities.update(handle, |this, entity| {
let mut listener = ListenerContext { entity, effects };
callback(this, event, &mut listener);
});
}
}
pub fn dragging<Payload: std::any::Any>(&self) -> bool {
self.entity.drag_type == Some(std::any::TypeId::of::<Payload>())
}
pub fn render_child<V: Render>(&mut self, child: Handle<V>) -> AnyElement {
let (theme, viewport) = (self.theme, self.viewport);
self.entity
.update(child, |view, entity| view.render(&mut ViewContext::new(theme, viewport, entity)))
.unwrap_or_else(|| div().into_element())
}
pub fn animate(&mut self, id: &str, animation: Animation) -> f32 {
let (progress, running) = self.entity.animations.progress(id, animation, Instant::now());
if running {
self.entity.timers.request_animation_frame();
}
progress
}
pub fn animate_between<L: Lerp>(&mut self, id: &str, animation: Animation, from: L, to: L) -> L {
from.lerp(to, self.animate(id, animation))
}
pub fn transition(&mut self, id: &str, target: f32, animation: Animation) -> f32 {
let (value, running) = self.entity.animations.transition(id, target, animation, Instant::now());
if running {
self.entity.timers.request_animation_frame();
}
value
}
pub fn new_focus_handle(&mut self) -> FocusHandle {
self.entity.focus.new_handle()
}
pub fn is_focused(&self, handle: &FocusHandle) -> bool {
self.entity.focus.is_focused(handle)
}
}
impl<'b, T> Deref for ViewContext<'_, 'b, T> {
type Target = EntityContext<'b, T>;
fn deref(&self) -> &Self::Target {
self.entity
}
}
impl<T> DerefMut for ViewContext<'_, '_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.entity
}
}
pub struct ListenerContext<'a, 'b, T> {
entity: &'a mut EntityContext<'b, T>,
effects: &'a mut Effects,
}
impl<T: 'static> ListenerContext<'_, '_, T> {
pub fn notify(&mut self) {
self.effects.notify();
self.entity.notify();
}
pub fn dispatch_action(&mut self, action: Action) {
self.effects.dispatch_action(action);
}
pub fn propagate(&mut self) {
self.effects.propagate();
}
pub fn pointer(&self) -> Option<crate::core::Point> {
self.effects.pointer
}
pub fn focus(&mut self, handle: &FocusHandle) {
self.entity.focus.focus(handle);
self.effects.notify();
}
}
impl<'b, T> Deref for ListenerContext<'_, 'b, T> {
type Target = EntityContext<'b, T>;
fn deref(&self) -> &Self::Target {
self.entity
}
}
impl<T> DerefMut for ListenerContext<'_, '_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.entity
}
}