learn how workspaces + proc macros work & restructure everything

This commit is contained in:
iris committed 2025-12-09 01:52:45 -05:00
1 parent 434e3c3af7
commit e44bb8eca4
76 files changed
+610 -576

No files matched your search

+163
View File
@@ -0,0 +1,163 @@
use std::{
cell::{Ref, RefMut},
marker::Unsize,
ops::CoerceUnsized,
sync::mpsc::Sender,
};
use crate::{
layout::{IdFnTag, IdTag, Ui, Widget, WidgetLike},
util::{Handle, Id, WeakHandle},
};
/// An handle for a widget in a UI.
///
/// TODO: ergonomic clones when they get put in rust-analyzer & don't cause ICEs?
pub struct WidgetRef<W: ?Sized = dyn Widget>(Handle<Inner<W>>);
pub struct WeakWidgetRef<W: ?Sized = dyn Widget>(WeakHandle<Inner<W>>);
struct Inner<W: ?Sized> {
id: Id,
send: Sender<WidgetUpdate>,
label: String,
widget: W,
}
pub enum WidgetUpdate {
Drop(Id),
Mutate(Id),
}
impl<W> PartialEq for WidgetRef<W> {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
impl<W> std::fmt::Debug for WidgetRef<W> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.id().fmt(f)
}
}
impl<W: ?Sized> Clone for WidgetRef<W> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<W: Widget> WidgetRef<W> {
pub(super) fn new(id: Id, widget: W, send: Sender<WidgetUpdate>) -> Self {
let mut label = std::any::type_name::<W>().to_string();
if let (Some(first), Some(last)) = (label.find(":"), label.rfind(":")) {
label = label.split_at(first).0.to_string() + "::" + label.split_at(last + 1).1;
}
Self(
Inner {
widget,
id,
send,
label,
}
.into(),
)
}
}
impl<W: Widget + ?Sized + Unsize<dyn Widget>> WidgetRef<W> {
pub fn any(self) -> WidgetRef<dyn Widget> {
WidgetRef(self.0)
}
pub fn as_any(&self) -> WidgetRef<dyn Widget> {
WidgetRef(self.0.clone())
}
}
impl<W: ?Sized> WidgetRef<W> {
pub fn id(&self) -> Id {
self.0.get().id
}
pub fn get(&self) -> Ref<'_, W> {
Ref::map(self.0.get(), |i| &i.widget)
}
pub fn get_mut(&self) -> RefMut<'_, W> {
let inner = self.0.get_mut();
let _ = inner.send.send(WidgetUpdate::Mutate(inner.id));
RefMut::map(inner, |i| &mut i.widget)
}
pub fn get_mut_quiet(&self) -> RefMut<'_, W> {
RefMut::map(self.0.get_mut(), |i| &mut i.widget)
}
pub fn get_label(&self) -> Ref<'_, String> {
Ref::map(self.0.get(), |i| &i.label)
}
pub fn set_label(&self, label: impl Into<String>) {
self.0.get_mut().label = label.into();
}
pub fn refs(&self) -> usize {
self.0.refs()
}
pub fn weak(&self) -> WeakWidgetRef<W> {
WeakWidgetRef(self.0.weak())
}
}
impl<W: ?Sized> WeakWidgetRef<W> {
/// should guarantee that widget is still valid to prevent indexing failures
pub(crate) fn expect_strong(&self) -> WidgetRef<W> {
WidgetRef(self.0.strong().expect("widget should not be dropped"))
}
}
impl<W: Widget + ?Sized + Unsize<dyn Widget>> WeakWidgetRef<W> {
pub fn any(self) -> WeakWidgetRef<dyn Widget> {
WeakWidgetRef(self.0.clone())
}
}
impl<W: ?Sized> Drop for Inner<W> {
fn drop(&mut self) {
let _ = self.send.send(WidgetUpdate::Drop(self.id));
}
}
pub trait WidgetIdFn<W: ?Sized = dyn Widget>: FnOnce(&mut Ui) -> WidgetRef<W> {}
impl<W: ?Sized, F: FnOnce(&mut Ui) -> WidgetRef<W>> WidgetIdFn<W> for F {}
pub trait WidgetRet: FnOnce(&mut Ui) -> WidgetRef {}
impl<F: FnOnce(&mut Ui) -> WidgetRef> WidgetRet for F {}
impl<W: Widget + ?Sized + Unsize<dyn Widget> + 'static> WidgetLike<IdTag> for WidgetRef<W> {
type Widget = W;
fn add(self, _: &mut Ui) -> WidgetRef<W> {
self
}
}
impl<W: Widget + ?Sized + Unsize<dyn Widget> + 'static, F: FnOnce(&mut Ui) -> WidgetRef<W>>
WidgetLike<IdFnTag> for F
{
type Widget = W;
fn add(self, ui: &mut Ui) -> WidgetRef<W> {
self(ui)
}
}
pub trait IdLike<W> {
fn id(&self) -> Id;
}
impl<W> IdLike<W> for WidgetRef<W> {
fn id(&self) -> Id {
self.id()
}
}
impl<W: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<WidgetRef<U>> for WidgetRef<W> {}