refactor project structure (start of redoing atomic branch without atomics)
This commit is contained in:
28
Cargo.lock
generated
28
Cargo.lock
generated
@@ -1042,16 +1042,36 @@ name = "iris"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arboard",
|
"arboard",
|
||||||
"bytemuck",
|
|
||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
"fxhash",
|
|
||||||
"image",
|
"image",
|
||||||
|
"iris-core",
|
||||||
|
"iris-macro",
|
||||||
"pollster",
|
"pollster",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iris-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"cosmic-text",
|
||||||
|
"fxhash",
|
||||||
|
"image",
|
||||||
|
"wgpu",
|
||||||
|
"winit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iris-macro"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@@ -2401,9 +2421,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.110"
|
version = "2.0.111"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
|
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
27
Cargo.toml
27
Cargo.toml
@@ -1,12 +1,30 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "iris"
|
name = "iris"
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
default-run = "test"
|
default-run = "test"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
iris-core = { workspace = true }
|
||||||
|
iris-macro = { workspace = true }
|
||||||
|
cosmic-text = { workspace = true }
|
||||||
|
unicode-segmentation = { workspace = true }
|
||||||
|
winit = { workspace = true }
|
||||||
|
arboard = { workspace = true, features = ["wayland-data-control"] }
|
||||||
|
pollster = { workspace = true }
|
||||||
|
wgpu = { workspace = true }
|
||||||
|
image = { workspace = true }
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ["core", "macro"]
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
winit = "0.30.12"
|
winit = "0.30.12"
|
||||||
wgpu = "27.0.1"
|
wgpu = "27.0.1"
|
||||||
@@ -15,5 +33,6 @@ image = "0.25.6"
|
|||||||
cosmic-text = "0.15.0"
|
cosmic-text = "0.15.0"
|
||||||
unicode-segmentation = "1.12.0"
|
unicode-segmentation = "1.12.0"
|
||||||
fxhash = "0.2.1"
|
fxhash = "0.2.1"
|
||||||
arboard = { version = "3.6.1", features = ["wayland-data-control"] }
|
arboard = "3.6.1"
|
||||||
|
iris-core = { path = "core" }
|
||||||
|
iris-macro = { path = "macro" }
|
||||||
|
|||||||
12
core/Cargo.toml
Normal file
12
core/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "iris-core"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
winit = { workspace = true }
|
||||||
|
wgpu = { workspace = true }
|
||||||
|
bytemuck ={ workspace = true }
|
||||||
|
image = { workspace = true }
|
||||||
|
cosmic-text = { workspace = true }
|
||||||
|
fxhash = { workspace = true }
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{hash::Hash, rc::Rc};
|
use std::{hash::Hash, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{IdFnTag, Ui, UiModule, WidgetId, WidgetIdFn, WidgetLike},
|
layout::{Ui, UiModule, WeakWidgetId, WidgetId},
|
||||||
util::{HashMap, Id},
|
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 type ECtx<'a, Ctx, Data, W> = EventIdCtx<'a, Ctx, Data, W>;
|
||||||
pub struct EventIdCtx<'a, Ctx, Data, W> {
|
pub struct EventIdCtx<'a, Ctx, Data, W> {
|
||||||
pub id: &'a WidgetId<W>,
|
pub id: &'a WeakWidgetId<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,
|
||||||
@@ -30,74 +30,8 @@ impl<F: Fn(EventCtx<Ctx, Data>) + 'static, Ctx, Data> EventFn<Ctx, Data> for F {
|
|||||||
pub trait WidgetEventFn<Ctx, Data, W>: Fn(EventIdCtx<Ctx, Data, W>) + 'static {}
|
pub trait WidgetEventFn<Ctx, Data, W>: Fn(EventIdCtx<Ctx, Data, W>) + 'static {}
|
||||||
impl<F: Fn(EventIdCtx<Ctx, Data, W>) + 'static, Ctx, Data, W> WidgetEventFn<Ctx, Data, W> for F {}
|
impl<F: Fn(EventIdCtx<Ctx, Data, W>) + 'static, Ctx, Data, W> WidgetEventFn<Ctx, Data, W> for F {}
|
||||||
|
|
||||||
// TODO: naming in here is a bit weird like eventable
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! event_ctx {
|
|
||||||
($ty: ty) => {
|
|
||||||
mod local_event_trait {
|
|
||||||
use super::*;
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
use $crate::prelude::*;
|
|
||||||
|
|
||||||
pub trait EventableCtx<W, Tag, Ctx: 'static> {
|
|
||||||
fn on<E: Event>(
|
|
||||||
self,
|
|
||||||
event: E,
|
|
||||||
f: impl WidgetEventFn<Ctx, E::Data, W>,
|
|
||||||
) -> impl WidgetIdFn<W> + EventableCtx<W, IdFnTag, Ctx>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<WL: WidgetLike<Tag>, Tag> EventableCtx<WL::Widget, Tag, $ty> for WL {
|
|
||||||
fn on<E: Event>(
|
|
||||||
self,
|
|
||||||
event: E,
|
|
||||||
f: impl WidgetEventFn<$ty, E::Data, WL::Widget>,
|
|
||||||
) -> impl WidgetIdFn<WL::Widget> + EventableCtx<WL::Widget, IdFnTag, $ty> {
|
|
||||||
eventable::Eventable::on(self, event, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
use local_event_trait::*;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub use event_ctx;
|
|
||||||
|
|
||||||
pub mod eventable {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub trait Eventable<W, Tag> {
|
|
||||||
fn on<E: Event, Ctx: 'static>(
|
|
||||||
self,
|
|
||||||
event: E,
|
|
||||||
f: impl WidgetEventFn<Ctx, E::Data, W>,
|
|
||||||
) -> impl WidgetIdFn<W> + Eventable<W, IdFnTag>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<WL: WidgetLike<Tag>, Tag> Eventable<WL::Widget, Tag> for WL {
|
|
||||||
fn on<E: Event, Ctx: 'static>(
|
|
||||||
self,
|
|
||||||
event: E,
|
|
||||||
f: impl WidgetEventFn<Ctx, E::Data, WL::Widget>,
|
|
||||||
) -> impl WidgetIdFn<WL::Widget> {
|
|
||||||
move |ui| {
|
|
||||||
let id = self.add(ui);
|
|
||||||
let id_ = id.weak();
|
|
||||||
ui.register_event(&id, event, move |ctx| {
|
|
||||||
f(EventIdCtx {
|
|
||||||
id: &id_.strong(),
|
|
||||||
state: ctx.state,
|
|
||||||
data: ctx.data,
|
|
||||||
ui: ctx.ui,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DefaultEvent: Hash + Eq + 'static {
|
pub trait DefaultEvent: Hash + Eq + 'static {
|
||||||
type Data: Clone;
|
type Data: Clone = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: DefaultEvent> Event for E {
|
impl<E: DefaultEvent> Event for E {
|
||||||
@@ -203,7 +137,7 @@ impl Ui {
|
|||||||
.data
|
.data
|
||||||
.modules
|
.modules
|
||||||
.get_mut::<E::Module<Ctx>>()
|
.get_mut::<E::Module<Ctx>>()
|
||||||
.run(&id.id, event)
|
.run(&id.id(), event)
|
||||||
{
|
{
|
||||||
f(EventCtx {
|
f(EventCtx {
|
||||||
ui: self,
|
ui: self,
|
||||||
@@ -1,33 +1,21 @@
|
|||||||
mod color;
|
mod attr;
|
||||||
mod event;
|
mod event;
|
||||||
mod id;
|
|
||||||
mod layer;
|
|
||||||
mod module;
|
mod module;
|
||||||
mod num;
|
mod num;
|
||||||
mod orientation;
|
mod orientation;
|
||||||
mod painter;
|
mod painter;
|
||||||
mod text;
|
mod primitive;
|
||||||
mod texture;
|
|
||||||
mod ui;
|
mod ui;
|
||||||
mod attr;
|
|
||||||
mod vec2;
|
|
||||||
mod widget;
|
mod widget;
|
||||||
mod widgets;
|
|
||||||
|
|
||||||
pub use color::*;
|
pub use attr::*;
|
||||||
pub use event::*;
|
pub use event::*;
|
||||||
pub use id::*;
|
|
||||||
pub use layer::*;
|
|
||||||
pub use module::*;
|
pub use module::*;
|
||||||
pub use num::*;
|
pub use num::*;
|
||||||
pub use orientation::*;
|
pub use orientation::*;
|
||||||
pub use painter::*;
|
pub use painter::*;
|
||||||
pub use text::*;
|
pub use primitive::*;
|
||||||
pub use texture::*;
|
|
||||||
pub use ui::*;
|
pub use ui::*;
|
||||||
pub use attr::*;
|
|
||||||
pub use vec2::*;
|
|
||||||
pub use widget::*;
|
pub use widget::*;
|
||||||
pub use widgets::*;
|
|
||||||
|
|
||||||
pub type UiColor = Color<u8>;
|
pub type UiColor = Color<u8>;
|
||||||
49
core/src/layout/num.rs
Normal file
49
core/src/layout/num.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use crate::util::Vec2;
|
||||||
|
use std::marker::Destruct;
|
||||||
|
|
||||||
|
pub const trait UiNum {
|
||||||
|
fn to_f32(self) -> f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl const UiNum for f32 {
|
||||||
|
fn to_f32(self) -> f32 {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl const UiNum for u32 {
|
||||||
|
fn to_f32(self) -> f32 {
|
||||||
|
self as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl const UiNum for i32 {
|
||||||
|
fn to_f32(self) -> f32 {
|
||||||
|
self as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn vec2(x: impl const UiNum, y: impl const UiNum) -> Vec2 {
|
||||||
|
Vec2::new(x.to_f32(), y.to_f32())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: const UiNum + Copy> const From<T> for Vec2 {
|
||||||
|
fn from(v: T) -> Self {
|
||||||
|
Self {
|
||||||
|
x: v.to_f32(),
|
||||||
|
y: v.to_f32(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: const UiNum, U: const UiNum> const From<(T, U)> for Vec2
|
||||||
|
where
|
||||||
|
(T, U): const Destruct,
|
||||||
|
{
|
||||||
|
fn from((x, y): (T, U)) -> Self {
|
||||||
|
Self {
|
||||||
|
x: x.to_f32(),
|
||||||
|
y: y.to_f32(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ mod axis;
|
|||||||
mod len;
|
mod len;
|
||||||
mod pos;
|
mod pos;
|
||||||
|
|
||||||
use super::vec2::*;
|
use crate::util::Vec2;
|
||||||
|
|
||||||
pub use align::*;
|
pub use align::*;
|
||||||
pub use axis::*;
|
pub use axis::*;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
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, WidgetId, Widgets,
|
TextureHandle, Textures, UiRegion, UiVec2, WidgetId, Widgets,
|
||||||
},
|
},
|
||||||
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
||||||
util::{HashMap, HashSet, Id, TrackedArena},
|
util::{HashMap, HashSet, Id, TrackedArena, Vec2},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// makes your surfaces look pretty
|
/// makes your surfaces look pretty
|
||||||
@@ -33,7 +33,7 @@ struct PainterCtx<'a> {
|
|||||||
pub modules: &'a mut Modules,
|
pub modules: &'a mut Modules,
|
||||||
pub cache_width: HashMap<Id, (UiVec2, Len)>,
|
pub cache_width: HashMap<Id, (UiVec2, Len)>,
|
||||||
pub cache_height: HashMap<Id, (UiVec2, Len)>,
|
pub cache_height: HashMap<Id, (UiVec2, Len)>,
|
||||||
pub needs_redraw: HashSet<Id>,
|
pub needs_redraw: &'a mut HashSet<Id>,
|
||||||
draw_started: HashSet<Id>,
|
draw_started: HashSet<Id>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ impl<'a> PainterCtx<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PainterData {
|
impl PainterData {
|
||||||
fn ctx(&mut self, needs_redraw: HashSet<Id>) -> PainterCtx<'_> {
|
fn ctx<'a>(&'a mut self, needs_redraw: &'a mut HashSet<Id>) -> PainterCtx<'a> {
|
||||||
PainterCtx {
|
PainterCtx {
|
||||||
widgets: &self.widgets,
|
widgets: &self.widgets,
|
||||||
active: &mut self.active,
|
active: &mut self.active,
|
||||||
@@ -341,13 +341,14 @@ impl PainterData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self, id: Id) {
|
pub fn draw(&mut self, id: Id) {
|
||||||
let mut ctx = self.ctx(Default::default());
|
let mut need_redraw = HashSet::default();
|
||||||
|
let mut ctx = self.ctx(&mut need_redraw);
|
||||||
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: &mut HashSet<Id>) {
|
||||||
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(id);
|
ctx.redraw(id);
|
||||||
@@ -399,9 +400,9 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn widget_at<W>(&mut self, id: &WidgetId<W>, region: UiRegion) {
|
fn widget_at<W>(&mut self, id: &WidgetId<W>, region: UiRegion) {
|
||||||
self.children.push(id.id);
|
self.children.push(id.id());
|
||||||
self.ctx
|
self.ctx
|
||||||
.draw_inner(self.layer, id.id, region, Some(self.id), self.mask, None);
|
.draw_inner(self.layer, id.id(), region, Some(self.id), self.mask, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {
|
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {
|
||||||
@@ -552,11 +553,11 @@ impl SizeCtx<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn width<W>(&mut self, id: &WidgetId<W>) -> Len {
|
pub fn width<W>(&mut self, id: &WidgetId<W>) -> Len {
|
||||||
self.width_inner(id.id)
|
self.width_inner(id.id())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height<W>(&mut self, id: &WidgetId<W>) -> Len {
|
pub fn height<W>(&mut self, id: &WidgetId<W>) -> Len {
|
||||||
self.height_inner(id.id)
|
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: &WidgetId<W>, axis: Axis) -> Len {
|
||||||
9
core/src/layout/primitive/mod.rs
Normal file
9
core/src/layout/primitive/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
mod color;
|
||||||
|
mod layer;
|
||||||
|
mod text;
|
||||||
|
mod texture;
|
||||||
|
|
||||||
|
pub use color::*;
|
||||||
|
pub use layer::*;
|
||||||
|
pub use text::*;
|
||||||
|
pub use texture::*;
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
use std::simd::{Simd, num::SimdUint};
|
use crate::{
|
||||||
|
layout::{Align, RegionAlign, TextureHandle, Textures, UiColor},
|
||||||
use crate::layout::{Align, RegionAlign, TextureHandle, Textures, UiColor, Vec2};
|
util::Vec2,
|
||||||
|
};
|
||||||
use cosmic_text::{
|
use cosmic_text::{
|
||||||
Attrs, AttrsList, Buffer, CacheKey, Color, Family, FontSystem, Metrics, Placement, SwashCache,
|
Attrs, AttrsList, Buffer, CacheKey, Color, Family, FontSystem, Metrics, Placement, SwashCache,
|
||||||
SwashContent,
|
SwashContent,
|
||||||
};
|
};
|
||||||
use image::{GenericImageView, RgbaImage};
|
use image::{GenericImageView, RgbaImage};
|
||||||
|
use std::simd::{Simd, num::SimdUint};
|
||||||
|
|
||||||
/// TODO: properly wrap this
|
/// TODO: properly wrap this
|
||||||
pub mod text_lib {
|
pub mod text_lib {
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
|
use crate::{
|
||||||
|
render::TexturePrimitive,
|
||||||
|
util::{RefCounter, Vec2},
|
||||||
|
};
|
||||||
|
use image::{DynamicImage, GenericImageView};
|
||||||
use std::{
|
use std::{
|
||||||
ops::Index,
|
ops::Index,
|
||||||
sync::mpsc::{Receiver, Sender, channel},
|
sync::mpsc::{Receiver, Sender, channel},
|
||||||
};
|
};
|
||||||
|
|
||||||
use image::{DynamicImage, GenericImageView};
|
|
||||||
|
|
||||||
use crate::{layout::Vec2, render::TexturePrimitive, util::RefCounter};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TextureHandle {
|
pub struct TextureHandle {
|
||||||
inner: TexturePrimitive,
|
inner: TexturePrimitive,
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
use image::DynamicImage;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{TextEdit, TextEditCtx},
|
|
||||||
layout::{
|
layout::{
|
||||||
Event, EventFn, EventModule, IdLike, PainterData, PixelRegion, TextureHandle, Vec2, Widget,
|
Event, EventFn, EventModule, IdLike, PainterData, PixelRegion, TextureHandle, Widget,
|
||||||
WidgetId, WidgetInstance, WidgetLike,
|
WidgetId, WidgetInstance, WidgetLike,
|
||||||
},
|
},
|
||||||
util::{HashSet, Id},
|
util::{Id, Vec2},
|
||||||
};
|
};
|
||||||
|
use image::DynamicImage;
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
ops::{Index, IndexMut},
|
ops::{Index, IndexMut},
|
||||||
@@ -16,9 +14,8 @@ use std::{
|
|||||||
|
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
// TODO: make this at least pub(super)
|
// TODO: make this at least pub(super)
|
||||||
pub(crate) data: PainterData,
|
pub data: PainterData,
|
||||||
root: Option<WidgetId>,
|
root: Option<WidgetId>,
|
||||||
updates: HashSet<Id>,
|
|
||||||
recv: Receiver<Id>,
|
recv: Receiver<Id>,
|
||||||
pub(super) send: Sender<Id>,
|
pub(super) send: Sender<Id>,
|
||||||
full_redraw: bool,
|
full_redraw: bool,
|
||||||
@@ -32,11 +29,11 @@ impl Ui {
|
|||||||
|
|
||||||
/// useful for debugging
|
/// useful for debugging
|
||||||
pub fn set_label<W>(&mut self, id: &WidgetId<W>, label: String) {
|
pub fn set_label<W>(&mut self, id: &WidgetId<W>, label: String) {
|
||||||
self.data.widgets.data_mut(&id.id).unwrap().label = label;
|
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: &WidgetId<W>) -> &String {
|
||||||
&self.data.widgets.data(&id.id).unwrap().label
|
&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) -> WidgetId<W> {
|
||||||
@@ -45,7 +42,7 @@ impl Ui {
|
|||||||
|
|
||||||
pub fn push<W: Widget>(&mut self, w: W) -> WidgetId<W> {
|
pub fn push<W: Widget>(&mut self, w: W) -> WidgetId<W> {
|
||||||
let id = self.new_id();
|
let id = self.new_id();
|
||||||
self.data.widgets.insert(id.id, w);
|
self.data.widgets.insert(id.id(), w);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,11 +55,11 @@ impl Ui {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<W: Widget>(&self, id: &impl IdLike<W>) -> Option<&W> {
|
pub fn get<I: IdLike>(&self, id: &I) -> Option<&I::Widget> {
|
||||||
self.data.widgets.get(id)
|
self.data.widgets.get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut<W: Widget>(&mut self, id: &impl IdLike<W>) -> Option<&mut W> {
|
pub fn get_mut<I: IdLike>(&mut self, id: &I) -> Option<&mut I::Widget> {
|
||||||
self.data.widgets.get_mut(id)
|
self.data.widgets.get_mut(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +84,7 @@ impl Ui {
|
|||||||
self.data
|
self.data
|
||||||
.modules
|
.modules
|
||||||
.get_mut::<E::Module<Ctx>>()
|
.get_mut::<E::Module<Ctx>>()
|
||||||
.register(id.id, event, f);
|
.register(id.id(), event, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, size: impl Into<Vec2>) {
|
pub fn resize(&mut self, size: impl Into<Vec2>) {
|
||||||
@@ -104,7 +101,7 @@ impl Ui {
|
|||||||
// free before bc nothing should exist
|
// free before bc nothing should exist
|
||||||
self.free();
|
self.free();
|
||||||
if let Some(root) = &self.root {
|
if let Some(root) = &self.root {
|
||||||
self.data.draw(root.id);
|
self.data.draw(root.id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,26 +109,19 @@ impl Ui {
|
|||||||
if self.full_redraw {
|
if self.full_redraw {
|
||||||
self.redraw_all();
|
self.redraw_all();
|
||||||
self.full_redraw = false;
|
self.full_redraw = false;
|
||||||
} else if !self.updates.is_empty() {
|
} else if self.data.widgets.has_updates() {
|
||||||
self.redraw_updates();
|
self.redraw_updates();
|
||||||
}
|
}
|
||||||
if self.resized {
|
if self.resized {
|
||||||
self.resized = false;
|
self.resized = false;
|
||||||
self.redraw_size();
|
self.redraw_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn redraw_size(&mut self) {
|
|
||||||
// let mut ctx = PainterCtx::new(&mut self.data);
|
|
||||||
// let dep = ctx.px_dependent.clone();
|
|
||||||
// for id in dep {
|
|
||||||
// ctx.redraw(id);
|
|
||||||
// }
|
|
||||||
self.redraw_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn redraw_updates(&mut self) {
|
fn redraw_updates(&mut self) {
|
||||||
self.data.redraw(std::mem::take(&mut self.updates));
|
let mut updates = std::mem::take(&mut self.data.widgets.updates);
|
||||||
|
self.data.redraw(&mut updates);
|
||||||
|
self.data.widgets.updates = updates;
|
||||||
self.free();
|
self.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +137,7 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn needs_redraw(&self) -> bool {
|
pub fn needs_redraw(&self) -> bool {
|
||||||
self.full_redraw || !self.updates.is_empty()
|
self.full_redraw || self.data.widgets.has_updates()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_widgets(&self) -> usize {
|
pub fn num_widgets(&self) -> usize {
|
||||||
@@ -158,14 +148,6 @@ impl Ui {
|
|||||||
self.data.active.len()
|
self.data.active.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text(&mut self, id: &impl IdLike<TextEdit>) -> TextEditCtx<'_> {
|
|
||||||
self.updates.insert(id.id());
|
|
||||||
TextEditCtx {
|
|
||||||
text: self.data.widgets.get_mut(id).unwrap(),
|
|
||||||
font_system: &mut self.data.text.font_system,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn debug_layers(&self) {
|
pub fn debug_layers(&self) {
|
||||||
for ((idx, depth), primitives) in self.data.layers.iter_depth() {
|
for ((idx, depth), primitives) in self.data.layers.iter_depth() {
|
||||||
let indent = " ".repeat(depth * 2);
|
let indent = " ".repeat(depth * 2);
|
||||||
@@ -178,7 +160,7 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_region<W>(&self, id: &impl IdLike<W>) -> Option<PixelRegion> {
|
pub fn window_region(&self, id: &impl IdLike) -> Option<PixelRegion> {
|
||||||
let region = self.data.active.get(&id.id())?.region;
|
let region = self.data.active.get(&id.id())?.region;
|
||||||
Some(region.to_px(self.data.output_size))
|
Some(region.to_px(self.data.output_size))
|
||||||
}
|
}
|
||||||
@@ -191,17 +173,16 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget> Index<&WidgetId<W>> for Ui {
|
impl<I: IdLike> Index<&I> for Ui {
|
||||||
type Output = W;
|
type Output = I::Widget;
|
||||||
|
|
||||||
fn index(&self, id: &WidgetId<W>) -> &Self::Output {
|
fn index(&self, id: &I) -> &Self::Output {
|
||||||
self.get(id).unwrap()
|
self.get(id).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Widget> IndexMut<&WidgetId<W>> for Ui {
|
impl<I: IdLike> IndexMut<&I> for Ui {
|
||||||
fn index_mut(&mut self, id: &WidgetId<W>) -> &mut Self::Output {
|
fn index_mut(&mut self, id: &I) -> &mut Self::Output {
|
||||||
self.updates.insert(id.id);
|
|
||||||
self.get_mut(id).unwrap()
|
self.get_mut(id).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +203,6 @@ impl Default for Ui {
|
|||||||
Self {
|
Self {
|
||||||
data: PainterData::default(),
|
data: PainterData::default(),
|
||||||
root: Default::default(),
|
root: Default::default(),
|
||||||
updates: Default::default(),
|
|
||||||
full_redraw: false,
|
full_redraw: false,
|
||||||
send,
|
send,
|
||||||
recv,
|
recv,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{any::TypeId, marker::PhantomData, sync::mpsc::Sender};
|
use std::{any::TypeId, marker::PhantomData, sync::mpsc::Sender};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{Ui, WidgetLike},
|
layout::{Ui, Widget},
|
||||||
util::{Id, RefCounter},
|
util::{Id, RefCounter},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ impl<W> Clone for WidgetId<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<W> WidgetId<W> {
|
impl<W> WidgetId<W> {
|
||||||
pub(super) fn new(id: Id, ty: TypeId, send: Sender<Id>) -> Self {
|
pub(crate) fn new(id: Id, ty: TypeId, send: Sender<Id>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ty,
|
ty,
|
||||||
id,
|
id,
|
||||||
@@ -77,7 +77,7 @@ impl<W> WidgetId<W> {
|
|||||||
unsafe { std::mem::transmute(self) }
|
unsafe { std::mem::transmute(self) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key(&self) -> Id {
|
pub fn id(&self) -> Id {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,26 +108,6 @@ impl<W> WidgetId<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W> WeakWidgetId<W> {
|
|
||||||
/// should guarantee that widget is still valid to prevent indexing failures
|
|
||||||
pub(crate) fn strong(&self) -> WidgetId<W> {
|
|
||||||
let Self {
|
|
||||||
ty,
|
|
||||||
id,
|
|
||||||
ref counter,
|
|
||||||
ref send,
|
|
||||||
_pd,
|
|
||||||
} = *self;
|
|
||||||
WidgetId {
|
|
||||||
ty,
|
|
||||||
id,
|
|
||||||
counter: counter.clone(),
|
|
||||||
send: send.clone(),
|
|
||||||
_pd,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W> Drop for WidgetId<W> {
|
impl<W> Drop for WidgetId<W> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.counter.drop() {
|
if self.counter.drop() {
|
||||||
@@ -136,29 +116,12 @@ impl<W> Drop for WidgetId<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IdTag;
|
|
||||||
pub struct IdFnTag;
|
|
||||||
|
|
||||||
pub trait WidgetIdFn<W>: FnOnce(&mut Ui) -> WidgetId<W> {}
|
pub trait WidgetIdFn<W>: FnOnce(&mut Ui) -> WidgetId<W> {}
|
||||||
impl<W, F: FnOnce(&mut Ui) -> WidgetId<W>> WidgetIdFn<W> for F {}
|
impl<W, F: FnOnce(&mut Ui) -> WidgetId<W>> WidgetIdFn<W> for F {}
|
||||||
|
|
||||||
pub trait WidgetRet: FnOnce(&mut Ui) -> WidgetId<AnyWidget> {}
|
pub trait WidgetRet: FnOnce(&mut Ui) -> WidgetId<AnyWidget> {}
|
||||||
impl<F: FnOnce(&mut Ui) -> WidgetId<AnyWidget>> WidgetRet for F {}
|
impl<F: FnOnce(&mut Ui) -> WidgetId<AnyWidget>> WidgetRet for F {}
|
||||||
|
|
||||||
impl<W: 'static> WidgetLike<IdTag> for WidgetId<W> {
|
|
||||||
type Widget = W;
|
|
||||||
fn add(self, _: &mut Ui) -> WidgetId<W> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: 'static, F: FnOnce(&mut Ui) -> WidgetId<W>> WidgetLike<IdFnTag> for F {
|
|
||||||
type Widget = W;
|
|
||||||
fn add(self, ui: &mut Ui) -> WidgetId<W> {
|
|
||||||
self(ui)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait WidgetIdLike<W> {
|
pub trait WidgetIdLike<W> {
|
||||||
fn id(self, send: &Sender<Id>) -> WidgetId<W>;
|
fn id(self, send: &Sender<Id>) -> WidgetId<W>;
|
||||||
}
|
}
|
||||||
@@ -169,11 +132,20 @@ impl<W> WidgetIdLike<W> for &WidgetId<W> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IdLike<W> {
|
pub trait IdLike {
|
||||||
|
type Widget: Widget + 'static;
|
||||||
fn id(&self) -> Id;
|
fn id(&self) -> Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W> IdLike<W> for WidgetId<W> {
|
impl<W: Widget> IdLike for WidgetId<W> {
|
||||||
|
type Widget = W;
|
||||||
|
fn id(&self) -> Id {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: Widget> IdLike for WeakWidgetId<W> {
|
||||||
|
type Widget = W;
|
||||||
fn id(&self) -> Id {
|
fn id(&self) -> Id {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,4 @@
|
|||||||
use crate::{
|
use super::*;
|
||||||
core::WidgetPtr,
|
|
||||||
layout::{Len, Painter, SizeCtx, Ui, WidgetId, WidgetIdFn},
|
|
||||||
};
|
|
||||||
|
|
||||||
use std::{any::Any, marker::PhantomData};
|
|
||||||
|
|
||||||
pub trait Widget: Any {
|
|
||||||
fn draw(&mut self, painter: &mut Painter);
|
|
||||||
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len;
|
|
||||||
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for () {
|
|
||||||
fn draw(&mut self, _: &mut Painter) {}
|
|
||||||
fn desired_width(&mut self, _: &mut SizeCtx) -> Len {
|
|
||||||
Len::ZERO
|
|
||||||
}
|
|
||||||
fn desired_height(&mut self, _: &mut SizeCtx) -> Len {
|
|
||||||
Len::ZERO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WidgetTag;
|
|
||||||
pub struct FnTag;
|
|
||||||
|
|
||||||
pub trait WidgetLike<Tag> {
|
pub trait WidgetLike<Tag> {
|
||||||
type Widget: 'static;
|
type Widget: 'static;
|
||||||
@@ -48,50 +24,8 @@ pub trait WidgetLike<Tag> {
|
|||||||
{
|
{
|
||||||
ui.set_root(self);
|
ui.set_root(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_ptr(self, ptr: &WidgetId<WidgetPtr>, ui: &mut Ui)
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
ui[ptr].inner = Some(self.add(ui).any());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A function that returns a widget given a UI.
|
|
||||||
/// Useful for defining trait functions on widgets that create a parent widget so that the children
|
|
||||||
/// don't need to be IDs yet
|
|
||||||
pub trait WidgetFn<W: Widget>: FnOnce(&mut Ui) -> W {}
|
|
||||||
impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetFn<W> for F {}
|
|
||||||
|
|
||||||
impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetLike<FnTag> for F {
|
|
||||||
type Widget = W;
|
|
||||||
fn add(self, ui: &mut Ui) -> WidgetId<W> {
|
|
||||||
self(ui).add(ui)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Widget> WidgetLike<WidgetTag> for W {
|
|
||||||
type Widget = W;
|
|
||||||
fn add(self, ui: &mut Ui) -> WidgetId<W> {
|
|
||||||
ui.add_widget(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WidgetArr<const LEN: usize, Ws> {
|
|
||||||
pub arr: [WidgetId; LEN],
|
|
||||||
_pd: PhantomData<Ws>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const LEN: usize, Ws> WidgetArr<LEN, Ws> {
|
|
||||||
pub fn new(arr: [WidgetId; LEN]) -> Self {
|
|
||||||
Self {
|
|
||||||
arr,
|
|
||||||
_pd: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ArrTag;
|
|
||||||
pub trait WidgetArrLike<const LEN: usize, Tag> {
|
pub trait WidgetArrLike<const LEN: usize, Tag> {
|
||||||
type Ws;
|
type Ws;
|
||||||
fn ui(self, ui: &mut Ui) -> WidgetArr<LEN, Self::Ws>;
|
fn ui(self, ui: &mut Ui) -> WidgetArr<LEN, Self::Ws>;
|
||||||
@@ -142,19 +76,3 @@ impl_widget_arr!(9;A B C D E F G H I);
|
|||||||
impl_widget_arr!(10;A B C D E F G H I J);
|
impl_widget_arr!(10;A B C D E F G H I J);
|
||||||
impl_widget_arr!(11;A B C D E F G H I J K);
|
impl_widget_arr!(11;A B C D E F G H I J K);
|
||||||
impl_widget_arr!(12;A B C D E F G H I J K L);
|
impl_widget_arr!(12;A B C D E F G H I J K L);
|
||||||
|
|
||||||
pub trait WidgetOption {
|
|
||||||
fn get(self, ui: &mut Ui) -> Option<WidgetId>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WidgetOption for () {
|
|
||||||
fn get(self, _: &mut Ui) -> Option<WidgetId> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: FnOnce(&mut Ui) -> Option<WidgetId>> WidgetOption for F {
|
|
||||||
fn get(self, ui: &mut Ui) -> Option<WidgetId> {
|
|
||||||
self(ui)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
64
core/src/layout/widget/mod.rs
Normal file
64
core/src/layout/widget/mod.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
use crate::layout::{Len, Painter, SizeCtx, Ui};
|
||||||
|
use std::{any::Any, marker::PhantomData};
|
||||||
|
|
||||||
|
mod id;
|
||||||
|
mod like;
|
||||||
|
mod tag;
|
||||||
|
mod widgets;
|
||||||
|
|
||||||
|
pub use id::*;
|
||||||
|
pub use like::*;
|
||||||
|
pub use tag::*;
|
||||||
|
pub use widgets::*;
|
||||||
|
|
||||||
|
pub trait Widget: Any {
|
||||||
|
fn draw(&mut self, painter: &mut Painter);
|
||||||
|
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len;
|
||||||
|
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Widget for () {
|
||||||
|
fn draw(&mut self, _: &mut Painter) {}
|
||||||
|
fn desired_width(&mut self, _: &mut SizeCtx) -> Len {
|
||||||
|
Len::ZERO
|
||||||
|
}
|
||||||
|
fn desired_height(&mut self, _: &mut SizeCtx) -> Len {
|
||||||
|
Len::ZERO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A function that returns a widget given a UI.
|
||||||
|
/// Useful for defining trait functions on widgets that create a parent widget so that the children
|
||||||
|
/// don't need to be IDs yet
|
||||||
|
pub trait WidgetFn<W: Widget>: FnOnce(&mut Ui) -> W {}
|
||||||
|
impl<W: Widget, F: FnOnce(&mut Ui) -> W> WidgetFn<W> for F {}
|
||||||
|
|
||||||
|
pub struct WidgetArr<const LEN: usize, Ws> {
|
||||||
|
pub arr: [WidgetId; LEN],
|
||||||
|
_pd: PhantomData<Ws>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const LEN: usize, Ws> WidgetArr<LEN, Ws> {
|
||||||
|
pub fn new(arr: [WidgetId; LEN]) -> Self {
|
||||||
|
Self {
|
||||||
|
arr,
|
||||||
|
_pd: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WidgetOption {
|
||||||
|
fn get(self, ui: &mut Ui) -> Option<WidgetId>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetOption for () {
|
||||||
|
fn get(self, _: &mut Ui) -> Option<WidgetId> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: FnOnce(&mut Ui) -> Option<WidgetId>> WidgetOption for F {
|
||||||
|
fn get(self, ui: &mut Ui) -> Option<WidgetId> {
|
||||||
|
self(ui)
|
||||||
|
}
|
||||||
|
}
|
||||||
36
core/src/layout/widget/tag.rs
Normal file
36
core/src/layout/widget/tag.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct ArrTag;
|
||||||
|
|
||||||
|
pub struct WidgetTag;
|
||||||
|
impl<W: Widget> WidgetLike<WidgetTag> for W {
|
||||||
|
type Widget = W;
|
||||||
|
fn add(self, ui: &mut Ui) -> WidgetId<W> {
|
||||||
|
ui.add_widget(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
self(ui).add(ui)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IdTag;
|
||||||
|
impl<W: 'static> WidgetLike<IdTag> for WidgetId<W> {
|
||||||
|
type Widget = W;
|
||||||
|
fn add(self, _: &mut Ui) -> WidgetId<W> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IdFnTag;
|
||||||
|
impl<W: 'static, F: FnOnce(&mut Ui) -> WidgetId<W>> WidgetLike<IdFnTag> for F {
|
||||||
|
type Widget = W;
|
||||||
|
fn add(self, ui: &mut Ui) -> WidgetId<W> {
|
||||||
|
self(ui)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layout::{IdLike, Widget},
|
layout::{IdLike, Widget},
|
||||||
util::{DynBorrower, HashMap, Id, IdTracker},
|
util::{DynBorrower, HashMap, HashSet, Id, IdTracker},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Widgets {
|
pub struct Widgets {
|
||||||
|
pub updates: HashSet<Id>,
|
||||||
ids: IdTracker,
|
ids: IdTracker,
|
||||||
map: HashMap<Id, WidgetData>,
|
map: HashMap<Id, WidgetData>,
|
||||||
}
|
}
|
||||||
@@ -17,11 +18,8 @@ pub struct WidgetData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Widgets {
|
impl Widgets {
|
||||||
pub fn new() -> Self {
|
pub fn has_updates(&self) -> bool {
|
||||||
Self {
|
!self.updates.is_empty()
|
||||||
ids: IdTracker::default(),
|
|
||||||
map: HashMap::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_dyn(&self, id: Id) -> Option<&dyn Widget> {
|
pub fn get_dyn(&self, id: Id) -> Option<&dyn Widget> {
|
||||||
@@ -29,6 +27,7 @@ impl Widgets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_dyn_mut(&mut self, id: Id) -> Option<&mut dyn Widget> {
|
pub fn get_dyn_mut(&mut self, id: Id) -> Option<&mut dyn Widget> {
|
||||||
|
self.updates.insert(id);
|
||||||
Some(self.map.get_mut(&id)?.widget.as_mut())
|
Some(self.map.get_mut(&id)?.widget.as_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,11 +46,11 @@ impl Widgets {
|
|||||||
WidgetWrapper::new(data.widget.as_mut(), &mut data.borrowed)
|
WidgetWrapper::new(data.widget.as_mut(), &mut data.borrowed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get<W: Widget>(&self, id: &impl IdLike<W>) -> Option<&W> {
|
pub fn get<I: IdLike>(&self, id: &I) -> Option<&I::Widget> {
|
||||||
self.get_dyn(id.id())?.as_any().downcast_ref()
|
self.get_dyn(id.id())?.as_any().downcast_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut<W: Widget>(&mut self, id: &impl IdLike<W>) -> Option<&mut W> {
|
pub fn get_mut<I: IdLike>(&mut self, id: &I) -> Option<&mut I::Widget> {
|
||||||
self.get_dyn_mut(id.id())?.as_any_mut().downcast_mut()
|
self.get_dyn_mut(id.id())?.as_any_mut().downcast_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
17
core/src/lib.rs
Normal file
17
core/src/lib.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#![feature(macro_metavar_expr_concat)]
|
||||||
|
#![feature(const_ops)]
|
||||||
|
#![feature(const_trait_impl)]
|
||||||
|
#![feature(const_convert)]
|
||||||
|
#![feature(map_try_insert)]
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
#![feature(fn_traits)]
|
||||||
|
#![feature(const_cmp)]
|
||||||
|
#![feature(const_destruct)]
|
||||||
|
#![feature(portable_simd)]
|
||||||
|
#![feature(associated_type_defaults)]
|
||||||
|
#![feature(unsize)]
|
||||||
|
#![feature(coerce_unsized)]
|
||||||
|
|
||||||
|
pub mod layout;
|
||||||
|
pub mod render;
|
||||||
|
pub mod util;
|
||||||
@@ -4,13 +4,15 @@ mod change;
|
|||||||
mod id;
|
mod id;
|
||||||
mod math;
|
mod math;
|
||||||
mod refcount;
|
mod refcount;
|
||||||
|
mod vec2;
|
||||||
|
|
||||||
pub(crate) use arena::*;
|
pub use arena::*;
|
||||||
pub(crate) use borrow::*;
|
pub use borrow::*;
|
||||||
pub use change::*;
|
pub use change::*;
|
||||||
pub(crate) use id::*;
|
pub use id::*;
|
||||||
pub(crate) use math::*;
|
pub use math::*;
|
||||||
pub(crate) use refcount::*;
|
pub use refcount::*;
|
||||||
|
pub use vec2::*;
|
||||||
|
|
||||||
pub type HashMap<K, V> = fxhash::FxHashMap<K, V>;
|
pub type HashMap<K, V> = fxhash::FxHashMap<K, V>;
|
||||||
pub type HashSet<K> = fxhash::FxHashSet<K>;
|
pub type HashSet<K> = fxhash::FxHashSet<K>;
|
||||||
@@ -22,6 +22,12 @@ impl RefCounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for RefCounter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Clone for RefCounter {
|
impl Clone for RefCounter {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
self.0.fetch_add(1, Ordering::Release);
|
self.0.fetch_add(1, Ordering::Release);
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
use crate::{
|
use crate::util::{DivOr, impl_op};
|
||||||
layout::UiNum,
|
use std::{hash::Hash, ops::*};
|
||||||
util::{DivOr, impl_op},
|
|
||||||
};
|
|
||||||
use std::{hash::Hash, marker::Destruct, ops::*};
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, PartialEq, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Clone, Copy, PartialEq, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
@@ -20,10 +17,6 @@ impl Hash for Vec2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn vec2(x: impl const UiNum, y: impl const UiNum) -> Vec2 {
|
|
||||||
Vec2::new(x.to_f32(), y.to_f32())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vec2 {
|
impl Vec2 {
|
||||||
pub const ZERO: Self = Self::new(0.0, 0.0);
|
pub const ZERO: Self = Self::new(0.0, 0.0);
|
||||||
pub const ONE: Self = Self::new(1.0, 1.0);
|
pub const ONE: Self = Self::new(1.0, 1.0);
|
||||||
@@ -68,15 +61,6 @@ impl Vec2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: const UiNum + Copy> const From<T> for Vec2 {
|
|
||||||
fn from(v: T) -> Self {
|
|
||||||
Self {
|
|
||||||
x: v.to_f32(),
|
|
||||||
y: v.to_f32(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this version looks kinda cool... is it more readable? more annoying to copy and change though
|
// this version looks kinda cool... is it more readable? more annoying to copy and change though
|
||||||
impl_op!(impl Add for Vec2: add x y);
|
impl_op!(impl Add for Vec2: add x y);
|
||||||
impl_op!(Vec2 Sub sub; x y);
|
impl_op!(Vec2 Sub sub; x y);
|
||||||
@@ -102,18 +86,6 @@ impl Neg for Vec2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: const UiNum, U: const UiNum> const From<(T, U)> for Vec2
|
|
||||||
where
|
|
||||||
(T, U): const Destruct,
|
|
||||||
{
|
|
||||||
fn from((x, y): (T, U)) -> Self {
|
|
||||||
Self {
|
|
||||||
x: x.to_f32(),
|
|
||||||
y: y.to_f32(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for Vec2 {
|
impl std::fmt::Debug for Vec2 {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "({}, {})", self.x, self.y)
|
write!(f, "({}, {})", self.x, self.y)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use iris::{prelude::*, winit::*};
|
use iris::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
DefaultApp::<State>::run();
|
DefaultApp::<State>::run();
|
||||||
|
|||||||
11
macro/Cargo.toml
Normal file
11
macro/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "iris-macro"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1.0.42"
|
||||||
|
syn = { version = "2.0.111", features = ["full"] }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
77
macro/src/lib.rs
Normal file
77
macro/src/lib.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
extern crate proc_macro;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{
|
||||||
|
Attribute, Block, Ident, ItemTrait, Signature, Token, Visibility,
|
||||||
|
parse::{Parse, ParseStream, Result},
|
||||||
|
parse_macro_input, parse_quote,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Input {
|
||||||
|
attrs: Vec<Attribute>,
|
||||||
|
vis: Visibility,
|
||||||
|
name: Ident,
|
||||||
|
fns: Vec<InputFn>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InputFn {
|
||||||
|
sig: Signature,
|
||||||
|
body: Block,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Input {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let attrs = input.call(Attribute::parse_outer)?;
|
||||||
|
let vis = input.parse()?;
|
||||||
|
input.parse::<Token![trait]>()?;
|
||||||
|
let name = input.parse()?;
|
||||||
|
input.parse::<Token![;]>()?;
|
||||||
|
let mut fns = Vec::new();
|
||||||
|
while !input.is_empty() {
|
||||||
|
let sig = input.parse()?;
|
||||||
|
let body = input.parse()?;
|
||||||
|
fns.push(InputFn { sig, body })
|
||||||
|
}
|
||||||
|
if !input.is_empty() {
|
||||||
|
input.error("function expected");
|
||||||
|
}
|
||||||
|
Ok(Input {
|
||||||
|
attrs,
|
||||||
|
vis,
|
||||||
|
name,
|
||||||
|
fns,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn widget_trait(input: TokenStream) -> TokenStream {
|
||||||
|
let Input {
|
||||||
|
attrs,
|
||||||
|
vis,
|
||||||
|
name,
|
||||||
|
fns,
|
||||||
|
} = parse_macro_input!(input as Input);
|
||||||
|
|
||||||
|
let sigs: Vec<_> = fns.iter().map(|f| f.sig.clone()).collect();
|
||||||
|
let impls: Vec<_> = fns
|
||||||
|
.iter()
|
||||||
|
.map(|InputFn { sig, body }| quote! { #sig #body })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut trai: ItemTrait = parse_quote!(
|
||||||
|
#vis trait #name<WL: WidgetLike<Tag>, Tag> {
|
||||||
|
#(#sigs;)*
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
trai.attrs = attrs;
|
||||||
|
|
||||||
|
TokenStream::from(quote! {
|
||||||
|
#trai
|
||||||
|
|
||||||
|
impl<WL: WidgetLike<Tag>, Tag> #name<WL, Tag> for WL {
|
||||||
|
#(#impls)*
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
use cosmic_text::Family;
|
use cosmic_text::Family;
|
||||||
use iris::{
|
use iris::prelude::*;
|
||||||
prelude::*,
|
|
||||||
winit::{attr::Selectable, event::Submit, *},
|
|
||||||
};
|
|
||||||
use len_fns::*;
|
use len_fns::*;
|
||||||
use winit::event::WindowEvent;
|
use winit::event::WindowEvent;
|
||||||
|
|
||||||
@@ -110,7 +107,7 @@ impl DefaultAppState for Client {
|
|||||||
.size(30)
|
.size(30)
|
||||||
.attr::<Selectable>(())
|
.attr::<Selectable>(())
|
||||||
.on(Submit, move |ctx| {
|
.on(Submit, move |ctx| {
|
||||||
let content = ctx.ui.text(ctx.id).take();
|
let content = ctx.id.edit(ctx.ui).take();
|
||||||
let text = wtext(content)
|
let text = wtext(content)
|
||||||
.editable(false)
|
.editable(false)
|
||||||
.size(30)
|
.size(30)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::{prelude::*, winit::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};
|
||||||
|
|
||||||
pub struct Selector;
|
pub struct Selector;
|
||||||
|
|
||||||
impl<W: 'static> WidgetAttr<W> for Selector {
|
impl<W: 'static + Widget> WidgetAttr<W> for Selector {
|
||||||
type Input = WidgetId<TextEdit>;
|
type Input = WidgetId<TextEdit>;
|
||||||
|
|
||||||
fn run(ui: &mut Ui, container: &WidgetId<W>, id: Self::Input) {
|
fn run(ui: &mut Ui, container: &WidgetId<W>, id: Self::Input) {
|
||||||
@@ -42,7 +42,7 @@ fn select(ui: &mut Ui, id: WidgetId<TextEdit>, state: &mut UiState, data: Cursor
|
|||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let recent = (now - state.last_click) < Duration::from_millis(300);
|
let recent = (now - state.last_click) < Duration::from_millis(300);
|
||||||
state.last_click = now;
|
state.last_click = now;
|
||||||
ui.text(&id)
|
id.edit(ui)
|
||||||
.select(data.cursor, data.size, data.sense.is_dragging(), recent);
|
.select(data.cursor, data.size, data.sense.is_dragging(), recent);
|
||||||
if let Some(region) = ui.window_region(&id) {
|
if let Some(region) = ui.window_region(&id) {
|
||||||
state.window.set_ime_allowed(true);
|
state.window.set_ime_allowed(true);
|
||||||
@@ -2,14 +2,8 @@ use crate::layout::DefaultEvent;
|
|||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Clone)]
|
#[derive(Eq, PartialEq, Hash, Clone)]
|
||||||
pub struct Submit;
|
pub struct Submit;
|
||||||
|
impl DefaultEvent for Submit {}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Clone)]
|
#[derive(Eq, PartialEq, Hash, Clone)]
|
||||||
pub struct Edited;
|
pub struct Edited;
|
||||||
|
impl DefaultEvent for Edited {}
|
||||||
impl DefaultEvent for Submit {
|
|
||||||
type Data = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DefaultEvent for Edited {
|
|
||||||
type Data = ();
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
use crate::{
|
use crate::prelude::*;
|
||||||
core::{CursorState, Modifiers},
|
|
||||||
layout::Vec2,
|
|
||||||
winit::UiState,
|
|
||||||
};
|
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{MouseButton, MouseScrollDelta, WindowEvent},
|
event::{MouseButton, MouseScrollDelta, WindowEvent},
|
||||||
keyboard::{Key, NamedKey},
|
keyboard::{Key, NamedKey},
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::winit::event::{Edited, Submit};
|
|
||||||
use crate::winit::{input::Input, render::UiRenderer};
|
|
||||||
use arboard::Clipboard;
|
use arboard::Clipboard;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
@@ -9,12 +7,16 @@ use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
|
|||||||
use winit::window::{Window, WindowAttributes};
|
use winit::window::{Window, WindowAttributes};
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
pub mod attr;
|
mod attr;
|
||||||
pub mod event;
|
mod event;
|
||||||
pub mod input;
|
mod input;
|
||||||
pub mod render;
|
mod render;
|
||||||
|
|
||||||
pub use app::*;
|
pub use app::*;
|
||||||
|
pub use attr::*;
|
||||||
|
pub use event::*;
|
||||||
|
pub use input::*;
|
||||||
|
pub use render::*;
|
||||||
|
|
||||||
pub type Proxy<Event> = EventLoopProxy<Event>;
|
pub type Proxy<Event> = EventLoopProxy<Event>;
|
||||||
pub type DefaultApp<Data> = App<DefaultState<Data>>;
|
pub type DefaultApp<Data> = App<DefaultState<Data>>;
|
||||||
@@ -105,7 +107,7 @@ impl<State: DefaultAppState> AppState for DefaultState<State> {
|
|||||||
if old != ui_state.focus
|
if old != ui_state.focus
|
||||||
&& let Some(old) = old
|
&& let Some(old) = old
|
||||||
{
|
{
|
||||||
ui.text(&old).deselect();
|
old.edit(ui).deselect();
|
||||||
}
|
}
|
||||||
match &event {
|
match &event {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
@@ -123,7 +125,7 @@ impl<State: DefaultAppState> AppState for DefaultState<State> {
|
|||||||
&& event.state.is_pressed()
|
&& event.state.is_pressed()
|
||||||
{
|
{
|
||||||
let sel = &sel.clone();
|
let sel = &sel.clone();
|
||||||
let mut text = ui.text(sel);
|
let mut text = sel.edit(ui);
|
||||||
match text.apply_event(event, &ui_state.input.modifiers) {
|
match text.apply_event(event, &ui_state.input.modifiers) {
|
||||||
TextInputResult::Unfocus => {
|
TextInputResult::Unfocus => {
|
||||||
ui_state.focus = None;
|
ui_state.focus = None;
|
||||||
@@ -152,7 +154,7 @@ impl<State: DefaultAppState> AppState for DefaultState<State> {
|
|||||||
}
|
}
|
||||||
WindowEvent::Ime(ime) => {
|
WindowEvent::Ime(ime) => {
|
||||||
if let Some(sel) = &ui_state.focus {
|
if let Some(sel) = &ui_state.focus {
|
||||||
let mut text = ui.text(sel);
|
let mut text = sel.edit(ui);
|
||||||
match ime {
|
match ime {
|
||||||
Ime::Enabled | Ime::Disabled => (),
|
Ime::Enabled | Ime::Disabled => (),
|
||||||
Ime::Preedit(content, _pos) => {
|
Ime::Preedit(content, _pos) => {
|
||||||
67
src/event.rs
Normal file
67
src/event.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
// TODO: naming in here is a bit weird like eventable
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! event_ctx {
|
||||||
|
($ty: ty) => {
|
||||||
|
mod local_event_trait {
|
||||||
|
use super::*;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use $crate::prelude::*;
|
||||||
|
|
||||||
|
pub trait EventableCtx<W, Tag, Ctx: 'static> {
|
||||||
|
fn on<E: Event>(
|
||||||
|
self,
|
||||||
|
event: E,
|
||||||
|
f: impl WidgetEventFn<Ctx, E::Data, W>,
|
||||||
|
) -> impl WidgetIdFn<W> + EventableCtx<W, IdFnTag, Ctx>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<WL: WidgetLike<Tag>, Tag> EventableCtx<WL::Widget, Tag, $ty> for WL {
|
||||||
|
fn on<E: Event>(
|
||||||
|
self,
|
||||||
|
event: E,
|
||||||
|
f: impl WidgetEventFn<$ty, E::Data, WL::Widget>,
|
||||||
|
) -> impl WidgetIdFn<WL::Widget> + EventableCtx<WL::Widget, IdFnTag, $ty> {
|
||||||
|
eventable::Eventable::on(self, event, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use local_event_trait::*;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub use event_ctx;
|
||||||
|
|
||||||
|
pub mod eventable {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub trait Eventable<W, Tag> {
|
||||||
|
fn on<E: Event, Ctx: 'static>(
|
||||||
|
self,
|
||||||
|
event: E,
|
||||||
|
f: impl WidgetEventFn<Ctx, E::Data, W>,
|
||||||
|
) -> impl WidgetIdFn<W> + Eventable<W, IdFnTag>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<WL: WidgetLike<Tag>, Tag> Eventable<WL::Widget, Tag> for WL {
|
||||||
|
fn on<E: Event, Ctx: 'static>(
|
||||||
|
self,
|
||||||
|
event: E,
|
||||||
|
f: impl WidgetEventFn<Ctx, E::Data, WL::Widget>,
|
||||||
|
) -> impl WidgetIdFn<WL::Widget> {
|
||||||
|
move |ui| {
|
||||||
|
let id = self.add(ui);
|
||||||
|
let id_ = id.weak();
|
||||||
|
ui.register_event(&id, event, move |ctx| {
|
||||||
|
f(EventIdCtx {
|
||||||
|
id: &id_,
|
||||||
|
state: ctx.state,
|
||||||
|
data: ctx.data,
|
||||||
|
ui: ctx.ui,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
//! tree structure for masking
|
|
||||||
|
|
||||||
use crate::layout::UiRegion;
|
|
||||||
|
|
||||||
pub struct Masks {
|
|
||||||
data: Vec<MaskNode>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct MaskPtr(u32);
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct MaskNode {
|
|
||||||
/// TODO: this is just a rect for now,
|
|
||||||
/// but would like to support arbitrary masks
|
|
||||||
/// at some point; custom shader
|
|
||||||
/// would probably handle that case
|
|
||||||
/// bc you'd need to render to a special target
|
|
||||||
/// anyways
|
|
||||||
region: UiRegion,
|
|
||||||
prev: MaskPtr,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MaskPtr {
|
|
||||||
const NONE: Self = Self(u32::MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Masks {
|
|
||||||
pub fn push(&mut self, parent: MaskPtr, region: UiRegion) -> MaskPtr {
|
|
||||||
match parent.0 {
|
|
||||||
_ => {
|
|
||||||
}
|
|
||||||
u32::MAX => {
|
|
||||||
let i = self.data.len();
|
|
||||||
self.data.push(MaskNode {
|
|
||||||
region,
|
|
||||||
prev: parent,
|
|
||||||
});
|
|
||||||
MaskPtr(i as u32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self, i: usize) {}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
pub const trait UiNum {
|
|
||||||
fn to_f32(self) -> f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl const UiNum for f32 {
|
|
||||||
fn to_f32(self) -> f32 {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl const UiNum for u32 {
|
|
||||||
fn to_f32(self) -> f32 {
|
|
||||||
self as f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl const UiNum for i32 {
|
|
||||||
fn to_f32(self) -> f32 {
|
|
||||||
self as f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
31
src/lib.rs
31
src/lib.rs
@@ -1,24 +1,23 @@
|
|||||||
#![feature(macro_metavar_expr_concat)]
|
|
||||||
#![feature(const_ops)]
|
|
||||||
#![feature(const_trait_impl)]
|
|
||||||
#![feature(const_convert)]
|
|
||||||
#![feature(map_try_insert)]
|
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![feature(fn_traits)]
|
#![feature(fn_traits)]
|
||||||
#![feature(const_cmp)]
|
|
||||||
#![feature(const_destruct)]
|
|
||||||
#![feature(portable_simd)]
|
|
||||||
#![feature(gen_blocks)]
|
#![feature(gen_blocks)]
|
||||||
#![feature(associated_type_defaults)]
|
#![feature(associated_type_defaults)]
|
||||||
|
|
||||||
pub mod core;
|
mod default;
|
||||||
pub mod layout;
|
mod event;
|
||||||
pub mod render;
|
mod widget;
|
||||||
pub mod util;
|
|
||||||
pub mod winit;
|
pub use iris_core::*;
|
||||||
|
pub use iris_macro::*;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::core::*;
|
use super::*;
|
||||||
pub use crate::layout::*;
|
pub use default::*;
|
||||||
pub use crate::render::*;
|
pub use event::*;
|
||||||
|
pub use iris_macro::*;
|
||||||
|
pub use layout::*;
|
||||||
|
pub use render::*;
|
||||||
|
pub use widget::*;
|
||||||
|
|
||||||
|
pub use super::util::Vec2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::{UiModule, UiRegion, Vec2},
|
layout::{UiModule, UiRegion},
|
||||||
util::{HashMap, Id},
|
util::{HashMap, Id, Vec2},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
@@ -166,8 +166,12 @@ impl<Ctx> CursorModule<Ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ui {
|
pub trait SensorUi {
|
||||||
pub fn run_sensors<Ctx: 'static>(
|
fn run_sensors<Ctx: 'static>(&mut self, ctx: &mut Ctx, cursor: &CursorState, window_size: Vec2);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SensorUi for Ui {
|
||||||
|
fn run_sensors<Ctx: 'static>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut Ctx,
|
ctx: &mut Ctx,
|
||||||
cursor: &CursorState,
|
cursor: &CursorState,
|
||||||
@@ -205,7 +209,11 @@ impl<Ctx: 'static> CursorModule<Ctx> {
|
|||||||
scroll_delta: cursor.scroll_delta,
|
scroll_delta: cursor.scroll_delta,
|
||||||
sense,
|
sense,
|
||||||
};
|
};
|
||||||
(sensor.f)(EventCtx { ui, state: ctx, data });
|
(sensor.f)(EventCtx {
|
||||||
|
ui,
|
||||||
|
state: ctx,
|
||||||
|
data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -610,3 +610,16 @@ impl DerefMut for TextEdit {
|
|||||||
&mut self.view
|
&mut self.view
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait TextEditable {
|
||||||
|
fn edit<'a>(&self, ui: &'a mut Ui) -> TextEditCtx<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: IdLike<Widget = TextEdit>> TextEditable for I {
|
||||||
|
fn edit<'a>(&self, ui: &'a mut Ui) -> TextEditCtx<'a> {
|
||||||
|
TextEditCtx {
|
||||||
|
text: ui.data.widgets.get_mut(self).unwrap(),
|
||||||
|
font_system: &mut ui.data.text.font_system,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user