Refactored the widget system #11

This commit is contained in:
2025-08-01 16:10:56 -05:00
parent af5428a2f3
commit 45db1fb774
6 changed files with 254 additions and 91 deletions
+188 -44
View File
@@ -1,7 +1,7 @@
use std::{
any::{Any, TypeId},
collections::HashMap,
sync::{Arc, Mutex},
sync::{Arc, Mutex, MutexGuard},
};
use crate::{render_scope::RenderScope, state::DependencyHandler};
@@ -25,15 +25,190 @@ pub trait Component: Send + Sync {
fn as_any_mut(&mut self) -> &mut dyn Any;
}
pub struct Widget(
pub Mutex<BoxedElement>,
pub struct WidgetLoad(BoxedElement, HashMap<TypeId, BoxedComponent>);
impl WidgetLoad {
pub fn new<E: Element + 'static>(e: E) -> Self {
Self(Box::new(e), HashMap::new())
}
pub fn component<C: Component + 'static>(mut self, c: C) -> Self {
self.1.entry(c.type_id()).or_insert_with(|| Box::new(c));
self
}
pub fn set_component<C: Component + 'static>(mut self, c: C) -> Self {
self.1.insert(c.type_id(), Box::new(c));
self
}
pub fn get<C: Component + 'static + Clone>(&self) -> Option<C> {
self.1
.get(&TypeId::of::<C>())
.and_then(|c| c.as_any().downcast_ref::<C>())
.map(|c| c.clone())
}
}
pub enum Widget {
Static(Arc<StaticWidget>),
Dynamic(Arc<DynWidget>),
}
// === Trait Implementation ===
impl Widget {
pub fn get_elem(&self) -> MutexGuard<BoxedElement> {
match self {
Widget::Static(w) => w.get_elem(),
Widget::Dynamic(w) => w.get_elem(),
}
}
pub fn after_render(&self) {
match self {
Widget::Static(w) => w.after_render(),
Widget::Dynamic(w) => w.after_render(),
}
}
pub fn component<C: Component + 'static>(self: &Arc<Self>, c: C) -> &Arc<Self> {
match &**self {
Widget::Static(w) => {
w.component(c);
}
Widget::Dynamic(w) => {
w.component(c);
}
}
self
}
pub fn set_component<C: Component + 'static>(self: &Arc<Self>, c: C) -> &Arc<Self> {
match &**self {
Widget::Static(w) => {
w.set_component(c);
}
Widget::Dynamic(w) => {
w.set_component(c);
}
}
self
}
pub fn get<C: Component + 'static + Clone>(&self) -> Option<C> {
match self {
Widget::Static(w) => w.get(),
Widget::Dynamic(w) => w.get(),
}
}
pub fn inject<F: FnMut(WidgetLoad) -> WidgetLoad + 'static + Send + Sync>(
self: &Arc<Self>,
f: F,
) {
match &**self {
Widget::Dynamic(w) => {
w.inject(f);
}
Widget::Static(_) => {}
}
}
pub fn refresh(self: &Arc<Self>) {
match &**self {
Widget::Dynamic(w) => {
w.refresh();
}
Widget::Static(_) => {}
}
}
pub fn auto_refresh(self: &Arc<Self>) {
match &**self {
Widget::Dynamic(w) => {
w.auto_refresh();
}
Widget::Static(_) => {}
}
}
pub fn dependency<D: DependencyHandler + 'static>(self: &Arc<Self>, d: D) -> &Arc<Self> {
match &**self {
Widget::Dynamic(w) => {
w.dependency(d);
}
Widget::Static(_) => {}
}
self
}
pub fn dependency_box(self: &Arc<Self>, d: Box<dyn DependencyHandler>) -> &Arc<Self> {
match &**self {
Widget::Dynamic(w) => {
w.dependency_box(d);
}
Widget::Static(_) => {}
}
self
}
}
// === Static Widget ===
pub struct StaticWidget(Mutex<BoxedElement>, Mutex<HashMap<TypeId, BoxedComponent>>);
impl StaticWidget {
fn after_render(&self) {}
fn get_elem(&self) -> MutexGuard<BoxedElement> {
self.0.lock().unwrap()
}
}
impl StaticWidget {
pub fn new(e: BoxedElement) -> Self {
Self(Mutex::new(e), Mutex::new(HashMap::new()))
}
pub fn component<C: Component + 'static>(self: &Arc<Self>, c: C) -> &Arc<Self> {
self.1
.lock()
.unwrap()
.entry(c.type_id())
.or_insert_with(|| Box::new(c));
self
}
pub fn set_component<C: Component + 'static>(self: &Arc<Self>, c: C) -> &Arc<Self> {
self.1.lock().unwrap().insert(c.type_id(), Box::new(c));
self
}
pub fn get<C: Component + 'static + Clone>(&self) -> Option<C> {
self.1
.lock()
.unwrap()
.get(&TypeId::of::<C>())
.and_then(|c| c.as_any().downcast_ref::<C>())
.map(Clone::clone)
}
}
// === Dynamic Widget ===
pub struct DynWidget(
Mutex<BoxedElement>,
Mutex<HashMap<TypeId, BoxedComponent>>,
Mutex<Box<dyn FnMut() -> WidgetLoad + Send + Sync>>,
Mutex<Vec<Box<dyn DependencyHandler>>>,
Mutex<Option<Box<dyn FnMut(WidgetLoad) -> WidgetLoad + Send + Sync>>>,
);
impl Widget {
impl DynWidget {
fn after_render(&self) {}
fn get_elem(&self) -> MutexGuard<BoxedElement> {
self.0.lock().unwrap()
}
}
impl DynWidget {
pub fn new<F: FnMut() -> WidgetLoad + 'static + Send + Sync>(mut e: F) -> Self {
let wl = e();
Self(
@@ -49,25 +224,19 @@ impl Widget {
self: &Arc<Self>,
f: F,
) {
{
*self.4.lock().unwrap() = Some(Box::new(f));
}
*self.4.lock().unwrap() = Some(Box::new(f));
self.refresh();
}
pub fn refresh(self: &Arc<Self>) {
let w = (self.2.lock().unwrap())();
match &mut *self.4.lock().unwrap() {
Some(inject) => {
let w = inject(w);
*self.0.lock().unwrap() = w.0;
*self.1.lock().unwrap() = w.1;
}
None => {
*self.0.lock().unwrap() = w.0;
*self.1.lock().unwrap() = w.1;
}
let mut w = (self.2.lock().unwrap())();
if let Some(we) = &mut *self.4.lock().unwrap() {
w = (we)(w);
}
*self.0.lock().unwrap() = w.0;
*self.1.lock().unwrap() = w.1;
}
pub fn auto_refresh(self: &Arc<Self>) {
@@ -110,31 +279,6 @@ impl Widget {
.unwrap()
.get(&TypeId::of::<C>())
.and_then(|c| c.as_any().downcast_ref::<C>())
.map(|c| c.clone())
}
}
pub struct WidgetLoad(BoxedElement, HashMap<TypeId, BoxedComponent>);
impl WidgetLoad {
pub fn new<E: Element + 'static>(e: E) -> Self {
Self(Box::new(e), HashMap::new())
}
pub fn component<C: Component + 'static>(mut self, c: C) -> Self {
self.1.entry(c.type_id()).or_insert_with(|| Box::new(c));
self
}
pub fn set_component<C: Component + 'static>(mut self, c: C) -> Self {
self.1.insert(c.type_id(), Box::new(c));
self
}
pub fn get<C: Component + 'static + Clone>(&self) -> Option<C> {
self.1
.get(&TypeId::of::<C>())
.and_then(|c| c.as_any().downcast_ref::<C>())
.map(|c| c.clone())
.map(Clone::clone)
}
}