aura-gui 0.1.0

UI nativa acelerada por GPU para escritorio, Android e iOS, en un solo crate: estilo tipo Tailwind, componentes, sombras, animaciones y agentes de IA. Reposo a cero. Licencia AGPL-3.0 o comercial.
//! Vistas con estado: `Render` y `ViewContext`, equivalentes a `Entity<T>` de GPUI.

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;

/// Una vista declara cómo se dibuja su estado en cada frame.
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 }
    }

    /// Convierte un cierre sobre el estado de la vista en un manejador de evento:
    /// `.on_click(cx.listener(|this, _event, cx| { this.count += 1; cx.notify(); }))`.
    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);
            });
        }
    }

    /// `true` mientras se arrastra una carga de tipo `T` (pestaña, panel…): para mostrar zonas de soltado.
    pub fn dragging<Payload: std::any::Any>(&self) -> bool {
        self.entity.drag_type == Some(std::any::TypeId::of::<Payload>())
    }

    /// Dibuja otra vista como hija de esta (por ejemplo, un editor dentro de un panel).
    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())
    }

    /// Progreso (0 a 1) de una animación con nombre; mientras corre pide más frames.
    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
    }

    /// Interpola entre dos valores (colores, posiciones, tamaños) con el progreso de una animación con nombre.
    pub fn animate_between<L: Lerp>(&mut self, id: &str, animation: Animation, from: L, to: L) -> L {
        from.lerp(to, self.animate(id, animation))
    }

    /// Como `transition` de CSS: el valor se desliza hacia `target` cada vez que este cambia, partiendo de
    /// donde iba. Solo pide frames mientras se mueve.
    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
    }
}

/// Contexto de un manejador creado con `listener`: acceso a la entidad y a los efectos.
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();
    }

    /// Dónde estaba el puntero al soltar un arrastre (solo dentro de un `on_drop`).
    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
    }
}