switch to element defined span lens + better size fn
This commit is contained in:
883
Cargo.lock
generated
883
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ winit = "0.30.12"
|
||||
wgpu = "27.0.1"
|
||||
bytemuck = "1.23.1"
|
||||
image = "0.25.6"
|
||||
cosmic-text = "0.14.2"
|
||||
cosmic-text = "0.15.0"
|
||||
unicode-segmentation = "1.12.0"
|
||||
fxhash = "0.2.1"
|
||||
arboard = { version = "3.6.1", features = ["wayland-data-control"] }
|
||||
|
||||
@@ -10,8 +10,8 @@ impl Widget for Image {
|
||||
painter.texture(&self.handle);
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, _: &mut SizeCtx) -> UiVec2 {
|
||||
UiVec2::abs(self.handle.size())
|
||||
fn desired_size(&mut self, _: &mut SizeCtx) -> Size {
|
||||
Size::abs(self.handle.size())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,12 @@ pub struct Aligned {
|
||||
|
||||
impl Widget for Aligned {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
let region = UiRegion::from_ui_size_align(painter.size(&self.inner), self.align);
|
||||
let region =
|
||||
UiRegion::from_ui_size_align(painter.size(&self.inner).to_uivec2(), self.align);
|
||||
painter.widget_within(&self.inner, region);
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size {
|
||||
ctx.size(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ impl Widget for Offset {
|
||||
painter.widget_within(&self.inner, region);
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size {
|
||||
ctx.size(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,22 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct Padded {
|
||||
pub struct Pad {
|
||||
pub padding: Padding,
|
||||
pub inner: WidgetId,
|
||||
}
|
||||
|
||||
impl Widget for Padded {
|
||||
impl Widget for Pad {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
painter.widget_within(&self.inner, self.padding.region());
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size {
|
||||
let mut size = ctx.size(&self.inner);
|
||||
// TODO: this is currently a hack
|
||||
// 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.x.rest == 0.0 {
|
||||
size.x.abs += self.padding.left + self.padding.right;
|
||||
}
|
||||
if size.rel.y != 1.0 {
|
||||
size.abs.y += self.padding.top + self.padding.bottom;
|
||||
if size.y.rest == 0.0 {
|
||||
size.y.abs += self.padding.top + self.padding.bottom;
|
||||
}
|
||||
size
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@ use crate::prelude::*;
|
||||
|
||||
pub struct Sized {
|
||||
pub inner: WidgetId,
|
||||
pub size: Vec2,
|
||||
pub x: Option<Len>,
|
||||
pub y: Option<Len>,
|
||||
}
|
||||
|
||||
impl Widget for Sized {
|
||||
@@ -10,7 +11,10 @@ impl Widget for Sized {
|
||||
painter.widget(&self.inner);
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, _: &mut SizeCtx) -> UiVec2 {
|
||||
UiVec2::abs(self.size)
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size {
|
||||
Size {
|
||||
x: self.x.unwrap_or_else(|| ctx.size(&self.inner).x),
|
||||
y: self.y.unwrap_or_else(|| ctx.size(&self.inner).y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,27 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct Span {
|
||||
pub children: Vec<(WidgetId, SpanLen)>,
|
||||
pub children: Vec<WidgetId>,
|
||||
pub dir: Dir,
|
||||
pub spacing: f32,
|
||||
}
|
||||
|
||||
impl Widget for Span {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
let total = self.setup(&mut painter.size_ctx());
|
||||
let total = self.len_sum(&mut painter.size_ctx());
|
||||
let mut start = UiScalar::rel_min();
|
||||
for (child, length) in &self.children {
|
||||
for child in &self.children {
|
||||
let mut child_region = UiRegion::full();
|
||||
let mut axis = child_region.axis_mut(self.dir.axis);
|
||||
axis.top_left.set(start);
|
||||
match *length {
|
||||
SpanLen::Fixed(offset) => {
|
||||
start.abs += offset;
|
||||
}
|
||||
SpanLen::Ratio(ratio) => {
|
||||
let len = painter.size(child).axis(self.dir.axis);
|
||||
start.abs += len.abs;
|
||||
start.rel += len.rel;
|
||||
if len.rest > 0.0 {
|
||||
let offset = UiScalar::new(total.rel, total.abs);
|
||||
let rel_end = UiScalar::from_anchor(ratio / total.ratio);
|
||||
let rel_end = UiScalar::from_anchor(len.rest / total.rest);
|
||||
start = rel_end.within(start, (UiScalar::rel_max() + start) - offset);
|
||||
}
|
||||
SpanLen::Relative(rel) => {
|
||||
start.rel += rel;
|
||||
}
|
||||
SpanLen::Sized(size) => {
|
||||
let size_axis = size.axis(self.dir.axis);
|
||||
start.abs += size_axis.abs;
|
||||
start.rel += size_axis.rel;
|
||||
}
|
||||
}
|
||||
axis.bot_right.set(start);
|
||||
if self.dir.sign == Sign::Neg {
|
||||
child_region.flip(self.dir.axis);
|
||||
@@ -41,31 +31,27 @@ impl Widget for Span {
|
||||
}
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||
let total = self.setup(ctx);
|
||||
let axis = self.dir.axis;
|
||||
let dir_len = if total.ratio != 0.0 {
|
||||
UiScalar::rel_max()
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size {
|
||||
let mut sums = self.len_sum(ctx);
|
||||
let dir_len = if sums.rest == 0.0 && sums.rel == 0.0 {
|
||||
sums.abs += self.spacing * self.children.len().saturating_sub(1) as f32;
|
||||
sums
|
||||
} else {
|
||||
UiScalar::new(
|
||||
total.rel,
|
||||
total.abs + self.spacing * self.children.len().saturating_sub(1) as f32,
|
||||
)
|
||||
Len::default()
|
||||
};
|
||||
let mut max_ortho = UiScalar::ZERO;
|
||||
for (child, _) in &self.children {
|
||||
let size = ctx.size(child);
|
||||
max_ortho = max_ortho.max(size.axis(!self.dir.axis));
|
||||
let mut max_ortho = Len::ZERO;
|
||||
for child in &self.children {
|
||||
let len = ctx.size(child).axis(!self.dir.axis);
|
||||
// TODO: rel shouldn't do this, but no easy way before actually calculating pixels
|
||||
if len.rel > 0.0 || len.rest > 0.0 {
|
||||
max_ortho.rest = 1.0;
|
||||
max_ortho.abs = 0.0;
|
||||
break;
|
||||
}
|
||||
UiVec2::from_axis(axis, dir_len, max_ortho)
|
||||
max_ortho.abs = max_ortho.abs.max(len.abs);
|
||||
}
|
||||
Size::from_axis(self.dir.axis, dir_len, max_ortho)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SpanLenSums {
|
||||
pub abs: f32,
|
||||
pub ratio: f32,
|
||||
pub rel: f32,
|
||||
}
|
||||
|
||||
impl Span {
|
||||
@@ -82,61 +68,10 @@ impl Span {
|
||||
self
|
||||
}
|
||||
|
||||
fn setup(&mut self, ctx: &mut SizeCtx) -> SpanLenSums {
|
||||
self.children
|
||||
.iter_mut()
|
||||
.fold(SpanLenSums::default(), |mut s, (id, l)| {
|
||||
match l {
|
||||
SpanLen::Fixed(v) => s.abs += *v,
|
||||
SpanLen::Ratio(v) => s.ratio += *v,
|
||||
SpanLen::Relative(v) => s.rel += *v,
|
||||
SpanLen::Sized(v) => {
|
||||
let size = ctx.size(id);
|
||||
let len = size.axis(self.dir.axis);
|
||||
*v = size;
|
||||
s.abs += len.abs;
|
||||
s.rel += len.rel;
|
||||
}
|
||||
}
|
||||
fn len_sum(&mut self, ctx: &mut SizeCtx) -> Len {
|
||||
self.children.iter_mut().fold(Len::ZERO, |mut s, id| {
|
||||
s += ctx.size(id).axis(self.dir.axis);
|
||||
s
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum SpanLen {
|
||||
/// exact (non dynamic) size
|
||||
Fixed(f32),
|
||||
/// relative to remaining free space and other ratios
|
||||
/// eg. 1 and 2 would take up 1/3 and 2/3 of the remaining space (after others)
|
||||
Ratio(f32),
|
||||
/// relative to the total space (of the entire span)
|
||||
/// eg. 0.5 means 1/2 of the total space
|
||||
Relative(f32),
|
||||
/// size determined by the child widget itself
|
||||
/// the value is not used externally, I just don't wanna make a duplicate enum
|
||||
/// there are util functions instead so
|
||||
Sized(UiVec2),
|
||||
}
|
||||
|
||||
pub fn fixed<N: UiNum>(x: N) -> SpanLen {
|
||||
SpanLen::Fixed(x.to_f32())
|
||||
}
|
||||
|
||||
pub fn ratio<N: UiNum>(x: N) -> SpanLen {
|
||||
SpanLen::Ratio(x.to_f32())
|
||||
}
|
||||
|
||||
pub fn relative<N: UiNum>(x: N) -> SpanLen {
|
||||
SpanLen::Relative(x.to_f32())
|
||||
}
|
||||
|
||||
pub fn sized() -> SpanLen {
|
||||
SpanLen::Sized(UiVec2::default())
|
||||
}
|
||||
|
||||
impl<N: UiNum> From<N> for SpanLen {
|
||||
fn from(value: N) -> Self {
|
||||
Self::Ratio(value.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ impl Widget for Stack {
|
||||
}
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size {
|
||||
match self.size {
|
||||
StackSize::Full => UiVec2::MAX_SIZE,
|
||||
StackSize::Default => Size::default(),
|
||||
StackSize::Child(i) => ctx.size(&self.children[i]),
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ impl Widget for Stack {
|
||||
#[derive(Default, Debug)]
|
||||
pub enum StackSize {
|
||||
#[default]
|
||||
Full,
|
||||
Default,
|
||||
Child(usize),
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ impl TextBuilderOutput for TextOutput {
|
||||
&builder.content,
|
||||
&Attrs::new(),
|
||||
Shaping::Advanced,
|
||||
None,
|
||||
);
|
||||
let mut text = Text {
|
||||
content: builder.content.into(),
|
||||
@@ -94,6 +95,7 @@ impl TextBuilderOutput for TextEditOutput {
|
||||
&builder.content,
|
||||
&Attrs::new(),
|
||||
Shaping::Advanced,
|
||||
None,
|
||||
);
|
||||
builder.attrs.apply(font_system, &mut text.buf, None);
|
||||
text
|
||||
|
||||
@@ -41,8 +41,8 @@ impl Widget for TextEdit {
|
||||
}
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||
UiVec2::abs(self.view.draw(ctx).size())
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size {
|
||||
Size::abs(self.view.draw(ctx).size())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ impl<'a> TextEditCtx<'a> {
|
||||
.join("\n");
|
||||
self.text
|
||||
.buf
|
||||
.set_text(self.font_system, "", &Attrs::new(), Shaping::Advanced);
|
||||
.set_text(self.font_system, "", &Attrs::new(), Shaping::Advanced, None);
|
||||
if let Some(cursor) = &mut self.text.cursor {
|
||||
cursor.line = 0;
|
||||
cursor.index = 0;
|
||||
|
||||
@@ -75,6 +75,7 @@ impl Text {
|
||||
&self.content,
|
||||
&Attrs::new().family(self.view.attrs.family),
|
||||
Shaping::Advanced,
|
||||
None,
|
||||
);
|
||||
}
|
||||
self.view.draw(ctx)
|
||||
@@ -88,8 +89,8 @@ impl Widget for Text {
|
||||
painter.texture_within(&tex.handle, region);
|
||||
}
|
||||
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||
UiVec2::abs(self.update_buf(ctx).size())
|
||||
fn desired_size(&mut self, ctx: &mut SizeCtx) -> Size {
|
||||
Size::abs(self.update_buf(ctx).size())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,19 +2,21 @@ use super::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub trait CoreWidget<W, Tag> {
|
||||
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Padded>;
|
||||
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Pad>;
|
||||
fn align(self, align: Align) -> impl WidgetFn<Aligned>;
|
||||
fn center(self) -> impl WidgetFn<Aligned>;
|
||||
fn label(self, label: impl Into<String>) -> impl WidgetIdFn<W>;
|
||||
fn sized(self, size: impl Into<Vec2>) -> impl WidgetFn<Sized>;
|
||||
fn sized(self, size: impl Into<Size>) -> impl WidgetFn<Sized>;
|
||||
fn width(self, len: impl Into<Len>) -> impl WidgetFn<Sized>;
|
||||
fn height(self, len: impl Into<Len>) -> impl WidgetFn<Sized>;
|
||||
fn offset(self, amt: impl Into<UiVec2>) -> impl WidgetFn<Offset>;
|
||||
fn scroll(self) -> impl WidgetIdFn<Offset>;
|
||||
fn masked(self) -> impl WidgetFn<Masked>;
|
||||
}
|
||||
|
||||
impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
|
||||
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Padded> {
|
||||
|ui| Padded {
|
||||
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Pad> {
|
||||
|ui| Pad {
|
||||
padding: padding.into(),
|
||||
inner: self.add(ui).any(),
|
||||
}
|
||||
@@ -39,10 +41,30 @@ impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
|
||||
}
|
||||
}
|
||||
|
||||
fn sized(self, size: impl Into<Vec2>) -> impl WidgetFn<Sized> {
|
||||
fn sized(self, size: impl Into<Size>) -> impl WidgetFn<Sized> {
|
||||
let size = size.into();
|
||||
move |ui| Sized {
|
||||
inner: self.add(ui).any(),
|
||||
size: size.into(),
|
||||
x: Some(size.x),
|
||||
y: Some(size.y),
|
||||
}
|
||||
}
|
||||
|
||||
fn width(self, len: impl Into<Len>) -> impl WidgetFn<Sized> {
|
||||
let len = len.into();
|
||||
move |ui| Sized {
|
||||
inner: self.add(ui).any(),
|
||||
x: Some(len),
|
||||
y: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn height(self, len: impl Into<Len>) -> impl WidgetFn<Sized> {
|
||||
let len = len.into();
|
||||
move |ui| Sized {
|
||||
inner: self.add(ui).any(),
|
||||
x: None,
|
||||
y: Some(len),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,15 +90,14 @@ impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
|
||||
}
|
||||
|
||||
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) -> impl WidgetFn<Span>;
|
||||
fn stack(self) -> StackBuilder<LEN, Wa, Tag>;
|
||||
}
|
||||
|
||||
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> {
|
||||
let lengths = lengths.into_lens();
|
||||
fn span(self, dir: Dir) -> impl WidgetFn<Span> {
|
||||
move |ui| Span {
|
||||
children: self.ui(ui).arr.into_iter().zip(lengths).collect(),
|
||||
children: self.ui(ui).arr.to_vec(),
|
||||
dir,
|
||||
spacing: 0.0,
|
||||
}
|
||||
@@ -85,19 +106,3 @@ impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> CoreWidgetArr<LEN, Wa,
|
||||
StackBuilder::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoSpanLens<const LEN: usize> {
|
||||
fn into_lens(self) -> [SpanLen; LEN];
|
||||
}
|
||||
|
||||
impl<const LEN: usize, T: Into<SpanLen>> IntoSpanLens<LEN> for [T; LEN] {
|
||||
fn into_lens(self) -> [SpanLen; LEN] {
|
||||
self.map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> IntoSpanLens<LEN> for SpanLen {
|
||||
fn into_lens(self) -> [SpanLen; LEN] {
|
||||
[self; LEN]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use std::ops::Not;
|
||||
|
||||
use crate::layout::{Vec2, vec2};
|
||||
use crate::{
|
||||
layout::{UiNum, UiVec2, Vec2, vec2},
|
||||
util::impl_op,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Axis {
|
||||
@@ -100,3 +103,172 @@ impl Align {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, PartialEq)]
|
||||
pub struct Size {
|
||||
pub x: Len,
|
||||
pub y: Len,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub struct Len {
|
||||
pub abs: f32,
|
||||
pub rel: f32,
|
||||
pub rest: f32,
|
||||
}
|
||||
|
||||
impl<N: UiNum> From<N> for Len {
|
||||
fn from(value: N) -> Self {
|
||||
Len::abs(value.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Nx: UiNum, Ny: UiNum> From<(Nx, Ny)> for Size {
|
||||
fn from((x, y): (Nx, Ny)) -> Self {
|
||||
Self {
|
||||
x: x.into(),
|
||||
y: y.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Size {
|
||||
pub const ZERO: Self = Self {
|
||||
x: Len::ZERO,
|
||||
y: Len::ZERO,
|
||||
};
|
||||
pub fn abs(v: Vec2) -> Self {
|
||||
Self {
|
||||
x: Len::abs(v.x),
|
||||
y: Len::abs(v.y),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_uivec2(self) -> UiVec2 {
|
||||
UiVec2 {
|
||||
rel: Vec2 {
|
||||
x: self.x.total_rel(),
|
||||
y: self.y.total_rel(),
|
||||
},
|
||||
abs: Vec2 {
|
||||
x: self.x.abs,
|
||||
y: self.y.abs,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_axis(axis: Axis, aligned: Len, ortho: Len) -> Self {
|
||||
match axis {
|
||||
Axis::X => Self {
|
||||
x: aligned,
|
||||
y: ortho,
|
||||
},
|
||||
Axis::Y => Self {
|
||||
x: ortho,
|
||||
y: aligned,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn axis(&self, axis: Axis) -> Len {
|
||||
match axis {
|
||||
Axis::X => self.x,
|
||||
Axis::Y => self.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Len {
|
||||
pub const ZERO: Self = Self {
|
||||
abs: 0.0,
|
||||
rel: 0.0,
|
||||
rest: 0.0,
|
||||
};
|
||||
|
||||
pub fn total_rel(&self) -> f32 {
|
||||
if self.rest > 0.0 {
|
||||
self.rel.max(1.0)
|
||||
} else {
|
||||
self.rel
|
||||
}
|
||||
}
|
||||
pub fn abs(abs: impl UiNum) -> Self {
|
||||
Self {
|
||||
abs: abs.to_f32(),
|
||||
rel: 0.0,
|
||||
rest: 0.0,
|
||||
}
|
||||
}
|
||||
pub fn rel(rel: impl UiNum) -> Self {
|
||||
Self {
|
||||
abs: 0.0,
|
||||
rel: rel.to_f32(),
|
||||
rest: 0.0,
|
||||
}
|
||||
}
|
||||
pub fn rest(ratio: impl UiNum) -> Self {
|
||||
Self {
|
||||
abs: 0.0,
|
||||
rel: 0.0,
|
||||
rest: ratio.to_f32(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod len_fns {
|
||||
use super::*;
|
||||
|
||||
pub fn abs(abs: impl UiNum) -> Len {
|
||||
Len {
|
||||
abs: abs.to_f32(),
|
||||
rel: 0.0,
|
||||
rest: 0.0,
|
||||
}
|
||||
}
|
||||
pub fn rel(rel: impl UiNum) -> Len {
|
||||
Len {
|
||||
abs: 0.0,
|
||||
rel: rel.to_f32(),
|
||||
rest: 0.0,
|
||||
}
|
||||
}
|
||||
pub fn rest(ratio: impl UiNum) -> Len {
|
||||
Len {
|
||||
abs: 0.0,
|
||||
rel: 0.0,
|
||||
rest: ratio.to_f32(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_op!(Len Add add; abs rel rest);
|
||||
impl_op!(Len Sub sub; abs rel rest);
|
||||
|
||||
impl_op!(Size Add add; x y);
|
||||
impl_op!(Size Sub sub; x y);
|
||||
|
||||
impl Default for Len {
|
||||
fn default() -> Self {
|
||||
Self::rest(1.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Size {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "({}, {})", self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Len {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.abs != 0.0 {
|
||||
write!(f, "{} abs;", self.abs)?;
|
||||
}
|
||||
if self.rel != 0.0 {
|
||||
write!(f, "{} rel;", self.abs)?;
|
||||
}
|
||||
if self.rest != 0.0 {
|
||||
write!(f, "{} leftover;", self.abs)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
layout::{
|
||||
Layers, Modules, TextAttrs, TextBuffer, TextData, TextTexture, TextureHandle, Textures,
|
||||
UiRegion, UiVec2, Vec2, WidgetId, Widgets,
|
||||
Layers, Modules, Size, TextAttrs, TextBuffer, TextData, TextTexture, TextureHandle,
|
||||
Textures, UiRegion, Vec2, WidgetId, Widgets,
|
||||
},
|
||||
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
||||
util::{HashMap, HashSet, Id, TrackedArena},
|
||||
@@ -14,7 +14,7 @@ pub struct Painter<'a, 'c> {
|
||||
textures: Vec<TextureHandle>,
|
||||
primitives: Vec<PrimitiveHandle>,
|
||||
children: Vec<Id>,
|
||||
sized_children: HashMap<Id, UiVec2>,
|
||||
sized_children: HashMap<Id, Size>,
|
||||
/// whether this widget depends on region's final pixel size or not
|
||||
/// TODO: decide if point (pt) should be used here instead of px
|
||||
pub layer: usize,
|
||||
@@ -41,10 +41,10 @@ pub struct WidgetInstance {
|
||||
pub textures: Vec<TextureHandle>,
|
||||
pub primitives: Vec<PrimitiveHandle>,
|
||||
pub children: Vec<Id>,
|
||||
pub resize: Option<(Id, UiVec2)>,
|
||||
pub resize: Option<(Id, Size)>,
|
||||
pub mask: MaskIdx,
|
||||
pub layer: usize,
|
||||
pub desired_size: UiVec2,
|
||||
pub desired_size: Size,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -348,7 +348,7 @@ impl<'a, 'c> Painter<'a, 'c> {
|
||||
self.region
|
||||
}
|
||||
|
||||
pub fn size<W>(&mut self, id: &WidgetId<W>) -> UiVec2 {
|
||||
pub fn size<W>(&mut self, id: &WidgetId<W>) -> Size {
|
||||
self.size_ctx().size(id)
|
||||
}
|
||||
|
||||
@@ -388,14 +388,14 @@ pub struct SizeCtx<'a> {
|
||||
pub textures: &'a mut Textures,
|
||||
widgets: &'a Widgets,
|
||||
px_dependent: &'a mut HashSet<Id>,
|
||||
checked: &'a mut HashMap<Id, UiVec2>,
|
||||
checked: &'a mut HashMap<Id, Size>,
|
||||
region: UiRegion,
|
||||
screen_size: Vec2,
|
||||
id: Id,
|
||||
}
|
||||
|
||||
impl SizeCtx<'_> {
|
||||
fn size_inner(&mut self, id: Id, region: UiRegion) -> UiVec2 {
|
||||
fn size_inner(&mut self, id: Id, region: UiRegion) -> Size {
|
||||
let self_region = self.region;
|
||||
self.region = region;
|
||||
let size = self.widgets.get_dyn_dynamic(id).desired_size(self);
|
||||
@@ -403,17 +403,17 @@ impl SizeCtx<'_> {
|
||||
self.checked.insert(id, size);
|
||||
size
|
||||
}
|
||||
pub fn size<W>(&mut self, id: &WidgetId<W>) -> UiVec2 {
|
||||
pub fn size<W>(&mut self, id: &WidgetId<W>) -> Size {
|
||||
// TODO: determine if this is useful
|
||||
// if let Some(size) = self.checked.get(&id.id) {
|
||||
// return Some(*size);
|
||||
// }
|
||||
if let Some(&size) = self.checked.get(&id.id) {
|
||||
return size;
|
||||
}
|
||||
self.size_inner(id.id, self.region)
|
||||
}
|
||||
fn size_raw(&mut self, id: Id) -> UiVec2 {
|
||||
fn size_raw(&mut self, id: Id) -> Size {
|
||||
self.size_inner(id, self.region)
|
||||
}
|
||||
pub fn size_within<W>(&mut self, id: &WidgetId<W>, region: UiRegion) -> UiVec2 {
|
||||
pub fn size_within<W>(&mut self, id: &WidgetId<W>, region: UiRegion) -> Size {
|
||||
self.size_inner(id.id, region.within(&self.region))
|
||||
}
|
||||
pub fn px_size(&mut self) -> Vec2 {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::layout::{Painter, SizeCtx, StaticWidgetId, Ui, UiVec2, WidgetId, WidgetIdFn};
|
||||
use crate::layout::{Painter, SizeCtx, StaticWidgetId, Ui, Size, WidgetId, WidgetIdFn};
|
||||
|
||||
use std::{any::Any, marker::PhantomData};
|
||||
|
||||
pub trait Widget: Any {
|
||||
fn draw(&mut self, painter: &mut Painter);
|
||||
fn desired_size(&mut self, _: &mut SizeCtx) -> UiVec2 {
|
||||
UiVec2::MAX_SIZE
|
||||
fn desired_size(&mut self, _: &mut SizeCtx) -> Size {
|
||||
Size::default()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use ui::prelude::*;
|
||||
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
|
||||
|
||||
use crate::testing::input::Input;
|
||||
use len_fns::*;
|
||||
|
||||
mod app;
|
||||
mod input;
|
||||
@@ -42,39 +43,35 @@ impl Client {
|
||||
let pad_test = (
|
||||
rrect.color(Color::BLUE),
|
||||
(
|
||||
rrect.color(Color::RED).sized(100).center(),
|
||||
rrect
|
||||
.color(Color::RED)
|
||||
.sized((100, 100))
|
||||
.center()
|
||||
.width(rest(2)),
|
||||
(
|
||||
rrect.color(Color::ORANGE),
|
||||
rrect.color(Color::LIME).pad(10.0),
|
||||
)
|
||||
.span(Dir::RIGHT, ratio(1)),
|
||||
.span(Dir::RIGHT)
|
||||
.width(rest(2)),
|
||||
rrect.color(Color::YELLOW),
|
||||
)
|
||||
.span(Dir::RIGHT, [2, 2, 1])
|
||||
.pad(10),
|
||||
.span(Dir::RIGHT)
|
||||
.pad(10)
|
||||
.width(rest(3)),
|
||||
)
|
||||
.span(Dir::RIGHT, [1, 3])
|
||||
.span(Dir::RIGHT)
|
||||
.add_static(&mut ui);
|
||||
|
||||
let span_test = (
|
||||
rrect.color(Color::GREEN),
|
||||
rrect.color(Color::GREEN).width(100),
|
||||
rrect.color(Color::ORANGE),
|
||||
rrect.color(Color::CYAN),
|
||||
rrect.color(Color::BLUE),
|
||||
rrect.color(Color::MAGENTA),
|
||||
rrect.color(Color::RED),
|
||||
)
|
||||
.span(
|
||||
Dir::LEFT,
|
||||
[
|
||||
fixed(100),
|
||||
ratio(1),
|
||||
ratio(1),
|
||||
relative(0.5),
|
||||
fixed(100),
|
||||
fixed(100),
|
||||
],
|
||||
rrect.color(Color::BLUE).width(rel(0.5)),
|
||||
rrect.color(Color::MAGENTA).width(100),
|
||||
rrect.color(Color::RED).width(100),
|
||||
)
|
||||
.span(Dir::LEFT)
|
||||
.add_static(&mut ui);
|
||||
|
||||
let span_add = Span::empty(Dir::RIGHT).add_static(&mut ui);
|
||||
@@ -86,9 +83,9 @@ impl Client {
|
||||
.ui
|
||||
.add(image(include_bytes!("assets/sungals.png")).center())
|
||||
.any();
|
||||
ctx.ui[span_add].children.push((child, sized()));
|
||||
ctx.ui[span_add].children.push(child);
|
||||
})
|
||||
.sized(150)
|
||||
.sized((150, 150))
|
||||
.align(Align::BotRight);
|
||||
|
||||
let del_button = rect(Color::RED)
|
||||
@@ -96,7 +93,7 @@ impl Client {
|
||||
.on(CursorSense::click(), move |ctx: &mut Client, _| {
|
||||
ctx.ui[span_add].children.pop();
|
||||
})
|
||||
.sized(150)
|
||||
.sized((150, 150))
|
||||
.align(Align::BotLeft);
|
||||
|
||||
let span_add_test = (span_add, add_button, del_button)
|
||||
@@ -117,18 +114,18 @@ impl Client {
|
||||
btext("'").family(Family::Monospace).align(Align::Top),
|
||||
btext("'").family(Family::Monospace),
|
||||
btext(":gamer mode").family(Family::Monospace),
|
||||
rect(Color::CYAN).sized(10).center(),
|
||||
rect(Color::RED).sized(100).center(),
|
||||
rect(Color::PURPLE).sized(50).align(Align::Top),
|
||||
rect(Color::CYAN).sized((10, 10)).center(),
|
||||
rect(Color::RED).sized((100, 100)).center(),
|
||||
rect(Color::PURPLE).sized((50, 50)).align(Align::Top),
|
||||
)
|
||||
.span(Dir::RIGHT, sized())
|
||||
.span(Dir::RIGHT)
|
||||
.center(),
|
||||
text("pretty cool right?").size(50),
|
||||
)
|
||||
.span(Dir::DOWN, sized())
|
||||
.span(Dir::DOWN)
|
||||
.add_static(&mut ui);
|
||||
|
||||
let texts = Span::empty(Dir::DOWN).add_static(&mut ui);
|
||||
let texts = Span::empty(Dir::DOWN).spacing(10).add_static(&mut ui);
|
||||
let msg_area = (Rect::new(Color::SKY), texts.scroll().masked()).stack();
|
||||
let add_text = text("add")
|
||||
.editable()
|
||||
@@ -153,7 +150,7 @@ impl Client {
|
||||
.stack()
|
||||
.size(StackSize::Child(1))
|
||||
.add(&mut client.ui);
|
||||
client.ui[texts].children.push((msg_box.any(), sized()));
|
||||
client.ui[texts].children.push(msg_box.any());
|
||||
})
|
||||
.add(&mut ui);
|
||||
let text_edit_scroll = (
|
||||
@@ -161,14 +158,14 @@ impl Client {
|
||||
(
|
||||
Rect::new(Color::WHITE.darker(0.9)),
|
||||
(
|
||||
add_text.clone(),
|
||||
add_text.clone().width(rest(1)),
|
||||
Rect::new(Color::GREEN)
|
||||
.on(CursorSense::click(), move |client: &mut Client, _| {
|
||||
client.run_event(&add_text, Submit, ());
|
||||
})
|
||||
.sized(40),
|
||||
.sized((40, 40)),
|
||||
)
|
||||
.span(Dir::RIGHT, [ratio(1), sized()])
|
||||
.span(Dir::RIGHT)
|
||||
.pad(10),
|
||||
)
|
||||
.stack()
|
||||
@@ -176,7 +173,7 @@ impl Client {
|
||||
.offset_layer(1)
|
||||
.align(Align::Bot),
|
||||
)
|
||||
.span(Dir::DOWN, [ratio(1), sized()])
|
||||
.span(Dir::DOWN)
|
||||
.add_static(&mut ui);
|
||||
|
||||
let switch_button = |color, to, label| {
|
||||
@@ -208,15 +205,12 @@ impl Client {
|
||||
"text edit scroll",
|
||||
),
|
||||
)
|
||||
.span(Dir::RIGHT, ratio(1));
|
||||
.span(Dir::RIGHT);
|
||||
|
||||
let info = text("").add(&mut ui);
|
||||
let info_sect = info.clone().pad(10).align(Align::Right);
|
||||
|
||||
(
|
||||
(tabs, main).span(Dir::DOWN, [fixed(40), ratio(1)]),
|
||||
info_sect,
|
||||
)
|
||||
((tabs.height(40), main).span(Dir::DOWN), info_sect)
|
||||
.stack()
|
||||
.set_root(&mut ui);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user