Compare commits

1 Commits

Author SHA1 Message Date
434e3c3af7 view + a bunch of fixes or smth idek man 2025-12-08 00:12:11 -05:00
18 changed files with 253 additions and 109 deletions

View File

@@ -1,8 +1,5 @@
use cosmic_text::Family; use cosmic_text::Family;
use iris::{ use iris::prelude::*;
prelude::*,
winit::{attr::Selectable, event::Submit, *},
};
use len_fns::*; use len_fns::*;
use winit::event::WindowEvent; use winit::event::WindowEvent;
@@ -109,7 +106,7 @@ impl DefaultAppState for Client {
.text_align(Align::LEFT) .text_align(Align::LEFT)
.size(30) .size(30)
.attr::<Selectable>(()) .attr::<Selectable>(())
.on(Submit, move |ctx| { .on(iris::winit::Submit, move |ctx| {
let content = ctx.widget.get_mut().take(); let content = ctx.widget.get_mut().take();
let text = wtext(content) let text = wtext(content)
.editable(false) .editable(false)

View File

@@ -11,7 +11,7 @@ use crate::{
}; };
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum Button { pub enum CursorButton {
Left, Left,
Right, Right,
Middle, Middle,
@@ -19,9 +19,9 @@ pub enum Button {
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum CursorSense { pub enum CursorSense {
PressStart(Button), PressStart(CursorButton),
Pressing(Button), Pressing(CursorButton),
PressEnd(Button), PressEnd(CursorButton),
HoverStart, HoverStart,
Hovering, Hovering,
HoverEnd, HoverEnd,
@@ -32,16 +32,16 @@ pub struct CursorSenses(Vec<CursorSense>);
impl CursorSense { impl CursorSense {
pub fn click() -> Self { pub fn click() -> Self {
Self::PressStart(Button::Left) Self::PressStart(CursorButton::Left)
} }
pub fn click_or_drag() -> CursorSenses { pub fn click_or_drag() -> CursorSenses {
Self::click() | Self::Pressing(Button::Left) Self::click() | Self::Pressing(CursorButton::Left)
} }
pub fn unclick() -> Self { pub fn unclick() -> Self {
Self::PressEnd(Button::Left) Self::PressEnd(CursorButton::Left)
} }
pub fn is_dragging(&self) -> bool { pub fn is_dragging(&self) -> bool {
matches!(self, CursorSense::Pressing(Button::Left)) matches!(self, CursorSense::Pressing(CursorButton::Left))
} }
} }
@@ -61,11 +61,11 @@ pub struct CursorButtons {
} }
impl CursorButtons { impl CursorButtons {
pub fn select(&self, button: &Button) -> &ActivationState { pub fn select(&self, button: &CursorButton) -> &ActivationState {
match button { match button {
Button::Left => &self.left, CursorButton::Left => &self.left,
Button::Right => &self.right, CursorButton::Right => &self.right,
Button::Middle => &self.middle, CursorButton::Middle => &self.middle,
} }
} }
@@ -205,7 +205,11 @@ impl<Ctx: 'static> CursorModule<Ctx> {
scroll_delta: cursor.scroll_delta, scroll_delta: cursor.scroll_delta,
sense, sense,
}; };
(sensor.f)(EventCtx { ui, state: ctx, data }); (sensor.f)(EventCtx {
ui,
state: ctx,
data,
});
} }
} }
} }

View File

@@ -75,7 +75,7 @@ impl TextBuilderOutput for TextOutput {
builder.attrs.line_height, builder.attrs.line_height,
)); ));
let hint = builder.hint.get(ui); let hint = builder.hint.get(ui);
let font_system = &mut ui.data.text.borrow_mut().font_system; let font_system = &mut ui.data.text.get_mut().font_system;
buf.set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None); buf.set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None);
let mut text = Text { let mut text = Text {
content: builder.content.into(), content: builder.content.into(),
@@ -103,7 +103,7 @@ impl TextBuilderOutput for TextEditOutput {
builder.output.single_line, builder.output.single_line,
ui.data.text.clone(), ui.data.text.clone(),
); );
let font_system = &mut ui.data.text.borrow_mut().font_system; let font_system = &mut ui.data.text.get_mut().font_system;
text.buf text.buf
.set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None); .set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None);
builder.attrs.apply(font_system, &mut text.buf, None); builder.attrs.apply(font_system, &mut text.buf, None);

