Compare commits
1 Commits
b66d4da5d7
...
434e3c3af7
| Author | SHA1 | Date | |
|---|---|---|---|
| 434e3c3af7 |
@@ -1,8 +1,5 @@
|
||||
use cosmic_text::Family;
|
||||
use iris::{
|
||||
prelude::*,
|
||||
winit::{attr::Selectable, event::Submit, *},
|
||||
};
|
||||
use iris::prelude::*;
|
||||
use len_fns::*;
|
||||
use winit::event::WindowEvent;
|
||||
|
||||
@@ -109,7 +106,7 @@ impl DefaultAppState for Client {
|
||||
.text_align(Align::LEFT)
|
||||
.size(30)
|
||||
.attr::<Selectable>(())
|
||||
.on(Submit, move |ctx| {
|
||||
.on(iris::winit::Submit, move |ctx| {
|
||||
let content = ctx.widget.get_mut().take();
|
||||
let text = wtext(content)
|
||||
.editable(false)
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum Button {
|
||||
pub enum CursorButton {
|
||||
Left,
|
||||
Right,
|
||||
Middle,
|
||||
@@ -19,9 +19,9 @@ pub enum Button {
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum CursorSense {
|
||||
PressStart(Button),
|
||||
Pressing(Button),
|
||||
PressEnd(Button),
|
||||
PressStart(CursorButton),
|
||||
Pressing(CursorButton),
|
||||
PressEnd(CursorButton),
|
||||
HoverStart,
|
||||
Hovering,
|
||||
HoverEnd,
|
||||
@@ -32,16 +32,16 @@ pub struct CursorSenses(Vec<CursorSense>);
|
||||
|
||||
impl CursorSense {
|
||||
pub fn click() -> Self {
|
||||
Self::PressStart(Button::Left)
|
||||
Self::PressStart(CursorButton::Left)
|
||||
}
|
||||
pub fn click_or_drag() -> CursorSenses {
|
||||
Self::click() | Self::Pressing(Button::Left)
|
||||
Self::click() | Self::Pressing(CursorButton::Left)
|
||||
}
|
||||
pub fn unclick() -> Self {
|
||||
Self::PressEnd(Button::Left)
|
||||
Self::PressEnd(CursorButton::Left)
|
||||
}
|
||||
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 {
|
||||
pub fn select(&self, button: &Button) -> &ActivationState {
|
||||
pub fn select(&self, button: &CursorButton) -> &ActivationState {
|
||||
match button {
|
||||
Button::Left => &self.left,
|
||||
Button::Right => &self.right,
|
||||
Button::Middle => &self.middle,
|
||||
CursorButton::Left => &self.left,
|
||||
CursorButton::Right => &self.right,
|
||||
CursorButton::Middle => &self.middle,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,11 @@ impl<Ctx: 'static> CursorModule<Ctx> {
|
||||
scroll_delta: cursor.scroll_delta,
|
||||
sense,
|
||||
};
|
||||
(sensor.f)(EventCtx { ui, state: ctx, data });
|
||||
(sensor.f)(EventCtx {
|
||||
ui,
|
||||
state: ctx,
|
||||
data,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ impl TextBuilderOutput for TextOutput {
|
||||
builder.attrs.line_height,
|
||||
));
|
||||
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);
|
||||
let mut text = Text {
|
||||
content: builder.content.into(),
|
||||
@@ -103,7 +103,7 @@ impl TextBuilderOutput for TextEditOutput {
|
||||
builder.output.single_line,
|
||||
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
|
||||
.set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None);
|
||||
builder.attrs.apply(font_system, &mut text.buf, None);
|
||||
|
||||
@@ -60,7 +60,7 @@ impl TextEdit {
|
||||
pub fn set(&mut self, text: &str) {
|
||||
let text = self.string(text);
|
||||
self.view.buf.set_text(
|
||||
&mut self.data.borrow_mut().font_system,
|
||||
&mut self.data.get_mut().font_system,
|
||||
&text,
|
||||
&Attrs::new(),
|
||||
SHAPING,
|
||||
@@ -238,7 +238,7 @@ impl TextEdit {
|
||||
self.view
|
||||
.buf
|
||||
.cursor_motion(
|
||||
&mut self.data.borrow_mut().font_system,
|
||||
&mut self.data.get_mut().font_system,
|
||||
cursor,
|
||||
None,
|
||||
motion,
|
||||
|
||||
@@ -67,7 +67,7 @@ impl TextView {
|
||||
return tex.clone();
|
||||
}
|
||||
self.width = width;
|
||||
let mut text_data = ctx.text.borrow_mut();
|
||||
let mut text_data = ctx.text.get_mut();
|
||||
self.attrs
|
||||
.apply(&mut text_data.font_system, &mut self.buf, width);
|
||||
self.buf
|
||||
@@ -139,7 +139,7 @@ impl Text {
|
||||
if self.content.changed {
|
||||
self.content.changed = false;
|
||||
self.view.buf.set_text(
|
||||
&mut ctx.text.borrow_mut().font_system,
|
||||
&mut ctx.text.get_mut().font_system,
|
||||
&self.content,
|
||||
&Attrs::new().family(self.view.attrs.family),
|
||||
SHAPING,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#![allow(clippy::multiple_bound_locations)]
|
||||
|
||||
use std::marker::Destruct;
|
||||
|
||||
/// stored in linear for sane manipulation
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, bytemuck::Zeroable, Debug)]
|
||||
@@ -56,23 +58,47 @@ pub trait ColorNum {
|
||||
const MAX: Self;
|
||||
}
|
||||
|
||||
impl<T: ColorNum + F32Conversion> Color<T> {
|
||||
pub fn mul_rgb(self, amt: impl F32Conversion) -> Self {
|
||||
macro_rules! map_rgb {
|
||||
($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();
|
||||
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();
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn brighter(self, amt: f32) -> Self {
|
||||
self.map_rgb(|x| {
|
||||
pub const fn brighter(self, amt: f32) -> Self {
|
||||
map_rgb!(x, self, {
|
||||
let x = x.to();
|
||||
T::from(x + (1.0 - x) * amt)
|
||||
})
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
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
|
||||
#[macro_export]
|
||||
@@ -40,6 +43,7 @@ macro_rules! event_ctx {
|
||||
#[allow(unused_imports)]
|
||||
use $crate::prelude::*;
|
||||
|
||||
#[allow(unused)]
|
||||
pub trait EventableCtx<W: ?Sized, Tag, Ctx: 'static> {
|
||||
fn on<E: Event>(
|
||||
self,
|
||||
@@ -57,6 +61,33 @@ macro_rules! event_ctx {
|
||||
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::*;
|
||||
};
|
||||
@@ -82,21 +113,47 @@ pub mod eventable {
|
||||
) -> impl WidgetIdFn<WL::Widget> {
|
||||
move |ui| {
|
||||
let id = self.add(ui);
|
||||
let id_ = id.weak();
|
||||
ui.register_event(&id, event, move |ctx| {
|
||||
f(EventIdCtx {
|
||||
widget: &id_.expect_strong(),
|
||||
state: ctx.state,
|
||||
data: ctx.data,
|
||||
ui: ctx.ui,
|
||||
});
|
||||
});
|
||||
ui.register_widget_event(&id, event, f);
|
||||
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 {
|
||||
type Data: Clone;
|
||||
}
|
||||
@@ -193,7 +250,7 @@ impl<E: Event + 'static, Ctx: 'static> Default for DefaultEventModule<E, Ctx> {
|
||||
}
|
||||
|
||||
impl Ui {
|
||||
pub fn run_event<E: Event, Ctx: 'static, W>(
|
||||
pub fn run_event<E: Event, Ctx: 'static, W: ?Sized>(
|
||||
&mut self,
|
||||
ctx: &mut Ctx,
|
||||
id: &WidgetRef<W>,
|
||||
|
||||
@@ -9,6 +9,7 @@ mod painter;
|
||||
mod text;
|
||||
mod texture;
|
||||
mod ui;
|
||||
mod view;
|
||||
mod widget;
|
||||
mod widget_ref;
|
||||
mod widgets;
|
||||
@@ -24,6 +25,7 @@ pub use painter::*;
|
||||
pub use text::*;
|
||||
pub use texture::*;
|
||||
pub use ui::*;
|
||||
pub use view::*;
|
||||
pub use widget::*;
|
||||
pub use widget_ref::*;
|
||||
pub use widgets::*;
|
||||
|
||||
@@ -450,7 +450,7 @@ impl<'a, 'c> Painter<'a, 'c> {
|
||||
pub fn render_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText {
|
||||
self.ctx
|
||||
.text
|
||||
.borrow_mut()
|
||||
.get_mut()
|
||||
.draw(buffer, attrs, self.ctx.textures)
|
||||
}
|
||||
|
||||
@@ -604,6 +604,6 @@ impl SizeCtx<'_> {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
simd::{Simd, num::SimdUint},
|
||||
};
|
||||
use std::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::{
|
||||
Attrs, AttrsList, Buffer, CacheKey, Color, Family, FontSystem, Metrics, Placement, SwashCache,
|
||||
SwashContent,
|
||||
@@ -16,7 +15,7 @@ pub mod text_lib {
|
||||
pub use cosmic_text::*;
|
||||
}
|
||||
|
||||
pub type TextData = Rc<RefCell<TextDataInner>>;
|
||||
pub type TextData = Handle<TextDataInner>;
|
||||
|
||||
pub struct TextDataInner {
|
||||
pub font_system: FontSystem,
|
||||
|
||||
@@ -3,7 +3,7 @@ use image::DynamicImage;
|
||||
use crate::{
|
||||
layout::{
|
||||
Event, EventFn, EventModule, IdLike, PainterData, PixelRegion, TextureHandle, Vec2, Widget,
|
||||
WidgetInstance, WidgetLike, WidgetRef, WidgetUpdate,
|
||||
WidgetEventFn, WidgetInstance, WidgetLike, WidgetRef, WidgetUpdate,
|
||||
},
|
||||
util::{HashSet, Id},
|
||||
};
|
||||
@@ -42,18 +42,6 @@ impl Ui {
|
||||
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>) {
|
||||
self.data.output_size = size.into();
|
||||
self.resized = true;
|
||||
|
||||
17
src/layout/view.rs
Normal file
17
src/layout/view.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ pub trait WidgetLike<Tag> {
|
||||
/// 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
|
||||
/// 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> WidgetLike<FnTag> for F {
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
cell::{Ref, RefMut},
|
||||
marker::Unsize,
|
||||
rc::{Rc, Weak},
|
||||
rc::Rc,
|
||||
sync::mpsc::Sender,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
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.
|
||||
/// 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.
|
||||
/// 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>(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> {
|
||||
id: Id,
|
||||
@@ -32,8 +28,6 @@ pub enum WidgetUpdate {
|
||||
Mutate(Id),
|
||||
}
|
||||
|
||||
pub struct WeakWidgetRef<W: ?Sized = dyn Widget>(Weak<RefCell<Inner<W>>>);
|
||||
|
||||
impl<W> PartialEq for WidgetRef<W> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id() == other.id()
|
||||
@@ -58,12 +52,15 @@ impl<W: Widget> WidgetRef<W> {
|
||||
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(Rc::new(RefCell::new(Inner {
|
||||
widget,
|
||||
id,
|
||||
send,
|
||||
label,
|
||||
})))
|
||||
Self(
|
||||
Inner {
|
||||
widget,
|
||||
id,
|
||||
send,
|
||||
label,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,44 +75,44 @@ impl<W: Widget + ?Sized + Unsize<dyn Widget>> WidgetRef<W> {
|
||||
|
||||
impl<W: ?Sized> WidgetRef<W> {
|
||||
pub fn id(&self) -> Id {
|
||||
self.0.borrow().id
|
||||
self.0.get().id
|
||||
}
|
||||
|
||||
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> {
|
||||
let inner = self.0.borrow_mut();
|
||||
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.borrow_mut(), |i| &mut i.widget)
|
||||
RefMut::map(self.0.get_mut(), |i| &mut i.widget)
|
||||
}
|
||||
|
||||
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>) {
|
||||
self.0.borrow_mut().label = label.into();
|
||||
self.0.get_mut().label = label.into();
|
||||
}
|
||||
|
||||
pub fn refs(&self) -> usize {
|
||||
Rc::strong_count(&self.0)
|
||||
self.0.refs()
|
||||
}
|
||||
|
||||
pub fn weak(&self) -> WeakWidgetRef<W> {
|
||||
WeakWidgetRef(Rc::downgrade(&self.0))
|
||||
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.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> {
|
||||
fn id(&self) -> Id;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#![feature(gen_blocks)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(unsize)]
|
||||
#![feature(coerce_unsized)]
|
||||
|
||||
pub mod core;
|
||||
pub mod layout;
|
||||
@@ -22,4 +23,6 @@ pub mod prelude {
|
||||
pub use crate::core::*;
|
||||
pub use crate::layout::*;
|
||||
pub use crate::render::*;
|
||||
pub use crate::util::Handle;
|
||||
pub use crate::winit::*;
|
||||
}
|
||||
|
||||
60
src/util/handle.rs
Normal file
60
src/util/handle.rs
Normal 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> {}
|
||||
@@ -4,6 +4,7 @@ mod id;
|
||||
mod math;
|
||||
mod refcount;
|
||||
mod vec2;
|
||||
mod handle;
|
||||
|
||||
pub(crate) use arena::*;
|
||||
pub use change::*;
|
||||
@@ -11,6 +12,7 @@ pub(crate) use id::*;
|
||||
pub(crate) use math::*;
|
||||
pub(crate) use refcount::*;
|
||||
pub use vec2::*;
|
||||
pub use handle::*;
|
||||
|
||||
pub type HashMap<K, V> = fxhash::FxHashMap<K, V>;
|
||||
pub type HashSet<K> = fxhash::FxHashSet<K>;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
use crate::prelude::*;
|
||||
use crate::winit::event::{Edited, Submit};
|
||||
use crate::winit::{input::Input, render::UiRenderer};
|
||||
use arboard::Clipboard;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
@@ -9,12 +7,16 @@ use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
|
||||
use winit::window::{Window, WindowAttributes};
|
||||
|
||||
mod app;
|
||||
pub mod attr;
|
||||
pub mod event;
|
||||
pub mod input;
|
||||
pub mod render;
|
||||
mod attr;
|
||||
mod event;
|
||||
mod input;
|
||||
mod render;
|
||||
|
||||
pub use app::*;
|
||||
pub use attr::*;
|
||||
pub use event::*;
|
||||
pub use input::*;
|
||||
pub use render::*;
|
||||
|
||||
pub type Proxy<Event> = EventLoopProxy<Event>;
|
||||
pub type DefaultApp<Data> = App<DefaultState<Data>>;
|
||||
|
||||
Reference in New Issue
Block a user