diff --git a/src/base/mod.rs b/src/base/mod.rs index 18758f6..d1203c8 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -49,18 +49,20 @@ impl Widget for Span { } impl Span { - pub fn proportioned( + pub fn proportioned( axis: Axis, - ratios: [impl UINum; LEN], - elements: [WidgetId; LEN], + elements: impl IntoIterator, ) -> Self { - let ratios = ratios.map(|r| r.to_f32()); - let total: f32 = ratios.iter().sum(); + // TODO: update + let elements = elements + .into_iter() + .map(|(w, r)| (w, r.to_f32())) + .collect::>(); + let total: f32 = elements.iter().map(|(_, r)| r).sum(); let mut start = 0.0; Self { elements: elements .into_iter() - .zip(ratios) .map(|(e, r)| { let end = start + r / total; let res = (start..end, e); @@ -118,11 +120,11 @@ impl From for Padding { } pub trait WidgetUtil { - fn pad(self, padding: impl Into) -> impl WidgetLike; + fn pad(self, padding: impl Into) -> impl WidgetLike; } -impl> WidgetUtil for WL { - fn pad(self, padding: impl Into) -> impl WidgetLike { +impl WidgetUtil for W { + fn pad(self, padding: impl Into) -> impl WidgetLike { WidgetFn(|ui| Regioned { region: padding.into().region(), inner: self.id(ui).erase_type(), @@ -130,13 +132,13 @@ impl> WidgetUtil for WL { } } -pub trait WidgetArrUtil { - fn span(self, axis: Axis, ratios: [impl UINum; LEN]) -> impl WidgetLike; +pub trait WidgetArrUtil { + fn span(self, axis: Axis, ratios: [impl UINum; Wa::LEN]) -> impl WidgetLike; } -impl> WidgetArrUtil for Wa { - fn span(self, axis: Axis, ratios: [impl UINum; LEN]) -> impl WidgetLike { - WidgetFn(move |ui| Span::proportioned(axis, ratios, self.ui(ui).arr)) +impl WidgetArrUtil for Wa { + fn span(self, axis: Axis, ratios: [impl UINum; Wa::LEN]) -> impl WidgetLike { + WidgetFn(move |ui| Span::proportioned(axis, self.ui(ui).ids().into_iter().zip(ratios))) } } diff --git a/src/layout/ui.rs b/src/layout/ui.rs index 0ddc123..b55416d 100644 --- a/src/layout/ui.rs +++ b/src/layout/ui.rs @@ -32,17 +32,17 @@ impl From for UIBuilder { impl UIBuilder { pub fn add(&mut self, w: W) -> WidgetRef { - WidgetRef::new(self.clone(), [self.push(w)]) + WidgetRef::new(self.clone(), (self.push(w), ())) } - pub fn push(&mut self, w: W) -> WidgetId { + pub fn push(&mut self, w: W) -> WidgetId { let mut ui = self.ui.borrow_mut(); let id = ui.ids.next(); ui.widgets.insert(id.duplicate(), w); WidgetId::new(id, TypeId::of::()) } - pub fn finish, W>(mut self, base: WL) -> UI { + pub fn finish(mut self, base: WL) -> UI { let base = base.id(&mut self).erase_type(); let mut ui = Rc::into_inner(self.ui).unwrap().into_inner(); ui.base = Some(base); diff --git a/src/layout/widget.rs b/src/layout/widget.rs index 1b44f99..5115d73 100644 --- a/src/layout/widget.rs +++ b/src/layout/widget.rs @@ -3,7 +3,11 @@ use std::{ marker::PhantomData, }; -use crate::{primitive::Painter, util::ID, UIBuilder}; +use crate::{ + primitive::Painter, + util::{IntoTupleList, TupleList, ID}, + UIBuilder, +}; pub trait Widget: 'static + Any { fn draw(&self, painter: &mut Painter); @@ -23,7 +27,7 @@ pub struct WidgetId { } // TODO: temp -impl Clone for WidgetId { +impl Clone for WidgetId { fn clone(&self) -> Self { Self { ty: self.ty, @@ -54,104 +58,129 @@ impl WidgetId { } } -pub trait WidgetLike { - fn id(self, ui: &mut UIBuilder) -> WidgetId; +pub trait WidgetLike { + type Widget; + fn id(self, ui: &mut UIBuilder) -> WidgetId; } /// wouldn't be needed if negative trait bounds & disjoint impls existed pub struct WidgetFn W, W>(pub F); -impl W> WidgetLike for WidgetFn { +impl W> WidgetLike for WidgetFn { + type Widget = W; fn id(self, ui: &mut UIBuilder) -> WidgetId { let w = (self.0)(ui); ui.add(w).to_id() } } -impl WidgetLike for W { +impl WidgetLike for W { + type Widget = W; fn id(self, ui: &mut UIBuilder) -> WidgetId { ui.add(self).to_id() } } -impl WidgetLike for WidgetId { +impl WidgetLike for WidgetId { + type Widget = W; fn id(self, _: &mut UIBuilder) -> WidgetId { self } } -impl WidgetLike for WidgetArr<1, (W,)> { - fn id(self, _: &mut UIBuilder) -> WidgetId { - let [id] = self.arr; - id.cast_type() - } -} - -pub struct WidgetArr { +pub struct WidgetArr { pub ui: UIBuilder, - pub arr: [WidgetId<()>; LEN], - _pd: PhantomData, + pub arr: Ws::Ids, } -impl WidgetArr { - pub fn new(ui: UIBuilder, arr: [WidgetId<()>; LEN]) -> Self { - Self { - ui, - arr, - _pd: PhantomData, - } +impl WidgetArr { + pub fn new(ui: UIBuilder, arr: Ws::Ids) -> Self { + Self { ui, arr } + } + pub fn ids(self) -> Vec { + self.arr.all() } } -pub type WidgetRef = WidgetArr<1, (W,)>; +pub type WidgetRef = WidgetArr<(W, ())>; impl WidgetRef { pub fn handle(&self) -> WidgetId { - let [id] = &self.arr; - id.clone().cast_type() + self.arr.head().clone() } pub fn to_id(self) -> WidgetId { - let [id] = self.arr; - id.cast_type() + self.arr.into_head() } } -pub trait WidgetArrLike { - fn ui(self, ui: &mut UIBuilder) -> WidgetArr; +impl WidgetLike for WidgetRef { + type Widget = W; + fn id(self, _: &mut UIBuilder) -> WidgetId { + self.arr.into_head() + } } -impl WidgetArrLike for WidgetArr { - fn ui(self, _: &mut UIBuilder) -> WidgetArr { +pub trait WidgetArrLike { + const LEN: usize; + type Ws: WidgetList; + fn ui(self, ui: &mut UIBuilder) -> WidgetArr; +} + +impl WidgetArrLike for WidgetArr { + const LEN: usize = Ws::LEN; + type Ws = Ws; + fn ui(self, _: &mut UIBuilder) -> WidgetArr { self } } -// I hate this language it's so bad why do I even use it -macro_rules! impl_node_arr { - ($n:expr;$($T:tt)*) => { - impl<$($T,${concat($T,$T)}: WidgetLike<$T>,)*> WidgetArrLike<$n, ($($T,)*)> for ($(${concat($T,$T)},)*) { - #[allow(unused_variables)] - fn ui(self, ui: &mut UIBuilder) -> WidgetArr<$n, ($($T,)*)> { - #[allow(non_snake_case)] - let ($($T,)*) = self; - WidgetArr::new( - ui.clone(), - [$($T.id(ui).cast_type(),)*], - ) - } - } - }; +impl WidgetArrLike for (W, ()) +where + Self: TupleList, +{ + const LEN: usize = ::LEN; + type Ws = (W::Widget, ()); + fn ui(self, ui: &mut UIBuilder) -> WidgetArr<(W::Widget, ())> { + WidgetArr::new(ui.clone(), (self.0.id(ui), ())) + } +} +impl WidgetArrLike for (W, T) +where + Self: TupleList, +{ + const LEN: usize = ::LEN; + type Ws = (W::Widget, T::Ws); + fn ui(self, ui: &mut UIBuilder) -> WidgetArr<(W::Widget, T::Ws)> { + WidgetArr::new(ui.clone(), (self.0.id(ui), self.1.ui(ui).arr)) + } } -impl_node_arr!(1;A); -impl_node_arr!(2;A B); -impl_node_arr!(3;A B C); -impl_node_arr!(4;A B C D); -impl_node_arr!(5;A B C D E); -impl_node_arr!(6;A B C D E F); -impl_node_arr!(7;A B C D E F G); -impl_node_arr!(8;A B C D E F G H); -impl_node_arr!(9;A B C D E F G H I); -impl_node_arr!(10;A B C D E F G H I J); -impl_node_arr!(11;A B C D E F G H I J K); -impl_node_arr!(12;A B C D E F G H I J K L); +pub trait WidgetList: TupleList { + type Ids: IdList; +} +impl WidgetList for (H, ()) { + type Ids = (WidgetId, ()); +} +impl WidgetList for (H, T) { + type Ids = (WidgetId, T::Ids); +} + +pub trait IdList: TupleList { + fn iter(self) -> impl Iterator; + fn all(self) -> Vec + where + Self: Sized, + { + self.iter().collect::>() + } +} +impl IdList for (WidgetId, ()) { + fn iter(self) -> impl Iterator { + core::iter::once(self.0.erase_type()) + } +} +impl IdList for (WidgetId, T) { + fn iter(self) -> impl Iterator { + core::iter::once(self.0.erase_type()).chain(self.1.iter()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 89d2b0e..af071d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,11 @@ #![feature(const_trait_impl)] #![feature(const_from)] #![feature(trait_alias)] +#![feature(generic_const_exprs)] mod layout; mod render; -mod util; +pub mod util; mod base; pub use layout::*; diff --git a/src/testing/mod.rs b/src/testing/mod.rs index 9d79ae3..b9f559e 100644 --- a/src/testing/mod.rs +++ b/src/testing/mod.rs @@ -1,7 +1,8 @@ +use gui::util::IntoTupleList; use std::sync::Arc; use app::App; -use gui::{primitive::Axis, RoundedRect, UIColor, WidgetArrLike, WidgetArrUtil, WidgetUtil, UI}; +use gui::{primitive::Axis, RoundedRect, UIColor, WidgetArrUtil, WidgetUtil, UI}; use render::Renderer; use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window}; @@ -38,15 +39,19 @@ impl Client { rect.color(UIColor::ORANGE), rect.color(UIColor::LIME).pad(10.0), ) - .span(Axis::Y, [1, 1]), + .into_list() + .span(Axis::Y, [1, 1].into()), rect.color(UIColor::YELLOW), ) + .into_list() .span(Axis::X, [2, 2, 1]) .pad(10), ) + .into_list() .span(Axis::X, [1, 3]), rect.color(UIColor::GREEN), ) + .into_list() .span(Axis::Y, [3, 1]) .pad(10), ); diff --git a/src/util/id.rs b/src/util/id.rs index ad6fc08..cca6616 100644 --- a/src/util/id.rs +++ b/src/util/id.rs @@ -27,6 +27,7 @@ impl IDTracker { id } + #[allow(dead_code)] pub fn free(&mut self, id: ID) { self.free.push(id); } diff --git a/src/util/mod.rs b/src/util/mod.rs index 3e76920..7b64d17 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,3 +1,5 @@ mod id; +mod tuple; pub use id::*; +pub use tuple::*; diff --git a/src/util/tuple.rs b/src/util/tuple.rs new file mode 100644 index 0000000..4162be2 --- /dev/null +++ b/src/util/tuple.rs @@ -0,0 +1,70 @@ +pub trait TupleList { + const LEN: usize; + type Head; + type Tail; + fn into_head(self) -> Self::Head; + fn head(&self) -> &Self::Head; + fn split(self) -> (Self::Head, Self::Tail); +} +impl TupleList for () { + const LEN: usize = 0; + type Head = (); + type Tail = (); + fn head(&self) -> &Self::Head { + &() + } + fn into_head(self) -> Self::Head {} + fn split(self) -> (Self::Head, Self::Tail) { + ((), ()) + } +} +impl TupleList for (T, Rest) { + const LEN: usize = Rest::LEN + 1; + type Head = T; + type Tail = Rest; + fn head(&self) -> &Self::Head { + &self.0 + } + fn into_head(self) -> Self::Head { + self.0 + } + fn split(self) -> (Self::Head, Self::Tail) { + (self.0, self.1) + } +} + +pub trait IntoTupleList { + type List; + fn into_list(self) -> Self::List; +} + +impl IntoTupleList for () { + type List = (); + fn into_list(self) -> Self::List {} +} + +macro_rules! impl_tuple { + ($H:tt $($T:tt)*) => { + impl<$H, $($T,)*> IntoTupleList for ($H, $($T,)*) { + type List = ($H, <($($T,)*) as IntoTupleList>::List); + fn into_list(self) -> Self::List { + #[allow(non_snake_case)] + let ($H, $($T,)*) = self; + ($H, ($($T,)*).into_list()) + } + } + }; +} + +impl_tuple!(A); +impl_tuple!(A B); +impl_tuple!(A B C); +impl_tuple!(A B C D); +impl_tuple!(A B C D E); +impl_tuple!(A B C D E F); +impl_tuple!(A B C D E F G); +impl_tuple!(A B C D E F G H); +impl_tuple!(A B C D E F G H I); +impl_tuple!(A B C D E F G H I J); +impl_tuple!(A B C D E F G H I J K); +impl_tuple!(A B C D E F G H I J K L);