View File

@@ -60,7 +60,7 @@ impl TextEdit {
pub fn set(&mut self, text: &str) { pub fn set(&mut self, text: &str) {
let text = self.string(text); let text = self.string(text);
self.view.buf.set_text( self.view.buf.set_text(
&mut self.data.borrow_mut().font_system, &mut self.data.get_mut().font_system,
&text, &text,
&Attrs::new(), &Attrs::new(),
SHAPING, SHAPING,
@@ -238,7 +238,7 @@ impl TextEdit {
self.view self.view
.buf .buf
.cursor_motion( .cursor_motion(
&mut self.data.borrow_mut().font_system, &mut self.data.get_mut().font_system,
cursor, cursor,
None, None,
motion, motion,

View File

@@ -67,7 +67,7 @@ impl TextView {
return tex.clone(); return tex.clone();
} }
self.width = width; self.width = width;
let mut text_data = ctx.text.borrow_mut(); let mut text_data = ctx.text.get_mut();
self.attrs self.attrs
.apply(&mut text_data.font_system, &mut self.buf, width); .apply(&mut text_data.font_system, &mut self.buf, width);
self.buf self.buf
@@ -139,7 +139,7 @@ impl Text {
if self.content.changed { if self.content.changed {
self.content.changed = false; self.content.changed = false;
self.view.buf.set_text( self.view.buf.set_text(
&mut ctx.text.borrow_mut().font_system, &mut ctx.text.get_mut().font_system,
&self.content, &self.content,
&Attrs::new().family(self.view.attrs.family), &Attrs::new().family(self.view.attrs.family),
SHAPING, SHAPING,

View File

@@ -1,5 +1,7 @@
#![allow(clippy::multiple_bound_locations)] #![allow(clippy::multiple_bound_locations)]
use std::marker::Destruct;
/// stored in linear for sane manipulation /// stored in linear for sane manipulation
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Hash, PartialEq, Eq, bytemuck::Zeroable, Debug)] #[derive(Clone, Copy, Hash, PartialEq, Eq, bytemuck::Zeroable, Debug)]
@@ -56,23 +58,47 @@ pub trait ColorNum {
const MAX: Self; const MAX: Self;
} }
impl<T: ColorNum + F32Conversion> Color<T> { macro_rules! map_rgb {
pub fn mul_rgb(self, amt: impl F32Conversion) -> Self { ($x:ident,$self:ident, $e:tt) => {
#[allow(unused_braces)]
Self {
r: {
let $x = $self.r;
$e
},
g: {
let $x = $self.g;
$e
},
b: {
let $x = $self.b;
$e
},
a: $self.a,
}
};
}
impl<T: ColorNum + const F32Conversion> Color<T>
where
Self: const Destruct,
{
pub const fn mul_rgb(self, amt: impl const F32Conversion) -> Self {
let amt = amt.to(); let amt = amt.to();
self.map_rgb(|x| T::from(x.to() * amt)) map_rgb!(x, self, { T::from(x.to() * amt) })
} }
pub fn add_rgb(self, amt: impl F32Conversion) -> Self { pub const fn add_rgb(self, amt: impl const F32Conversion) -> Self {
let amt = amt.to(); let amt = amt.to();
self.map_rgb(|x| T::from(x.to() + amt)) map_rgb!(x, self, { T::from(x.to() + amt) })
} }
pub fn darker(self, amt: f32) -> Self { pub const fn darker(self, amt: f32) -> Self {
self.mul_rgb(1.0 - amt) self.mul_rgb(1.0 - amt)
} }
pub fn brighter(self, amt: f32) -> Self { pub const fn brighter(self, amt: f32) -> Self {
self.map_rgb(|x| { map_rgb!(x, self, {
let x = x.to(); let x = x.to();
T::from(x + (1.0 - x) * amt) T::from(x + (1.0 - x) * amt)
}) })

View File

@@ -28,7 +28,10 @@ pub trait EventFn<Ctx, Data>: Fn(EventCtx<Ctx, Data>) + 'static {}
impl<F: Fn(EventCtx<Ctx, Data>) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {} impl<F: Fn(EventCtx<Ctx, Data>) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {}
pub trait WidgetEventFn<Ctx, Data, W: ?Sized>: Fn(EventIdCtx<Ctx, Data, W>) + 'static {} pub trait WidgetEventFn<Ctx, Data, W: ?Sized>: Fn(EventIdCtx<Ctx, Data, W>) + 'static {}
impl<F: Fn(EventIdCtx<Ctx, Data, W>) + 'static, Ctx, Data, W> WidgetEventFn<Ctx, Data, W> for F {} impl<F: Fn(EventIdCtx<Ctx, Data, W>) + 'static, Ctx, Data, W: ?Sized> WidgetEventFn<Ctx, Data, W>
for F
{
}
// TODO: naming in here is a bit weird like eventable // TODO: naming in here is a bit weird like eventable
#[macro_export] #[macro_export]
@@ -40,6 +43,7 @@ macro_rules! event_ctx {
#[allow(unused_imports)] #[allow(unused_imports)]
use $crate::prelude::*; use $crate::prelude::*;
#[allow(unused)]
pub trait EventableCtx<W: ?Sized, Tag, Ctx: 'static> { pub trait EventableCtx<W: ?Sized, Tag, Ctx: 'static> {
fn on<E: Event>( fn on<E: Event>(
self, self,
@@ -57,6 +61,33 @@ macro_rules! event_ctx {
eventable::Eventable::on(self, event, f) eventable::Eventable::on(self, event, f)
} }
} }
#[allow(unused)]
pub trait EventableCtxUi<W: ?Sized, Tag, Ctx: 'static>
where
WidgetRef<W>: EventableCtx<W, Tag, Ctx>,
{
fn on<E: Event>(
&mut self,
widget: &WidgetRef<W>,
event: E,
f: impl WidgetEventFn<Ctx, E::Data, W>,
);
}
impl<W: ?Sized + 'static, Tag> EventableCtxUi<W, Tag, $ty> for Ui
where
WidgetRef<W>: EventableCtx<W, Tag, $ty>,
{
fn on<E: Event>(
&mut self,
widget: &WidgetRef<W>,
event: E,
f: impl WidgetEventFn<$ty, E::Data, W>,
) {
self.register_widget_event(&widget, event, f);
}
}
} }
use local_event_trait::*; use local_event_trait::*;
}; };
@@ -82,21 +113,47 @@ pub mod eventable {
) -> impl WidgetIdFn<WL::Widget> { ) -> impl WidgetIdFn<WL::Widget> {
move |ui| { move |ui| {
let id = self.add(ui); let id = self.add(ui);
let id_ = id.weak(); ui.register_widget_event(&id, event, f);
ui.register_event(&id, event, move |ctx| {
f(EventIdCtx {
widget: &id_.expect_strong(),
state: ctx.state,
data: ctx.data,
ui: ctx.ui,
});
});
id id
} }
} }
} }
} }
impl Ui {
pub fn register_event<W: ?Sized, E: Event, Ctx: 'static>(
&mut self,
id: &WidgetRef<W>,
event: E,
f: impl EventFn<Ctx, E::Data>,
) {
self.data
.modules
.get_mut::<E::Module<Ctx>>()
.register(id.id(), event, f);
}
pub fn register_widget_event<W: ?Sized + 'static, E: Event, Ctx: 'static>(
&mut self,
id: &WidgetRef<W>,
event: E,
f: impl WidgetEventFn<Ctx, E::Data, W>,
) {
let id_ = id.weak();
self.data
.modules
.get_mut::<E::Module<Ctx>>()
.register(id.id(), event, move |ctx| {
f(EventIdCtx {
widget: &id_.expect_strong(),
ui: ctx.ui,
state: ctx.state,
data: ctx.data,
})
});
}
}
pub trait DefaultEvent: Hash + Eq + 'static { pub trait DefaultEvent: Hash + Eq + 'static {
type Data: Clone; type Data: Clone;
} }
@@ -193,7 +250,7 @@ impl<E: Event + 'static, Ctx: 'static> Default for DefaultEventModule<E, Ctx> {
} }
impl Ui { impl Ui {
pub fn run_event<E: Event, Ctx: 'static, W>( pub fn run_event<E: Event, Ctx: 'static, W: ?Sized>(
&mut self, &mut self,
ctx: &mut Ctx, ctx: &mut Ctx,
id: &WidgetRef<W>, id: &WidgetRef<W>,

View File

@@ -9,6 +9,7 @@ mod painter;
mod text; mod text;
mod texture; mod texture;
mod ui; mod ui;
mod view;
mod widget; mod widget;
mod widget_ref; mod widget_ref;
mod widgets; mod widgets;
@@ -24,6 +25,7 @@ pub use painter::*;
pub use text::*; pub use text::*;
pub use texture::*; pub use texture::*;
pub use ui::*; pub use ui::*;
pub use view::*;
pub use widget::*; pub use widget::*;
pub use widget_ref::*; pub use widget_ref::*;
pub use widgets::*; pub use widgets::*;

View File

@@ -450,7 +450,7 @@ impl<'a, 'c> Painter<'a, 'c> {
pub fn render_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText { pub fn render_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText {
self.ctx self.ctx
.text .text
.borrow_mut() .get_mut()
.draw(buffer, attrs, self.ctx.textures) .draw(buffer, attrs, self.ctx.textures)
} }
@@ -604,6 +604,6 @@ impl SizeCtx<'_> {
} }
pub fn draw_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText { pub fn draw_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText {
self.text.borrow_mut().draw(buffer, attrs, self.textures) self.text.get_mut().draw(buffer, attrs, self.textures)
} }
} }

View File

@@ -1,10 +1,9 @@
use std::{ use std::simd::{Simd, num::SimdUint};
cell::RefCell,
rc::Rc,
simd::{Simd, num::SimdUint},
};
use crate::layout::{Align, RegionAlign, TextureHandle, Textures, UiColor, Vec2}; use crate::{
layout::{Align, RegionAlign, TextureHandle, Textures, UiColor, Vec2},
util::Handle,
};
use cosmic_text::{ use cosmic_text::{
Attrs, AttrsList, Buffer, CacheKey, Color, Family, FontSystem, Metrics, Placement, SwashCache, Attrs, AttrsList, Buffer, CacheKey, Color, Family, FontSystem, Metrics, Placement, SwashCache,
SwashContent, SwashContent,
@@ -16,7 +15,7 @@ pub mod text_lib {
pub use cosmic_text::*; pub use cosmic_text::*;
} }
pub type TextData = Rc<RefCell<TextDataInner>>; pub type TextData = Handle<TextDataInner>;
pub struct TextDataInner { pub struct TextDataInner {
pub font_system: FontSystem, pub font_system: FontSystem,

View File

@@ -3,7 +3,7 @@ use image::DynamicImage;
use crate::{ use crate::{
layout::{ layout::{
Event, EventFn, EventModule, IdLike, PainterData, PixelRegion, TextureHandle, Vec2, Widget, Event, EventFn, EventModule, IdLike, PainterData, PixelRegion, TextureHandle, Vec2, Widget,
WidgetInstance, WidgetLike, WidgetRef, WidgetUpdate, WidgetEventFn, WidgetInstance, WidgetLike, WidgetRef, WidgetUpdate,
}, },
util::{HashSet, Id}, util::{HashSet, Id},
}; };
@@ -42,18 +42,6 @@ impl Ui {
self.data.textures.add(image) self.data.textures.add(image)
} }
pub fn register_event<W: ?Sized, E: Event, Ctx: 'static>(
&mut self,
id: &WidgetRef<W>,
event: E,
f: impl EventFn<Ctx, E::Data>,
) {
self.data
.modules
.get_mut::<E::Module<Ctx>>()
.register(id.id(), event, f);
}
pub fn resize(&mut self, size: impl Into<Vec2>) { pub fn resize(&mut self, size: impl Into<Vec2>) {
self.data.output_size = size.into(); self.data.output_size = size.into();
self.resized = true; self.resized = true;

17
src/layout/view.rs Normal file
View File

@@ -0,0 +1,17 @@
use crate::layout::{Widget, WidgetLike, WidgetRef};
use std::marker::Unsize;
pub trait WidgetView {
type Widget: Widget + ?Sized + Unsize<dyn Widget> = dyn Widget;
fn view(&self) -> &WidgetRef<Self::Widget>;
}
pub struct ViewTag;
impl<WV: WidgetView> WidgetLike<ViewTag> for WV {
type Widget = WV::Widget;
fn add(self, _ui: &mut super::Ui) -> WidgetRef<Self::Widget> {
self.view().clone()
}
}

View File

@@ -61,7 +61,7 @@ pub trait WidgetLike<Tag> {
/// A function that returns a widget given a UI. /// A function that returns a widget given a UI.
/// Useful for defining trait functions on widgets that create a parent widget so that the children /// Useful for defining trait functions on widgets that create a parent widget so that the children
/// don't need to be IDs yet /// don't need to be IDs yet
pub trait WidgetFn<W: Widget>: FnOnce(&mut Ui) -> W {} pub trait WidgetFn<W: Widget + ?Sized>: FnOnce(&mut Ui) -> W {}
impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetFn<W> for F {} impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetFn<W> for F {}
impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetLike<FnTag> for F { impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetLike<FnTag> for F {

View File

@@ -1,24 +1,20 @@
use std::{ use std::{
cell::{Ref, RefCell, RefMut}, cell::{Ref, RefMut},
marker::Unsize, marker::Unsize,
rc::{Rc, Weak}, rc::Rc,
sync::mpsc::Sender, sync::mpsc::Sender,
}; };
use crate::{ use crate::{
layout::{Ui, Widget, WidgetLike}, layout::{Ui, Widget, WidgetLike},
util::Id, util::{Handle, Id, WeakHandle},
}; };
/// An identifier for a widget that can index a UI to get the associated widget. /// An handle for a widget in a UI.
/// It should always remain valid; it keeps a ref count and removes the widget from the UI if all
/// references are dropped.
///
/// W does not need to implement widget so that AnyWidget is valid;
/// Instead, add generic bounds on methods that take an ID if they need specific data.
/// ///
/// TODO: ergonomic clones when they get put in rust-analyzer & don't cause ICEs? /// TODO: ergonomic clones when they get put in rust-analyzer & don't cause ICEs?
pub struct WidgetRef<W: ?Sized = dyn Widget>(Rc<RefCell<Inner<W>>>); pub struct WidgetRef<W: ?Sized = dyn Widget>(Handle<Inner<W>>);
pub struct WeakWidgetRef<W: ?Sized = dyn Widget>(WeakHandle<Inner<W>>);
struct Inner<W: ?Sized> { struct Inner<W: ?Sized> {
id: Id, id: Id,
@@ -32,8 +28,6 @@ pub enum WidgetUpdate {
Mutate(Id), Mutate(Id),
} }
pub struct WeakWidgetRef<W: ?Sized = dyn Widget>(Weak<RefCell<Inner<W>>>);
impl<W> PartialEq for WidgetRef<W> { impl<W> PartialEq for WidgetRef<W> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.id() == other.id() self.id() == other.id()
@@ -58,12 +52,15 @@ impl<W: Widget> WidgetRef<W> {
if let (Some(first), Some(last)) = (label.find(":"), label.rfind(":")) { if let (Some(first), Some(last)) = (label.find(":"), label.rfind(":")) {
label = label.split_at(first).0.to_string() + "::" + label.split_at(last + 1).1; label = label.split_at(first).0.to_string() + "::" + label.split_at(last + 1).1;
} }
Self(Rc::new(RefCell::new(Inner { Self(
widget, Inner {
id, widget,
send, id,
label, send,
}))) label,
}
.into(),
)
} }
} }
@@ -78,44 +75,44 @@ impl<W: Widget + ?Sized + Unsize<dyn Widget>> WidgetRef<W> {
impl<W: ?Sized> WidgetRef<W> { impl<W: ?Sized> WidgetRef<W> {
pub fn id(&self) -> Id { pub fn id(&self) -> Id {
self.0.borrow().id self.0.get().id
} }
pub fn get(&self) -> Ref<'_, W> { pub fn get(&self) -> Ref<'_, W> {
Ref::map(self.0.borrow(), |i| &i.widget) Ref::map(self.0.get(), |i| &i.widget)
} }
pub fn get_mut(&self) -> RefMut<'_, W> { pub fn get_mut(&self) -> RefMut<'_, W> {
let inner = self.0.borrow_mut(); let inner = self.0.get_mut();
let _ = inner.send.send(WidgetUpdate::Mutate(inner.id)); let _ = inner.send.send(WidgetUpdate::Mutate(inner.id));
RefMut::map(inner, |i| &mut i.widget) RefMut::map(inner, |i| &mut i.widget)
} }
pub fn get_mut_quiet(&self) -> RefMut<'_, W> { pub fn get_mut_quiet(&self) -> RefMut<'_, W> {
RefMut::map(self.0.borrow_mut(), |i| &mut i.widget) RefMut::map(self.0.get_mut(), |i| &mut i.widget)
} }
pub fn get_label(&self) -> Ref<'_, String> { pub fn get_label(&self) -> Ref<'_, String> {
Ref::map(self.0.borrow(), |i| &i.label) Ref::map(self.0.get(), |i| &i.label)
} }
pub fn set_label(&self, label: impl Into<String>) { pub fn set_label(&self, label: impl Into<String>) {
self.0.borrow_mut().label = label.into(); self.0.get_mut().label = label.into();
} }
pub fn refs(&self) -> usize { pub fn refs(&self) -> usize {
Rc::strong_count(&self.0) self.0.refs()
} }
pub fn weak(&self) -> WeakWidgetRef<W> { pub fn weak(&self) -> WeakWidgetRef<W> {
WeakWidgetRef(Rc::downgrade(&self.0)) WeakWidgetRef(self.0.weak())
} }
} }
impl<W: ?Sized> WeakWidgetRef<W> { impl<W: ?Sized> WeakWidgetRef<W> {
/// should guarantee that widget is still valid to prevent indexing failures /// should guarantee that widget is still valid to prevent indexing failures
pub(crate) fn expect_strong(&self) -> WidgetRef<W> { pub(crate) fn expect_strong(&self) -> WidgetRef<W> {
WidgetRef(self.0.upgrade().expect("widget should not be dropped")) WidgetRef(self.0.strong().expect("widget should not be dropped"))
} }
} }
@@ -156,16 +153,6 @@ impl<W: Widget + ?Sized + Unsize<dyn Widget> + 'static, F: FnOnce(&mut Ui) -> Wi
} }
} }
pub trait WidgetIdLike<W> {
fn rf(self, send: &Sender<Id>) -> WidgetRef<W>;
}
impl<W> WidgetIdLike<W> for &WidgetRef<W> {
fn rf(self, _: &Sender<Id>) -> WidgetRef<W> {
self.clone()
}
}
pub trait IdLike<W> { pub trait IdLike<W> {
fn id(&self) -> Id; fn id(&self) -> Id;
} }

