stack & padding fix sorta, preparing for scroll areas
This commit is contained in:
0
src/core/empty.rs
Normal file
0
src/core/empty.rs
Normal file
@@ -12,8 +12,20 @@ impl Widget for Padded {
|
|||||||
|
|
||||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||||
let mut size = ctx.size(&self.inner);
|
let mut size = ctx.size(&self.inner);
|
||||||
size.abs.x += self.padding.left + self.padding.right;
|
// TODO: this is currently a hack
|
||||||
size.abs.y += self.padding.top + self.padding.bottom;
|
// the correct solution is that the position is not linear
|
||||||
|
// becauase if you have 0.5 rel + 100 abs, it's linear
|
||||||
|
// until you fill up parent rel (in abs units) and then 1.0 rel (piecewise linear)
|
||||||
|
// so I guess yet another detection system is needed
|
||||||
|
// to determine when abs translated to rel + rel > 1.0
|
||||||
|
// hopefully find a way to get working on gpu so no cpu changing needed
|
||||||
|
// eg by sending size to calculate above and then doing... something?
|
||||||
|
if size.rel.x != 1.0 {
|
||||||
|
size.abs.x += self.padding.left + self.padding.right;
|
||||||
|
}
|
||||||
|
if size.rel.y != 1.0 {
|
||||||
|
size.abs.y += self.padding.top + self.padding.bottom;
|
||||||
|
}
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ impl Widget for Span {
|
|||||||
} else {
|
} else {
|
||||||
UiScalar::new(total.rel, total.abs)
|
UiScalar::new(total.rel, total.abs)
|
||||||
};
|
};
|
||||||
let mut max_ortho = UiScalar::default();
|
let mut max_ortho = UiScalar::ZERO;
|
||||||
for (child, _) in &self.children {
|
for (child, _) in &self.children {
|
||||||
let size = ctx.size(child);
|
let size = ctx.size(child);
|
||||||
max_ortho = max_ortho.max(size.axis(!self.dir.axis));
|
max_ortho = max_ortho.max(size.axis(!self.dir.axis));
|
||||||
|
|||||||
@@ -1,19 +1,82 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Stack {
|
pub struct Stack {
|
||||||
pub children: Vec<WidgetId>,
|
pub children: Vec<WidgetId>,
|
||||||
|
pub size: StackSize,
|
||||||
|
pub offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Stack {
|
impl Widget for Stack {
|
||||||
fn draw(&mut self, painter: &mut Painter) {
|
fn draw(&mut self, painter: &mut Painter) {
|
||||||
|
for _ in 0..self.offset {
|
||||||
|
painter.layer = painter.next_layer();
|
||||||
|
}
|
||||||
let base = painter.layer;
|
let base = painter.layer;
|
||||||
for child in &self.children {
|
for child in &self.children {
|
||||||
if painter.layer == base {
|
painter.layer = if painter.layer == base {
|
||||||
painter.layer = painter.child_layer();
|
painter.child_layer()
|
||||||
} else {
|
} else {
|
||||||
painter.layer = painter.next_layer();
|
painter.next_layer()
|
||||||
}
|
};
|
||||||
painter.widget(child);
|
painter.widget(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||||
|
match self.size {
|
||||||
|
StackSize::Full => UiVec2::MAX_SIZE,
|
||||||
|
StackSize::Child(i) => ctx.size(&self.children[i]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub enum StackSize {
|
||||||
|
#[default]
|
||||||
|
Full,
|
||||||
|
Child(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StackBuilder<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> {
|
||||||
|
pub children: Wa,
|
||||||
|
pub size: StackSize,
|
||||||
|
pub offset: usize,
|
||||||
|
_pd: PhantomData<Tag>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> FnOnce<(&mut Ui,)>
|
||||||
|
for StackBuilder<LEN, Wa, Tag>
|
||||||
|
{
|
||||||
|
type Output = Stack;
|
||||||
|
|
||||||
|
extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output {
|
||||||
|
Stack {
|
||||||
|
children: self.children.ui(args.0).arr.to_vec(),
|
||||||
|
offset: self.offset,
|
||||||
|
size: self.size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> StackBuilder<LEN, Wa, Tag> {
|
||||||
|
pub fn new(children: Wa) -> Self {
|
||||||
|
Self {
|
||||||
|
children,
|
||||||
|
size: StackSize::default(),
|
||||||
|
offset: 0,
|
||||||
|
_pd: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stack_size(mut self, size: StackSize) -> Self {
|
||||||
|
self.size = size;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset_layer(mut self, offset: usize) -> Self {
|
||||||
|
self.offset = offset;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CoreWidgetArr<const LEN: usize, Tag> {
|
pub trait CoreWidgetArr<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> {
|
||||||
fn span(self, dir: Dir, lengths: impl IntoSpanLens<LEN>) -> impl WidgetFn<Span>;
|
fn span(self, dir: Dir, lengths: impl IntoSpanLens<LEN>) -> impl WidgetFn<Span>;
|
||||||
fn stack(self) -> impl WidgetFn<Stack>;
|
fn stack(self) -> StackBuilder<LEN, Wa, Tag>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> CoreWidgetArr<LEN, Tag> for Wa {
|
impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> CoreWidgetArr<LEN, Wa, Tag> for Wa {
|
||||||
fn span(self, dir: Dir, lengths: impl IntoSpanLens<LEN>) -> impl WidgetFn<Span> {
|
fn span(self, dir: Dir, lengths: impl IntoSpanLens<LEN>) -> impl WidgetFn<Span> {
|
||||||
let lengths = lengths.into_lens();
|
let lengths = lengths.into_lens();
|
||||||
move |ui| Span {
|
move |ui| Span {
|
||||||
@@ -57,10 +57,8 @@ impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> CoreWidgetArr<LEN, Tag>
|
|||||||
dir,
|
dir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn stack(self) -> impl WidgetFn<Stack> {
|
fn stack(self) -> StackBuilder<LEN, Wa, Tag> {
|
||||||
move |ui| Stack {
|
StackBuilder::new(self)
|
||||||
children: self.ui(ui).arr.to_vec(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ enum Ptr {
|
|||||||
/// is that realistically desired?
|
/// is that realistically desired?
|
||||||
pub struct Layers {
|
pub struct Layers {
|
||||||
vec: Vec<LayerNode>,
|
vec: Vec<LayerNode>,
|
||||||
|
/// index of last layer at top level (start at first = 0)
|
||||||
|
last: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: this can be replaced with Primitives itself atm
|
/// TODO: this can be replaced with Primitives itself atm
|
||||||
@@ -45,6 +47,7 @@ impl Layers {
|
|||||||
pub fn new() -> Layers {
|
pub fn new() -> Layers {
|
||||||
Self {
|
Self {
|
||||||
vec: vec![LayerNode::head()],
|
vec: vec![LayerNode::head()],
|
||||||
|
last: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +76,7 @@ impl Layers {
|
|||||||
match self.vec[i_new].next {
|
match self.vec[i_new].next {
|
||||||
Ptr::Next(i) => self.vec[i].prev = Ptr::Next(i_new),
|
Ptr::Next(i) => self.vec[i].prev = Ptr::Next(i_new),
|
||||||
Ptr::Parent(i) => self.vec[i].child.as_mut().unwrap().tail = i_new,
|
Ptr::Parent(i) => self.vec[i].child.as_mut().unwrap().tail = i_new,
|
||||||
Ptr::None => (),
|
Ptr::None => self.last = i_new,
|
||||||
}
|
}
|
||||||
i_new
|
i_new
|
||||||
}
|
}
|
||||||
@@ -95,11 +98,15 @@ impl Layers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_mut(&mut self) -> LayerIteratorMut<'_> {
|
pub fn iter_mut(&mut self) -> LayerIteratorMut<'_> {
|
||||||
LayerIteratorMut::new(&mut self.vec)
|
LayerIteratorMut::new(&mut self.vec, self.last)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = (usize, &Layer)> {
|
||||||
|
self.indices().map(|i| (i, &self.vec[i].data))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn indices(&self) -> LayerIndexIterator<'_> {
|
pub fn indices(&self) -> LayerIndexIterator<'_> {
|
||||||
LayerIndexIterator::new(&self.vec)
|
LayerIndexIterator::new(&self.vec, self.last)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write<P: Primitive>(
|
pub fn write<P: Primitive>(
|
||||||
@@ -179,9 +186,9 @@ impl<'a> DoubleEndedIterator for LayerIteratorMut<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LayerIteratorMut<'a> {
|
impl<'a> LayerIteratorMut<'a> {
|
||||||
fn new(vec: &'a mut Vec<LayerNode>) -> Self {
|
fn new(vec: &'a mut Vec<LayerNode>, last: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: LayerIndexIterator::new(vec),
|
inner: LayerIndexIterator::new(vec, last),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,7 +210,10 @@ impl<'a> Iterator for LayerIndexIterator<'a> {
|
|||||||
} else if let Ptr::Next(i) = node.next {
|
} else if let Ptr::Next(i) = node.next {
|
||||||
Some(i)
|
Some(i)
|
||||||
} else if let Ptr::Parent(i) = node.next {
|
} else if let Ptr::Parent(i) = node.next {
|
||||||
let node = &self.vec[i];
|
let mut node = &self.vec[i];
|
||||||
|
while let Ptr::Parent(i) = node.next {
|
||||||
|
node = &self.vec[i];
|
||||||
|
}
|
||||||
if let Ptr::Next(i) = node.next {
|
if let Ptr::Next(i) = node.next {
|
||||||
Some(i)
|
Some(i)
|
||||||
} else {
|
} else {
|
||||||
@@ -243,8 +253,8 @@ impl<'a> DoubleEndedIterator for LayerIndexIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LayerIndexIterator<'a> {
|
impl<'a> LayerIndexIterator<'a> {
|
||||||
fn new(vec: &'a Vec<LayerNode>) -> Self {
|
fn new(vec: &'a Vec<LayerNode>, last: usize) -> Self {
|
||||||
let mut last = 0;
|
let mut last = last;
|
||||||
while let Some(c) = vec[last].child {
|
while let Some(c) = vec[last].child {
|
||||||
last = c.tail;
|
last = c.tail;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,9 +69,19 @@ impl<'a> PainterCtx<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some((rid, size)) = &active.resize {
|
if let Some((rid, size)) = &active.resize {
|
||||||
self.redraw(&rid.duplicate());
|
let checked = &mut HashMap::default();
|
||||||
if self.drawing.contains(id) {
|
let mut ctx = SizeCtx {
|
||||||
return;
|
checked,
|
||||||
|
text: self.text,
|
||||||
|
textures: self.textures,
|
||||||
|
widgets: self.widgets,
|
||||||
|
};
|
||||||
|
let desired = ctx.size_inner(id);
|
||||||
|
if *size != desired {
|
||||||
|
self.redraw(&rid.duplicate());
|
||||||
|
if self.drawing.contains(id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,14 +308,17 @@ pub struct SizeCtx<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SizeCtx<'_> {
|
impl SizeCtx<'_> {
|
||||||
|
fn size_inner(&mut self, id: &Id) -> UiVec2 {
|
||||||
|
let size = self.widgets.get_dyn_dynamic(id).desired_size(self);
|
||||||
|
self.checked.insert(id.duplicate(), size);
|
||||||
|
size
|
||||||
|
}
|
||||||
pub fn size<W>(&mut self, id: &WidgetId<W>) -> UiVec2 {
|
pub fn size<W>(&mut self, id: &WidgetId<W>) -> UiVec2 {
|
||||||
// TODO: determine if this is useful
|
// TODO: determine if this is useful
|
||||||
// if let Some(size) = self.checked.get(&id.id) {
|
// if let Some(size) = self.checked.get(&id.id) {
|
||||||
// return Some(*size);
|
// return Some(*size);
|
||||||
// }
|
// }
|
||||||
let size = self.widgets.get_dyn_dynamic(&id.id).desired_size(self);
|
self.size_inner(&id.id)
|
||||||
self.checked.insert(id.id.duplicate(), size);
|
|
||||||
size
|
|
||||||
}
|
}
|
||||||
pub fn draw_text(
|
pub fn draw_text(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
@@ -100,9 +100,7 @@ impl UiVec2 {
|
|||||||
self.rel * size + self.abs
|
self.rel * size + self.abs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn max_size() -> Self {
|
pub const MAX_SIZE: Self = Self::rel(Vec2::ONE);
|
||||||
Self::rel(Vec2::ONE)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn from_axis(axis: Axis, aligned: UiScalar, ortho: UiScalar) -> Self {
|
pub const fn from_axis(axis: Axis, aligned: UiScalar, ortho: UiScalar) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -134,6 +132,8 @@ impl_op!(UiScalar Add add; rel abs);
|
|||||||
impl_op!(UiScalar Sub sub; rel abs);
|
impl_op!(UiScalar Sub sub; rel abs);
|
||||||
|
|
||||||
impl UiScalar {
|
impl UiScalar {
|
||||||
|
pub const ZERO: Self = Self { rel: 0.0, abs: 0.0 };
|
||||||
|
|
||||||
pub fn new(rel: f32, abs: f32) -> Self {
|
pub fn new(rel: f32, abs: f32) -> Self {
|
||||||
Self { rel, abs }
|
Self { rel, abs }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{any::Any, marker::PhantomData};
|
|||||||
pub trait Widget: Any {
|
pub trait Widget: Any {
|
||||||
fn draw(&mut self, painter: &mut Painter);
|
fn draw(&mut self, painter: &mut Painter);
|
||||||
fn desired_size(&mut self, _: &mut SizeCtx) -> UiVec2 {
|
fn desired_size(&mut self, _: &mut SizeCtx) -> UiVec2 {
|
||||||
UiVec2::max_size()
|
UiVec2::MAX_SIZE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ impl<const LEN: usize, Ws> WidgetArr<LEN, Ws> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ArrTag;
|
pub struct ArrTag;
|
||||||
pub trait WidgetArrLike<const LEN: usize, Tags> {
|
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>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,27 +138,37 @@ impl Client {
|
|||||||
let content = client.ui.text(id).take();
|
let content = client.ui.text(id).take();
|
||||||
let text = text_edit(content)
|
let text = text_edit(content)
|
||||||
.font_size(30)
|
.font_size(30)
|
||||||
|
.text_align(Align::Left)
|
||||||
.id_on(Sense::click(), |id, client: &mut Client, ctx| {
|
.id_on(Sense::click(), |id, client: &mut Client, ctx| {
|
||||||
client.ui.text(id).select(ctx.cursor, ctx.size);
|
client.ui.text(id).select(ctx.cursor, ctx.size);
|
||||||
client.focus = Some(id.clone());
|
client.focus = Some(id.clone());
|
||||||
})
|
});
|
||||||
.pad(10)
|
let msg_box = (rect(Color::WHITE.darker(0.5)), text)
|
||||||
|
.stack()
|
||||||
|
.stack_size(StackSize::Child(1))
|
||||||
.add(&mut client.ui);
|
.add(&mut client.ui);
|
||||||
client.ui[texts].children.push((text.any(), sized()));
|
client.ui[texts].children.push((msg_box.any(), sized()));
|
||||||
})
|
})
|
||||||
.add(&mut ui);
|
.add(&mut ui);
|
||||||
let text_edit_scroll = (
|
let text_edit_scroll = (
|
||||||
(Rect::new(Color::SKY), texts).stack(),
|
(Rect::new(Color::SKY), texts).stack(),
|
||||||
(
|
(
|
||||||
add_text.clone(),
|
Rect::new(Color::WHITE.darker(0.9)),
|
||||||
Rect::new(Color::GREEN)
|
(
|
||||||
.on(Sense::click(), move |client: &mut Client, _| {
|
add_text.clone(),
|
||||||
client.run_event(&add_text, Submit, ());
|
Rect::new(Color::GREEN)
|
||||||
})
|
.on(Sense::click(), move |client: &mut Client, _| {
|
||||||
.size(40),
|
client.run_event(&add_text, Submit, ());
|
||||||
|
})
|
||||||
|
.size(40),
|
||||||
|
)
|
||||||
|
.span(Dir::RIGHT, [ratio(1), sized()])
|
||||||
|
.pad(10),
|
||||||
)
|
)
|
||||||
.span(Dir::RIGHT, [ratio(1), sized()])
|
.stack()
|
||||||
.pad(30),
|
.stack_size(StackSize::Child(1))
|
||||||
|
.offset_layer(1)
|
||||||
|
.align(Align::Bot),
|
||||||
)
|
)
|
||||||
.span(Dir::DOWN, [ratio(1), sized()])
|
.span(Dir::DOWN, [ratio(1), sized()])
|
||||||
.add_static(&mut ui);
|
.add_static(&mut ui);
|
||||||
@@ -192,7 +202,7 @@ impl Client {
|
|||||||
.span(Dir::RIGHT, ratio(1));
|
.span(Dir::RIGHT, ratio(1));
|
||||||
|
|
||||||
let info = text("").add(&mut ui);
|
let info = text("").add(&mut ui);
|
||||||
let info_sect = info.clone().pad(10).align(Align::BotLeft);
|
let info_sect = info.clone().pad(10).align(Align::Right);
|
||||||
|
|
||||||
(
|
(
|
||||||
(tabs, main).span(Dir::DOWN, [fixed(40), ratio(1)]),
|
(tabs, main).span(Dir::DOWN, [fixed(40), ratio(1)]),
|
||||||
|
|||||||
Reference in New Issue
Block a user