Compare commits
9
Commits
32f6ad8c79
...
work
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa771a99eb | ||
|
|
e817bc83af | ||
|
|
a648c62aa2 | ||
|
|
c118bb446b | ||
|
|
1102dc7338 | ||
|
|
1aadef0e7e | ||
|
|
426ff0adfc | ||
|
|
dab6cf298a | ||
|
|
38d896d44d |
No files matched your search
Generated
+698
-615
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -28,9 +28,9 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
pollster = "0.4.0"
|
pollster = "1.0.1"
|
||||||
winit = "0.30.12"
|
winit = "0.30.12"
|
||||||
wgpu = "28.0.0"
|
wgpu = "30.0.0"
|
||||||
bytemuck = "1.23.1"
|
bytemuck = "1.23.1"
|
||||||
image = "0.25.6"
|
image = "0.25.6"
|
||||||
cosmic-text = "0.16.0"
|
cosmic-text = "0.16.0"
|
||||||
|
|||||||
@@ -2,10 +2,8 @@
|
|||||||
#![feature(const_ops)]
|
#![feature(const_ops)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(const_convert)]
|
#![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(const_destruct)]
|
||||||
#![feature(portable_simd)]
|
#![feature(portable_simd)]
|
||||||
#![feature(associated_type_defaults)]
|
#![feature(associated_type_defaults)]
|
||||||
|
|||||||
+5
-5
@@ -5,19 +5,19 @@ pub const trait UiNum {
|
|||||||
fn to_f32(self) -> f32;
|
fn to_f32(self) -> f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const UiNum for f32 {
|
const impl UiNum for f32 {
|
||||||
fn to_f32(self) -> f32 {
|
fn to_f32(self) -> f32 {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const UiNum for u32 {
|
const impl UiNum for u32 {
|
||||||
fn to_f32(self) -> f32 {
|
fn to_f32(self) -> f32 {
|
||||||
self as f32
|
self as f32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const UiNum for i32 {
|
const impl UiNum for i32 {
|
||||||
fn to_f32(self) -> f32 {
|
fn to_f32(self) -> f32 {
|
||||||
self as f32
|
self as f32
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ pub const fn vec2(x: impl const UiNum, y: impl const UiNum) -> Vec2 {
|
|||||||
Vec2::new(x.to_f32(), y.to_f32())
|
Vec2::new(x.to_f32(), y.to_f32())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: const UiNum + Copy> const From<T> for Vec2 {
|
const impl<T: const UiNum + Copy> From<T> for Vec2 {
|
||||||
fn from(v: T) -> Self {
|
fn from(v: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: v.to_f32(),
|
x: v.to_f32(),
|
||||||
@@ -36,7 +36,7 @@ impl<T: const UiNum + Copy> const From<T> for Vec2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: const UiNum, U: const UiNum> const From<(T, U)> for Vec2
|
const impl<T: const UiNum, U: const UiNum> From<(T, U)> for Vec2
|
||||||
where
|
where
|
||||||
(T, U): const Destruct,
|
(T, U): const Destruct,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ impl From<CardinalAlign> for Align {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const From<RegionAlign> for UiVec2 {
|
const impl From<RegionAlign> for UiVec2 {
|
||||||
fn from(align: RegionAlign) -> Self {
|
fn from(align: RegionAlign) -> Self {
|
||||||
Self::rel(align.rel())
|
Self::rel(align.rel())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,14 +74,14 @@ pub const trait AxisT {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct XAxis;
|
pub struct XAxis;
|
||||||
impl const AxisT for XAxis {
|
const impl AxisT for XAxis {
|
||||||
fn get() -> Axis {
|
fn get() -> Axis {
|
||||||
Axis::X
|
Axis::X
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct YAxis;
|
pub struct YAxis;
|
||||||
impl const AxisT for YAxis {
|
const impl AxisT for YAxis {
|
||||||
fn get() -> Axis {
|
fn get() -> Axis {
|
||||||
Axis::Y
|
Axis::Y
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,13 +124,13 @@ impl Display for UiVec2 {
|
|||||||
impl_op!(UiVec2 Add add; x y);
|
impl_op!(UiVec2 Add add; x y);
|
||||||
impl_op!(UiVec2 Sub sub; x y);
|
impl_op!(UiVec2 Sub sub; x y);
|
||||||
|
|
||||||
impl const From<Vec2> for UiVec2 {
|
const impl From<Vec2> for UiVec2 {
|
||||||
fn from(abs: Vec2) -> Self {
|
fn from(abs: Vec2) -> Self {
|
||||||
Self::abs(abs)
|
Self::abs(abs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: const UiNum, U: const UiNum> const From<(T, U)> for UiVec2
|
const impl<T: const UiNum, U: const UiNum> From<(T, U)> for UiVec2
|
||||||
where
|
where
|
||||||
(T, U): const Destruct,
|
(T, U): const Destruct,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ impl ColorNum for f32 {
|
|||||||
|
|
||||||
unsafe impl bytemuck::Pod for Color<u8> {}
|
unsafe impl bytemuck::Pod for Color<u8> {}
|
||||||
|
|
||||||
impl const F32Conversion for f32 {
|
const impl F32Conversion for f32 {
|
||||||
fn to(self) -> f32 {
|
fn to(self) -> f32 {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ impl const F32Conversion for f32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const F32Conversion for u8 {
|
const impl F32Conversion for u8 {
|
||||||
fn to(self) -> f32 {
|
fn to(self) -> f32 {
|
||||||
self as f32 / 255.0
|
self as f32 / 255.0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ impl UiRenderNode {
|
|||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
||||||
label: Some("UI Shape Pipeline Layout"),
|
label: Some("UI Shape Pipeline Layout"),
|
||||||
bind_group_layouts: &[&uniform_layout, &primitive_layout, &rsc_layout],
|
bind_group_layouts: &[&uniform_layout, &primitive_layout, &rsc_layout].map(Some),
|
||||||
immediate_size: 0,
|
immediate_size: 0,
|
||||||
});
|
});
|
||||||
let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
|
let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
|
||||||
@@ -197,7 +197,7 @@ impl UiRenderNode {
|
|||||||
vertex: VertexState {
|
vertex: VertexState {
|
||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: Some("vs_main"),
|
entry_point: Some("vs_main"),
|
||||||
buffers: &[PrimitiveInstance::desc()],
|
buffers: &[Some(PrimitiveInstance::desc())],
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
},
|
},
|
||||||
fragment: Some(FragmentState {
|
fragment: Some(FragmentState {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
enable wgpu_binding_array;
|
||||||
|
|
||||||
const RECT: u32 = 0u;
|
const RECT: u32 = 0u;
|
||||||
const TEXTURE: u32 = 1u;
|
const TEXTURE: u32 = 1u;
|
||||||
|
|
||||||
@@ -65,9 +67,9 @@ struct VertexOutput {
|
|||||||
@location(0) top_left: vec2<f32>,
|
@location(0) top_left: vec2<f32>,
|
||||||
@location(1) bot_right: vec2<f32>,
|
@location(1) bot_right: vec2<f32>,
|
||||||
@location(2) uv: vec2<f32>,
|
@location(2) uv: vec2<f32>,
|
||||||
@location(3) binding: u32,
|
@location(3) @interpolate(flat) binding: u32,
|
||||||
@location(4) idx: u32,
|
@location(4) @interpolate(flat) idx: u32,
|
||||||
@location(5) mask_idx: u32,
|
@location(5) @interpolate(flat) mask_idx: u32,
|
||||||
@builtin(position) clip_position: vec4<f32>,
|
@builtin(position) clip_position: vec4<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ pub trait UiRsc {
|
|||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn on_remove(&mut self, id: WidgetId) {}
|
fn on_remove(&mut self, id: WidgetId) {}
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn on_draw(&mut self, active: &ActiveData) {}
|
fn on_draw(&mut self, active: &ActiveData, redrawn: bool) {}
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn on_undraw(&mut self, active: &ActiveData) {}
|
fn on_undraw(&mut self, active: &ActiveData) {}
|
||||||
|
|
||||||
|
|||||||
@@ -81,10 +81,12 @@ impl UiRenderState {
|
|||||||
old_children: Option<Vec<WidgetId>>,
|
old_children: Option<Vec<WidgetId>>,
|
||||||
rsc: &mut dyn UiRsc,
|
rsc: &mut dyn UiRsc,
|
||||||
) {
|
) {
|
||||||
|
let mut redrawn = old_children.is_some();
|
||||||
let mut old_children = old_children.unwrap_or_default();
|
let mut old_children = old_children.unwrap_or_default();
|
||||||
if let Some(active) = self.active.get_mut(&id)
|
if let Some(active) = self.active.get_mut(&id)
|
||||||
&& !rsc.widgets().needs_redraw.contains(&id)
|
&& !rsc.widgets().needs_redraw.contains(&id)
|
||||||
{
|
{
|
||||||
|
redrawn = true;
|
||||||
// check to see if we can skip drawing first
|
// check to see if we can skip drawing first
|
||||||
if active.region == region {
|
if active.region == region {
|
||||||
return;
|
return;
|
||||||
@@ -149,7 +151,7 @@ impl UiRenderState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rsc.on_draw(&active);
|
rsc.on_draw(&active, redrawn);
|
||||||
self.active.insert(id, active);
|
self.active.insert(id, active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,15 +9,16 @@ pub const trait DivOr {
|
|||||||
fn div_or(self, rhs: Self, other: Self) -> Self;
|
fn div_or(self, rhs: Self, other: Self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const DivOr for f32 {
|
const impl DivOr for f32 {
|
||||||
fn div_or(self, rhs: Self, other: Self) -> Self {
|
fn div_or(self, rhs: Self, other: Self) -> Self {
|
||||||
let res = self / rhs;
|
let res = self / rhs;
|
||||||
if res.is_nan() { other } else { res }
|
if res.is_nan() { other } else { res }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: const Add<Output = T> + const Sub<Output = T> + const Mul<Output = T> + const DivOr + Copy> const
|
const impl<
|
||||||
LerpUtil for T
|
T: const Add<Output = T> + const Sub<Output = T> + const Mul<Output = T> + const DivOr + Copy,
|
||||||
|
> LerpUtil for T
|
||||||
{
|
{
|
||||||
/// linear interpolation
|
/// linear interpolation
|
||||||
/// from * (1.0 - self) + to * self
|
/// from * (1.0 - self) + to * self
|
||||||
@@ -37,7 +38,7 @@ macro_rules! impl_op {
|
|||||||
use super::*;
|
use super::*;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use std::ops::*;
|
use std::ops::*;
|
||||||
impl const $op for $T {
|
const impl $op for $T {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn $fn(self, rhs: Self) -> Self::Output {
|
fn $fn(self, rhs: Self) -> Self::Output {
|
||||||
@@ -46,12 +47,12 @@ macro_rules! impl_op {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl const $opa for $T {
|
const impl $opa for $T {
|
||||||
fn $fna(&mut self, rhs: Self) {
|
fn $fna(&mut self, rhs: Self) {
|
||||||
*self = self.$fn(rhs);
|
*self = self.$fn(rhs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl const $op<f32> for $T {
|
const impl $op<f32> for $T {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn $fn(self, rhs: f32) -> Self::Output {
|
fn $fn(self, rhs: f32) -> Self::Output {
|
||||||
@@ -60,7 +61,7 @@ macro_rules! impl_op {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl const $op<$T> for f32 {
|
const impl $op<$T> for f32 {
|
||||||
type Output = $T;
|
type Output = $T;
|
||||||
|
|
||||||
fn $fn(self, rhs: $T) -> Self::Output {
|
fn $fn(self, rhs: $T) -> Self::Output {
|
||||||
@@ -69,7 +70,7 @@ macro_rules! impl_op {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl const $opa<f32> for $T {
|
const impl $opa<f32> for $T {
|
||||||
fn $fna(&mut self, rhs: f32) {
|
fn $fna(&mut self, rhs: f32) {
|
||||||
*self = self.$fn(rhs);
|
*self = self.$fn(rhs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ impl_op!(Vec2 Sub sub; x y);
|
|||||||
impl_op!(Vec2 Mul mul; x y);
|
impl_op!(Vec2 Mul mul; x y);
|
||||||
impl_op!(Vec2 Div div; x y);
|
impl_op!(Vec2 Div div; x y);
|
||||||
|
|
||||||
impl const DivOr for Vec2 {
|
const impl DivOr for Vec2 {
|
||||||
fn div_or(self, rhs: Self, other: Self) -> Self {
|
fn div_or(self, rhs: Self, other: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: self.x.div_or(rhs.x, other.x),
|
x: self.x.div_or(rhs.x, other.x),
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ pub trait HasRoot {
|
|||||||
|
|
||||||
pub trait WidgetArrLike<Rsc, const LEN: usize, Tag> {
|
pub trait WidgetArrLike<Rsc, const LEN: usize, Tag> {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn add(self, state: &mut Rsc) -> WidgetArr<LEN>;
|
fn add(self, rsc: &mut Rsc) -> WidgetArr<LEN>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Rsc, const LEN: usize> WidgetArrLike<Rsc, LEN, ArrTag> for WidgetArr<LEN> {
|
impl<Rsc, const LEN: usize> WidgetArrLike<Rsc, LEN, ArrTag> for WidgetArr<LEN> {
|
||||||
@@ -58,6 +58,13 @@ macro_rules! impl_widget_arr {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<Rsc: UiRsc, $($W: WidgetLike<Rsc, $Tag>,$Tag,)*> IntoWidgetVec<Rsc, ($($Tag,)*), ArrTag> for ($($W,)*) {
|
||||||
|
fn into_vec(self, rsc: &mut Rsc) -> Vec<StrongWidget> {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let ($($W,)*) = self;
|
||||||
|
vec![$($W.add(rsc).upgrade(rsc),)*]
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-1
@@ -1,4 +1,4 @@
|
|||||||
use crate::{Axis, AxisT, Len, Painter, SizeCtx};
|
use crate::{Axis, AxisT, Len, Painter, SizeCtx, UiRsc};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
mod data;
|
mod data;
|
||||||
@@ -85,3 +85,16 @@ impl<State, F: FnOnce(&mut State) -> Option<StrongWidget>> WidgetOption<State> f
|
|||||||
self(state)
|
self(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait IntoWidgetVec<Rsc, WTag, GTag> {
|
||||||
|
fn into_vec(self, rsc: &mut Rsc) -> Vec<StrongWidget>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Rsc: UiRsc, I: IntoIterator, Tag> IntoWidgetVec<Rsc, Tag, IterTag> for I
|
||||||
|
where
|
||||||
|
I::Item: WidgetLike<Rsc, Tag>,
|
||||||
|
{
|
||||||
|
fn into_vec(self, rsc: &mut Rsc) -> Vec<StrongWidget> {
|
||||||
|
self.into_iter().map(|w| w.add_strong(rsc).any()).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,3 +62,4 @@ impl<Rsc: UiRsc, V: WidgetView> WidgetLike<Rsc, ViewTag> for V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ArrTag;
|
pub struct ArrTag;
|
||||||
|
pub struct IterTag;
|
||||||
+1
-5
@@ -10,11 +10,7 @@ struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultAppState for State {
|
impl DefaultAppState for State {
|
||||||
fn new(
|
fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>) -> Self {
|
||||||
mut ui_state: DefaultUiState,
|
|
||||||
rsc: &mut DefaultRsc<Self>,
|
|
||||||
_: Proxy<Self::Event>,
|
|
||||||
) -> Self {
|
|
||||||
rect(Color::RED).set_root(rsc, &mut ui_state);
|
rect(Color::RED).set_root(rsc, &mut ui_state);
|
||||||
Self { ui_state }
|
Self { ui_state }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,7 @@ pub struct Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultAppState for Client {
|
impl DefaultAppState for Client {
|
||||||
fn new(
|
fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>) -> Self {
|
||||||
mut ui_state: DefaultUiState,
|
|
||||||
rsc: &mut DefaultRsc<Self>,
|
|
||||||
_: Proxy<Self::Event>,
|
|
||||||
) -> Self {
|
|
||||||
let rrect = rect(Color::WHITE).radius(20);
|
let rrect = rect(Color::WHITE).radius(20);
|
||||||
let pad_test = (
|
let pad_test = (
|
||||||
rrect.color(Color::BLUE),
|
rrect.color(Color::BLUE),
|
||||||
@@ -148,7 +144,7 @@ impl DefaultAppState for Client {
|
|||||||
.span(Dir::DOWN)
|
.span(Dir::DOWN)
|
||||||
.add(rsc);
|
.add(rsc);
|
||||||
|
|
||||||
let main = WidgetPtr::new().add(rsc);
|
let main = WidgetPtr::empty().add(rsc);
|
||||||
|
|
||||||
let vals = Rc::new(RefCell::new((0, Vec::new())));
|
let vals = Rc::new(RefCell::new((0, Vec::new())));
|
||||||
let mut switch_button = |color, to: WeakWidget, label| {
|
let mut switch_button = |color, to: WeakWidget, label| {
|
||||||
|
|||||||
+1
-5
@@ -11,11 +11,7 @@ struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultAppState for State {
|
impl DefaultAppState for State {
|
||||||
fn new(
|
fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>) -> Self {
|
||||||
mut ui_state: DefaultUiState,
|
|
||||||
rsc: &mut DefaultRsc<Self>,
|
|
||||||
_: Proxy<Self::Event>,
|
|
||||||
) -> Self {
|
|
||||||
let rect = rect(Color::RED).add(rsc);
|
let rect = rect(Color::RED).add(rsc);
|
||||||
rect.task_on(CursorSense::click(), async move |mut ctx| {
|
rect.task_on(CursorSense::click(), async move |mut ctx| {
|
||||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
|
|||||||
+1
-5
@@ -36,11 +36,7 @@ impl Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultAppState for State {
|
impl DefaultAppState for State {
|
||||||
fn new(
|
fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>) -> Self {
|
||||||
mut ui_state: DefaultUiState,
|
|
||||||
rsc: &mut DefaultRsc<Self>,
|
|
||||||
_: Proxy<Self::Event>,
|
|
||||||
) -> Self {
|
|
||||||
let test = Test::new(rsc);
|
let test = Test::new(rsc);
|
||||||
|
|
||||||
test.on(CursorSense::click(), move |_, rsc| {
|
test.on(CursorSense::click(), move |_, rsc| {
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ edition.workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "1.0.103"
|
proc-macro2 = "1.0.103"
|
||||||
quote = "1.0.42"
|
quote = "1.0.42"
|
||||||
syn = { version = "2.0.111", features = ["full"] }
|
syn = { version = "3.0.3", features = ["full"] }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
@@ -7,3 +7,11 @@ impl Event for Submit {}
|
|||||||
#[derive(Eq, PartialEq, Hash, Clone)]
|
#[derive(Eq, PartialEq, Hash, Clone)]
|
||||||
pub struct Edited;
|
pub struct Edited;
|
||||||
impl Event for Edited {}
|
impl Event for Edited {}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Hash, Clone)]
|
||||||
|
pub struct Draw;
|
||||||
|
impl Event for Draw {}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Hash, Clone)]
|
||||||
|
pub struct Undraw;
|
||||||
|
impl Event for Undraw {}
|
||||||
+145
-45
@@ -29,7 +29,26 @@ pub use sense::*;
|
|||||||
pub use state::*;
|
pub use state::*;
|
||||||
pub use task::*;
|
pub use task::*;
|
||||||
|
|
||||||
pub type Proxy<Event> = EventLoopProxy<Event>;
|
pub struct EventSender<State: DefaultAppState> {
|
||||||
|
proxy: EventLoopProxy<UiMainEvent<State>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<State: DefaultAppState> Clone for EventSender<State> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
proxy: self.proxy.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<State: DefaultAppState> EventSender<State> {
|
||||||
|
pub fn send(&self, event: State::Event) {
|
||||||
|
let _ = self.proxy.send_event(UiMainEvent::App(event));
|
||||||
|
}
|
||||||
|
pub fn run(&self, f: impl MainCallback<State>) {
|
||||||
|
let _ = self.proxy.send_event(UiMainEvent::Callback(Box::new(f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DefaultUiState {
|
pub struct DefaultUiState {
|
||||||
pub root: Option<StrongWidget>,
|
pub root: Option<StrongWidget>,
|
||||||
@@ -70,9 +89,8 @@ pub trait HasDefaultUiState: Sized + 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait DefaultAppState: HasDefaultUiState {
|
pub trait DefaultAppState: HasDefaultUiState {
|
||||||
type Event = ();
|
type Event: Send = ();
|
||||||
fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>, proxy: Proxy<Self::Event>)
|
fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>) -> Self;
|
||||||
-> Self;
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn event(
|
fn event(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -96,23 +114,54 @@ pub trait DefaultAppState: HasDefaultUiState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DefaultRsc<State: 'static> {
|
pub struct DefaultRsc<State: 'static + DefaultAppState> {
|
||||||
pub ui: UiData,
|
pub ui: UiData,
|
||||||
pub events: EventManager<Self>,
|
pub events: EventManager<Self>,
|
||||||
pub tasks: Tasks<Self>,
|
pub tasks: Tasks<Self>,
|
||||||
pub state: WidgetState,
|
pub state: WidgetState,
|
||||||
|
pub widget_events: Vec<WidgetEvent>,
|
||||||
|
pub window_event: EventSender<State>,
|
||||||
_state: PhantomData<State>,
|
_state: PhantomData<State>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State> DefaultRsc<State> {
|
pub struct WidgetEvent {
|
||||||
fn init(window: Arc<Window>) -> (Self, TaskMsgReceiver<Self>) {
|
id: WidgetId,
|
||||||
let (tasks, recv) = Tasks::init(window);
|
ty: WidgetEventType,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum WidgetEventType {
|
||||||
|
Draw,
|
||||||
|
Undraw,
|
||||||
|
Remove,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MainCallback<State>: FnOnce(&mut DefaultRsc<State>) + Sync + Send + 'static {}
|
||||||
|
impl<F: FnOnce(&mut DefaultRsc<State>) + Sync + Send + 'static, State> MainCallback<State> for F {}
|
||||||
|
|
||||||
|
pub enum UiMainEvent<State: DefaultAppState> {
|
||||||
|
RequestUpdate,
|
||||||
|
Callback(Box<dyn MainCallback<State>>),
|
||||||
|
App(State::Event),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<State: DefaultAppState> DefaultRsc<State> {
|
||||||
|
fn init(proxy: EventLoopProxy<UiMainEvent<State>>) -> (Self, TaskMsgReceiver<Self>) {
|
||||||
|
let window_event = EventSender {
|
||||||
|
proxy: proxy.clone(),
|
||||||
|
};
|
||||||
|
let (tasks, recv) = Tasks::init(move || {
|
||||||
|
if proxy.send_event(UiMainEvent::RequestUpdate).is_err() {
|
||||||
|
panic!("main thread blew up or smth");
|
||||||
|
}
|
||||||
|
});
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
ui: Default::default(),
|
ui: Default::default(),
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
tasks,
|
tasks,
|
||||||
|
widget_events: Default::default(),
|
||||||
state: Default::default(),
|
state: Default::default(),
|
||||||
|
window_event,
|
||||||
_state: Default::default(),
|
_state: Default::default(),
|
||||||
},
|
},
|
||||||
recv,
|
recv,
|
||||||
@@ -124,7 +173,7 @@ impl<State> DefaultRsc<State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State> UiRsc for DefaultRsc<State> {
|
impl<State: DefaultAppState> UiRsc for DefaultRsc<State> {
|
||||||
fn ui(&self) -> &UiData {
|
fn ui(&self) -> &UiData {
|
||||||
&self.ui
|
&self.ui
|
||||||
}
|
}
|
||||||
@@ -133,25 +182,39 @@ impl<State> UiRsc for DefaultRsc<State> {
|
|||||||
&mut self.ui
|
&mut self.ui
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_draw(&mut self, active: &ActiveData) {
|
fn on_draw(&mut self, active: &ActiveData, redrawn: bool) {
|
||||||
self.events.draw(active);
|
self.events.draw(active);
|
||||||
|
if !redrawn {
|
||||||
|
self.widget_events.push(WidgetEvent {
|
||||||
|
id: active.id,
|
||||||
|
ty: WidgetEventType::Draw,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_undraw(&mut self, active: &ActiveData) {
|
fn on_undraw(&mut self, active: &ActiveData) {
|
||||||
self.events.undraw(active);
|
self.events.undraw(active);
|
||||||
|
self.widget_events.push(WidgetEvent {
|
||||||
|
id: active.id,
|
||||||
|
ty: WidgetEventType::Undraw,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_remove(&mut self, id: WidgetId) {
|
fn on_remove(&mut self, id: WidgetId) {
|
||||||
self.events.remove(id);
|
self.events.remove(id);
|
||||||
self.state.remove(id);
|
self.state.remove(id);
|
||||||
|
self.widget_events.push(WidgetEvent {
|
||||||
|
id,
|
||||||
|
ty: WidgetEventType::Remove,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State: 'static> HasState for DefaultRsc<State> {
|
impl<State: 'static + DefaultAppState> HasState for DefaultRsc<State> {
|
||||||
type State = State;
|
type State = State;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State: 'static> HasEvents for DefaultRsc<State> {
|
impl<State: 'static + DefaultAppState> HasEvents for DefaultRsc<State> {
|
||||||
fn events(&self) -> &EventManager<Self> {
|
fn events(&self) -> &EventManager<Self> {
|
||||||
&self.events
|
&self.events
|
||||||
}
|
}
|
||||||
@@ -161,13 +224,13 @@ impl<State: 'static> HasEvents for DefaultRsc<State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State: 'static> HasTasks for DefaultRsc<State> {
|
impl<State: 'static + DefaultAppState> HasTasks for DefaultRsc<State> {
|
||||||
fn tasks_mut(&mut self) -> &mut Tasks<Self> {
|
fn tasks_mut(&mut self) -> &mut Tasks<Self> {
|
||||||
&mut self.tasks
|
&mut self.tasks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State: 'static> HasWidgetState for DefaultRsc<State> {
|
impl<State: 'static + DefaultAppState> HasWidgetState for DefaultRsc<State> {
|
||||||
fn widget_state(&self) -> &WidgetState {
|
fn widget_state(&self) -> &WidgetState {
|
||||||
&self.state
|
&self.state
|
||||||
}
|
}
|
||||||
@@ -185,15 +248,15 @@ pub struct DefaultApp<State: DefaultAppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||||
type Event = State::Event;
|
type Event = UiMainEvent<State>;
|
||||||
|
|
||||||
fn new(event_loop: &ActiveEventLoop, proxy: EventLoopProxy<Self::Event>) -> Self {
|
fn new(event_loop: &ActiveEventLoop, proxy: EventLoopProxy<Self::Event>) -> Self {
|
||||||
let window = event_loop
|
let window = event_loop
|
||||||
.create_window(State::window_attributes())
|
.create_window(State::window_attributes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let default_state = DefaultUiState::new(window);
|
let default_state = DefaultUiState::new(window);
|
||||||
let (mut rsc, task_recv) = DefaultRsc::init(default_state.window.clone());
|
let (mut rsc, task_recv) = DefaultRsc::init(proxy);
|
||||||
let state = State::new(default_state, &mut rsc, proxy);
|
let state = State::new(default_state, &mut rsc);
|
||||||
let render = UiRenderState::new();
|
let render = UiRenderState::new();
|
||||||
Self {
|
Self {
|
||||||
rsc,
|
rsc,
|
||||||
@@ -204,38 +267,39 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn event(&mut self, event: Self::Event, _: &ActiveEventLoop) {
|
fn event(&mut self, event: Self::Event, _: &ActiveEventLoop) {
|
||||||
self.state.event(event, &mut self.rsc, &mut self.render);
|
match event {
|
||||||
|
UiMainEvent::RequestUpdate => {
|
||||||
|
self.check_updates();
|
||||||
|
}
|
||||||
|
UiMainEvent::App(event) => {
|
||||||
|
self.state.event(event, &mut self.rsc, &mut self.render);
|
||||||
|
}
|
||||||
|
UiMainEvent::Callback(f) => f(&mut self.rsc),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
||||||
let Self {
|
let Self {
|
||||||
rsc,
|
rsc, render, state, ..
|
||||||
render,
|
|
||||||
state,
|
|
||||||
task_recv,
|
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
for update in task_recv.try_iter() {
|
// input handling
|
||||||
update(state, rsc);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ui_state = state.default_state_mut();
|
let ui_state = state.default_state_mut();
|
||||||
let input_changed = ui_state.input.event(&event);
|
if ui_state.input.event(&event) {
|
||||||
let cursor_state = ui_state.cursor_state().clone();
|
let cursor_state = ui_state.cursor_state().clone();
|
||||||
let old = ui_state.focus;
|
let old = ui_state.focus;
|
||||||
if cursor_state.buttons.left.is_start() {
|
if cursor_state.buttons.left.is_start() {
|
||||||
ui_state.focus = None;
|
ui_state.focus = None;
|
||||||
}
|
}
|
||||||
if input_changed {
|
|
||||||
let window_size = ui_state.window_size();
|
let window_size = ui_state.window_size();
|
||||||
render.run_sensors(rsc, state, cursor_state, window_size);
|
render.run_sensors(rsc, state, cursor_state, window_size);
|
||||||
|
if old != state.default_state().focus
|
||||||
|
&& let Some(old) = old
|
||||||
|
{
|
||||||
|
old.edit(rsc).deselect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let ui_state = state.default_state_mut();
|
let ui_state = state.default_state_mut();
|
||||||
if old != ui_state.focus
|
|
||||||
&& let Some(old) = old
|
|
||||||
{
|
|
||||||
old.edit(rsc).deselect();
|
|
||||||
}
|
|
||||||
match &event {
|
match &event {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
@@ -297,11 +361,9 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
state.window_event(event, rsc, render);
|
state.window_event(event, rsc, render);
|
||||||
let ui_state = self.state.default_state_mut();
|
|
||||||
if render.needs_redraw(&ui_state.root, rsc.widgets()) {
|
self.check_updates();
|
||||||
ui_state.renderer.window().request_redraw();
|
self.state.default_state_mut().input.end_frame();
|
||||||
}
|
|
||||||
ui_state.input.end_frame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit(&mut self) {
|
fn exit(&mut self) {
|
||||||
@@ -309,13 +371,49 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<State: DefaultAppState> DefaultApp<State> {
|
||||||
|
pub fn check_updates(&mut self) {
|
||||||
|
let Self {
|
||||||
|
rsc,
|
||||||
|
render,
|
||||||
|
state,
|
||||||
|
task_recv,
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
for update in task_recv.try_iter() {
|
||||||
|
update(state, rsc);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut events = std::mem::take(&mut rsc.widget_events);
|
||||||
|
for event in events.drain(..) {
|
||||||
|
match event.ty {
|
||||||
|
WidgetEventType::Draw => {
|
||||||
|
rsc.run_event::<Draw>(event.id, (), state);
|
||||||
|
}
|
||||||
|
WidgetEventType::Undraw => {
|
||||||
|
rsc.run_event::<Undraw>(event.id, (), state);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rsc.widget_events = events;
|
||||||
|
|
||||||
|
let ui_state = state.default_state();
|
||||||
|
if render.needs_redraw(&ui_state.root, rsc.widgets()) {
|
||||||
|
ui_state.renderer.window().request_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait RscIdx<Rsc> {
|
pub trait RscIdx<Rsc> {
|
||||||
type Output;
|
type Output;
|
||||||
fn get(self, rsc: &Rsc) -> &Self::Output;
|
fn get(self, rsc: &Rsc) -> &Self::Output;
|
||||||
fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output;
|
fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State: 'static, I: RscIdx<DefaultRsc<State>>> std::ops::Index<I> for DefaultRsc<State> {
|
impl<State: 'static + DefaultAppState, I: RscIdx<DefaultRsc<State>>> std::ops::Index<I>
|
||||||
|
for DefaultRsc<State>
|
||||||
|
{
|
||||||
type Output = I::Output;
|
type Output = I::Output;
|
||||||
|
|
||||||
fn index(&self, index: I) -> &Self::Output {
|
fn index(&self, index: I) -> &Self::Output {
|
||||||
@@ -323,7 +421,9 @@ impl<State: 'static, I: RscIdx<DefaultRsc<State>>> std::ops::Index<I> for Defaul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State: 'static, I: RscIdx<DefaultRsc<State>>> std::ops::IndexMut<I> for DefaultRsc<State> {
|
impl<State: 'static + DefaultAppState, I: RscIdx<DefaultRsc<State>>> std::ops::IndexMut<I>
|
||||||
|
for DefaultRsc<State>
|
||||||
|
{
|
||||||
fn index_mut(&mut self, index: I) -> &mut Self::Output {
|
fn index_mut(&mut self, index: I) -> &mut Self::Output {
|
||||||
index.get_mut(self)
|
index.get_mut(self)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-4
@@ -22,7 +22,11 @@ impl UiRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self) {
|
pub fn draw(&mut self) {
|
||||||
let output = self.surface.get_current_texture().unwrap();
|
let output = match self.surface.get_current_texture() {
|
||||||
|
CurrentSurfaceTexture::Success(v) => v,
|
||||||
|
CurrentSurfaceTexture::Suboptimal(v) => v,
|
||||||
|
_ => panic!("failed"),
|
||||||
|
};
|
||||||
let view = output
|
let view = output
|
||||||
.texture
|
.texture
|
||||||
.create_view(&TextureViewDescriptor::default());
|
.create_view(&TextureViewDescriptor::default());
|
||||||
@@ -45,7 +49,7 @@ impl UiRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
output.present();
|
self.queue.present(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, size: &PhysicalSize<u32>) {
|
pub fn resize(&mut self, size: &PhysicalSize<u32>) {
|
||||||
@@ -64,9 +68,12 @@ impl UiRenderer {
|
|||||||
pub fn new(window: Arc<Window>) -> Self {
|
pub fn new(window: Arc<Window>) -> Self {
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
|
|
||||||
let instance = Instance::new(&InstanceDescriptor {
|
let instance = Instance::new(InstanceDescriptor {
|
||||||
backends: Backends::PRIMARY,
|
backends: Backends::PRIMARY,
|
||||||
..Default::default()
|
flags: Default::default(),
|
||||||
|
memory_budget_thresholds: Default::default(),
|
||||||
|
backend_options: Default::default(),
|
||||||
|
display: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let surface = instance
|
let surface = instance
|
||||||
@@ -78,6 +85,7 @@ impl UiRenderer {
|
|||||||
power_preference: PowerPreference::default(),
|
power_preference: PowerPreference::default(),
|
||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
force_fallback_adapter: false,
|
force_fallback_adapter: false,
|
||||||
|
apply_limit_buckets: false,
|
||||||
})
|
})
|
||||||
.block_on()
|
.block_on()
|
||||||
.expect("Could not get adapter!");
|
.expect("Could not get adapter!");
|
||||||
@@ -119,6 +127,7 @@ impl UiRenderer {
|
|||||||
alpha_mode: surface_caps.alpha_modes[0],
|
alpha_mode: surface_caps.alpha_modes[0],
|
||||||
desired_maximum_frame_latency: 2,
|
desired_maximum_frame_latency: 2,
|
||||||
view_formats: vec![],
|
view_formats: vec![],
|
||||||
|
color_space: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
surface.configure(&device, &config);
|
surface.configure(&device, &config);
|
||||||
|
|||||||
+5
-6
@@ -13,7 +13,6 @@ use tokio::{
|
|||||||
unbounded_channel as async_channel,
|
unbounded_channel as async_channel,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use winit::window::Window;
|
|
||||||
|
|
||||||
pub type TaskMsgSender<Rsc> = SyncSender<Box<dyn TaskUpdate<Rsc>>>;
|
pub type TaskMsgSender<Rsc> = SyncSender<Box<dyn TaskUpdate<Rsc>>>;
|
||||||
pub type TaskMsgReceiver<Rsc> = SyncReceiver<Box<dyn TaskUpdate<Rsc>>>;
|
pub type TaskMsgReceiver<Rsc> = SyncReceiver<Box<dyn TaskUpdate<Rsc>>>;
|
||||||
@@ -23,7 +22,7 @@ impl<F: FnOnce(&mut Rsc::State, &mut Rsc) + Send, Rsc: HasState> TaskUpdate<Rsc>
|
|||||||
|
|
||||||
pub struct Tasks<Rsc: HasState> {
|
pub struct Tasks<Rsc: HasState> {
|
||||||
start: AsyncSender<BoxTask>,
|
start: AsyncSender<BoxTask>,
|
||||||
window: Arc<Window>,
|
request_update: Arc<dyn Fn() + Send + Sync>,
|
||||||
msg_send: SyncSender<Box<dyn TaskUpdate<Rsc>>>,
|
msg_send: SyncSender<Box<dyn TaskUpdate<Rsc>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +44,7 @@ impl<Rsc: HasState + 'static> TaskCtx<Rsc> {
|
|||||||
type BoxTask = Pin<Box<dyn Future<Output = ()> + Send>>;
|
type BoxTask = Pin<Box<dyn Future<Output = ()> + Send>>;
|
||||||
|
|
||||||
impl<Rsc: HasState> Tasks<Rsc> {
|
impl<Rsc: HasState> Tasks<Rsc> {
|
||||||
pub fn init(window: Arc<Window>) -> (Self, TaskMsgReceiver<Rsc>) {
|
pub fn init(request_update: impl Fn() + 'static + Send + Sync) -> (Self, TaskMsgReceiver<Rsc>) {
|
||||||
let (start, start_recv) = async_channel();
|
let (start, start_recv) = async_channel();
|
||||||
let (msgs, msgs_recv) = sync_channel();
|
let (msgs, msgs_recv) = sync_channel();
|
||||||
std::thread::spawn(|| {
|
std::thread::spawn(|| {
|
||||||
@@ -56,7 +55,7 @@ impl<Rsc: HasState> Tasks<Rsc> {
|
|||||||
Self {
|
Self {
|
||||||
start,
|
start,
|
||||||
msg_send: msgs,
|
msg_send: msgs,
|
||||||
window,
|
request_update: Arc::new(request_update),
|
||||||
},
|
},
|
||||||
msgs_recv,
|
msgs_recv,
|
||||||
)
|
)
|
||||||
@@ -67,10 +66,10 @@ impl<Rsc: HasState> Tasks<Rsc> {
|
|||||||
F::CallOnceFuture: Send,
|
F::CallOnceFuture: Send,
|
||||||
{
|
{
|
||||||
let send = self.msg_send.clone();
|
let send = self.msg_send.clone();
|
||||||
let window = self.window.clone();
|
let request_update = self.request_update.clone();
|
||||||
let _ = self.start.send(Box::pin(async move {
|
let _ = self.start.send(Box::pin(async move {
|
||||||
task(TaskCtx::new(send)).await;
|
task(TaskCtx::new(send)).await;
|
||||||
window.request_redraw();
|
request_update();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ mod ptr;
|
|||||||
mod rect;
|
mod rect;
|
||||||
mod text;
|
mod text;
|
||||||
mod trait_fns;
|
mod trait_fns;
|
||||||
|
mod selector;
|
||||||
|
|
||||||
pub use image::*;
|
pub use image::*;
|
||||||
pub use mask::*;
|
pub use mask::*;
|
||||||
@@ -13,3 +14,4 @@ pub use ptr::*;
|
|||||||
pub use rect::*;
|
pub use rect::*;
|
||||||
pub use text::*;
|
pub use text::*;
|
||||||
pub use trait_fns::*;
|
pub use trait_fns::*;
|
||||||
|
pub use selector::*;
|
||||||
@@ -152,32 +152,32 @@ impl Span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SpanBuilder<State, const LEN: usize, Wa: WidgetArrLike<State, LEN, Tag>, Tag> {
|
pub struct SpanBuilder<Children, Rsc, Tag, GTag> {
|
||||||
pub children: Wa,
|
pub children: Children,
|
||||||
pub dir: Dir,
|
pub dir: Dir,
|
||||||
pub gap: f32,
|
pub gap: f32,
|
||||||
_pd: PhantomData<(State, Tag)>,
|
_pd: PhantomData<(Rsc, Tag, GTag)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Rsc, const LEN: usize, Wa: WidgetArrLike<Rsc, LEN, Tag>, Tag> WidgetFnTrait<Rsc>
|
impl<Children: IntoWidgetVec<Rsc, Tag, GTag>, Rsc, Tag, GTag> WidgetFnTrait<Rsc>
|
||||||
for SpanBuilder<Rsc, LEN, Wa, Tag>
|
for SpanBuilder<Children, Rsc, Tag, GTag>
|
||||||
{
|
{
|
||||||
type Widget = Span;
|
type Widget = Span;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn run(self, rsc: &mut Rsc) -> Self::Widget {
|
fn run(self, rsc: &mut Rsc) -> Self::Widget {
|
||||||
Span {
|
Span {
|
||||||
children: self.children.add(rsc).arr.into_iter().collect(),
|
children: self.children.into_vec(rsc),
|
||||||
dir: self.dir,
|
dir: self.dir,
|
||||||
gap: self.gap,
|
gap: self.gap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, const LEN: usize, Wa: WidgetArrLike<State, LEN, Tag>, Tag>
|
impl<Children: IntoWidgetVec<Rsc, Tag, GTag>, Rsc, Tag, GTag>
|
||||||
SpanBuilder<State, LEN, Wa, Tag>
|
SpanBuilder<Children, Rsc, Tag, GTag>
|
||||||
{
|
{
|
||||||
pub fn new(children: Wa, dir: Dir) -> Self {
|
pub fn new(children: Children, dir: Dir) -> Self {
|
||||||
Self {
|
Self {
|
||||||
children,
|
children,
|
||||||
dir,
|
dir,
|
||||||
|
|||||||
@@ -42,30 +42,28 @@ pub enum StackSize {
|
|||||||
Child(usize),
|
Child(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StackBuilder<State, const LEN: usize, Wa: WidgetArrLike<State, LEN, Tag>, Tag> {
|
pub struct StackBuilder<Children, Rsc, Tag, GTag> {
|
||||||
pub children: Wa,
|
pub children: Children,
|
||||||
pub size: StackSize,
|
pub size: StackSize,
|
||||||
_pd: PhantomData<(State, Tag)>,
|
_pd: PhantomData<(Rsc, Tag, GTag)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Rsc, const LEN: usize, Wa: WidgetArrLike<Rsc, LEN, Tag>, Tag> WidgetFnTrait<Rsc>
|
impl<Children: IntoWidgetVec<Rsc, Tag, GTag>, Rsc, Tag, GTag> WidgetFnTrait<Rsc>
|
||||||
for StackBuilder<Rsc, LEN, Wa, Tag>
|
for StackBuilder<Children, Rsc, Tag, GTag>
|
||||||
{
|
{
|
||||||
type Widget = Stack;
|
type Widget = Stack;
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn run(self, rsc: &mut Rsc) -> Self::Widget {
|
fn run(self, rsc: &mut Rsc) -> Self::Widget {
|
||||||
Stack {
|
Stack {
|
||||||
children: self.children.add(rsc).arr.into_iter().collect(),
|
children: self.children.into_vec(rsc),
|
||||||
size: self.size,
|
size: self.size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, const LEN: usize, Wa: WidgetArrLike<State, LEN, Tag>, Tag>
|
impl<Children: IntoWidgetVec<Rsc, Tag, GTag>, Rsc, Tag, GTag> StackBuilder<Children, Rsc, Tag, GTag> {
|
||||||
StackBuilder<State, LEN, Wa, Tag>
|
pub fn new(children: Children) -> Self {
|
||||||
{
|
|
||||||
pub fn new(children: Wa) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
children,
|
children,
|
||||||
size: StackSize::default(),
|
size: StackSize::default(),
|
||||||
|
|||||||
+4
-2
@@ -30,8 +30,10 @@ impl Widget for WidgetPtr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetPtr {
|
impl WidgetPtr {
|
||||||
pub fn new() -> Self {
|
pub fn new(widget: StrongWidget) -> Self {
|
||||||
Self::default()
|
Self {
|
||||||
|
inner: Some(widget),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
use iris_core::util::HashMap;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub struct WidgetSelector<T> {
|
||||||
|
current: (T, StrongWidget),
|
||||||
|
map: HashMap<T, StrongWidget>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Hash + Eq> WidgetSelector<T> {
|
||||||
|
pub fn new(key: T, widget: StrongWidget) -> Self {
|
||||||
|
Self {
|
||||||
|
current: (key, widget),
|
||||||
|
map: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, key: T, widget: StrongWidget) {
|
||||||
|
self.map.insert(key, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select(&mut self, key: T) -> bool {
|
||||||
|
if let Some(val) = self.map.remove(&key) {
|
||||||
|
let mut new = (key, val);
|
||||||
|
std::mem::swap(&mut new, &mut self.current);
|
||||||
|
self.map.insert(new.0, new.1);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Widget for WidgetSelector<T> {
|
||||||
|
fn draw(&mut self, painter: &mut Painter) {
|
||||||
|
painter.widget(&self.current.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len {
|
||||||
|
ctx.width(&self.current.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len {
|
||||||
|
ctx.height(&self.current.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
-7
@@ -131,18 +131,61 @@ widget_trait! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CoreWidgetArr<Rsc, const LEN: usize, Wa: WidgetArrLike<Rsc, LEN, Tag>, Tag> {
|
pub trait CoreWidgetArr<Children, Rsc, Tag, GTag> {
|
||||||
fn span(self, dir: Dir) -> SpanBuilder<Rsc, LEN, Wa, Tag>;
|
fn span(self, dir: Dir) -> SpanBuilder<Children, Rsc, Tag, GTag>;
|
||||||
fn stack(self) -> StackBuilder<Rsc, LEN, Wa, Tag>;
|
fn stack(self) -> StackBuilder<Children, Rsc, Tag, GTag>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, const LEN: usize, Wa: WidgetArrLike<State, LEN, Tag>, Tag>
|
impl<Children: IntoWidgetVec<Rsc, Tag, GTag>, Rsc, Tag, GTag>
|
||||||
CoreWidgetArr<State, LEN, Wa, Tag> for Wa
|
CoreWidgetArr<Children, Rsc, Tag, GTag> for Children
|
||||||
{
|
{
|
||||||
fn span(self, dir: Dir) -> SpanBuilder<State, LEN, Wa, Tag> {
|
fn span(self, dir: Dir) -> SpanBuilder<Children, Rsc, Tag, GTag> {
|
||||||
SpanBuilder::new(self, dir)
|
SpanBuilder::new(self, dir)
|
||||||
}
|
}
|
||||||
fn stack(self) -> StackBuilder<State, LEN, Wa, Tag> {
|
fn stack(self) -> StackBuilder<Children, Rsc, Tag, GTag> {
|
||||||
StackBuilder::new(self)
|
StackBuilder::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait RscFnMap<Rsc> {
|
||||||
|
type Input;
|
||||||
|
fn rsc_map<O>(
|
||||||
|
self,
|
||||||
|
f: impl Fn(Self::Input, &mut Rsc) -> O + Clone,
|
||||||
|
) -> impl Iterator<Item = impl FnOnce(&mut Rsc) -> O>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: IntoIterator, Rsc> RscFnMap<Rsc> for I {
|
||||||
|
type Input = I::Item;
|
||||||
|
fn rsc_map<O>(
|
||||||
|
self,
|
||||||
|
f: impl Fn(Self::Input, &mut Rsc) -> O + Clone,
|
||||||
|
) -> impl Iterator<Item = impl FnOnce(&mut Rsc) -> O> {
|
||||||
|
self.into_iter().map(move |i| {
|
||||||
|
let f = f.clone();
|
||||||
|
move |rsc: &mut Rsc| f(i, rsc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WidgetFnMap<Rsc: UiRsc> {
|
||||||
|
fn widget_map<O: WidgetLike<Rsc, Tag>, Tag>(
|
||||||
|
self,
|
||||||
|
f: impl Fn(WeakWidget) -> O + Clone,
|
||||||
|
) -> impl Iterator<Item = impl FnOnce(&mut Rsc) -> WeakWidget>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: IntoIterator, Rsc: UiRsc> WidgetFnMap<Rsc> for I
|
||||||
|
where
|
||||||
|
I::Item: WidgetIdFn<Rsc>,
|
||||||
|
{
|
||||||
|
fn widget_map<O: WidgetLike<Rsc, Tag>, Tag>(
|
||||||
|
self,
|
||||||
|
f: impl Fn(WeakWidget) -> O + Clone,
|
||||||
|
) -> impl Iterator<Item = impl FnOnce(&mut Rsc) -> WeakWidget> {
|
||||||
|
self.into_iter().map(move |f2| {
|
||||||
|
let f = f.clone();
|
||||||
|
move |rsc: &mut Rsc| f(f2(rsc)).add(rsc) as WeakWidget
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user