initial global widget store
This commit is contained in:
@@ -2,7 +2,7 @@ use crate::layout::{Ui, WidgetIdFn, WidgetLike, WidgetRef};
|
|||||||
|
|
||||||
pub trait WidgetAttr<W: ?Sized> {
|
pub trait WidgetAttr<W: ?Sized> {
|
||||||
type Input;
|
type Input;
|
||||||
fn run(ui: &mut Ui, id: &WidgetRef<W>, input: Self::Input);
|
fn run(ui: &mut Ui, id: WidgetRef<W>, input: Self::Input);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Attrable<W: ?Sized, Tag> {
|
pub trait Attrable<W: ?Sized, Tag> {
|
||||||
@@ -13,7 +13,7 @@ impl<WL: WidgetLike<Tag>, Tag> Attrable<WL::Widget, Tag> for WL {
|
|||||||
fn attr<A: WidgetAttr<WL::Widget>>(self, input: A::Input) -> impl WidgetIdFn<WL::Widget> {
|
fn attr<A: WidgetAttr<WL::Widget>>(self, input: A::Input) -> impl WidgetIdFn<WL::Widget> {
|
||||||
|ui| {
|
|ui| {
|
||||||
let id = self.add(ui);
|
let id = self.add(ui);
|
||||||
A::run(ui, &id, input);
|
A::run(ui, id.weak(), input);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::{hash::Hash, rc::Rc};
|
use std::hash::Hash;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{IdFnTag, Ui, UiModule, WidgetIdFn, WidgetLike, WidgetRef},
|
layout::{Ui, UiModule, WidgetId, WidgetRef},
|
||||||
util::{HashMap, Id},
|
util::HashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Event: Sized {
|
pub trait Event: Sized {
|
||||||
@@ -18,26 +18,25 @@ pub struct EventCtx<'a, Ctx, Data> {
|
|||||||
|
|
||||||
pub type ECtx<'a, Ctx, Data, W> = EventIdCtx<'a, Ctx, Data, W>;
|
pub type ECtx<'a, Ctx, Data, W> = EventIdCtx<'a, Ctx, Data, W>;
|
||||||
pub struct EventIdCtx<'a, Ctx, Data, W: ?Sized> {
|
pub struct EventIdCtx<'a, Ctx, Data, W: ?Sized> {
|
||||||
pub widget: &'a WidgetRef<W>,
|
pub widget: WidgetRef<W>,
|
||||||
pub ui: &'a mut Ui,
|
pub ui: &'a mut Ui,
|
||||||
pub state: &'a mut Ctx,
|
pub state: &'a mut Ctx,
|
||||||
pub data: Data,
|
pub data: Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EventFn<Ctx, Data>: Fn(EventCtx<Ctx, Data>) + 'static {}
|
pub trait EventFn<Ctx, Data>: FnMut(EventCtx<Ctx, Data>) + 'static {}
|
||||||
impl<F: Fn(EventCtx<Ctx, Data>) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {}
|
impl<F: FnMut(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>: FnMut(EventIdCtx<Ctx, Data, W>) + 'static {}
|
||||||
impl<F: Fn(EventIdCtx<Ctx, Data, W>) + 'static, Ctx, Data, W: ?Sized> WidgetEventFn<Ctx, Data, W>
|
impl<F: FnMut(EventIdCtx<Ctx, Data, W>) + 'static, Ctx, Data, W: ?Sized> WidgetEventFn<Ctx, Data, W>
|
||||||
for F
|
for F
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Ui {
|
impl Ui {
|
||||||
pub fn register_event<W: ?Sized, E: Event, Ctx: 'static>(
|
pub fn register_event<W: ?Sized, E: Event, Ctx: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &WidgetRef<W>,
|
id: WidgetRef<W>,
|
||||||
event: E,
|
event: E,
|
||||||
f: impl EventFn<Ctx, E::Data>,
|
f: impl EventFn<Ctx, E::Data>,
|
||||||
) {
|
) {
|
||||||
@@ -49,17 +48,16 @@ impl Ui {
|
|||||||
|
|
||||||
pub fn register_widget_event<W: ?Sized + 'static, E: Event, Ctx: 'static>(
|
pub fn register_widget_event<W: ?Sized + 'static, E: Event, Ctx: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &WidgetRef<W>,
|
id: WidgetRef<W>,
|
||||||
event: E,
|
event: E,
|
||||||
f: impl WidgetEventFn<Ctx, E::Data, W>,
|
mut f: impl WidgetEventFn<Ctx, E::Data, W>,
|
||||||
) {
|
) {
|
||||||
let id_ = id.weak();
|
|
||||||
self.data
|
self.data
|
||||||
.modules
|
.modules
|
||||||
.get_mut::<E::Module<Ctx>>()
|
.get_mut::<E::Module<Ctx>>()
|
||||||
.register(id.id(), event, move |ctx| {
|
.register(id.id(), event, move |ctx| {
|
||||||
f(EventIdCtx {
|
(&mut f)(EventIdCtx {
|
||||||
widget: &id_.expect_strong(),
|
widget: id,
|
||||||
ui: ctx.ui,
|
ui: ctx.ui,
|
||||||
state: ctx.state,
|
state: ctx.state,
|
||||||
data: ctx.data,
|
data: ctx.data,
|
||||||
@@ -78,21 +76,17 @@ impl<E: DefaultEvent> Event for E {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait EventModule<E: Event, Ctx>: UiModule + Default {
|
pub trait EventModule<E: Event, Ctx>: UiModule + Default {
|
||||||
fn register(&mut self, id: Id, event: E, f: impl EventFn<Ctx, E::Data>);
|
fn register(&mut self, id: WidgetId, event: E, f: impl EventFn<Ctx, E::Data>);
|
||||||
fn run<'a>(
|
fn run(&mut self, id: WidgetId, event: E) -> Option<impl FnOnce(EventCtx<Ctx, E::Data>)>;
|
||||||
&self,
|
|
||||||
id: &Id,
|
|
||||||
event: E,
|
|
||||||
) -> Option<impl Fn(EventCtx<Ctx, E::Data>) + use<'a, Self, E, Ctx>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventFnMap<Ctx, Data> = HashMap<Id, Vec<Rc<dyn EventFn<Ctx, Data>>>>;
|
type EventFnMap<Ctx, Data> = HashMap<WidgetId, Vec<Box<dyn EventFn<Ctx, Data>>>>;
|
||||||
pub struct DefaultEventModule<E: Event, Ctx> {
|
pub struct DefaultEventModule<E: Event, Ctx> {
|
||||||
map: HashMap<E, EventFnMap<Ctx, <E as Event>::Data>>,
|
map: HashMap<E, EventFnMap<Ctx, <E as Event>::Data>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Event + 'static, Ctx: 'static> UiModule for DefaultEventModule<E, Ctx> {
|
impl<E: Event + 'static, Ctx: 'static> UiModule for DefaultEventModule<E, Ctx> {
|
||||||
fn on_remove(&mut self, id: &Id) {
|
fn on_remove(&mut self, id: &WidgetId) {
|
||||||
for map in self.map.values_mut() {
|
for map in self.map.values_mut() {
|
||||||
map.remove(id);
|
map.remove(id);
|
||||||
}
|
}
|
||||||
@@ -103,26 +97,21 @@ pub trait HashableEvent: Event + Hash + Eq + 'static {}
|
|||||||
impl<E: Event + Hash + Eq + 'static> HashableEvent for E {}
|
impl<E: Event + Hash + Eq + 'static> HashableEvent for E {}
|
||||||
|
|
||||||
impl<E: HashableEvent, Ctx: 'static> EventModule<E, Ctx> for DefaultEventModule<E, Ctx> {
|
impl<E: HashableEvent, Ctx: 'static> EventModule<E, Ctx> for DefaultEventModule<E, Ctx> {
|
||||||
fn register(&mut self, id: Id, event: E, f: impl EventFn<Ctx, <E as Event>::Data>) {
|
fn register(&mut self, id: WidgetId, event: E, f: impl EventFn<Ctx, <E as Event>::Data>) {
|
||||||
self.map
|
self.map
|
||||||
.entry(event)
|
.entry(event)
|
||||||
.or_default()
|
.or_default()
|
||||||
.entry(id)
|
.entry(id)
|
||||||
.or_default()
|
.or_default()
|
||||||
.push(Rc::new(f));
|
.push(Box::new(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run<'a>(
|
fn run(&mut self, id: WidgetId, event: E) -> Option<impl FnOnce(EventCtx<Ctx, E::Data>)> {
|
||||||
&self,
|
if let Some(map) = self.map.get_mut(&event)
|
||||||
id: &Id,
|
&& let Some(fs) = map.get_mut(&id)
|
||||||
event: E,
|
|
||||||
) -> Option<impl Fn(EventCtx<Ctx, E::Data>) + use<'a, E, Ctx>> {
|
|
||||||
if let Some(map) = self.map.get(&event)
|
|
||||||
&& let Some(fs) = map.get(id)
|
|
||||||
{
|
{
|
||||||
let fs = fs.clone();
|
|
||||||
Some(move |ctx: EventCtx<Ctx, <E as Event>::Data>| {
|
Some(move |ctx: EventCtx<Ctx, <E as Event>::Data>| {
|
||||||
for f in &fs {
|
for f in fs {
|
||||||
f(EventCtx {
|
f(EventCtx {
|
||||||
ui: ctx.ui,
|
ui: ctx.ui,
|
||||||
state: ctx.state,
|
state: ctx.state,
|
||||||
@@ -137,12 +126,12 @@ impl<E: HashableEvent, Ctx: 'static> EventModule<E, Ctx> for DefaultEventModule<
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: HashableEvent, Ctx: 'static> DefaultEventModule<E, Ctx> {
|
impl<E: HashableEvent, Ctx: 'static> DefaultEventModule<E, Ctx> {
|
||||||
pub fn run_all(&self, event: E, ctx: EventCtx<Ctx, E::Data>)
|
pub fn run_all(&mut self, event: E, ctx: EventCtx<Ctx, E::Data>)
|
||||||
where
|
where
|
||||||
E::Data: Clone,
|
E::Data: Clone,
|
||||||
{
|
{
|
||||||
if let Some(map) = self.map.get(&event) {
|
if let Some(map) = self.map.get_mut(&event) {
|
||||||
for fs in map.values() {
|
for fs in map.values_mut() {
|
||||||
for f in fs {
|
for f in fs {
|
||||||
f(EventCtx {
|
f(EventCtx {
|
||||||
ui: ctx.ui,
|
ui: ctx.ui,
|
||||||
@@ -167,7 +156,7 @@ impl Ui {
|
|||||||
pub fn run_event<E: Event, Ctx: 'static, W: ?Sized>(
|
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>,
|
||||||
event: E,
|
event: E,
|
||||||
data: E::Data,
|
data: E::Data,
|
||||||
) {
|
) {
|
||||||
@@ -175,10 +164,11 @@ impl Ui {
|
|||||||
.data
|
.data
|
||||||
.modules
|
.modules
|
||||||
.get_mut::<E::Module<Ctx>>()
|
.get_mut::<E::Module<Ctx>>()
|
||||||
.run(&id.id(), event)
|
.run(id.id(), event)
|
||||||
{
|
{
|
||||||
|
eprintln!("FIXME");
|
||||||
f(EventCtx {
|
f(EventCtx {
|
||||||
ui: self,
|
ui: &mut Ui::new(),
|
||||||
state: ctx,
|
state: ctx,
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::WidgetInstance,
|
layout::{WidgetId, WidgetInstance},
|
||||||
util::{HashMap, Id},
|
util::HashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait UiModule: Any {
|
pub trait UiModule: Any {
|
||||||
fn on_draw(&mut self, inst: &WidgetInstance) {}
|
fn on_draw(&mut self, inst: &WidgetInstance) {}
|
||||||
fn on_undraw(&mut self, inst: &WidgetInstance) {}
|
fn on_undraw(&mut self, inst: &WidgetInstance) {}
|
||||||
fn on_remove(&mut self, id: &Id) {}
|
fn on_remove(&mut self, id: &WidgetId) {}
|
||||||
fn on_move(&mut self, inst: &WidgetInstance) {}
|
fn on_move(&mut self, inst: &WidgetInstance) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,84 +1,85 @@
|
|||||||
use std::{cell::Ref, marker::Unsize, sync::mpsc::Sender};
|
use std::{marker::Unsize, sync::mpsc::Sender};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{
|
layout::{
|
||||||
Axis, Len, Modules, PrimitiveLayers, RenderedText, Size, TextAttrs, TextBuffer, TextData,
|
Axis, Len, Modules, PrimitiveLayers, RenderedText, Size, TextAttrs, TextBuffer, TextData,
|
||||||
TextureHandle, Textures, UiRegion, UiVec2, Vec2, Widget, WidgetRef, WidgetUpdate, Widgets,
|
TextureHandle, Textures, UiRegion, UiVec2, Vec2, Widget, WidgetHandle, WidgetId,
|
||||||
|
WidgetUpdate,
|
||||||
},
|
},
|
||||||
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
||||||
util::{HashMap, HashSet, Id, TrackedArena},
|
util::{HashMap, HashSet, RefMap, TrackedArena},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// makes your surfaces look pretty
|
/// makes your surfaces look pretty
|
||||||
pub struct Painter<'a, 'c> {
|
pub struct Painter<'a, 'c> {
|
||||||
ctx: &'a mut PainterCtx<'c>,
|
ctx: &'a mut PainterCtx<'c>,
|
||||||
widget: WidgetRef,
|
widget: WidgetHandle,
|
||||||
id: Id,
|
id: WidgetId,
|
||||||
region: UiRegion,
|
region: UiRegion,
|
||||||
mask: MaskIdx,
|
mask: MaskIdx,
|
||||||
textures: Vec<TextureHandle>,
|
textures: Vec<TextureHandle>,
|
||||||
primitives: Vec<PrimitiveHandle>,
|
primitives: Vec<PrimitiveHandle>,
|
||||||
children: Vec<Id>,
|
children: Vec<WidgetId>,
|
||||||
children_width: HashMap<Id, (UiVec2, Len)>,
|
children_width: HashMap<WidgetId, (UiVec2, Len)>,
|
||||||
children_height: HashMap<Id, (UiVec2, Len)>,
|
children_height: HashMap<WidgetId, (UiVec2, Len)>,
|
||||||
pub layer: usize,
|
pub layer: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// context for a painter; lets you draw and redraw widgets
|
/// context for a painter; lets you draw and redraw widgets
|
||||||
struct PainterCtx<'a> {
|
struct PainterCtx<'a> {
|
||||||
pub widgets: &'a Widgets,
|
pub active: &'a mut HashMap<WidgetId, WidgetInstance>,
|
||||||
pub active: &'a mut HashMap<Id, WidgetInstance>,
|
|
||||||
pub layers: &'a mut PrimitiveLayers,
|
pub layers: &'a mut PrimitiveLayers,
|
||||||
pub textures: &'a mut Textures,
|
pub textures: &'a mut Textures,
|
||||||
pub masks: &'a mut TrackedArena<Mask, u32>,
|
pub masks: &'a mut TrackedArena<Mask, u32>,
|
||||||
pub text: &'a mut TextData,
|
pub text: &'a mut TextData,
|
||||||
pub output_size: Vec2,
|
pub output_size: Vec2,
|
||||||
pub modules: &'a mut Modules,
|
pub modules: &'a mut Modules,
|
||||||
pub cache_width: HashMap<Id, (UiVec2, Len)>,
|
send: &'a Sender<WidgetUpdate>,
|
||||||
pub cache_height: HashMap<Id, (UiVec2, Len)>,
|
pub cache_width: HashMap<WidgetId, (UiVec2, Len)>,
|
||||||
pub needs_redraw: HashSet<Id>,
|
pub cache_height: HashMap<WidgetId, (UiVec2, Len)>,
|
||||||
draw_started: HashSet<Id>,
|
pub needs_redraw: HashSet<WidgetId>,
|
||||||
|
draw_started: HashSet<WidgetId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// stores information for children about the highest level parent that needed their size
|
/// stores information for children about the highest level parent that needed their size
|
||||||
/// so that they can redraw the parent if their size changes
|
/// so that they can redraw the parent if their size changes
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct ResizeRef {
|
pub struct ResizeRef {
|
||||||
x: Option<(Id, (UiVec2, Len))>,
|
x: Option<(WidgetId, (UiVec2, Len))>,
|
||||||
y: Option<(Id, (UiVec2, Len))>,
|
y: Option<(WidgetId, (UiVec2, Len))>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// important non rendering data for retained drawing
|
/// important non rendering data for retained drawing
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WidgetInstance {
|
pub struct WidgetInstance {
|
||||||
pub id: Id,
|
pub id: WidgetId,
|
||||||
pub region: UiRegion,
|
pub region: UiRegion,
|
||||||
pub parent: Option<Id>,
|
pub parent: Option<WidgetId>,
|
||||||
pub textures: Vec<TextureHandle>,
|
pub textures: Vec<TextureHandle>,
|
||||||
pub primitives: Vec<PrimitiveHandle>,
|
pub primitives: Vec<PrimitiveHandle>,
|
||||||
pub children: Vec<Id>,
|
pub children: Vec<WidgetId>,
|
||||||
pub resize: ResizeRef,
|
pub resize: ResizeRef,
|
||||||
pub mask: MaskIdx,
|
pub mask: MaskIdx,
|
||||||
pub layer: usize,
|
pub layer: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// data to be stored in Ui to create PainterCtxs easily
|
/// data to be stored in Ui to create PainterCtxs easily
|
||||||
|
/// TODO: actually use this LMAO
|
||||||
pub struct PainterData {
|
pub struct PainterData {
|
||||||
pub widgets: Widgets,
|
pub active: HashMap<WidgetId, WidgetInstance>,
|
||||||
pub active: HashMap<Id, WidgetInstance>,
|
|
||||||
pub layers: PrimitiveLayers,
|
pub layers: PrimitiveLayers,
|
||||||
pub textures: Textures,
|
pub textures: Textures,
|
||||||
pub text: TextData,
|
pub text: TextData,
|
||||||
pub output_size: Vec2,
|
pub output_size: Vec2,
|
||||||
pub modules: Modules,
|
pub modules: Modules,
|
||||||
pub px_dependent: HashSet<Id>,
|
pub px_dependent: HashSet<WidgetId>,
|
||||||
pub masks: TrackedArena<Mask, u32>,
|
pub masks: TrackedArena<Mask, u32>,
|
||||||
|
send: Sender<WidgetUpdate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PainterData {
|
impl PainterData {
|
||||||
pub fn new(send: Sender<WidgetUpdate>) -> Self {
|
pub fn new(send: Sender<WidgetUpdate>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
widgets: Widgets::new(send),
|
|
||||||
active: Default::default(),
|
active: Default::default(),
|
||||||
layers: Default::default(),
|
layers: Default::default(),
|
||||||
textures: Default::default(),
|
textures: Default::default(),
|
||||||
@@ -87,6 +88,7 @@ impl PainterData {
|
|||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
px_dependent: Default::default(),
|
px_dependent: Default::default(),
|
||||||
masks: Default::default(),
|
masks: Default::default(),
|
||||||
|
send,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +97,7 @@ impl<'a> PainterCtx<'a> {
|
|||||||
/// redraws a widget that's currently active (drawn)
|
/// redraws a widget that's currently active (drawn)
|
||||||
/// can be called on something already drawn or removed,
|
/// can be called on something already drawn or removed,
|
||||||
/// will just return if so
|
/// will just return if so
|
||||||
pub fn redraw<W: Widget + ?Sized + Unsize<dyn Widget>>(&mut self, widget: &WidgetRef<W>) {
|
pub fn redraw<W: Widget + ?Sized + Unsize<dyn Widget>>(&mut self, widget: &WidgetHandle<W>) {
|
||||||
let id = widget.id();
|
let id = widget.id();
|
||||||
self.needs_redraw.remove(&id);
|
self.needs_redraw.remove(&id);
|
||||||
if self.draw_started.contains(&id) {
|
if self.draw_started.contains(&id) {
|
||||||
@@ -131,9 +133,11 @@ impl<'a> PainterCtx<'a> {
|
|||||||
id,
|
id,
|
||||||
}
|
}
|
||||||
.width(widget);
|
.width(widget);
|
||||||
if new_desired != *old_desired {
|
if new_desired != *old_desired
|
||||||
|
&& let Some(w) = rid.strong()
|
||||||
|
{
|
||||||
// unsure if I need to walk down the tree here
|
// unsure if I need to walk down the tree here
|
||||||
self.redraw(&self.widgets.get(*rid));
|
self.redraw(&w);
|
||||||
*old_desired = new_desired;
|
*old_desired = new_desired;
|
||||||
if self.draw_started.contains(&id) {
|
if self.draw_started.contains(&id) {
|
||||||
ret = true;
|
ret = true;
|
||||||
@@ -156,8 +160,10 @@ impl<'a> PainterCtx<'a> {
|
|||||||
id,
|
id,
|
||||||
}
|
}
|
||||||
.height(widget);
|
.height(widget);
|
||||||
if new_desired != *old_desired {
|
if new_desired != *old_desired
|
||||||
self.redraw(&self.widgets.get(*rid));
|
&& let Some(w) = rid.strong()
|
||||||
|
{
|
||||||
|
self.redraw(&w);
|
||||||
*old_desired = new_desired;
|
*old_desired = new_desired;
|
||||||
if self.draw_started.contains(&id) {
|
if self.draw_started.contains(&id) {
|
||||||
ret = true;
|
ret = true;
|
||||||
@@ -187,13 +193,14 @@ impl<'a> PainterCtx<'a> {
|
|||||||
fn draw_inner<W: Widget + ?Sized + Unsize<dyn Widget>>(
|
fn draw_inner<W: Widget + ?Sized + Unsize<dyn Widget>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
layer: usize,
|
layer: usize,
|
||||||
widget: &WidgetRef<W>,
|
widget: &WidgetHandle<W>,
|
||||||
region: UiRegion,
|
region: UiRegion,
|
||||||
parent: Option<Id>,
|
parent: Option<WidgetId>,
|
||||||
mask: MaskIdx,
|
mask: MaskIdx,
|
||||||
old_children: Option<Vec<Id>>,
|
old_children: Option<Vec<WidgetId>>,
|
||||||
) {
|
) {
|
||||||
let id = widget.id();
|
let id = widget.id();
|
||||||
|
widget.data_mut().send = Some(self.send.clone());
|
||||||
// I have no idea if these checks work lol
|
// I have no idea if these checks work lol
|
||||||
// the idea is u can't redraw stuff u already drew,
|
// the idea is u can't redraw stuff u already drew,
|
||||||
// and if parent is different then there's another copy with a different parent
|
// and if parent is different then there's another copy with a different parent
|
||||||
@@ -293,7 +300,7 @@ impl<'a> PainterCtx<'a> {
|
|||||||
self.active.insert(id, instance);
|
self.active.insert(id, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mov(&mut self, id: Id, from: UiRegion, to: UiRegion) {
|
fn mov(&mut self, id: WidgetId, from: UiRegion, to: UiRegion) {
|
||||||
let active = self.active.get_mut(&id).unwrap();
|
let active = self.active.get_mut(&id).unwrap();
|
||||||
for h in &active.primitives {
|
for h in &active.primitives {
|
||||||
let region = self.layers[h.layer].region_mut(h);
|
let region = self.layers[h.layer].region_mut(h);
|
||||||
@@ -312,7 +319,7 @@ impl<'a> PainterCtx<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// NOTE: instance textures are cleared and self.textures freed
|
/// NOTE: instance textures are cleared and self.textures freed
|
||||||
fn remove(&mut self, id: Id) -> Option<WidgetInstance> {
|
fn remove(&mut self, id: WidgetId) -> Option<WidgetInstance> {
|
||||||
let mut inst = self.active.remove(&id);
|
let mut inst = self.active.remove(&id);
|
||||||
if let Some(inst) = &mut inst {
|
if let Some(inst) = &mut inst {
|
||||||
for h in &inst.primitives {
|
for h in &inst.primitives {
|
||||||
@@ -330,7 +337,7 @@ impl<'a> PainterCtx<'a> {
|
|||||||
inst
|
inst
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_rec(&mut self, id: Id) -> Option<WidgetInstance> {
|
fn remove_rec(&mut self, id: WidgetId) -> Option<WidgetInstance> {
|
||||||
let inst = self.remove(id);
|
let inst = self.remove(id);
|
||||||
if let Some(inst) = &inst {
|
if let Some(inst) = &inst {
|
||||||
for c in &inst.children {
|
for c in &inst.children {
|
||||||
@@ -342,9 +349,8 @@ impl<'a> PainterCtx<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PainterData {
|
impl PainterData {
|
||||||
fn ctx(&mut self, needs_redraw: HashSet<Id>) -> PainterCtx<'_> {
|
fn ctx(&mut self, needs_redraw: HashSet<WidgetId>) -> PainterCtx<'_> {
|
||||||
PainterCtx {
|
PainterCtx {
|
||||||
widgets: &self.widgets,
|
|
||||||
active: &mut self.active,
|
active: &mut self.active,
|
||||||
layers: &mut self.layers,
|
layers: &mut self.layers,
|
||||||
textures: &mut self.textures,
|
textures: &mut self.textures,
|
||||||
@@ -352,6 +358,7 @@ impl PainterData {
|
|||||||
output_size: self.output_size,
|
output_size: self.output_size,
|
||||||
modules: &mut self.modules,
|
modules: &mut self.modules,
|
||||||
masks: &mut self.masks,
|
masks: &mut self.masks,
|
||||||
|
send: &self.send,
|
||||||
cache_width: Default::default(),
|
cache_width: Default::default(),
|
||||||
cache_height: Default::default(),
|
cache_height: Default::default(),
|
||||||
draw_started: Default::default(),
|
draw_started: Default::default(),
|
||||||
@@ -359,17 +366,19 @@ impl PainterData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw<W: Widget + ?Sized + Unsize<dyn Widget>>(&mut self, id: &WidgetRef<W>) {
|
pub fn draw<W: Widget + ?Sized + Unsize<dyn Widget>>(&mut self, id: &WidgetHandle<W>) {
|
||||||
let mut ctx = self.ctx(Default::default());
|
let mut ctx = self.ctx(Default::default());
|
||||||
ctx.draw_started.clear();
|
ctx.draw_started.clear();
|
||||||
ctx.layers.clear();
|
ctx.layers.clear();
|
||||||
ctx.draw_inner(0, id, UiRegion::FULL, None, MaskIdx::NONE, None);
|
ctx.draw_inner(0, id, UiRegion::FULL, None, MaskIdx::NONE, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redraw(&mut self, ids: HashSet<Id>) {
|
pub fn redraw(&mut self, ids: HashSet<WidgetId>) {
|
||||||
let mut ctx = self.ctx(ids);
|
let mut ctx = self.ctx(ids);
|
||||||
while let Some(&id) = ctx.needs_redraw.iter().next() {
|
while let Some(&id) = ctx.needs_redraw.iter().next() {
|
||||||
ctx.redraw(&ctx.widgets.get(id));
|
if let Some(w) = id.strong() {
|
||||||
|
ctx.redraw(&w);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,7 +416,7 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draws a widget within this widget's region.
|
/// Draws a widget within this widget's region.
|
||||||
pub fn widget<W: Widget + ?Sized + Unsize<dyn Widget>>(&mut self, id: &WidgetRef<W>) {
|
pub fn widget<W: Widget + ?Sized + Unsize<dyn Widget>>(&mut self, id: &WidgetHandle<W>) {
|
||||||
self.widget_at(id, self.region);
|
self.widget_at(id, self.region);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,7 +424,7 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
/// Useful for drawing child widgets in select areas.
|
/// Useful for drawing child widgets in select areas.
|
||||||
pub fn widget_within<W: Widget + ?Sized + Unsize<dyn Widget>>(
|
pub fn widget_within<W: Widget + ?Sized + Unsize<dyn Widget>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &WidgetRef<W>,
|
id: &WidgetHandle<W>,
|
||||||
region: UiRegion,
|
region: UiRegion,
|
||||||
) {
|
) {
|
||||||
self.widget_at(id, region.within(&self.region));
|
self.widget_at(id, region.within(&self.region));
|
||||||
@@ -423,7 +432,7 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
|
|
||||||
fn widget_at<W: Widget + ?Sized + Unsize<dyn Widget>>(
|
fn widget_at<W: Widget + ?Sized + Unsize<dyn Widget>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &WidgetRef<W>,
|
id: &WidgetHandle<W>,
|
||||||
region: UiRegion,
|
region: UiRegion,
|
||||||
) {
|
) {
|
||||||
self.children.push(id.id());
|
self.children.push(id.id());
|
||||||
@@ -458,11 +467,11 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
self.region
|
self.region
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size<W: Widget + ?Sized>(&mut self, id: &WidgetRef<W>) -> Size {
|
pub fn size<W: Widget + ?Sized>(&mut self, id: &WidgetHandle<W>) -> Size {
|
||||||
self.size_ctx().size(id)
|
self.size_ctx().size(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len_axis<W: Widget + ?Sized>(&mut self, id: &WidgetRef<W>, axis: Axis) -> Len {
|
pub fn len_axis<W: Widget + ?Sized>(&mut self, id: &WidgetHandle<W>, axis: Axis) -> Len {
|
||||||
match axis {
|
match axis {
|
||||||
Axis::X => self.size_ctx().width(id),
|
Axis::X => self.size_ctx().width(id),
|
||||||
Axis::Y => self.size_ctx().height(id),
|
Axis::Y => self.size_ctx().height(id),
|
||||||
@@ -504,11 +513,11 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
self.layer = self.ctx.layers.next(self.layer);
|
self.layer = self.ctx.layers.next(self.layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn label(&self) -> Ref<'_, String> {
|
pub fn label(&self) -> RefMap<'_, String> {
|
||||||
self.widget.get_label()
|
self.widget.get_label()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> Id {
|
pub fn id(&self) -> WidgetId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -516,27 +525,27 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
pub struct SizeCtx<'a> {
|
pub struct SizeCtx<'a> {
|
||||||
pub text: &'a mut TextData,
|
pub text: &'a mut TextData,
|
||||||
pub textures: &'a mut Textures,
|
pub textures: &'a mut Textures,
|
||||||
source: Id,
|
source: WidgetId,
|
||||||
cache_width: &'a mut HashMap<Id, (UiVec2, Len)>,
|
cache_width: &'a mut HashMap<WidgetId, (UiVec2, Len)>,
|
||||||
cache_height: &'a mut HashMap<Id, (UiVec2, Len)>,
|
cache_height: &'a mut HashMap<WidgetId, (UiVec2, Len)>,
|
||||||
checked_width: &'a mut HashMap<Id, (UiVec2, Len)>,
|
checked_width: &'a mut HashMap<WidgetId, (UiVec2, Len)>,
|
||||||
checked_height: &'a mut HashMap<Id, (UiVec2, Len)>,
|
checked_height: &'a mut HashMap<WidgetId, (UiVec2, Len)>,
|
||||||
/// TODO: should this be pub? rn used for sized
|
/// TODO: should this be pub? rn used for sized
|
||||||
pub outer: UiVec2,
|
pub outer: UiVec2,
|
||||||
output_size: Vec2,
|
output_size: Vec2,
|
||||||
id: Id,
|
id: WidgetId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SizeCtx<'_> {
|
impl SizeCtx<'_> {
|
||||||
pub fn id(&self) -> &Id {
|
pub fn id(&self) -> &WidgetId {
|
||||||
&self.id
|
&self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source(&self) -> &Id {
|
pub fn source(&self) -> &WidgetId {
|
||||||
&self.source
|
&self.source
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width<W: Widget + ?Sized>(&mut self, widget: &WidgetRef<W>) -> Len {
|
pub fn width<W: Widget + ?Sized>(&mut self, widget: &WidgetHandle<W>) -> Len {
|
||||||
// first check cache
|
// first check cache
|
||||||
// TODO: is this needed? broken rn bc does not store children during upper size check,
|
// TODO: is this needed? broken rn bc does not store children during upper size check,
|
||||||
// so if something actually using check_* hits cache it fails to add them
|
// so if something actually using check_* hits cache it fails to add them
|
||||||
@@ -562,7 +571,7 @@ impl SizeCtx<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should be refactored to share code w width_inner
|
// TODO: should be refactored to share code w width_inner
|
||||||
pub fn height<W: Widget + ?Sized>(&mut self, widget: &WidgetRef<W>) -> Len {
|
pub fn height<W: Widget + ?Sized>(&mut self, widget: &WidgetHandle<W>) -> Len {
|
||||||
// if let Some(&(outer, len)) = self.cache_height.get(&id)
|
// if let Some(&(outer, len)) = self.cache_height.get(&id)
|
||||||
// && outer == self.outer
|
// && outer == self.outer
|
||||||
// {
|
// {
|
||||||
@@ -581,14 +590,14 @@ impl SizeCtx<'_> {
|
|||||||
len
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len_axis<W: Widget + ?Sized>(&mut self, id: &WidgetRef<W>, axis: Axis) -> Len {
|
pub fn len_axis<W: Widget + ?Sized>(&mut self, id: &WidgetHandle<W>, axis: Axis) -> Len {
|
||||||
match axis {
|
match axis {
|
||||||
Axis::X => self.width(id),
|
Axis::X => self.width(id),
|
||||||
Axis::Y => self.height(id),
|
Axis::Y => self.height(id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size<W: Widget + ?Sized>(&mut self, id: &WidgetRef<W>) -> Size {
|
pub fn size<W: Widget + ?Sized>(&mut self, id: &WidgetHandle<W>) -> Size {
|
||||||
Size {
|
Size {
|
||||||
x: self.width(id),
|
x: self.width(id),
|
||||||
y: self.height(id),
|
y: self.height(id),
|
||||||
|
|||||||
@@ -2,32 +2,24 @@ use image::DynamicImage;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{
|
layout::{
|
||||||
IdLike, PainterData, PixelRegion, TextureHandle, Vec2, Widget, WidgetInstance, WidgetLike,
|
IdLike, PainterData, PixelRegion, TextureHandle, Vec2, Widget, WidgetHandle, WidgetId,
|
||||||
WidgetRef, WidgetUpdate,
|
WidgetInstance, WidgetLike, WidgetUpdate,
|
||||||
},
|
},
|
||||||
util::{HashSet, Id},
|
util::HashSet,
|
||||||
};
|
};
|
||||||
use std::sync::mpsc::{Receiver, channel};
|
use std::sync::mpsc::{Receiver, channel};
|
||||||
|
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
pub(crate) data: PainterData,
|
pub(crate) data: PainterData,
|
||||||
root: Option<WidgetRef>,
|
root: Option<WidgetHandle>,
|
||||||
updates: HashSet<Id>,
|
updates: HashSet<WidgetId>,
|
||||||
free: Vec<Id>,
|
free: Vec<WidgetId>,
|
||||||
recv: Receiver<WidgetUpdate>,
|
recv: Receiver<WidgetUpdate>,
|
||||||
full_redraw: bool,
|
full_redraw: bool,
|
||||||
resized: bool,
|
resized: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ui {
|
impl Ui {
|
||||||
pub fn add<W: Widget, Tag>(&mut self, w: impl WidgetLike<Tag, Widget = W>) -> WidgetRef<W> {
|
|
||||||
w.add(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_widget<W: Widget>(&mut self, w: W) -> WidgetRef<W> {
|
|
||||||
self.data.widgets.insert(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_root<Tag>(&mut self, w: impl WidgetLike<Tag>) {
|
pub fn set_root<Tag>(&mut self, w: impl WidgetLike<Tag>) {
|
||||||
self.root = Some(w.add(self));
|
self.root = Some(w.add(self));
|
||||||
self.full_redraw = true;
|
self.full_redraw = true;
|
||||||
@@ -97,7 +89,6 @@ impl Ui {
|
|||||||
for m in self.data.modules.iter_mut() {
|
for m in self.data.modules.iter_mut() {
|
||||||
m.on_remove(&id);
|
m.on_remove(&id);
|
||||||
}
|
}
|
||||||
self.data.widgets.delete(id);
|
|
||||||
}
|
}
|
||||||
self.data.textures.free();
|
self.data.textures.free();
|
||||||
}
|
}
|
||||||
@@ -106,10 +97,6 @@ impl Ui {
|
|||||||
self.full_redraw || !self.updates.is_empty()
|
self.full_redraw || !self.updates.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_widgets(&self) -> usize {
|
|
||||||
self.data.widgets.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn active_widgets(&self) -> usize {
|
pub fn active_widgets(&self) -> usize {
|
||||||
self.data.active.len()
|
self.data.active.len()
|
||||||
}
|
}
|
||||||
@@ -133,7 +120,7 @@ impl Ui {
|
|||||||
|
|
||||||
pub fn debug(&self, label: &str) -> impl Iterator<Item = &WidgetInstance> {
|
pub fn debug(&self, label: &str) -> impl Iterator<Item = &WidgetInstance> {
|
||||||
self.data.active.iter().filter_map(move |(id, inst)| {
|
self.data.active.iter().filter_map(move |(id, inst)| {
|
||||||
let widget = &self.data.widgets.get(*id);
|
let widget = id.strong().unwrap();
|
||||||
if widget.get_label().as_str() == label {
|
if widget.get_label().as_str() == label {
|
||||||
Some(inst)
|
Some(inst)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::layout::{Widget, WidgetLike, WidgetRef};
|
use crate::layout::{Widget, WidgetHandle, WidgetLike};
|
||||||
use std::marker::Unsize;
|
use std::marker::Unsize;
|
||||||
|
|
||||||
pub trait WidgetView {
|
pub trait WidgetView {
|
||||||
type Widget: Widget + ?Sized + Unsize<dyn Widget> = dyn Widget;
|
type Widget: Widget + ?Sized + Unsize<dyn Widget> = dyn Widget;
|
||||||
fn view(&self) -> &WidgetRef<Self::Widget>;
|
fn view(self) -> WidgetHandle<Self::Widget>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ViewTag;
|
pub struct ViewTag;
|
||||||
@@ -11,7 +11,7 @@ pub struct ViewTag;
|
|||||||
impl<WV: WidgetView> WidgetLike<ViewTag> for WV {
|
impl<WV: WidgetView> WidgetLike<ViewTag> for WV {
|
||||||
type Widget = WV::Widget;
|
type Widget = WV::Widget;
|
||||||
|
|
||||||
fn add(self, _ui: &mut super::Ui) -> WidgetRef<Self::Widget> {
|
fn add(self, _ui: &mut super::Ui) -> WidgetHandle<Self::Widget> {
|
||||||
self.view().clone()
|
self.view()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,53 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefMut},
|
|
||||||
marker::Unsize,
|
marker::Unsize,
|
||||||
ops::CoerceUnsized,
|
mem::MaybeUninit,
|
||||||
|
ops::{CoerceUnsized, Deref, DerefMut},
|
||||||
sync::mpsc::Sender,
|
sync::mpsc::Sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{IdFnTag, IdTag, Ui, Widget, WidgetLike},
|
layout::{IdFnTag, IdTag, Ui, WIDGETS, Widget, WidgetLike},
|
||||||
util::{Handle, Id, WeakHandle},
|
util::{Handle, Ref, RefMap, RefMapMut, RefMut, WeakHandle},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An handle for a widget in a UI.
|
pub(super) type SlotTy = u32;
|
||||||
///
|
|
||||||
/// 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> {
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
id: Id,
|
pub struct WidgetId {
|
||||||
send: Sender<WidgetUpdate>,
|
pub(super) i: SlotTy,
|
||||||
label: String,
|
pub(super) genr: SlotTy,
|
||||||
widget: W,
|
}
|
||||||
|
|
||||||
|
/// A strong handle to a widget. Cannot be cloned, only one may exist
|
||||||
|
/// Use .weak() to obtain weak references to this
|
||||||
|
pub struct WidgetHandle<W: ?Sized = dyn Widget>(WidgetId, Handle<WidgetData<W>>);
|
||||||
|
/// A weak handle to a widget. Implements Copy so you can easily pass into closures
|
||||||
|
pub struct WidgetRef<W: ?Sized = dyn Widget>(WidgetId, *const W);
|
||||||
|
|
||||||
|
pub(crate) struct WidgetData<W: ?Sized> {
|
||||||
|
pub id: WidgetId,
|
||||||
|
pub send: Option<Sender<WidgetUpdate>>,
|
||||||
|
pub label: String,
|
||||||
|
pub widget: W,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum WidgetUpdate {
|
pub enum WidgetUpdate {
|
||||||
Drop(Id),
|
Drop(WidgetId),
|
||||||
Mutate(Id),
|
Mutate(WidgetId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W> PartialEq for WidgetRef<W> {
|
impl<W: Widget> WidgetHandle<W> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
pub(super) fn new(id: WidgetId, widget: W) -> Self {
|
||||||
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();
|
let mut label = std::any::type_name::<W>().to_string();
|
||||||
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(
|
Self(
|
||||||
Inner {
|
|
||||||
widget,
|
|
||||||
id,
|
id,
|
||||||
send,
|
WidgetData {
|
||||||
|
id,
|
||||||
|
widget,
|
||||||
|
send: None,
|
||||||
label,
|
label,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
@@ -64,100 +55,225 @@ impl<W: Widget> WidgetRef<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget + ?Sized + Unsize<dyn Widget>> WidgetRef<W> {
|
impl<W: Widget + ?Sized + Unsize<dyn Widget>> WidgetHandle<W> {
|
||||||
pub fn any(self) -> WidgetRef<dyn Widget> {
|
pub(super) fn weak_inner(&self) -> WeakHandle<WidgetData<W>> {
|
||||||
WidgetRef(self.0)
|
self.1.weak()
|
||||||
}
|
}
|
||||||
pub fn as_any(&self) -> WidgetRef<dyn Widget> {
|
|
||||||
WidgetRef(self.0.clone())
|
pub fn any(self) -> WidgetHandle<dyn Widget> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DO NOT CALL OTHER THAN TEMP IN PAINTER
|
||||||
|
pub(crate) fn as_any(&self) -> WidgetHandle<dyn Widget> {
|
||||||
|
WidgetHandle(self.0, self.1.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: ?Sized> WidgetRef<W> {
|
impl<W: ?Sized> WidgetHandle<W> {
|
||||||
pub fn id(&self) -> Id {
|
pub fn id(&self) -> WidgetId {
|
||||||
self.0.get().id
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> Ref<'_, W> {
|
pub fn get(&self) -> RefMap<'_, W> {
|
||||||
Ref::map(self.0.get(), |i| &i.widget)
|
Ref::map(self.1.get(), |i| &mut i.widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&self) -> RefMut<'_, W> {
|
pub fn get_mut(&self) -> RefMapMut<'_, W> {
|
||||||
let inner = self.0.get_mut();
|
let inner = self.1.get_mut();
|
||||||
let _ = inner.send.send(WidgetUpdate::Mutate(inner.id));
|
if let Some(send) = &inner.send {
|
||||||
|
let _ = send.send(WidgetUpdate::Mutate(self.0));
|
||||||
|
}
|
||||||
RefMut::map(inner, |i| &mut i.widget)
|
RefMut::map(inner, |i| &mut i.widget)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut_quiet(&self) -> RefMut<'_, W> {
|
pub(crate) fn data_mut(&self) -> RefMut<'_, WidgetData<W>> {
|
||||||
RefMut::map(self.0.get_mut(), |i| &mut i.widget)
|
self.1.get_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_label(&self) -> Ref<'_, String> {
|
pub fn get_mut_quiet(&self) -> RefMapMut<'_, W> {
|
||||||
Ref::map(self.0.get(), |i| &i.label)
|
RefMut::map(self.1.get_mut(), |i| &mut i.widget)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_label(&self) -> RefMap<'_, String> {
|
||||||
|
Ref::map(self.1.get(), |i| &mut i.label)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_label(&self, label: impl Into<String>) {
|
pub fn set_label(&self, label: impl Into<String>) {
|
||||||
self.0.get_mut().label = label.into();
|
self.1.get_mut().label = label.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: THIS SHOULD ALWAYS BE 1, remove this probably (weak count might be nice though)
|
||||||
pub fn refs(&self) -> usize {
|
pub fn refs(&self) -> usize {
|
||||||
self.0.refs()
|
self.1.refs()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn weak(&self) -> WeakWidgetRef<W> {
|
pub fn weak(&self) -> WidgetRef<W> {
|
||||||
WeakWidgetRef(self.0.weak())
|
WidgetRef(self.0, null_ptr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: ?Sized> WeakWidgetRef<W> {
|
impl<W: Widget> WidgetRef<W> {
|
||||||
/// should guarantee that widget is still valid to prevent indexing failures
|
fn handle(&self) -> Handle<WidgetData<W>> {
|
||||||
pub(crate) fn expect_strong(&self) -> WidgetRef<W> {
|
WIDGETS.get_type(self.0).unwrap()
|
||||||
WidgetRef(self.0.strong().expect("widget should not be dropped"))
|
}
|
||||||
|
|
||||||
|
pub fn get<'a>(&self) -> WRef<'a, W> {
|
||||||
|
let handle = self.handle();
|
||||||
|
WRef {
|
||||||
|
val: unsafe {
|
||||||
|
std::mem::transmute::<RefMap<'_, W>, RefMap<'_, W>>(Ref::map(handle.get(), |i| {
|
||||||
|
&mut i.widget
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
_handle: handle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut<'a>(&self) -> WRefMut<'a, W> {
|
||||||
|
let handle = self.handle();
|
||||||
|
if let Some(send) = &handle.get().send {
|
||||||
|
let _ = send.send(WidgetUpdate::Mutate(self.0));
|
||||||
|
}
|
||||||
|
WRefMut {
|
||||||
|
val: unsafe {
|
||||||
|
std::mem::transmute::<RefMapMut<'_, W>, RefMapMut<'_, W>>(RefMut::map(
|
||||||
|
handle.get_mut(),
|
||||||
|
|i| &mut i.widget,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
_handle: handle,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget + ?Sized + Unsize<dyn Widget>> WeakWidgetRef<W> {
|
pub struct WRef<'a, W> {
|
||||||
pub fn any(self) -> WeakWidgetRef<dyn Widget> {
|
_handle: Handle<WidgetData<W>>,
|
||||||
WeakWidgetRef(self.0.clone())
|
val: RefMap<'a, W>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WRefMut<'a, W> {
|
||||||
|
_handle: Handle<WidgetData<W>>,
|
||||||
|
val: RefMapMut<'a, W>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Widget + ?Sized + Unsize<dyn Widget>> WidgetRef<W> {
|
||||||
|
pub fn any(self) -> WidgetRef<dyn Widget> {
|
||||||
|
WidgetRef(self.0, null_ptr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: ?Sized> Drop for Inner<W> {
|
fn null_ptr<T: ?Sized>() -> *const T {
|
||||||
|
unsafe { MaybeUninit::zeroed().assume_init() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: ?Sized> WidgetRef<W> {
|
||||||
|
pub fn id(&self) -> WidgetId {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetId {
|
||||||
|
/// THIS SHOULD ONLY BE CALLED FOR TEMP STUFF DURING PAINTING
|
||||||
|
pub(crate) fn strong(self) -> Option<WidgetHandle> {
|
||||||
|
Some(WidgetHandle(self, WIDGETS.get(self)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: ?Sized> Drop for WidgetData<W> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.send.send(WidgetUpdate::Drop(self.id));
|
if let Some(send) = &self.send {
|
||||||
|
WIDGETS.remove(self.id);
|
||||||
|
let _ = send.send(WidgetUpdate::Drop(self.id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WidgetIdFn<W: ?Sized = dyn Widget>: FnOnce(&mut Ui) -> WidgetRef<W> {}
|
pub trait WidgetIdFn<W: ?Sized = dyn Widget>: FnOnce(&mut Ui) -> WidgetHandle<W> {}
|
||||||
impl<W: ?Sized, F: FnOnce(&mut Ui) -> WidgetRef<W>> WidgetIdFn<W> for F {}
|
impl<W: ?Sized, F: FnOnce(&mut Ui) -> WidgetHandle<W>> WidgetIdFn<W> for F {}
|
||||||
|
|
||||||
pub trait WidgetRet: FnOnce(&mut Ui) -> WidgetRef {}
|
pub trait WidgetRet: FnOnce(&mut Ui) -> WidgetHandle {}
|
||||||
impl<F: FnOnce(&mut Ui) -> WidgetRef> WidgetRet for F {}
|
impl<F: FnOnce(&mut Ui) -> WidgetHandle> WidgetRet for F {}
|
||||||
|
|
||||||
impl<W: Widget + ?Sized + Unsize<dyn Widget> + 'static> WidgetLike<IdTag> for WidgetRef<W> {
|
impl<W: Widget + ?Sized + Unsize<dyn Widget> + 'static> WidgetLike<IdTag> for WidgetHandle<W> {
|
||||||
type Widget = W;
|
type Widget = W;
|
||||||
fn add(self, _: &mut Ui) -> WidgetRef<W> {
|
fn add(self, _: &mut Ui) -> WidgetHandle<W> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget + ?Sized + Unsize<dyn Widget> + 'static, F: FnOnce(&mut Ui) -> WidgetRef<W>>
|
impl<W: Widget + ?Sized + Unsize<dyn Widget> + 'static, F: FnOnce(&mut Ui) -> WidgetHandle<W>>
|
||||||
WidgetLike<IdFnTag> for F
|
WidgetLike<IdFnTag> for F
|
||||||
{
|
{
|
||||||
type Widget = W;
|
type Widget = W;
|
||||||
fn add(self, ui: &mut Ui) -> WidgetRef<W> {
|
fn add(self, ui: &mut Ui) -> WidgetHandle<W> {
|
||||||
self(ui)
|
self(ui)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IdLike<W> {
|
pub trait IdLike<W> {
|
||||||
fn id(&self) -> Id;
|
fn id(&self) -> WidgetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W> IdLike<W> for WidgetRef<W> {
|
impl<W> IdLike<W> for WidgetHandle<W> {
|
||||||
fn id(&self) -> Id {
|
fn id(&self) -> WidgetId {
|
||||||
self.id()
|
self.id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<WidgetRef<U>> for WidgetRef<W> {}
|
impl<W> IdLike<W> for WidgetRef<W> {
|
||||||
|
fn id(&self) -> WidgetId {
|
||||||
|
self.id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<WidgetHandle<U>> for WidgetHandle<T> {}
|
||||||
|
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<WidgetRef<U>> for WidgetRef<T> {}
|
||||||
|
|
||||||
|
impl<W> PartialEq for WidgetHandle<W> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id() == other.id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W> std::fmt::Debug for WidgetHandle<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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: ?Sized> Copy for WidgetRef<W> {}
|
||||||
|
|
||||||
|
impl<W: ?Sized> PartialEq for WidgetRef<W> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.0 == other.0 && self.1 == other.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for WRef<'_, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for WRefMut<'_, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for WRefMut<'_, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use std::marker::Unsize;
|
|||||||
pub trait WidgetLike<Tag> {
|
pub trait WidgetLike<Tag> {
|
||||||
type Widget: Widget + ?Sized + Unsize<dyn Widget> + 'static;
|
type Widget: Widget + ?Sized + Unsize<dyn Widget> + 'static;
|
||||||
|
|
||||||
fn add(self, ui: &mut Ui) -> WidgetRef<Self::Widget>;
|
fn add(self, ui: &mut Ui) -> WidgetHandle<Self::Widget>;
|
||||||
|
|
||||||
fn with_id<W2>(
|
fn with_id<W2>(
|
||||||
self,
|
self,
|
||||||
f: impl FnOnce(&mut Ui, WidgetRef<Self::Widget>) -> WidgetRef<W2>,
|
f: impl FnOnce(&mut Ui, WidgetHandle<Self::Widget>) -> WidgetHandle<W2>,
|
||||||
) -> impl WidgetIdFn<W2>
|
) -> impl WidgetIdFn<W2>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@@ -28,11 +28,11 @@ pub trait WidgetLike<Tag> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct WidgetArr<const LEN: usize> {
|
pub struct WidgetArr<const LEN: usize> {
|
||||||
pub arr: [WidgetRef; LEN],
|
pub arr: [WidgetHandle; LEN],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const LEN: usize> WidgetArr<LEN> {
|
impl<const LEN: usize> WidgetArr<LEN> {
|
||||||
pub fn new(arr: [WidgetRef; LEN]) -> Self {
|
pub fn new(arr: [WidgetHandle; LEN]) -> Self {
|
||||||
Self { arr }
|
Self { arr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ pub use widgets::*;
|
|||||||
|
|
||||||
use crate::layout::{Len, Painter, SizeCtx, Ui};
|
use crate::layout::{Len, Painter, SizeCtx, Ui};
|
||||||
|
|
||||||
pub trait Widget: 'static {
|
pub trait Widget: 'static + Send + Sync {
|
||||||
fn draw(&mut self, painter: &mut Painter);
|
fn draw(&mut self, painter: &mut Painter);
|
||||||
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len;
|
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len;
|
||||||
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len;
|
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len;
|
||||||
@@ -34,30 +34,30 @@ 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 {
|
||||||
type Widget = W;
|
type Widget = W;
|
||||||
fn add(self, ui: &mut Ui) -> WidgetRef<W> {
|
fn add(self, ui: &mut Ui) -> WidgetHandle<W> {
|
||||||
self(ui).add(ui)
|
self(ui).add(ui)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget> WidgetLike<WidgetTag> for W {
|
impl<W: Widget> WidgetLike<WidgetTag> for W {
|
||||||
type Widget = W;
|
type Widget = W;
|
||||||
fn add(self, ui: &mut Ui) -> WidgetRef<W> {
|
fn add(self, _: &mut Ui) -> WidgetHandle<W> {
|
||||||
ui.add_widget(self)
|
WIDGETS.insert(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WidgetOption {
|
pub trait WidgetOption {
|
||||||
fn get(self, ui: &mut Ui) -> Option<WidgetRef>;
|
fn get(self, ui: &mut Ui) -> Option<WidgetHandle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetOption for () {
|
impl WidgetOption for () {
|
||||||
fn get(self, _: &mut Ui) -> Option<WidgetRef> {
|
fn get(self, _: &mut Ui) -> Option<WidgetHandle> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: FnOnce(&mut Ui) -> Option<WidgetRef>> WidgetOption for F {
|
impl<F: FnOnce(&mut Ui) -> Option<WidgetHandle>> WidgetOption for F {
|
||||||
fn get(self, ui: &mut Ui) -> Option<WidgetRef> {
|
fn get(self, ui: &mut Ui) -> Option<WidgetHandle> {
|
||||||
self(ui)
|
self(ui)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +1,108 @@
|
|||||||
use std::sync::mpsc::Sender;
|
use std::{
|
||||||
|
any::Any,
|
||||||
use crate::{
|
sync::{Mutex, MutexGuard},
|
||||||
layout::{WeakWidgetRef, Widget, WidgetRef, WidgetUpdate},
|
|
||||||
util::{HashMap, Id, IdTracker},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Widgets {
|
use crate::{
|
||||||
ids: IdTracker,
|
layout::{
|
||||||
map: HashMap<Id, WeakWidgetRef>,
|
Widget, WidgetData, WidgetHandle,
|
||||||
send: Sender<WidgetUpdate>,
|
widget::{SlotTy, WidgetId},
|
||||||
|
},
|
||||||
|
util::{Handle, WeakHandle},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) static WIDGETS: Widgets = Widgets::new();
|
||||||
|
pub(crate) struct Widgets(Mutex<Inner>);
|
||||||
|
|
||||||
|
pub fn total_widgets() -> usize {
|
||||||
|
WIDGETS.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WidgetSlot {
|
||||||
|
genr: SlotTy,
|
||||||
|
data: WeakHandle<WidgetData<dyn Widget + Sync + Send>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Inner {
|
||||||
|
cur_id: SlotTy,
|
||||||
|
vec: Vec<WidgetSlot>,
|
||||||
|
free: Vec<SlotTy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widgets {
|
impl Widgets {
|
||||||
pub fn new(send: Sender<WidgetUpdate>) -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self(Mutex::new(Inner {
|
||||||
ids: IdTracker::default(),
|
cur_id: 0,
|
||||||
map: HashMap::default(),
|
vec: Vec::new(),
|
||||||
send,
|
free: Vec::new(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect(&self) -> MutexGuard<'_, Inner> {
|
||||||
|
self.0.lock().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type<W: 'static>(&self, id: WidgetId) -> Option<Handle<WidgetData<W>>> {
|
||||||
|
let slot = &self.expect().vec[id.i as usize];
|
||||||
|
if slot.genr != id.genr {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
unsafe { slot.data.clone().downcast() }
|
||||||
|
.unwrap()
|
||||||
|
.clone()
|
||||||
|
.strong()?,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, id: Id) -> WidgetRef {
|
pub fn get(&self, id: WidgetId) -> Option<Handle<WidgetData<dyn Widget>>> {
|
||||||
self.map.get(&id).unwrap().expect_strong()
|
let slot = &self.expect().vec[id.i as usize];
|
||||||
|
if slot.genr != id.genr {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(slot.data.clone().strong()?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert<W: Widget>(&mut self, widget: W) -> WidgetRef<W> {
|
pub fn insert<W: Widget>(&self, widget: W) -> WidgetHandle<W> {
|
||||||
let id = self.ids.next();
|
let mut s = self.expect();
|
||||||
let rf = WidgetRef::new(id, widget, self.send.clone());
|
let id = s
|
||||||
self.map.insert(id, rf.weak().any());
|
.free
|
||||||
rf
|
.pop()
|
||||||
|
.map(|i| {
|
||||||
|
assert!(s.vec[i as usize].data.dropped());
|
||||||
|
WidgetId {
|
||||||
|
i,
|
||||||
|
genr: s.vec[i as usize].genr,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let i = s.cur_id;
|
||||||
|
s.cur_id += 1;
|
||||||
|
WidgetId { i, genr: 0 }
|
||||||
|
});
|
||||||
|
let handle = WidgetHandle::new(id, widget);
|
||||||
|
let slot = WidgetSlot {
|
||||||
|
genr: id.genr,
|
||||||
|
data: handle.weak_inner(),
|
||||||
|
};
|
||||||
|
if id.i == s.vec.len() as SlotTy {
|
||||||
|
s.vec.push(slot);
|
||||||
|
} else {
|
||||||
|
s.vec[id.i as usize] = slot;
|
||||||
|
}
|
||||||
|
handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(&mut self, id: Id) {
|
pub fn remove(&self, id: WidgetId) {
|
||||||
self.map.remove(&id);
|
let mut s = self.expect();
|
||||||
self.ids.free(id);
|
s.vec[id.i as usize].genr += 1;
|
||||||
}
|
s.free.push(id.i);
|
||||||
|
|
||||||
pub fn reserve(&mut self) -> Id {
|
|
||||||
self.ids.next()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.map.len()
|
let s = self.expect();
|
||||||
}
|
s.vec.len() - s.free.len()
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.map.is_empty()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
#![feature(associated_type_defaults)]
|
#![feature(associated_type_defaults)]
|
||||||
#![feature(unsize)]
|
#![feature(unsize)]
|
||||||
#![feature(coerce_unsized)]
|
#![feature(coerce_unsized)]
|
||||||
|
#![feature(mapped_lock_guards)]
|
||||||
|
#![feature(ptr_metadata)]
|
||||||
|
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{Color, UiRegion},
|
layout::{Color, UiRegion, WidgetId},
|
||||||
render::{
|
render::{
|
||||||
ArrBuf,
|
ArrBuf,
|
||||||
data::{MaskIdx, PrimitiveInstance},
|
data::{MaskIdx, PrimitiveInstance},
|
||||||
},
|
},
|
||||||
util::Id,
|
|
||||||
};
|
};
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use wgpu::*;
|
use wgpu::*;
|
||||||
|
|
||||||
pub struct Primitives {
|
pub struct Primitives {
|
||||||
instances: Vec<PrimitiveInstance>,
|
instances: Vec<PrimitiveInstance>,
|
||||||
assoc: Vec<Id>,
|
assoc: Vec<WidgetId>,
|
||||||
data: PrimitiveData,
|
data: PrimitiveData,
|
||||||
free: Vec<usize>,
|
free: Vec<usize>,
|
||||||
pub updated: bool,
|
pub updated: bool,
|
||||||
@@ -99,7 +97,7 @@ macro_rules! primitives {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct PrimitiveInst<P> {
|
pub struct PrimitiveInst<P> {
|
||||||
pub id: Id,
|
pub id: WidgetId,
|
||||||
pub primitive: P,
|
pub primitive: P,
|
||||||
pub region: UiRegion,
|
pub region: UiRegion,
|
||||||
pub mask_idx: MaskIdx,
|
pub mask_idx: MaskIdx,
|
||||||
@@ -175,7 +173,7 @@ impl Primitives {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct PrimitiveChange {
|
pub struct PrimitiveChange {
|
||||||
pub id: Id,
|
pub id: WidgetId,
|
||||||
pub old: usize,
|
pub old: usize,
|
||||||
pub new: usize,
|
pub new: usize,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,34 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell, RefMut},
|
any::{Any, TypeId},
|
||||||
marker::Unsize,
|
marker::Unsize,
|
||||||
ops::CoerceUnsized,
|
ops::CoerceUnsized,
|
||||||
rc::{Rc, Weak},
|
sync::{Arc, Mutex, Weak},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Handle<T: ?Sized>(Rc<RefCell<T>>);
|
pub struct Handle<T: ?Sized>(Arc<Mutex<T>>);
|
||||||
pub struct WeakHandle<T: ?Sized>(Weak<RefCell<T>>);
|
pub struct WeakHandle<T: ?Sized>(Weak<Mutex<T>>);
|
||||||
|
|
||||||
|
pub type Ref<'a, T> = std::sync::MutexGuard<'a, T>;
|
||||||
|
pub type RefMut<'a, T> = std::sync::MutexGuard<'a, T>;
|
||||||
|
|
||||||
|
pub type RefMap<'a, T> = std::sync::MappedMutexGuard<'a, T>;
|
||||||
|
pub type RefMapMut<'a, T> = std::sync::MappedMutexGuard<'a, T>;
|
||||||
|
|
||||||
impl<T: ?Sized> Handle<T> {
|
impl<T: ?Sized> Handle<T> {
|
||||||
pub fn get(&self) -> Ref<'_, T> {
|
pub fn get(&self) -> Ref<'_, T> {
|
||||||
self.0.borrow()
|
self.0.lock().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&self) -> RefMut<'_, T> {
|
pub fn get_mut(&self) -> RefMut<'_, T> {
|
||||||
self.0.borrow_mut()
|
self.0.lock().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refs(&self) -> usize {
|
pub fn refs(&self) -> usize {
|
||||||
Rc::strong_count(&self.0)
|
Arc::strong_count(&self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn weak(&self) -> WeakHandle<T> {
|
pub fn weak(&self) -> WeakHandle<T> {
|
||||||
WeakHandle(Rc::downgrade(&self.0))
|
WeakHandle(Arc::downgrade(&self.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +36,21 @@ impl<T: ?Sized> WeakHandle<T> {
|
|||||||
pub fn strong(&self) -> Option<Handle<T>> {
|
pub fn strong(&self) -> Option<Handle<T>> {
|
||||||
Some(Handle(self.0.upgrade()?))
|
Some(Handle(self.0.upgrade()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dropped(&self) -> bool {
|
||||||
|
self.0.strong_count() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// you must guarantee the type outside
|
||||||
|
pub unsafe fn downcast<U: 'static>(self) -> Option<WeakHandle<U>>
|
||||||
|
where
|
||||||
|
T: 'static,
|
||||||
|
{
|
||||||
|
let raw: *const Mutex<T> = self.0.into_raw();
|
||||||
|
let raw: *const Mutex<U> = raw.cast();
|
||||||
|
Some(WeakHandle(unsafe { Weak::from_raw(raw) }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> Clone for Handle<T> {
|
impl<T: ?Sized> Clone for Handle<T> {
|
||||||
@@ -52,7 +73,7 @@ impl<T: Default> Default for Handle<T> {
|
|||||||
|
|
||||||
impl<T> From<T> for Handle<T> {
|
impl<T> From<T> for Handle<T> {
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
Self(Rc::new(RefCell::new(value)))
|
Self(Arc::new(Mutex::new(value)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ impl DefaultAppState for Client {
|
|||||||
.add(ui);
|
.add(ui);
|
||||||
|
|
||||||
let span_add = Span::empty(Dir::RIGHT).add(ui);
|
let span_add = Span::empty(Dir::RIGHT).add(ui);
|
||||||
let span_add_ = span_add.clone();
|
let span_add_ = span_add.weak();
|
||||||
|
|
||||||
let add_button = rect(Color::LIME)
|
let add_button = rect(Color::LIME)
|
||||||
.radius(30)
|
.radius(30)
|
||||||
@@ -64,7 +64,6 @@ impl DefaultAppState for Client {
|
|||||||
.sized((150, 150))
|
.sized((150, 150))
|
||||||
.align(Align::BOT_RIGHT);
|
.align(Align::BOT_RIGHT);
|
||||||
|
|
||||||
let span_add_ = span_add.clone();
|
|
||||||
let del_button = rect(Color::RED)
|
let del_button = rect(Color::RED)
|
||||||
.radius(30)
|
.radius(30)
|
||||||
.on(CursorSense::click(), move |_| {
|
.on(CursorSense::click(), move |_| {
|
||||||
@@ -99,7 +98,8 @@ impl DefaultAppState for Client {
|
|||||||
.add(ui);
|
.add(ui);
|
||||||
|
|
||||||
let texts = Span::empty(Dir::DOWN).gap(10).add(ui);
|
let texts = Span::empty(Dir::DOWN).gap(10).add(ui);
|
||||||
let msg_area = texts.clone().scroll().masked().background(rect(Color::SKY));
|
let texts_ = texts.weak();
|
||||||
|
let msg_area = texts.scroll().masked().background(rect(Color::SKY));
|
||||||
let add_text = wtext("add")
|
let add_text = wtext("add")
|
||||||
.editable(false)
|
.editable(false)
|
||||||
.text_align(Align::LEFT)
|
.text_align(Align::LEFT)
|
||||||
@@ -114,18 +114,19 @@ impl DefaultAppState for Client {
|
|||||||
.wrap(true)
|
.wrap(true)
|
||||||
.attr::<Selectable>(());
|
.attr::<Selectable>(());
|
||||||
let msg_box = text.background(rect(Color::WHITE.darker(0.5))).add(ctx.ui);
|
let msg_box = text.background(rect(Color::WHITE.darker(0.5))).add(ctx.ui);
|
||||||
texts.get_mut().children.push(msg_box);
|
texts_.get_mut().children.push(msg_box);
|
||||||
})
|
})
|
||||||
.add(ui);
|
.add(ui);
|
||||||
|
let add_text_ = add_text.weak();
|
||||||
let text_edit_scroll = (
|
let text_edit_scroll = (
|
||||||
msg_area.height(rest(1)),
|
msg_area.height(rest(1)),
|
||||||
(
|
(
|
||||||
Rect::new(Color::WHITE.darker(0.9)),
|
Rect::new(Color::WHITE.darker(0.9)),
|
||||||
(
|
(
|
||||||
add_text.clone().width(rest(1)),
|
add_text.width(rest(1)),
|
||||||
Rect::new(Color::GREEN)
|
Rect::new(Color::GREEN)
|
||||||
.on(CursorSense::click(), move |ctx| {
|
.on(CursorSense::click(), move |ctx| {
|
||||||
ctx.ui.run_event(ctx.state, &add_text, Submit, ());
|
ctx.ui.run_event(ctx.state, add_text_, Submit, ());
|
||||||
})
|
})
|
||||||
.sized((40, 40)),
|
.sized((40, 40)),
|
||||||
)
|
)
|
||||||
@@ -140,13 +141,24 @@ impl DefaultAppState for Client {
|
|||||||
.span(Dir::DOWN)
|
.span(Dir::DOWN)
|
||||||
.add(ui);
|
.add(ui);
|
||||||
|
|
||||||
let main = pad_test.clone().pad(10).add(ui);
|
let main = pad_test.pad(10).add(ui);
|
||||||
|
let main_ = main.weak();
|
||||||
|
|
||||||
let switch_button = |color, to: WidgetRef, label| {
|
let tab_handles = Handle::from((0, Vec::new()));
|
||||||
let main_ = main.clone();
|
|
||||||
|
let switch_button = |color, to: Option<WidgetHandle>, label| {
|
||||||
|
let tab_handles = tab_handles.clone();
|
||||||
|
let i = tab_handles.get().1.len();
|
||||||
|
tab_handles.get_mut().1.push(to);
|
||||||
let rect = rect(color)
|
let rect = rect(color)
|
||||||
.on(CursorSense::click(), move |ctx| {
|
.on(CursorSense::click(), move |ctx| {
|
||||||
main_.get_mut().inner = to.clone();
|
let (prev, all) = &mut *tab_handles.get_mut();
|
||||||
|
if let Some(to) = &mut all[i] {
|
||||||
|
let mut main = main_.get_mut();
|
||||||
|
std::mem::swap(&mut main.inner, to);
|
||||||
|
all.swap(*prev, i);
|
||||||
|
*prev = i;
|
||||||
|
}
|
||||||
ctx.widget.get_mut().color = color.darker(0.3);
|
ctx.widget.get_mut().color = color.darker(0.3);
|
||||||
})
|
})
|
||||||
.on(
|
.on(
|
||||||
@@ -162,20 +174,21 @@ impl DefaultAppState for Client {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let tabs = (
|
let tabs = (
|
||||||
switch_button(Color::RED, pad_test, "pad"),
|
switch_button(Color::RED, None, "pad"),
|
||||||
switch_button(Color::GREEN, span_test, "span"),
|
switch_button(Color::GREEN, Some(span_test), "span"),
|
||||||
switch_button(Color::BLUE, span_add_test, "image span"),
|
switch_button(Color::BLUE, Some(span_add_test), "image span"),
|
||||||
switch_button(Color::MAGENTA, text_test, "text layout"),
|
switch_button(Color::MAGENTA, Some(text_test), "text layout"),
|
||||||
switch_button(
|
switch_button(
|
||||||
Color::YELLOW.mul_rgb(0.5),
|
Color::YELLOW.mul_rgb(0.5),
|
||||||
text_edit_scroll,
|
Some(text_edit_scroll),
|
||||||
"text edit scroll",
|
"text edit scroll",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.span(Dir::RIGHT);
|
.span(Dir::RIGHT);
|
||||||
|
|
||||||
let info = wtext("").add(ui);
|
let info_ = wtext("").add(ui);
|
||||||
let info_sect = info.clone().pad(10).align(Align::RIGHT);
|
let info = info_.weak();
|
||||||
|
let info_sect = info_.pad(10).align(Align::RIGHT);
|
||||||
|
|
||||||
((tabs.height(40), main).span(Dir::DOWN), info_sect)
|
((tabs.height(40), main).span(Dir::DOWN), info_sect)
|
||||||
.stack()
|
.stack()
|
||||||
@@ -187,7 +200,7 @@ impl DefaultAppState for Client {
|
|||||||
fn window_event(&mut self, _: WindowEvent, ui: &mut Ui, state: &UiState) {
|
fn window_event(&mut self, _: WindowEvent, ui: &mut Ui, state: &UiState) {
|
||||||
let new = format!(
|
let new = format!(
|
||||||
"widgets: {}\nactive:{}\nviews: {}",
|
"widgets: {}\nactive:{}\nviews: {}",
|
||||||
ui.num_widgets(),
|
total_widgets(),
|
||||||
ui.active_widgets(),
|
ui.active_widgets(),
|
||||||
state.renderer.ui.view_count()
|
state.renderer.ui.view_count()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{prelude::*, default::UiState};
|
use crate::{default::UiState, prelude::*};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use winit::dpi::{LogicalPosition, LogicalSize};
|
use winit::dpi::{LogicalPosition, LogicalSize};
|
||||||
|
|
||||||
@@ -7,21 +7,16 @@ pub struct Selector;
|
|||||||
impl<W: 'static> WidgetAttr<W> for Selector {
|
impl<W: 'static> WidgetAttr<W> for Selector {
|
||||||
type Input = WidgetRef<TextEdit>;
|
type Input = WidgetRef<TextEdit>;
|
||||||
|
|
||||||
fn run(ui: &mut Ui, container: &WidgetRef<W>, id: Self::Input) {
|
fn run(ui: &mut Ui, container: WidgetRef<W>, id: Self::Input) {
|
||||||
let container = container.clone();
|
ui.register_event(container, CursorSense::click_or_drag(), move |mut ctx| {
|
||||||
ui.register_event(
|
|
||||||
&container.clone(),
|
|
||||||
CursorSense::click_or_drag(),
|
|
||||||
move |mut ctx| {
|
|
||||||
let ui = ctx.ui;
|
let ui = ctx.ui;
|
||||||
let region = ui.window_region(&id).unwrap();
|
let region = ui.window_region(&id).unwrap();
|
||||||
let id_pos = region.top_left;
|
let id_pos = region.top_left;
|
||||||
let container_pos = ui.window_region(&container).unwrap().top_left;
|
let container_pos = ui.window_region(&container).unwrap().top_left;
|
||||||
ctx.data.cursor += container_pos - id_pos;
|
ctx.data.cursor += container_pos - id_pos;
|
||||||
ctx.data.size = region.size();
|
ctx.data.size = region.size();
|
||||||
select(ui, id.clone(), ctx.state, ctx.data);
|
select(ui, id, ctx.state, ctx.data);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,10 +25,9 @@ pub struct Selectable;
|
|||||||
impl WidgetAttr<TextEdit> for Selectable {
|
impl WidgetAttr<TextEdit> for Selectable {
|
||||||
type Input = ();
|
type Input = ();
|
||||||
|
|
||||||
fn run(ui: &mut Ui, id: &WidgetRef<TextEdit>, _: Self::Input) {
|
fn run(ui: &mut Ui, id: WidgetRef<TextEdit>, _: Self::Input) {
|
||||||
let id = id.clone();
|
ui.register_event(id, CursorSense::click_or_drag(), move |ctx| {
|
||||||
ui.register_event(&id.clone(), CursorSense::click_or_drag(), move |ctx| {
|
select(ctx.ui, id, ctx.state, ctx.data);
|
||||||
select(ctx.ui, id.clone(), ctx.state, ctx.data);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,10 +120,9 @@ impl<State: DefaultAppState> AppState for DefaultState<State> {
|
|||||||
ui_state.renderer.resize(size)
|
ui_state.renderer.resize(size)
|
||||||
}
|
}
|
||||||
WindowEvent::KeyboardInput { event, .. } => {
|
WindowEvent::KeyboardInput { event, .. } => {
|
||||||
if let Some(sel) = &ui_state.focus
|
if let Some(sel) = ui_state.focus
|
||||||
&& event.state.is_pressed()
|
&& event.state.is_pressed()
|
||||||
{
|
{
|
||||||
let sel = &sel.clone();
|
|
||||||
let res = sel.get_mut().apply_event(event, &ui_state.input.modifiers);
|
let res = sel.get_mut().apply_event(event, &ui_state.input.modifiers);
|
||||||
match res {
|
match res {
|
||||||
TextInputResult::Unfocus => {
|
TextInputResult::Unfocus => {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ 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);
|
||||||
ui.register_widget_event(&id, event, f);
|
ui.register_widget_event(id.weak(), event, f);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ macro_rules! event_ctx {
|
|||||||
{
|
{
|
||||||
fn on<E: Event>(
|
fn on<E: Event>(
|
||||||
&mut self,
|
&mut self,
|
||||||
widget: &WidgetRef<W>,
|
widget: WidgetRef<W>,
|
||||||
event: E,
|
event: E,
|
||||||
f: impl WidgetEventFn<Ctx, E::Data, W>,
|
f: impl WidgetEventFn<Ctx, E::Data, W>,
|
||||||
);
|
);
|
||||||
@@ -68,11 +68,11 @@ macro_rules! event_ctx {
|
|||||||
{
|
{
|
||||||
fn on<E: Event>(
|
fn on<E: Event>(
|
||||||
&mut self,
|
&mut self,
|
||||||
widget: &WidgetRef<W>,
|
widget: WidgetRef<W>,
|
||||||
event: E,
|
event: E,
|
||||||
f: impl WidgetEventFn<$ty, E::Data, W>,
|
f: impl WidgetEventFn<$ty, E::Data, W>,
|
||||||
) {
|
) {
|
||||||
self.register_widget_event(&widget, event, f);
|
self.register_widget_event(widget, event, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Masked {
|
pub struct Masked {
|
||||||
pub inner: WidgetRef,
|
pub inner: WidgetHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Masked {
|
impl Widget for Masked {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Aligned {
|
pub struct Aligned {
|
||||||
pub inner: WidgetRef,
|
pub inner: WidgetHandle,
|
||||||
pub align: Align,
|
pub align: Align,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct LayerOffset {
|
pub struct LayerOffset {
|
||||||
pub inner: WidgetRef,
|
pub inner: WidgetHandle,
|
||||||
pub offset: usize,
|
pub offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct MaxSize {
|
pub struct MaxSize {
|
||||||
pub inner: WidgetRef,
|
pub inner: WidgetHandle,
|
||||||
pub x: Option<Len>,
|
pub x: Option<Len>,
|
||||||
pub y: Option<Len>,
|
pub y: Option<Len>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Offset {
|
pub struct Offset {
|
||||||
pub inner: WidgetRef,
|
pub inner: WidgetHandle,
|
||||||
pub amt: UiVec2,
|
pub amt: UiVec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
pub struct Pad {
|
pub struct Pad {
|
||||||
pub padding: Padding,
|
pub padding: Padding,
|
||||||
pub inner: WidgetRef,
|
pub inner: WidgetHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Pad {
|
impl Widget for Pad {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Scroll {
|
pub struct Scroll {
|
||||||
inner: WidgetRef,
|
inner: WidgetHandle,
|
||||||
axis: Axis,
|
axis: Axis,
|
||||||
amt: f32,
|
amt: f32,
|
||||||
snap_end: bool,
|
snap_end: bool,
|
||||||
@@ -41,7 +41,7 @@ impl Widget for Scroll {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Scroll {
|
impl Scroll {
|
||||||
pub fn new(inner: WidgetRef, axis: Axis) -> Self {
|
pub fn new(inner: WidgetHandle, axis: Axis) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner,
|
inner,
|
||||||
axis,
|
axis,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Sized {
|
pub struct Sized {
|
||||||
pub inner: WidgetRef,
|
pub inner: WidgetHandle,
|
||||||
pub x: Option<Len>,
|
pub x: Option<Len>,
|
||||||
pub y: Option<Len>,
|
pub y: Option<Len>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::prelude::*;
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
pub children: Vec<WidgetRef>,
|
pub children: Vec<WidgetHandle>,
|
||||||
pub dir: Dir,
|
pub dir: Dir,
|
||||||
pub gap: f32,
|
pub gap: f32,
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> FnOnce<(&mut Ui,)>
|
|||||||
|
|
||||||
extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output {
|
extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output {
|
||||||
Span {
|
Span {
|
||||||
children: self.children.ui(args.0).arr.to_vec(),
|
children: self.children.ui(args.0).arr.into_iter().collect(),
|
||||||
dir: self.dir,
|
dir: self.dir,
|
||||||
gap: self.gap,
|
gap: self.gap,
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> SpanBuilder<LEN, Wa, Ta
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for Span {
|
impl std::ops::Deref for Span {
|
||||||
type Target = Vec<WidgetRef>;
|
type Target = Vec<WidgetHandle>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.children
|
&self.children
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Stack {
|
pub struct Stack {
|
||||||
pub children: Vec<WidgetRef>,
|
pub children: Vec<WidgetHandle>,
|
||||||
pub size: StackSize,
|
pub size: StackSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> FnOnce<(&mut Ui,)>
|
|||||||
|
|
||||||
extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output {
|
extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output {
|
||||||
Stack {
|
Stack {
|
||||||
children: self.children.ui(args.0).arr.to_vec(),
|
children: self.children.ui(args.0).arr.into_iter().collect(),
|
||||||
size: self.size,
|
size: self.size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct WidgetPtr {
|
pub struct WidgetPtr {
|
||||||
pub inner: Option<WidgetRef>,
|
pub inner: Option<WidgetHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for WidgetPtr {
|
impl Widget for WidgetPtr {
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::util::Id;
|
|
||||||
|
|
||||||
use std::{
|
|
||||||
ops::{BitOr, Deref, DerefMut},
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{UiModule, UiRegion, Vec2},
|
layout::{UiModule, UiRegion, Vec2},
|
||||||
util::HashMap,
|
util::HashMap,
|
||||||
};
|
};
|
||||||
|
use std::{
|
||||||
|
ops::{BitOr, Deref, DerefMut},
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub enum CursorButton {
|
pub enum CursorButton {
|
||||||
@@ -100,10 +97,10 @@ pub enum ActivationState {
|
|||||||
/// but I'm not sure how or if worth it
|
/// but I'm not sure how or if worth it
|
||||||
pub struct Sensor<Ctx, Data> {
|
pub struct Sensor<Ctx, Data> {
|
||||||
pub senses: CursorSenses,
|
pub senses: CursorSenses,
|
||||||
pub f: Rc<dyn EventFn<Ctx, Data>>,
|
pub f: Box<dyn EventFn<Ctx, Data>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type SensorMap<Ctx, Data> = HashMap<Id, SensorGroup<Ctx, Data>>;
|
pub type SensorMap<Ctx, Data> = HashMap<WidgetId, SensorGroup<Ctx, Data>>;
|
||||||
pub type SenseShape = UiRegion;
|
pub type SenseShape = UiRegion;
|
||||||
pub struct SensorGroup<Ctx, Data> {
|
pub struct SensorGroup<Ctx, Data> {
|
||||||
pub hover: ActivationState,
|
pub hover: ActivationState,
|
||||||
@@ -122,7 +119,7 @@ pub struct CursorData {
|
|||||||
|
|
||||||
pub struct CursorModule<Ctx> {
|
pub struct CursorModule<Ctx> {
|
||||||
map: SensorMap<Ctx, CursorData>,
|
map: SensorMap<Ctx, CursorData>,
|
||||||
active: HashMap<usize, HashMap<Id, SenseShape>>,
|
active: HashMap<usize, HashMap<WidgetId, SenseShape>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Ctx: 'static> UiModule for CursorModule<Ctx> {
|
impl<Ctx: 'static> UiModule for CursorModule<Ctx> {
|
||||||
@@ -141,7 +138,7 @@ impl<Ctx: 'static> UiModule for CursorModule<Ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_remove(&mut self, id: &Id) {
|
fn on_remove(&mut self, id: &WidgetId) {
|
||||||
self.map.remove(id);
|
self.map.remove(id);
|
||||||
for layer in self.active.values_mut() {
|
for layer in self.active.values_mut() {
|
||||||
layer.remove(id);
|
layer.remove(id);
|
||||||
@@ -307,34 +304,34 @@ impl Event for CursorSense {
|
|||||||
impl<E: Event<Data = <CursorSenses as Event>::Data> + Into<CursorSenses>, Ctx: 'static>
|
impl<E: Event<Data = <CursorSenses as Event>::Data> + Into<CursorSenses>, Ctx: 'static>
|
||||||
EventModule<E, Ctx> for CursorModule<Ctx>
|
EventModule<E, Ctx> for CursorModule<Ctx>
|
||||||
{
|
{
|
||||||
fn register(&mut self, id: Id, senses: E, f: impl EventFn<Ctx, <E as Event>::Data>) {
|
fn register(&mut self, id: WidgetId, senses: E, f: impl EventFn<Ctx, <E as Event>::Data>) {
|
||||||
// TODO: does not add to active if currently active
|
// TODO: does not add to active if currently active
|
||||||
self.map.entry(id).or_default().sensors.push(Sensor {
|
self.map.entry(id).or_default().sensors.push(Sensor {
|
||||||
senses: senses.into(),
|
senses: senses.into(),
|
||||||
f: Rc::new(f),
|
f: Box::new(f),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run<'a>(
|
fn run(
|
||||||
&self,
|
&mut self,
|
||||||
id: &Id,
|
id: WidgetId,
|
||||||
event: E,
|
event: E,
|
||||||
) -> Option<impl Fn(EventCtx<Ctx, <E as Event>::Data>) + use<'a, E, Ctx>> {
|
) -> Option<impl FnOnce(EventCtx<Ctx, <E as Event>::Data>)> {
|
||||||
let senses = event.into();
|
let senses = event.into();
|
||||||
if let Some(group) = self.map.get(id) {
|
if let Some(group) = self.map.get_mut(&id) {
|
||||||
let fs: Vec<_> = group
|
let fs: Vec<_> = group
|
||||||
.sensors
|
.sensors
|
||||||
.iter()
|
.iter_mut()
|
||||||
.filter_map(|sensor| {
|
.filter_map(|sensor| {
|
||||||
if sensor.senses.iter().any(|s| senses.contains(s)) {
|
if sensor.senses.iter().any(|s| senses.contains(s)) {
|
||||||
Some(sensor.f.clone())
|
Some(&mut sensor.f)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Some(move |ctx: EventCtx<Ctx, CursorData>| {
|
Some(move |ctx: EventCtx<Ctx, CursorData>| {
|
||||||
for f in &fs {
|
for f in fs {
|
||||||
f(EventCtx {
|
f(EventCtx {
|
||||||
state: ctx.state,
|
state: ctx.state,
|
||||||
ui: ctx.ui,
|
ui: ctx.ui,
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ pub struct TextView {
|
|||||||
// cache
|
// cache
|
||||||
tex: Option<RenderedText>,
|
tex: Option<RenderedText>,
|
||||||
width: Option<f32>,
|
width: Option<f32>,
|
||||||
pub hint: Option<WidgetRef>,
|
pub hint: Option<WidgetHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextView {
|
impl TextView {
|
||||||
pub fn new(buf: TextBuffer, attrs: TextAttrs, hint: Option<WidgetRef>) -> Self {
|
pub fn new(buf: TextBuffer, attrs: TextAttrs, hint: Option<WidgetHandle>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
attrs: attrs.into(),
|
attrs: attrs.into(),
|
||||||
buf: buf.into(),
|
buf: buf.into(),
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ widget_trait! {
|
|||||||
|ui| self.add(ui)
|
|ui| self.add(ui)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_ptr(self, ptr: &WidgetRef<WidgetPtr>, ui: &mut Ui) {
|
fn set_ptr(self, ptr: &WidgetHandle<WidgetPtr>, ui: &mut Ui) {
|
||||||
ptr.get_mut().inner = Some(self.add(ui));
|
ptr.get_mut().inner = Some(self.add(ui));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user