View File

@@ -11,6 +11,7 @@
#![feature(gen_blocks)] #![feature(gen_blocks)]
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]
#![feature(unsize)] #![feature(unsize)]
#![feature(coerce_unsized)]
pub mod core; pub mod core;
pub mod layout; pub mod layout;
@@ -22,4 +23,6 @@ pub mod prelude {
pub use crate::core::*; pub use crate::core::*;
pub use crate::layout::*; pub use crate::layout::*;
pub use crate::render::*; pub use crate::render::*;
pub use crate::util::Handle;
pub use crate::winit::*;
} }

60
src/util/handle.rs Normal file
View File

@@ -0,0 +1,60 @@
use std::{
cell::{Ref, RefCell, RefMut},
marker::Unsize,
ops::CoerceUnsized,
rc::{Rc, Weak},
};
pub struct Handle<T: ?Sized>(Rc<RefCell<T>>);
pub struct WeakHandle<T: ?Sized>(Weak<RefCell<T>>);
impl<T: ?Sized> Handle<T> {
pub fn get(&self) -> Ref<T> {
self.0.borrow()
}
pub fn get_mut(&self) -> RefMut<'_, T> {
self.0.borrow_mut()
}
pub fn refs(&self) -> usize {
Rc::strong_count(&self.0)
}
pub fn weak(&self) -> WeakHandle<T> {
WeakHandle(Rc::downgrade(&self.0))
}
}
impl<T: ?Sized> WeakHandle<T> {
pub fn strong(&self) -> Option<Handle<T>> {
Some(Handle(self.0.upgrade()?))
}
}
impl<T: ?Sized> Clone for Handle<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: ?Sized> Clone for WeakHandle<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T: ?Sized + Default> Default for Handle<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T> From<T> for Handle<T> {
fn from(value: T) -> Self {
Self(Rc::new(RefCell::new(value)))
}
}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Handle<U>> for Handle<T> {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<WeakHandle<U>> for WeakHandle<T> {}

View File

@@ -4,6 +4,7 @@ mod id;
mod math; mod math;
mod refcount; mod refcount;
mod vec2; mod vec2;
mod handle;
pub(crate) use arena::*; pub(crate) use arena::*;
pub use change::*; pub use change::*;
@@ -11,6 +12,7 @@ pub(crate) use id::*;
pub(crate) use math::*; pub(crate) use math::*;
pub(crate) use refcount::*; pub(crate) use refcount::*;
pub use vec2::*; pub use vec2::*;
pub use handle::*;
pub type HashMap<K, V> = fxhash::FxHashMap<K, V>; pub type HashMap<K, V> = fxhash::FxHashMap<K, V>;
pub type HashSet<K> = fxhash::FxHashSet<K>; pub type HashSet<K> = fxhash::FxHashSet<K>;

View File

@@ -1,6 +1,4 @@
use crate::prelude::*; use crate::prelude::*;
use crate::winit::event::{Edited, Submit};
use crate::winit::{input::Input, render::UiRenderer};
use arboard::Clipboard; use arboard::Clipboard;
use std::sync::Arc; use std::sync::Arc;
use std::time::Instant; use std::time::Instant;
@@ -9,12 +7,16 @@ use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
use winit::window::{Window, WindowAttributes}; use winit::window::{Window, WindowAttributes};
mod app; mod app;
pub mod attr; mod attr;
pub mod event; mod event;
pub mod input; mod input;
pub mod render; mod render;
pub use app::*; pub use app::*;
pub use attr::*;
pub use event::*;
pub use input::*;
pub use render::*;
pub type Proxy<Event> = EventLoopProxy<Event>; pub type Proxy<Event> = EventLoopProxy<Event>;
pub type DefaultApp<Data> = App<DefaultState<Data>>; pub type DefaultApp<Data> = App<DefaultState<Data>>;