move everything out of layout

This commit is contained in:
2025-12-11 05:48:29 -05:00
parent 174c447706
commit a85e129026
48 changed files with 142 additions and 160 deletions

View File

@@ -1,8 +1,8 @@
use crate::layout::{Ui, WidgetId, WidgetIdFn, WidgetLike};
use crate::{Ui, WidgetHandle, WidgetIdFn, WidgetLike};
pub trait WidgetAttr<W> {
type Input;
fn run(ui: &mut Ui, id: &WidgetId<W>, input: Self::Input);
fn run(ui: &mut Ui, id: &WidgetHandle<W>, input: Self::Input);
}
pub trait Attrable<W, Tag> {

View File

@@ -1,7 +1,7 @@
use std::{hash::Hash, rc::Rc};
use crate::{
layout::{Ui, UiModule, WeakWidgetId, WidgetId},
Ui, UiModule, WidgetHandle, WidgetView,
util::{HashMap, Id},
};
@@ -18,7 +18,7 @@ pub struct EventCtx<'a, Ctx, Data> {
pub type ECtx<'a, Ctx, Data, W> = EventIdCtx<'a, Ctx, Data, W>;
pub struct EventIdCtx<'a, Ctx, Data, W> {
pub id: &'a WeakWidgetId<W>,
pub id: &'a WidgetView<W>,
pub ui: &'a mut Ui,
pub state: &'a mut Ctx,
pub data: Data,
@@ -129,7 +129,7 @@ impl Ui {
pub fn run_event<E: Event, Ctx: 'static, W>(
&mut self,
ctx: &mut Ctx,
id: &WidgetId<W>,
id: &WidgetHandle<W>,
event: E,
data: E::Data,
) {

View File

@@ -1,21 +0,0 @@
mod attr;
mod event;
mod module;
mod num;
mod orientation;
mod painter;
mod primitive;
mod ui;
mod widget;
pub use attr::*;
pub use event::*;
pub use module::*;
pub use num::*;
pub use orientation::*;
pub use painter::*;
pub use primitive::*;
pub use ui::*;
pub use widget::*;
pub type UiColor = Color<u8>;

View File

@@ -12,6 +12,28 @@
#![feature(unsize)]
#![feature(coerce_unsized)]
pub mod layout;
pub mod render;
mod attr;
mod event;
mod module;
mod num;
mod orientation;
mod painter;
mod primitive;
mod render;
mod ui;
mod widget;
pub mod util;
pub use attr::*;
pub use event::*;
pub use module::*;
pub use num::*;
pub use orientation::*;
pub use painter::*;
pub use primitive::*;
pub use render::*;
pub use ui::*;
pub use widget::*;
pub type UiColor = primitive::Color<u8>;

View File

@@ -1,16 +1,16 @@
use std::any::{Any, TypeId};
use crate::{
layout::WidgetInstance,
ActiveData,
util::{HashMap, Id},
};
#[allow(unused_variables)]
pub trait UiModule: Any {
fn on_draw(&mut self, inst: &WidgetInstance) {}
fn on_undraw(&mut self, inst: &WidgetInstance) {}
fn on_draw(&mut self, inst: &ActiveData) {}
fn on_undraw(&mut self, inst: &ActiveData) {}
fn on_remove(&mut self, id: &Id) {}
fn on_move(&mut self, inst: &WidgetInstance) {}
fn on_move(&mut self, inst: &ActiveData) {}
}
#[derive(Default)]

View File

@@ -1,4 +1,4 @@
use crate::layout::vec2;
use crate::vec2;
use super::*;

View File

@@ -1,5 +1,5 @@
use super::*;
use crate::{layout::UiNum, util::impl_op};
use crate::{UiNum, util::impl_op};
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct Size {

View File

@@ -2,7 +2,7 @@ use std::{fmt::Display, hash::Hash, marker::Destruct};
use super::*;
use crate::{
layout::UiNum,
UiNum,
util::{LerpUtil, impl_op},
};

View File

@@ -1,8 +1,6 @@
use crate::{
layout::{
Axis, Len, Modules, PrimitiveLayers, RenderedText, Size, TextAttrs, TextBuffer, TextData,
TextureHandle, Textures, UiRegion, UiVec2, WidgetId, Widgets,
},
Axis, Len, Modules, PrimitiveLayers, RenderedText, Size, TextAttrs, TextBuffer, TextData,
TextureHandle, Textures, UiRegion, UiVec2, WidgetHandle, Widgets,
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
util::{HashMap, HashSet, Id, TrackedArena, Vec2},
};
@@ -24,7 +22,7 @@ pub struct Painter<'a, 'c> {
/// context for a painter; lets you draw and redraw widgets
struct PainterCtx<'a> {
pub widgets: &'a Widgets,
pub active: &'a mut HashMap<Id, WidgetInstance>,
pub active: &'a mut HashMap<Id, ActiveData>,
pub layers: &'a mut PrimitiveLayers,
pub textures: &'a mut Textures,
pub masks: &'a mut TrackedArena<Mask, u32>,
@@ -47,7 +45,7 @@ pub struct ResizeRef {
/// important non rendering data for retained drawing
#[derive(Debug)]
pub struct WidgetInstance {
pub struct ActiveData {
pub id: Id,
pub region: UiRegion,
pub parent: Option<Id>,
@@ -63,7 +61,7 @@ pub struct WidgetInstance {
#[derive(Default)]
pub struct PainterData {
pub widgets: Widgets,
pub active: HashMap<Id, WidgetInstance>,
pub active: HashMap<Id, ActiveData>,
pub layers: PrimitiveLayers,
pub textures: Textures,
pub text: TextData,
@@ -233,7 +231,7 @@ impl<'a> PainterCtx<'a> {
let children_height = painter.children_height;
// add to active
let instance = WidgetInstance {
let instance = ActiveData {
id,
region,
parent,
@@ -293,7 +291,7 @@ impl<'a> PainterCtx<'a> {
}
/// NOTE: instance textures are cleared and self.textures freed
fn remove(&mut self, id: Id) -> Option<WidgetInstance> {
fn remove(&mut self, id: Id) -> Option<ActiveData> {
let mut inst = self.active.remove(&id);
if let Some(inst) = &mut inst {
for h in &inst.primitives {
@@ -311,7 +309,7 @@ impl<'a> PainterCtx<'a> {
inst
}
fn remove_rec(&mut self, id: Id) -> Option<WidgetInstance> {
fn remove_rec(&mut self, id: Id) -> Option<ActiveData> {
let inst = self.remove(id);
if let Some(inst) = &inst {
for c in &inst.children {
@@ -389,17 +387,17 @@ impl<'a, 'c> Painter<'a, 'c> {
}
/// Draws a widget within this widget's region.
pub fn widget<W>(&mut self, id: &WidgetId<W>) {
pub fn widget<W>(&mut self, id: &WidgetHandle<W>) {
self.widget_at(id, self.region);
}
/// Draws a widget somewhere within this one.
/// Useful for drawing child widgets in select areas.
pub fn widget_within<W>(&mut self, id: &WidgetId<W>, region: UiRegion) {
pub fn widget_within<W>(&mut self, id: &WidgetHandle<W>, region: UiRegion) {
self.widget_at(id, region.within(&self.region));
}
fn widget_at<W>(&mut self, id: &WidgetId<W>, region: UiRegion) {
fn widget_at<W>(&mut self, id: &WidgetHandle<W>, region: UiRegion) {
self.children.push(id.id());
self.ctx
.draw_inner(self.layer, id.id(), region, Some(self.id), self.mask, None);
@@ -429,11 +427,11 @@ impl<'a, 'c> Painter<'a, 'c> {
self.region
}
pub fn size<W>(&mut self, id: &WidgetId<W>) -> Size {
pub fn size<W>(&mut self, id: &WidgetHandle<W>) -> Size {
self.size_ctx().size(id)
}
pub fn len_axis<W>(&mut self, id: &WidgetId<W>, axis: Axis) -> Len {
pub fn len_axis<W>(&mut self, id: &WidgetHandle<W>, axis: Axis) -> Len {
match axis {
Axis::X => self.size_ctx().width(id),
Axis::Y => self.size_ctx().height(id),
@@ -552,22 +550,22 @@ impl SizeCtx<'_> {
len
}
pub fn width<W>(&mut self, id: &WidgetId<W>) -> Len {
pub fn width<W>(&mut self, id: &WidgetHandle<W>) -> Len {
self.width_inner(id.id())
}
pub fn height<W>(&mut self, id: &WidgetId<W>) -> Len {
pub fn height<W>(&mut self, id: &WidgetHandle<W>) -> Len {
self.height_inner(id.id())
}
pub fn len_axis<W>(&mut self, id: &WidgetId<W>, axis: Axis) -> Len {
pub fn len_axis<W>(&mut self, id: &WidgetHandle<W>, axis: Axis) -> Len {
match axis {
Axis::X => self.width(id),
Axis::Y => self.height(id),
}
}
pub fn size<W>(&mut self, id: &WidgetId<W>) -> Size {
pub fn size<W>(&mut self, id: &WidgetHandle<W>) -> Size {
Size {
x: self.width(id),
y: self.height(id),

View File

@@ -1,7 +1,4 @@
use crate::{
layout::{Align, RegionAlign, TextureHandle, Textures, UiColor},
util::Vec2,
};
use crate::{Align, RegionAlign, TextureHandle, Textures, UiColor, util::Vec2};
use cosmic_text::{
Attrs, AttrsList, Buffer, CacheKey, Color, Family, FontSystem, Metrics, Placement, SwashCache,
SwashContent,

View File

@@ -1,4 +1,4 @@
use crate::{layout::UiRegion, util::Id};
use crate::{UiRegion, util::Id};
use wgpu::*;
#[repr(C)]

View File

@@ -1,7 +1,7 @@
use std::num::NonZero;
use crate::{
layout::Ui,
Ui,
render::{data::PrimitiveInstance, texture::GpuTextures, util::ArrBuf},
util::HashMap,
};

View File

@@ -1,7 +1,7 @@
use std::ops::{Deref, DerefMut};
use crate::{
layout::{Color, UiRegion},
Color, UiRegion,
render::{
ArrBuf,
data::{MaskIdx, PrimitiveInstance},

View File

@@ -1,7 +1,7 @@
use image::{DynamicImage, EncodableLayout};
use wgpu::{util::DeviceExt, *};
use crate::layout::{TextureUpdate, Textures};
use crate::{TextureUpdate, Textures};
pub struct GpuTextures {
device: Device,

View File

@@ -1,8 +1,6 @@
use crate::{
layout::{
Event, EventFn, EventModule, IdLike, PainterData, PixelRegion, TextureHandle, Widget,
WidgetId, WidgetInstance, WidgetLike,
},
ActiveData, Event, EventFn, EventModule, IdLike, PainterData, PixelRegion, TextureHandle,
Widget, WidgetHandle, WidgetLike,
util::{Id, Vec2},
};
use image::DynamicImage;
@@ -15,7 +13,7 @@ use std::{
pub struct Ui {
// TODO: make this at least pub(super)
pub data: PainterData,
root: Option<WidgetId>,
root: Option<WidgetHandle>,
recv: Receiver<Id>,
pub(super) send: Sender<Id>,
full_redraw: bool,
@@ -23,24 +21,24 @@ pub struct Ui {
}
impl Ui {
pub fn add<W: Widget, Tag>(&mut self, w: impl WidgetLike<Tag, Widget = W>) -> WidgetId<W> {
pub fn add<W: Widget, Tag>(&mut self, w: impl WidgetLike<Tag, Widget = W>) -> WidgetHandle<W> {
w.add(self)
}
/// useful for debugging
pub fn set_label<W>(&mut self, id: &WidgetId<W>, label: String) {
pub fn set_label<W>(&mut self, id: &WidgetHandle<W>, label: String) {
self.data.widgets.data_mut(&id.id()).unwrap().label = label;
}
pub fn label<W>(&self, id: &WidgetId<W>) -> &String {
pub fn label<W>(&self, id: &WidgetHandle<W>) -> &String {
&self.data.widgets.data(&id.id()).unwrap().label
}
pub fn add_widget<W: Widget>(&mut self, w: W) -> WidgetId<W> {
pub fn add_widget<W: Widget>(&mut self, w: W) -> WidgetHandle<W> {
self.push(w)
}
pub fn push<W: Widget>(&mut self, w: W) -> WidgetId<W> {
pub fn push<W: Widget>(&mut self, w: W) -> WidgetHandle<W> {
let id = self.new_id();
self.data.widgets.insert(id.id(), w);
id
@@ -63,8 +61,8 @@ impl Ui {
self.data.widgets.get_mut(id)
}
fn new_id<W: Widget>(&mut self) -> WidgetId<W> {
WidgetId::new(
fn new_id<W: Widget>(&mut self) -> WidgetHandle<W> {
WidgetHandle::new(
self.data.widgets.reserve(),
TypeId::of::<W>(),
self.send.clone(),
@@ -77,7 +75,7 @@ impl Ui {
pub fn register_event<W, E: Event, Ctx: 'static>(
&mut self,
id: &WidgetId<W>,
id: &WidgetHandle<W>,
event: E,
f: impl EventFn<Ctx, E::Data>,
) {
@@ -165,7 +163,7 @@ impl Ui {
Some(region.to_px(self.data.output_size))
}
pub fn debug(&self, label: &str) -> impl Iterator<Item = &WidgetInstance> {
pub fn debug(&self, label: &str) -> impl Iterator<Item = &ActiveData> {
self.data.active.iter().filter_map(move |(id, inst)| {
let l = &self.data.widgets.label(id);
if *l == label { Some(inst) } else { None }

View File

@@ -1,7 +1,7 @@
use std::{any::TypeId, marker::PhantomData, sync::mpsc::Sender};
use crate::{
layout::{Ui, Widget},
Ui, Widget,
util::{Id, RefCounter},
};
@@ -16,7 +16,7 @@ pub struct AnyWidget;
///
/// TODO: ergonomic clones when they get put in rust-analyzer & don't cause ICEs?
#[repr(C)]
pub struct WidgetId<W = AnyWidget> {
pub struct WidgetHandle<W = AnyWidget> {
pub(super) ty: TypeId,
pub(super) id: Id,
counter: RefCounter,
@@ -25,7 +25,7 @@ pub struct WidgetId<W = AnyWidget> {
}
#[repr(C)]
pub struct WeakWidgetId<W = AnyWidget> {
pub struct WidgetView<W = AnyWidget> {
pub(super) ty: TypeId,
pub(super) id: Id,
counter: RefCounter,
@@ -33,19 +33,19 @@ pub struct WeakWidgetId<W = AnyWidget> {
_pd: PhantomData<W>,
}
impl<W> PartialEq for WidgetId<W> {
impl<W> PartialEq for WidgetHandle<W> {
fn eq(&self, other: &Self) -> bool {
self.ty == other.ty && self.id == other.id
}
}
impl<W> std::fmt::Debug for WidgetId<W> {
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> Clone for WidgetId<W> {
impl<W> Clone for WidgetHandle<W> {
fn clone(&self) -> Self {
Self {
id: self.id,
@@ -57,7 +57,7 @@ impl<W> Clone for WidgetId<W> {
}
}
impl<W> WidgetId<W> {
impl<W> WidgetHandle<W> {
pub(crate) fn new(id: Id, ty: TypeId, send: Sender<Id>) -> Self {
Self {
ty,
@@ -68,11 +68,11 @@ impl<W> WidgetId<W> {
}
}
pub fn any(self) -> WidgetId<AnyWidget> {
pub fn any(self) -> WidgetHandle<AnyWidget> {
self.cast_type()
}
pub fn as_any(&self) -> &WidgetId<AnyWidget> {
pub fn as_any(&self) -> &WidgetHandle<AnyWidget> {
// SAFETY: self is repr(C) and generic only used for phantom data
unsafe { std::mem::transmute(self) }
}
@@ -81,7 +81,7 @@ impl<W> WidgetId<W> {
self.id
}
pub(super) fn cast_type<W2>(self) -> WidgetId<W2> {
pub(super) fn cast_type<W2>(self) -> WidgetHandle<W2> {
// SAFETY: self is repr(C) and generic only used for phantom data
unsafe { std::mem::transmute(self) }
}
@@ -90,7 +90,7 @@ impl<W> WidgetId<W> {
self.counter.refs()
}
pub fn weak(&self) -> WeakWidgetId<W> {
pub fn weak(&self) -> WidgetView<W> {
let Self {
ty,
id,
@@ -98,7 +98,7 @@ impl<W> WidgetId<W> {
ref send,
_pd,
} = *self;
WeakWidgetId {
WidgetView {
ty,
id,
counter: counter.quiet_clone(),
@@ -108,7 +108,7 @@ impl<W> WidgetId<W> {
}
}
impl<W> Drop for WidgetId<W> {
impl<W> Drop for WidgetHandle<W> {
fn drop(&mut self) {
if self.counter.drop() {
let _ = self.send.send(self.id);
@@ -116,18 +116,18 @@ impl<W> Drop for WidgetId<W> {
}
}
pub trait WidgetIdFn<W>: FnOnce(&mut Ui) -> WidgetId<W> {}
impl<W, F: FnOnce(&mut Ui) -> WidgetId<W>> WidgetIdFn<W> for F {}
pub trait WidgetIdFn<W>: FnOnce(&mut Ui) -> WidgetHandle<W> {}
impl<W, F: FnOnce(&mut Ui) -> WidgetHandle<W>> WidgetIdFn<W> for F {}
pub trait WidgetRet: FnOnce(&mut Ui) -> WidgetId<AnyWidget> {}
impl<F: FnOnce(&mut Ui) -> WidgetId<AnyWidget>> WidgetRet for F {}
pub trait WidgetRet: FnOnce(&mut Ui) -> WidgetHandle<AnyWidget> {}
impl<F: FnOnce(&mut Ui) -> WidgetHandle<AnyWidget>> WidgetRet for F {}
pub trait WidgetIdLike<W> {
fn id(self, send: &Sender<Id>) -> WidgetId<W>;
fn id(self, send: &Sender<Id>) -> WidgetHandle<W>;
}
impl<W> WidgetIdLike<W> for &WidgetId<W> {
fn id(self, _: &Sender<Id>) -> WidgetId<W> {
impl<W> WidgetIdLike<W> for &WidgetHandle<W> {
fn id(self, _: &Sender<Id>) -> WidgetHandle<W> {
self.clone()
}
}
@@ -137,14 +137,14 @@ pub trait IdLike {
fn id(&self) -> Id;
}
impl<W: Widget> IdLike for WidgetId<W> {
impl<W: Widget> IdLike for WidgetHandle<W> {
type Widget = W;
fn id(&self) -> Id {
self.id
}
}
impl<W: Widget> IdLike for WeakWidgetId<W> {
impl<W: Widget> IdLike for WidgetView<W> {
type Widget = W;
fn id(&self) -> Id {
self.id

View File

@@ -3,11 +3,11 @@ use super::*;
pub trait WidgetLike<Tag> {
type Widget: 'static;
fn add(self, ui: &mut Ui) -> WidgetId<Self::Widget>;
fn add(self, ui: &mut Ui) -> WidgetHandle<Self::Widget>;
fn with_id<W2>(
self,
f: impl FnOnce(&mut Ui, WidgetId<Self::Widget>) -> WidgetId<W2>,
f: impl FnOnce(&mut Ui, WidgetHandle<Self::Widget>) -> WidgetHandle<W2>,
) -> impl WidgetIdFn<W2>
where
Self: Sized,

View File

@@ -1,4 +1,4 @@
use crate::layout::{Len, Painter, SizeCtx, Ui};
use crate::{Len, Painter, SizeCtx, Ui};
use std::{any::Any, marker::PhantomData};
mod id;
@@ -34,12 +34,12 @@ pub trait WidgetFn<W: Widget>: FnOnce(&mut Ui) -> W {}
impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetFn<W> for F {}
pub struct WidgetArr<const LEN: usize, Ws> {
pub arr: [WidgetId; LEN],
pub arr: [WidgetHandle; LEN],
_pd: PhantomData<Ws>,
}
impl<const LEN: usize, Ws> WidgetArr<LEN, Ws> {
pub fn new(arr: [WidgetId; LEN]) -> Self {
pub fn new(arr: [WidgetHandle; LEN]) -> Self {
Self {
arr,
_pd: PhantomData,
@@ -48,17 +48,17 @@ impl<const LEN: usize, Ws> WidgetArr<LEN, Ws> {
}
pub trait WidgetOption {
fn get(self, ui: &mut Ui) -> Option<WidgetId>;
fn get(self, ui: &mut Ui) -> Option<WidgetHandle>;
}
impl WidgetOption for () {
fn get(self, _: &mut Ui) -> Option<WidgetId> {
fn get(self, _: &mut Ui) -> Option<WidgetHandle> {
None
}
}
impl<F: FnOnce(&mut Ui) -> Option<WidgetId>> WidgetOption for F {
fn get(self, ui: &mut Ui) -> Option<WidgetId> {
impl<F: FnOnce(&mut Ui) -> Option<WidgetHandle>> WidgetOption for F {
fn get(self, ui: &mut Ui) -> Option<WidgetHandle> {
self(ui)
}
}

View File

@@ -5,7 +5,7 @@ pub struct ArrTag;
pub struct WidgetTag;
impl<W: Widget> WidgetLike<WidgetTag> for W {
type Widget = W;
fn add(self, ui: &mut Ui) -> WidgetId<W> {
fn add(self, ui: &mut Ui) -> WidgetHandle<W> {
ui.add_widget(self)
}
}
@@ -13,23 +13,23 @@ impl<W: Widget> WidgetLike<WidgetTag> for W {
pub struct FnTag;
impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetLike<FnTag> for F {
type Widget = W;
fn add(self, ui: &mut Ui) -> WidgetId<W> {
fn add(self, ui: &mut Ui) -> WidgetHandle<W> {
self(ui).add(ui)
}
}
pub struct IdTag;
impl<W: 'static> WidgetLike<IdTag> for WidgetId<W> {
impl<W: 'static> WidgetLike<IdTag> for WidgetHandle<W> {
type Widget = W;
fn add(self, _: &mut Ui) -> WidgetId<W> {
fn add(self, _: &mut Ui) -> WidgetHandle<W> {
self
}
}
pub struct IdFnTag;
impl<W: 'static, F: FnOnce(&mut Ui) -> WidgetId<W>> WidgetLike<IdFnTag> for F {
impl<W: 'static, F: FnOnce(&mut Ui) -> WidgetHandle<W>> WidgetLike<IdFnTag> for F {
type Widget = W;
fn add(self, ui: &mut Ui) -> WidgetId<W> {
fn add(self, ui: &mut Ui) -> WidgetHandle<W> {
self(ui)
}
}

View File

@@ -1,5 +1,5 @@
use crate::{
layout::{IdLike, Widget},
IdLike, Widget,
util::{DynBorrower, HashMap, HashSet, Id, IdTracker},
};