the great orientation refactor (move to x & y UiScalars/Spans) + don't call full size in align

This commit is contained in:
2025-11-20 15:44:39 -05:00
parent 96ef0c529b
commit 6251c23d37
20 changed files with 832 additions and 578 deletions

View File

@@ -7,8 +7,32 @@ pub struct Aligned {
impl Widget for Aligned { impl Widget for Aligned {
fn draw(&mut self, painter: &mut Painter) { fn draw(&mut self, painter: &mut Painter) {
let region = let region = match self.align {
UiRegion::from_ui_size_align(painter.size(&self.inner).to_uivec2(), self.align); Align {
x: Some(x),
y: Some(y),
} => {
painter
.size(&self.inner)
.to_uivec2()
.align(RegionAlign { x, y })
}
Align {
x: Some(x),
y: None,
} => {
let x = painter.size_ctx().width(&self.inner).apply_rest().align(x);
UiRegion::new(x, UiSpan::FULL)
}
Align {
x: None,
y: Some(y),
} => {
let y = painter.size_ctx().height(&self.inner).apply_rest().align(y);
UiRegion::new(UiSpan::FULL, y)
}
Align { x: None, y: None } => UiRegion::FULL,
};
painter.widget_within(&self.inner, region); painter.widget_within(&self.inner, region);
} }

View File

@@ -7,7 +7,7 @@ pub struct Offset {
impl Widget for Offset { impl Widget for Offset {
fn draw(&mut self, painter: &mut Painter) { fn draw(&mut self, painter: &mut Painter) {
let region = UiRegion::full().offset(self.amt); let region = UiRegion::FULL.offset(self.amt);
painter.widget_within(&self.inner, region); painter.widget_within(&self.inner, region);
} }

View File

@@ -13,8 +13,8 @@ impl Widget for Pad {
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len {
let width = self.padding.left + self.padding.right; let width = self.padding.left + self.padding.right;
let height = self.padding.top + self.padding.bottom; let height = self.padding.top + self.padding.bottom;
ctx.outer.abs.x -= width; ctx.outer.x.abs -= width;
ctx.outer.abs.y -= height; ctx.outer.y.abs -= height;
let mut size = ctx.width(&self.inner); let mut size = ctx.width(&self.inner);
size.abs += width; size.abs += width;
size size
@@ -23,8 +23,8 @@ impl Widget for Pad {
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len {
let width = self.padding.left + self.padding.right; let width = self.padding.left + self.padding.right;
let height = self.padding.top + self.padding.bottom; let height = self.padding.top + self.padding.bottom;
ctx.outer.abs.x -= width; ctx.outer.x.abs -= width;
ctx.outer.abs.y -= height; ctx.outer.y.abs -= height;
let mut size = ctx.height(&self.inner); let mut size = ctx.height(&self.inner);
size.abs += height; size.abs += height;
size size
@@ -49,11 +49,11 @@ impl Padding {
} }
} }
pub fn region(&self) -> UiRegion { pub fn region(&self) -> UiRegion {
let mut region = UiRegion::full(); let mut region = UiRegion::FULL;
region.top_left.abs.x += self.left; region.x.start.abs += self.left;
region.top_left.abs.y += self.top; region.y.start.abs += self.top;
region.bot_right.abs.x -= self.right; region.x.end.abs -= self.right;
region.bot_right.abs.y -= self.bottom; region.y.end.abs -= self.bottom;
region region
} }
pub fn x(amt: impl UiNum) -> Self { pub fn x(amt: impl UiNum) -> Self {

View File

@@ -9,16 +9,10 @@ pub struct Sized {
impl Sized { impl Sized {
fn apply_to_outer(&self, ctx: &mut SizeCtx) { fn apply_to_outer(&self, ctx: &mut SizeCtx) {
if let Some(x) = self.x { if let Some(x) = self.x {
let outer = ctx.outer.axis(Axis::X); ctx.outer.x.select_len(x.apply_rest());
ctx.outer
.axis_mut(Axis::X)
.set(x.apply_rest().within_len(outer));
} }
if let Some(y) = self.y { if let Some(y) = self.y {
let outer = ctx.outer.axis(Axis::Y); ctx.outer.y.select_len(y.apply_rest());
ctx.outer
.axis_mut(Axis::Y)
.set(y.apply_rest().within_len(outer));
} }
} }
} }

View File

@@ -1,6 +1,5 @@
use std::marker::PhantomData;
use crate::prelude::*; use crate::prelude::*;
use std::marker::PhantomData;
pub struct Span { pub struct Span {
pub children: Vec<WidgetId>, pub children: Vec<WidgetId>,
@@ -13,18 +12,19 @@ impl Widget for Span {
let total = self.len_sum(&mut painter.size_ctx()); let total = self.len_sum(&mut painter.size_ctx());
let mut start = UiScalar::rel_min(); let mut start = UiScalar::rel_min();
for child in &self.children { for child in &self.children {
let mut child_region = UiRegion::full(); let mut span = UiSpan::FULL;
let mut axis = child_region.axis_mut(self.dir.axis); span.start = start;
axis.top_left.set(start);
let len = painter.len_axis(child, self.dir.axis); let len = painter.len_axis(child, self.dir.axis);
if len.rest > 0.0 { if len.rest > 0.0 {
let offset = UiScalar::new(total.rel, total.abs); let offset = UiScalar::new(total.rel, total.abs);
let rel_end = UiScalar::from_anchor(len.rest / total.rest); let rel_end = UiScalar::rel(len.rest / total.rest);
start = rel_end.within(start, (UiScalar::rel_max() + start) - offset); let end = (UiScalar::rel_max() + start) - offset;
start = rel_end.within(&start.to(end));
} }
start.abs += len.abs; start.abs += len.abs;
start.rel += len.rel; start.rel += len.rel;
axis.bot_right.set(start); span.end = start;
let mut child_region = UiRegion::from_axis(self.dir.axis, span, UiSpan::FULL);
if self.dir.sign == Sign::Neg { if self.dir.sign == Sign::Neg {
child_region.flip(self.dir.axis); child_region.flip(self.dir.axis);
} }
@@ -89,33 +89,29 @@ impl Span {
fn desired_ortho(&mut self, ctx: &mut SizeCtx) -> Len { fn desired_ortho(&mut self, ctx: &mut SizeCtx) -> Len {
// this is an awful hack to get text wrapping to work properly when in a downward span // this is an awful hack to get text wrapping to work properly when in a downward span
let outer = ctx.outer.axis(self.dir.axis);
if self.dir.axis == Axis::X { if self.dir.axis == Axis::X {
// so....... this literally copies draw so that the lengths are correctly set in the // so....... this literally copies draw so that the lengths are correctly set in the
// context, which makes this slow and not cool // context, which makes this slow and not cool
let total = self.len_sum(ctx); let total = self.len_sum(ctx);
let mut start = UiScalar::rel_min(); let mut start = UiScalar::rel_min();
let outer = ctx.outer.axis(self.dir.axis);
let mut ortho_len = Len::ZERO; let mut ortho_len = Len::ZERO;
for child in &self.children { for child in &self.children {
let mut child_region = UiRegion::full(); let mut span = UiSpan::FULL;
let mut axis = child_region.axis_mut(self.dir.axis); span.start = start;
axis.top_left.set(start);
let len = ctx.len_axis(child, self.dir.axis); let len = ctx.len_axis(child, self.dir.axis);
if len.rest > 0.0 { if len.rest > 0.0 {
let offset = UiScalar::new(total.rel, total.abs); let offset = UiScalar::new(total.rel, total.abs);
let rel_end = UiScalar::from_anchor(len.rest / total.rest); let rel_end = UiScalar::rel(len.rest / total.rest);
start = rel_end.within(start, (UiScalar::rel_max() + start) - offset); let end = (UiScalar::rel_max() + start) - offset;
start = rel_end.within(&start.to(end));
} }
start.abs += len.abs; start.abs += len.abs;
start.rel += len.rel; start.rel += len.rel;
axis.bot_right.set(start); span.end = start;
// if self.dir.sign == Sign::Neg {
// child_region.flip(self.dir.axis); let scalar = span.len();
// } *ctx.outer.axis_mut(self.dir.axis) = outer.select_len(scalar);
let scalar = child_region.size().axis(self.dir.axis);
ctx.outer
.axis_mut(self.dir.axis)
.set(scalar.within_len(outer));
let ortho = ctx.len_axis(child, !self.dir.axis); let ortho = ctx.len_axis(child, !self.dir.axis);
// TODO: rel shouldn't do this, but no easy way before actually calculating pixels // TODO: rel shouldn't do this, but no easy way before actually calculating pixels
if ortho.rel > 0.0 || ortho.rest > 0.0 { if ortho.rel > 0.0 || ortho.rest > 0.0 {

View File

@@ -32,8 +32,8 @@ impl<O> TextBuilder<O> {
self.attrs.line_height = height; self.attrs.line_height = height;
self self
} }
pub fn text_align(mut self, align: Align) -> Self { pub fn text_align(mut self, align: impl Into<RegionAlign>) -> Self {
self.attrs.align = align; self.attrs.align = align.into();
self self
} }
pub fn wrap(mut self, wrap: bool) -> Self { pub fn wrap(mut self, wrap: bool) -> Self {

View File

@@ -15,10 +15,10 @@ pub struct TextEdit {
impl TextEdit { impl TextEdit {
pub fn region(&self) -> UiRegion { pub fn region(&self) -> UiRegion {
UiRegion::from_size_align( self.tex()
self.tex().map(|t| t.size()).unwrap_or(Vec2::ZERO), .map(|t| t.size())
self.align, .unwrap_or(Vec2::ZERO)
) .align(self.align)
} }
pub fn content(&self) -> String { pub fn content(&self) -> String {
@@ -44,7 +44,7 @@ impl Widget for TextEdit {
let size = vec2(1, self.attrs.line_height); let size = vec2(1, self.attrs.line_height);
painter.primitive_within( painter.primitive_within(
RectPrimitive::color(Color::WHITE), RectPrimitive::color(Color::WHITE),
UiRegion::from_size_align(size, Align::TopLeft) size.align(Align::TOP_LEFT)
.offset(offset) .offset(offset)
.within(&region), .within(&region),
); );
@@ -205,7 +205,7 @@ impl<'a> TextEditCtx<'a> {
} }
pub fn select(&mut self, pos: Vec2, size: Vec2) { pub fn select(&mut self, pos: Vec2, size: Vec2) {
let pos = pos - self.text.region().top_left.to_abs(size); let pos = pos - self.text.region().top_left().to_abs(size);
self.text.cursor = self.text.buf.hit(pos.x, pos.y); self.text.cursor = self.text.buf.hit(pos.x, pos.y);
} }

View File

@@ -100,11 +100,13 @@ impl Widget for Text {
} }
} }
pub fn text_region(tex: &TextTexture, align: Align) -> UiRegion { pub fn text_region(tex: &TextTexture, align: RegionAlign) -> UiRegion {
let tex_dims = tex.handle.size(); let tex_dims = tex.handle.size();
let mut region = UiRegion::from_size_align(tex.size(), align); let mut region = tex.size().align(align);
region.top_left.abs += tex.top_left; region.x.start.abs += tex.top_left.x;
region.bot_right.abs = region.top_left.abs + tex_dims; region.y.start.abs += tex.top_left.y;
region.x.end.abs = region.x.start.abs + tex_dims.x;
region.y.end.abs = region.y.start.abs + tex_dims.y;
region region
} }

View File

@@ -3,7 +3,7 @@ use crate::prelude::*;
pub trait CoreWidget<W, Tag> { pub trait CoreWidget<W, Tag> {
fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Pad>; fn pad(self, padding: impl Into<Padding>) -> impl WidgetFn<Pad>;
fn align(self, align: Align) -> impl WidgetFn<Aligned>; fn align(self, align: impl Into<Align>) -> impl WidgetFn<Aligned>;
fn center(self) -> impl WidgetFn<Aligned>; fn center(self) -> impl WidgetFn<Aligned>;
fn label(self, label: impl Into<String>) -> impl WidgetIdFn<W>; fn label(self, label: impl Into<String>) -> impl WidgetIdFn<W>;
fn sized(self, size: impl Into<Size>) -> impl WidgetFn<Sized>; fn sized(self, size: impl Into<Size>) -> impl WidgetFn<Sized>;
@@ -24,15 +24,15 @@ impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
} }
} }
fn align(self, align: Align) -> impl WidgetFn<Aligned> { fn align(self, align: impl Into<Align>) -> impl WidgetFn<Aligned> {
move |ui| Aligned { move |ui| Aligned {
inner: self.add(ui).any(), inner: self.add(ui).any(),
align, align: align.into(),
} }
} }
fn center(self) -> impl WidgetFn<Aligned> { fn center(self) -> impl WidgetFn<Aligned> {
self.align(Align::Center) self.align(Align::CENTER)
} }
fn label(self, label: impl Into<String>) -> impl WidgetIdFn<W::Widget> { fn label(self, label: impl Into<String>) -> impl WidgetIdFn<W::Widget> {

View File

@@ -6,7 +6,6 @@ mod module;
mod num; mod num;
mod orientation; mod orientation;
mod painter; mod painter;
mod pos;
mod text; mod text;
mod texture; mod texture;
mod ui; mod ui;
@@ -22,7 +21,6 @@ pub use module::*;
pub use num::*; pub use num::*;
pub use orientation::*; pub use orientation::*;
pub use painter::*; pub use painter::*;
pub use pos::*;
pub use text::*; pub use text::*;
pub use texture::*; pub use texture::*;
pub use ui::*; pub use ui::*;

View File

@@ -0,0 +1,196 @@
use crate::layout::vec2;
use super::*;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Align {
pub x: Option<AxisAlign>,
pub y: Option<AxisAlign>,
}
impl Align {
pub const TOP_LEFT: RegionAlign = RegionAlign::TOP_LEFT;
pub const TOP_CENTER: RegionAlign = RegionAlign::TOP_CENTER;
pub const TOP_RIGHT: RegionAlign = RegionAlign::TOP_RIGHT;
pub const CENTER_LEFT: RegionAlign = RegionAlign::CENTER_LEFT;
pub const CENTER: RegionAlign = RegionAlign::CENTER;
pub const CENTER_RIGHT: RegionAlign = RegionAlign::CENTER_RIGHT;
pub const BOT_LEFT: RegionAlign = RegionAlign::BOT_LEFT;
pub const BOT_CENTER: RegionAlign = RegionAlign::BOT_CENTER;
pub const BOT_RIGHT: RegionAlign = RegionAlign::BOT_RIGHT;
pub const LEFT: CardinalAlign = CardinalAlign::LEFT;
pub const H_CENTER: CardinalAlign = CardinalAlign::H_CENTER;
pub const RIGHT: CardinalAlign = CardinalAlign::RIGHT;
pub const TOP: CardinalAlign = CardinalAlign::TOP;
pub const V_CENTER: CardinalAlign = CardinalAlign::V_CENTER;
pub const BOT: CardinalAlign = CardinalAlign::BOT;
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum AxisAlign {
Neg,
Center,
Pos,
}
impl AxisAlign {
pub const fn rel(&self) -> f32 {
match self {
Self::Neg => 0.0,
Self::Center => 0.5,
Self::Pos => 1.0,
}
}
}
pub struct CardinalAlign {
axis: Axis,
align: AxisAlign,
}
impl CardinalAlign {
pub const LEFT: Self = Self::new(Axis::X, AxisAlign::Neg);
pub const H_CENTER: Self = Self::new(Axis::X, AxisAlign::Center);
pub const RIGHT: Self = Self::new(Axis::X, AxisAlign::Pos);
pub const TOP: Self = Self::new(Axis::Y, AxisAlign::Neg);
pub const V_CENTER: Self = Self::new(Axis::Y, AxisAlign::Center);
pub const BOT: Self = Self::new(Axis::Y, AxisAlign::Pos);
pub const fn new(axis: Axis, align: AxisAlign) -> Self {
Self { axis, align }
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct RegionAlign {
pub x: AxisAlign,
pub y: AxisAlign,
}
impl RegionAlign {
pub const TOP_LEFT: Self = Self::new(AxisAlign::Neg, AxisAlign::Neg);
pub const TOP_CENTER: Self = Self::new(AxisAlign::Center, AxisAlign::Neg);
pub const TOP_RIGHT: Self = Self::new(AxisAlign::Pos, AxisAlign::Neg);
pub const CENTER_LEFT: Self = Self::new(AxisAlign::Neg, AxisAlign::Center);
pub const CENTER: Self = Self::new(AxisAlign::Center, AxisAlign::Center);
pub const CENTER_RIGHT: Self = Self::new(AxisAlign::Pos, AxisAlign::Center);
pub const BOT_LEFT: Self = Self::new(AxisAlign::Neg, AxisAlign::Pos);
pub const BOT_CENTER: Self = Self::new(AxisAlign::Center, AxisAlign::Pos);
pub const BOT_RIGHT: Self = Self::new(AxisAlign::Pos, AxisAlign::Pos);
pub const fn new(x: AxisAlign, y: AxisAlign) -> Self {
Self { x, y }
}
pub const fn rel(&self) -> Vec2 {
vec2(self.x.rel(), self.y.rel())
}
}
impl UiVec2 {
pub fn partial_align(&self, align: Align) -> UiRegion {
UiRegion {
x: if let Some(align) = align.x {
self.x.align(align)
} else {
UiSpan::FULL
},
y: if let Some(align) = align.y {
self.y.align(align)
} else {
UiSpan::FULL
},
}
}
pub fn align(&self, align: RegionAlign) -> UiRegion {
UiRegion {
x: self.x.align(align.x),
y: self.y.align(align.y),
}
}
}
impl Vec2 {
pub fn partial_align(&self, align: Align) -> UiRegion {
let s = UiVec2::from(*self);
UiRegion {
x: if let Some(align) = align.x {
s.x.align(align)
} else {
UiSpan::FULL
},
y: if let Some(align) = align.y {
s.y.align(align)
} else {
UiSpan::FULL
},
}
}
pub fn align(&self, align: RegionAlign) -> UiRegion {
let s = UiVec2::from(*self);
UiRegion {
x: s.x.align(align.x),
y: s.y.align(align.y),
}
}
}
impl UiScalar {
pub const fn align(&self, align: AxisAlign) -> UiSpan {
let rel = align.rel();
let mut start = UiScalar::rel(rel);
start.abs -= self.abs * rel;
start.rel -= self.rel * rel;
let mut end = UiScalar::rel(rel);
end.abs += self.abs * (1.0 - rel);
end.rel += self.rel * (1.0 - rel);
UiSpan { start, end }
}
}
impl From<RegionAlign> for Align {
fn from(region: RegionAlign) -> Self {
Self {
x: Some(region.x),
y: Some(region.y),
}
}
}
impl From<Align> for RegionAlign {
fn from(align: Align) -> Self {
Self {
x: align.x.unwrap_or(AxisAlign::Center),
y: align.y.unwrap_or(AxisAlign::Center),
}
}
}
impl From<CardinalAlign> for RegionAlign {
fn from(align: CardinalAlign) -> Self {
Align::from(align).into()
}
}
impl From<CardinalAlign> for Align {
fn from(cardinal: CardinalAlign) -> Self {
let align = Some(cardinal.align);
match cardinal.axis {
Axis::X => Self { x: align, y: None },
Axis::Y => Self { x: None, y: align },
}
}
}
impl const From<RegionAlign> for UiVec2 {
fn from(align: RegionAlign) -> Self {
Self::rel(align.rel())
}
}
impl RegionAlign {
pub const fn pos(self) -> UiVec2 {
UiVec2::from(self)
}
}

View File

@@ -0,0 +1,70 @@
use super::*;
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Axis {
X,
Y,
}
impl std::ops::Not for Axis {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Self::X => Self::Y,
Self::Y => Self::X,
}
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Dir {
pub axis: Axis,
pub sign: Sign,
}
impl Dir {
pub const fn new(axis: Axis, dir: Sign) -> Self {
Self { axis, sign: dir }
}
pub const LEFT: Self = Self::new(Axis::X, Sign::Neg);
pub const RIGHT: Self = Self::new(Axis::X, Sign::Pos);
pub const UP: Self = Self::new(Axis::Y, Sign::Neg);
pub const DOWN: Self = Self::new(Axis::Y, Sign::Pos);
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Sign {
Neg,
Pos,
}
impl Vec2 {
pub fn axis(&self, axis: Axis) -> f32 {
match axis {
Axis::X => self.x,
Axis::Y => self.y,
}
}
pub fn axis_mut(&mut self, axis: Axis) -> &mut f32 {
match axis {
Axis::X => &mut self.x,
Axis::Y => &mut self.y,
}
}
pub const fn from_axis(axis: Axis, aligned: f32, ortho: f32) -> Self {
Self {
x: match axis {
Axis::X => aligned,
Axis::Y => ortho,
},
y: match axis {
Axis::Y => aligned,
Axis::X => ortho,
},
}
}
}

View File

@@ -1,107 +1,5 @@
use std::ops::Not; use super::*;
use crate::{layout::UiNum, util::impl_op};
use crate::{
layout::{UiNum, UiScalar, UiVec2, Vec2, vec2},
util::impl_op,
};
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Axis {
X,
Y,
}
impl Not for Axis {
type Output = Self;
fn not(self) -> Self::Output {
match self {
Self::X => Self::Y,
Self::Y => Self::X,
}
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Dir {
pub axis: Axis,
pub sign: Sign,
}
impl Dir {
pub const fn new(axis: Axis, dir: Sign) -> Self {
Self { axis, sign: dir }
}
pub const LEFT: Self = Self::new(Axis::X, Sign::Neg);
pub const RIGHT: Self = Self::new(Axis::X, Sign::Pos);
pub const UP: Self = Self::new(Axis::Y, Sign::Neg);
pub const DOWN: Self = Self::new(Axis::Y, Sign::Pos);
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Sign {
Neg,
Pos,
}
impl Vec2 {
pub fn axis(&self, axis: Axis) -> f32 {
match axis {
Axis::X => self.x,
Axis::Y => self.y,
}
}
pub fn axis_mut(&mut self, axis: Axis) -> &mut f32 {
match axis {
Axis::X => &mut self.x,
Axis::Y => &mut self.y,
}
}
pub const fn from_axis(axis: Axis, aligned: f32, ortho: f32) -> Self {
Self {
x: match axis {
Axis::X => aligned,
Axis::Y => ortho,
},
y: match axis {
Axis::Y => aligned,
Axis::X => ortho,
},
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Align {
TopLeft,
Top,
TopRight,
Left,
Center,
Right,
BotLeft,
Bot,
BotRight,
}
impl Align {
pub const fn rel(&self) -> Vec2 {
match self {
Self::TopLeft => vec2(0.0, 0.0),
Self::Top => vec2(0.5, 0.0),
Self::TopRight => vec2(1.0, 0.0),
Self::Left => vec2(0.0, 0.5),
Self::Center => vec2(0.5, 0.5),
Self::Right => vec2(1.0, 0.5),
Self::BotLeft => vec2(0.0, 1.0),
Self::Bot => vec2(0.5, 1.0),
Self::BotRight => vec2(1.0, 1.0),
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq)] #[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct Size { pub struct Size {
@@ -159,7 +57,10 @@ impl Size {
} }
pub fn to_uivec2(self) -> UiVec2 { pub fn to_uivec2(self) -> UiVec2 {
UiVec2::from_scalars(self.x.apply_rest(), self.y.apply_rest()) UiVec2 {
x: self.x.apply_rest(),
y: self.y.apply_rest(),
}
} }
pub fn from_axis(axis: Axis, aligned: Len, ortho: Len) -> Self { pub fn from_axis(axis: Axis, aligned: Len, ortho: Len) -> Self {

View File

@@ -0,0 +1,11 @@
mod align;
mod axis;
mod len;
mod pos;
use super::vec2::*;
pub use align::*;
pub use axis::*;
pub use len::*;
pub use pos::*;

View File

@@ -0,0 +1,449 @@
use std::{fmt::Display, hash::Hash, marker::Destruct};
use super::*;
use crate::{
layout::UiNum,
util::{LerpUtil, impl_op},
};
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, bytemuck::Pod, bytemuck::Zeroable, Default)]
pub struct UiVec2 {
pub x: UiScalar,
pub y: UiScalar,
}
impl UiVec2 {
pub const ZERO: Self = Self {
x: UiScalar::ZERO,
y: UiScalar::ZERO,
};
pub const fn new(x: UiScalar, y: UiScalar) -> Self {
Self { x, y }
}
pub const fn abs(abs: impl const Into<Vec2>) -> Self {
let abs = abs.into();
Self {
x: UiScalar::abs(abs.x),
y: UiScalar::abs(abs.y),
}
}
pub const fn rel(rel: impl const Into<Vec2>) -> Self {
let rel = rel.into();
Self {
x: UiScalar::rel(rel.x),
y: UiScalar::rel(rel.y),
}
}
pub const fn shift(&mut self, offset: impl const Into<UiVec2>) {
let offset = offset.into();
*self += offset;
}
pub const fn offset(mut self, offset: impl const Into<UiVec2>) -> Self {
self.shift(offset);
self
}
pub const fn within(&self, region: &UiRegion) -> UiVec2 {
UiVec2 {
x: self.x.within(&region.x),
y: self.y.within(&region.y),
}
}
pub const fn outside(&self, region: &UiRegion) -> UiVec2 {
UiVec2 {
x: self.x.outside(&region.x),
y: self.y.outside(&region.y),
}
}
pub fn axis_mut(&mut self, axis: Axis) -> &mut UiScalar {
match axis {
Axis::X => &mut self.x,
Axis::Y => &mut self.y,
}
}
pub fn axis(&self, axis: Axis) -> UiScalar {
match axis {
Axis::X => self.x,
Axis::Y => self.y,
}
}
pub fn to_abs(&self, rel: Vec2) -> Vec2 {
self.get_rel() * rel + self.get_abs()
}
pub const FULL_SIZE: Self = Self::rel(Vec2::ONE);
pub const fn from_axis(axis: Axis, aligned: UiScalar, ortho: UiScalar) -> Self {
match axis {
Axis::X => Self {
x: aligned,
y: ortho,
},
Axis::Y => Self {
x: ortho,
y: aligned,
},
}
}
pub fn get_abs(&self) -> Vec2 {
(self.x.abs, self.y.abs).into()
}
pub fn get_rel(&self) -> Vec2 {
(self.x.rel, self.y.rel).into()
}
pub fn abs_mut(&mut self) -> Vec2View<'_> {
Vec2View {
x: &mut self.x.abs,
y: &mut self.y.abs,
}
}
}
impl Display for UiVec2 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "rel{};abs{}", self.get_rel(), self.get_abs())
}
}
impl_op!(UiVec2 Add add; x y);
impl_op!(UiVec2 Sub sub; x y);
impl const From<Vec2> for UiVec2 {
fn from(abs: Vec2) -> Self {
Self::abs(abs)
}
}
impl<T: const UiNum, U: const UiNum> const From<(T, U)> for UiVec2
where
(T, U): const Destruct,
{
fn from(abs: (T, U)) -> Self {
Self::abs(abs)
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, Default, bytemuck::Zeroable)]
pub struct UiScalar {
pub rel: f32,
pub abs: f32,
}
impl Eq for UiScalar {}
impl Hash for UiScalar {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write_u32(self.rel.to_bits());
state.write_u32(self.abs.to_bits());
}
}
impl_op!(UiScalar Add add; rel abs);
impl_op!(UiScalar Sub sub; rel abs);
impl UiScalar {
pub const ZERO: Self = Self { rel: 0.0, abs: 0.0 };
pub const FULL: Self = Self { rel: 1.0, abs: 0.0 };
pub const fn new(rel: f32, abs: f32) -> Self {
Self { rel, abs }
}
pub const fn rel(rel: f32) -> Self {
Self { rel, abs: 0.0 }
}
pub const fn abs(abs: f32) -> Self {
Self { rel: 0.0, abs }
}
pub const fn rel_min() -> Self {
Self::new(0.0, 0.0)
}
pub const fn rel_max() -> Self {
Self::new(1.0, 0.0)
}
pub const fn max(&self, other: Self) -> Self {
Self {
rel: self.rel.max(other.rel),
abs: self.abs.max(other.abs),
}
}
pub const fn min(&self, other: Self) -> Self {
Self {
rel: self.rel.min(other.rel),
abs: self.abs.min(other.abs),
}
}
pub const fn offset(mut self, amt: f32) -> Self {
self.abs += amt;
self
}
pub const fn within(&self, span: &UiSpan) -> Self {
let anchor = self.rel.lerp(span.start.rel, span.end.rel);
let offset = self.abs + self.rel.lerp(span.start.abs, span.end.abs);
Self {
rel: anchor,
abs: offset,
}
}
pub const fn outside(&self, span: &UiSpan) -> Self {
let rel = self.rel.lerp_inv(span.start.rel, span.end.rel);
let abs = self.abs - rel.lerp(span.start.abs, span.end.abs);
Self { rel, abs }
}
pub fn within_len(&self, len: UiScalar) -> Self {
self.within(&UiSpan {
start: UiScalar::ZERO,
end: len,
})
}
pub fn select_len(&self, len: UiScalar) -> Self {
len.within_len(*self)
}
pub const fn flip(&mut self) {
self.rel = 1.0 - self.rel;
self.abs = -self.abs;
}
pub const fn to(&self, end: Self) -> UiSpan {
UiSpan { start: *self, end }
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
pub struct UiSpan {
pub start: UiScalar,
pub end: UiScalar,
}
impl UiSpan {
pub const FULL: Self = Self {
start: UiScalar::ZERO,
end: UiScalar::FULL,
};
pub const fn rel(rel: f32) -> Self {
Self {
start: UiScalar::rel(rel),
end: UiScalar::rel(rel),
}
}
pub const fn new(start: UiScalar, end: UiScalar) -> Self {
Self { start, end }
}
pub const fn flip(&mut self) {
self.start.flip();
self.end.flip();
std::mem::swap(&mut self.start.rel, &mut self.end.rel);
std::mem::swap(&mut self.start.abs, &mut self.end.abs);
}
pub const fn shift(&mut self, offset: UiScalar) {
self.start += offset;
self.end += offset;
}
pub const fn within(&self, parent: &Self) -> Self {
Self {
start: self.start.within(parent),
end: self.end.within(parent),
}
}
pub const fn outside(&self, parent: &Self) -> Self {
Self {
start: self.start.outside(parent),
end: self.end.outside(parent),
}
}
pub const fn len(&self) -> UiScalar {
self.end - self.start
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
pub struct UiRegion {
pub x: UiSpan,
pub y: UiSpan,
}
impl UiRegion {
pub const FULL: Self = Self {
x: UiSpan::FULL,
y: UiSpan::FULL,
};
pub const fn new(x: UiSpan, y: UiSpan) -> Self {
Self { x, y }
}
pub const fn rel(rel: Vec2) -> Self {
Self {
x: UiSpan::rel(rel.x),
y: UiSpan::rel(rel.y),
}
}
pub const fn within(&self, parent: &Self) -> Self {
Self {
x: self.x.within(&parent.x),
y: self.y.within(&parent.y),
}
}
pub const fn outside(&self, parent: &Self) -> Self {
Self {
x: self.x.outside(&parent.x),
y: self.y.outside(&parent.y),
}
}
pub const fn axis_mut(&mut self, axis: Axis) -> &mut UiSpan {
match axis {
Axis::X => &mut self.x,
Axis::Y => &mut self.y,
}
}
pub const fn flip(&mut self, axis: Axis) {
match axis {
Axis::X => self.x.flip(),
Axis::Y => self.y.flip(),
}
}
pub fn shift(&mut self, offset: impl Into<UiVec2>) {
let offset = offset.into();
self.x.shift(offset.x);
self.y.shift(offset.y);
}
pub fn offset(mut self, offset: impl Into<UiVec2>) -> Self {
self.shift(offset);
self
}
pub fn to_px(&self, size: Vec2) -> PixelRegion {
PixelRegion {
top_left: self.top_left().get_rel() * size + self.top_left().get_abs(),
bot_right: self.bot_right().get_rel() * size + self.bot_right().get_abs(),
}
}
pub const fn center(&self) -> UiVec2 {
Align::CENTER.pos().within(self)
}
pub const fn size(&self) -> UiVec2 {
UiVec2 {
x: self.x.len(),
y: self.y.len(),
}
}
pub const fn top_left(&self) -> UiVec2 {
UiVec2 {
x: self.x.start,
y: self.y.start,
}
}
pub const fn bot_right(&self) -> UiVec2 {
UiVec2 {
x: self.x.end,
y: self.y.end,
}
}
pub const fn from_axis(axis: Axis, aligned: UiSpan, ortho: UiSpan) -> Self {
Self {
x: match axis {
Axis::X => aligned,
Axis::Y => ortho,
},
y: match axis {
Axis::X => ortho,
Axis::Y => aligned,
},
}
}
}
impl Display for UiRegion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} -> {} (size: {})",
self.top_left(),
self.bot_right(),
self.size()
)
}
}
#[derive(Debug)]
pub struct PixelRegion {
pub top_left: Vec2,
pub bot_right: Vec2,
}
impl PixelRegion {
pub fn contains(&self, pos: Vec2) -> bool {
pos.x >= self.top_left.x
&& pos.x <= self.bot_right.x
&& pos.y >= self.top_left.y
&& pos.y <= self.bot_right.y
}
pub fn size(&self) -> Vec2 {
self.bot_right - self.top_left
}
}
impl Display for PixelRegion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} -> {}", self.top_left, self.bot_right)
}
}
pub struct Vec2View<'a> {
pub x: &'a mut f32,
pub y: &'a mut f32,
}
impl Vec2View<'_> {
pub fn set(&mut self, other: Vec2) {
*self.x = other.x;
*self.y = other.y;
}
pub fn add(&mut self, other: Vec2) {
*self.x += other.x;
*self.y += other.y;
}
}

View File

@@ -31,7 +31,6 @@ pub struct PainterCtx<'a> {
pub text: &'a mut TextData, pub text: &'a mut TextData,
pub screen_size: Vec2, pub screen_size: Vec2,
pub modules: &'a mut Modules, pub modules: &'a mut Modules,
pub px_dependent: &'a mut HashSet<Id>,
pub cache_width: HashMap<Id, (UiVec2, Len)>, pub cache_width: HashMap<Id, (UiVec2, Len)>,
pub cache_height: HashMap<Id, (UiVec2, Len)>, pub cache_height: HashMap<Id, (UiVec2, Len)>,
draw_started: HashSet<Id>, draw_started: HashSet<Id>,
@@ -78,7 +77,6 @@ impl<'a> PainterCtx<'a> {
text: &mut data.text, text: &mut data.text,
screen_size: data.output_size, screen_size: data.output_size,
modules: &mut data.modules, modules: &mut data.modules,
px_dependent: &mut data.px_dependent,
masks: &mut data.masks, masks: &mut data.masks,
cache_width: Default::default(), cache_width: Default::default(),
cache_height: Default::default(), cache_height: Default::default(),
@@ -107,7 +105,6 @@ impl<'a> PainterCtx<'a> {
output_size: self.screen_size, output_size: self.screen_size,
checked_width: &mut Default::default(), checked_width: &mut Default::default(),
checked_height: &mut Default::default(), checked_height: &mut Default::default(),
px_dependent: &mut Default::default(),
id, id,
} }
.width_inner(id); .width_inner(id);
@@ -134,7 +131,6 @@ impl<'a> PainterCtx<'a> {
output_size: self.screen_size, output_size: self.screen_size,
checked_width: &mut Default::default(), checked_width: &mut Default::default(),
checked_height: &mut Default::default(), checked_height: &mut Default::default(),
px_dependent: &mut Default::default(),
id, id,
} }
.height_inner(id); .height_inner(id);
@@ -164,7 +160,7 @@ impl<'a> PainterCtx<'a> {
pub fn draw(&mut self, id: Id) { pub fn draw(&mut self, id: Id) {
self.draw_started.clear(); self.draw_started.clear();
self.layers.clear(); self.layers.clear();
self.draw_inner(0, id, UiRegion::full(), None, MaskIdx::NONE, None); self.draw_inner(0, id, UiRegion::FULL, None, MaskIdx::NONE, None);
} }
fn draw_inner( fn draw_inner(
@@ -300,7 +296,6 @@ impl<'a> PainterCtx<'a> {
m.on_undraw(inst); m.on_undraw(inst);
} }
} }
self.px_dependent.remove(&id);
inst inst
} }
@@ -405,7 +400,6 @@ impl<'a, 'c> Painter<'a, 'c> {
textures: self.ctx.textures, textures: self.ctx.textures,
widgets: self.ctx.widgets, widgets: self.ctx.widgets,
output_size: self.ctx.screen_size, output_size: self.ctx.screen_size,
px_dependent: self.ctx.px_dependent,
checked_width: &mut self.children_width, checked_width: &mut self.children_width,
checked_height: &mut self.children_height, checked_height: &mut self.children_height,
cache_width: &mut self.ctx.cache_width, cache_width: &mut self.ctx.cache_width,
@@ -417,7 +411,6 @@ impl<'a, 'c> Painter<'a, 'c> {
} }
pub fn px_size(&mut self) -> Vec2 { pub fn px_size(&mut self) -> Vec2 {
self.ctx.px_dependent.insert(self.id);
self.region.size().to_abs(self.ctx.screen_size) self.region.size().to_abs(self.ctx.screen_size)
} }
@@ -443,7 +436,6 @@ pub struct SizeCtx<'a> {
pub textures: &'a mut Textures, pub textures: &'a mut Textures,
source: Id, source: Id,
widgets: &'a Widgets, widgets: &'a Widgets,
px_dependent: &'a mut HashSet<Id>,
cache_width: &'a mut HashMap<Id, (UiVec2, Len)>, cache_width: &'a mut HashMap<Id, (UiVec2, Len)>,
cache_height: &'a mut HashMap<Id, (UiVec2, Len)>, cache_height: &'a mut HashMap<Id, (UiVec2, Len)>,
checked_width: &'a mut HashMap<Id, (UiVec2, Len)>, checked_width: &'a mut HashMap<Id, (UiVec2, Len)>,
@@ -523,8 +515,6 @@ impl SizeCtx<'_> {
} }
pub fn px_size(&mut self) -> Vec2 { pub fn px_size(&mut self) -> Vec2 {
// WARNING IF UNCOMMENT: self.id is no longer valid
// self.px_dependent.insert(self.id);
self.outer.to_abs(self.output_size) self.outer.to_abs(self.output_size)
} }

View File

@@ -1,382 +0,0 @@
use std::{fmt::Display, marker::Destruct};
use crate::{
layout::{Align, Axis, UiNum, Vec2},
util::{LerpUtil, impl_op},
};
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, bytemuck::Pod, bytemuck::Zeroable, Default)]
pub struct UiVec2 {
pub rel: Vec2,
pub abs: Vec2,
}
impl UiVec2 {
pub const ZERO: Self = Self {
rel: Vec2::ZERO,
abs: Vec2::ZERO,
};
/// expands this position into a sized region centered at self
pub fn expand(&self, size: impl Into<Vec2>) -> UiRegion {
let size = size.into();
UiRegion {
top_left: self.offset(-size / 2.0),
bot_right: self.offset(size / 2.0),
}
}
pub const fn abs(abs: impl const Into<Vec2>) -> Self {
Self {
rel: Vec2::ZERO,
abs: abs.into(),
}
}
pub const fn rel(rel: impl const Into<Vec2>) -> Self {
Self {
rel: rel.into(),
abs: Vec2::ZERO,
}
}
pub const fn shift(&mut self, offset: impl const Into<UiVec2>) {
let offset = offset.into();
*self += offset;
}
pub const fn offset(mut self, offset: impl const Into<UiVec2>) -> Self {
self.shift(offset);
self
}
pub const fn within(&self, region: &UiRegion) -> UiVec2 {
let rel = self.rel.lerp(region.top_left.rel, region.bot_right.rel);
let abs = self.abs + self.rel.lerp(region.top_left.abs, region.bot_right.abs);
UiVec2 { rel, abs }
}
pub const fn outside(&self, region: &UiRegion) -> UiVec2 {
let rel = self.rel.lerp_inv(region.top_left.rel, region.bot_right.rel);
let abs = self.abs - rel.lerp(region.top_left.abs, region.bot_right.abs);
UiVec2 { rel, abs }
}
pub fn axis_mut(&mut self, axis: Axis) -> UiScalarView<'_> {
match axis {
Axis::X => UiScalarView {
rel: &mut self.rel.x,
abs: &mut self.abs.x,
},
Axis::Y => UiScalarView {
rel: &mut self.rel.y,
abs: &mut self.abs.y,
},
}
}
pub fn axis(&self, axis: Axis) -> UiScalar {
match axis {
Axis::X => UiScalar {
rel: self.rel.x,
abs: self.abs.x,
},
Axis::Y => UiScalar {
rel: self.rel.y,
abs: self.abs.y,
},
}
}
/// reflection about an axis
pub fn flip(&mut self, axis: Axis) {
*self.rel.axis_mut(axis) = 1.0 - self.rel.axis(axis);
*self.abs.axis_mut(axis) = -self.abs.axis(axis);
}
pub fn flipped(mut self, axis: Axis) -> Self {
self.flip(axis);
self
}
pub fn to_abs(&self, rel: Vec2) -> Vec2 {
self.rel * rel + self.abs
}
pub const FULL_SIZE: Self = Self::rel(Vec2::ONE);
pub const fn from_axis(axis: Axis, aligned: UiScalar, ortho: UiScalar) -> Self {
Self {
rel: Vec2::from_axis(axis, aligned.rel, ortho.rel),
abs: Vec2::from_axis(axis, aligned.abs, ortho.abs),
}
}
pub const fn from_scalars(x: UiScalar, y: UiScalar) -> Self {
Self {
rel: Vec2 { x: x.rel, y: y.rel },
abs: Vec2 { x: x.abs, y: y.abs },
}
}
}
impl Display for UiVec2 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "rel{};abs{}", self.rel, self.abs)
}
}
impl_op!(UiVec2 Add add; rel abs);
impl_op!(UiVec2 Sub sub; rel abs);
impl const From<Align> for UiVec2 {
fn from(align: Align) -> Self {
Self::rel(align.rel())
}
}
impl Align {
pub fn pos(self) -> UiVec2 {
UiVec2::from(self)
}
}
impl const From<Vec2> for UiVec2 {
fn from(abs: Vec2) -> Self {
Self::abs(abs)
}
}
impl<T: const UiNum, U: const UiNum> const From<(T, U)> for UiVec2
where
(T, U): const Destruct,
{
fn from(abs: (T, U)) -> Self {
Self::abs(abs)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct UiScalar {
pub rel: f32,
pub abs: f32,
}
impl_op!(UiScalar Add add; rel abs);
impl_op!(UiScalar Sub sub; rel abs);
impl UiScalar {
pub const ZERO: Self = Self { rel: 0.0, abs: 0.0 };
pub const FULL: Self = Self { rel: 1.0, abs: 0.0 };
pub fn new(rel: f32, abs: f32) -> Self {
Self { rel, abs }
}
pub fn rel_min() -> Self {
Self::new(0.0, 0.0)
}
pub fn rel_max() -> Self {
Self::new(1.0, 0.0)
}
pub fn max(&self, other: Self) -> Self {
Self {
rel: self.rel.max(other.rel),
abs: self.abs.max(other.abs),
}
}
pub fn min(&self, other: Self) -> Self {
Self {
rel: self.rel.min(other.rel),
abs: self.abs.min(other.abs),
}
}
pub fn from_anchor(anchor: f32) -> Self {
Self::new(anchor, 0.0)
}
pub fn offset(mut self, amt: f32) -> Self {
self.abs += amt;
self
}
pub fn within(&self, start: UiScalar, end: UiScalar) -> Self {
let anchor = self.rel.lerp(start.rel, end.rel);
let offset = self.abs + self.rel.lerp(start.abs, end.abs);
Self {
rel: anchor,
abs: offset,
}
}
pub fn within_len(&self, len: UiScalar) -> Self {
self.within(UiScalar::ZERO, len)
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
pub struct UiRegion {
pub top_left: UiVec2,
pub bot_right: UiVec2,
}
impl UiRegion {
pub const fn full() -> Self {
Self {
top_left: Align::TopLeft.into(),
bot_right: Align::BotRight.into(),
}
}
pub fn rel(anchor: Vec2) -> Self {
Self {
top_left: UiVec2::rel(anchor),
bot_right: UiVec2::rel(anchor),
}
}
pub fn within(&self, parent: &Self) -> Self {
Self {
top_left: self.top_left.within(parent),
bot_right: self.bot_right.within(parent),
}
}
pub fn outside(&self, parent: &Self) -> Self {
Self {
top_left: self.top_left.outside(parent),
bot_right: self.bot_right.outside(parent),
}
}
pub fn axis_mut(&mut self, axis: Axis) -> UIRegionAxisView<'_> {
UIRegionAxisView {
top_left: self.top_left.axis_mut(axis),
bot_right: self.bot_right.axis_mut(axis),
}
}
pub fn flip(&mut self, axis: Axis) {
self.top_left.flip(axis);
self.bot_right.flip(axis);
let tl = self.top_left.axis_mut(axis);
let br = self.bot_right.axis_mut(axis);
std::mem::swap(tl.rel, br.rel);
std::mem::swap(tl.abs, br.abs);
}
pub fn shift(&mut self, offset: impl Into<UiVec2>) {
let offset = offset.into();
self.top_left.shift(offset);
self.bot_right.shift(offset);
}
pub fn offset(mut self, offset: impl Into<UiVec2>) -> Self {
self.shift(offset);
self
}
pub fn to_px(&self, size: Vec2) -> PixelRegion {
PixelRegion {
top_left: self.top_left.rel * size + self.top_left.abs,
bot_right: self.bot_right.rel * size + self.bot_right.abs,
}
}
pub fn center(&self) -> UiVec2 {
Align::Center.pos().within(self)
}
pub fn size(&self) -> UiVec2 {
self.bot_right - self.top_left
}
pub fn select_aligned(&self, size: Vec2, align: Align) -> Self {
Self::from_size_align(size, align).within(self)
}
pub fn from_size_align(size: Vec2, align: Align) -> Self {
let mut top_left = UiVec2::from(align);
top_left.abs -= size * align.rel();
let mut bot_right = UiVec2::from(align);
bot_right.abs += size * (Vec2::ONE - align.rel());
Self {
top_left,
bot_right,
}
}
pub fn from_ui_size_align(size: UiVec2, align: Align) -> Self {
let mut top_left = UiVec2::from(align);
top_left.abs -= size.abs * align.rel();
top_left.rel -= size.rel * align.rel();
let mut bot_right = UiVec2::from(align);
bot_right.abs += size.abs * (Vec2::ONE - align.rel());
bot_right.rel += size.rel * (Vec2::ONE - align.rel());
Self {
top_left,
bot_right,
}
}
}
impl Display for UiRegion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} -> {} (size: {})",
self.top_left,
self.bot_right,
self.size()
)
}
}
#[derive(Debug)]
pub struct PixelRegion {
pub top_left: Vec2,
pub bot_right: Vec2,
}
impl PixelRegion {
pub fn contains(&self, pos: Vec2) -> bool {
pos.x >= self.top_left.x
&& pos.x <= self.bot_right.x
&& pos.y >= self.top_left.y
&& pos.y <= self.bot_right.y
}
pub fn size(&self) -> Vec2 {
self.bot_right - self.top_left
}
}
impl Display for PixelRegion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} -> {}", self.top_left, self.bot_right)
}
}
pub struct UIRegionAxisView<'a> {
pub top_left: UiScalarView<'a>,
pub bot_right: UiScalarView<'a>,
}
pub struct UiScalarView<'a> {
pub rel: &'a mut f32,
pub abs: &'a mut f32,
}
impl UiScalarView<'_> {
pub fn set(&mut self, scalar: UiScalar) {
*self.rel = scalar.rel;
*self.abs = scalar.abs;
}
pub fn get(self) -> UiScalar {
UiScalar {
rel: *self.rel,
abs: *self.abs,
}
}
}

View File

@@ -4,7 +4,7 @@ use cosmic_text::{
use image::{Rgba, RgbaImage}; use image::{Rgba, RgbaImage};
use crate::{ use crate::{
layout::{Align, TextureHandle, Textures, UiColor, Vec2}, layout::{Align, RegionAlign, TextureHandle, Textures, UiColor, Vec2},
util::HashMap, util::HashMap,
}; };
@@ -35,7 +35,7 @@ pub struct TextAttrs {
pub family: Family<'static>, pub family: Family<'static>,
pub wrap: bool, pub wrap: bool,
/// inner alignment of text region (within where its drawn) /// inner alignment of text region (within where its drawn)
pub align: Align, pub align: RegionAlign,
} }
impl TextAttrs { impl TextAttrs {
@@ -65,7 +65,7 @@ impl Default for TextAttrs {
line_height: size * 1.2, line_height: size * 1.2,
family: Family::SansSerif, family: Family::SansSerif,
wrap: false, wrap: false,
align: Align::Center, align: Align::CENTER,
} }
} }
} }

View File

@@ -42,10 +42,10 @@ struct WindowUniform {
}; };
struct InstanceInput { struct InstanceInput {
@location(0) top_left_anchor: vec2<f32>, @location(0) x_start: vec2<f32>,
@location(1) top_left_offset: vec2<f32>, @location(1) x_end: vec2<f32>,
@location(2) bottom_right_anchor: vec2<f32>, @location(2) y_start: vec2<f32>,
@location(3) bottom_right_offset: vec2<f32>, @location(3) y_end: vec2<f32>,
@location(4) binding: u32, @location(4) binding: u32,
@location(5) idx: u32, @location(5) idx: u32,
@location(6) mask_idx: u32, @location(6) mask_idx: u32,
@@ -75,8 +75,13 @@ fn vs_main(
) -> VertexOutput { ) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
let top_left = floor(in.top_left_anchor * window.dim) + floor(in.top_left_offset); let top_left_rel = vec2(in.x_start.x, in.y_start.x);
let bot_right = floor(in.bottom_right_anchor * window.dim) + floor(in.bottom_right_offset); let top_left_abs = vec2(in.x_start.y, in.y_start.y);
let bot_right_rel = vec2(in.x_end.x, in.y_end.x);
let bot_right_abs = vec2(in.x_end.y, in.y_end.y);
let top_left = floor(top_left_rel * window.dim) + floor(top_left_abs);
let bot_right = floor(bot_right_rel * window.dim) + floor(bot_right_abs);
let size = bot_right - top_left; let size = bot_right - top_left;
let uv = vec2<f32>( let uv = vec2<f32>(

View File

@@ -86,7 +86,7 @@ impl Client {
ctx.ui[span_add].children.push(child); ctx.ui[span_add].children.push(child);
}) })
.sized((150, 150)) .sized((150, 150))
.align(Align::BotRight); .align(Align::BOT_RIGHT);
let del_button = rect(Color::RED) let del_button = rect(Color::RED)
.radius(30) .radius(30)
@@ -94,7 +94,7 @@ impl Client {
ctx.ui[span_add].children.pop(); ctx.ui[span_add].children.pop();
}) })
.sized((150, 150)) .sized((150, 150))
.align(Align::BotLeft); .align(Align::BOT_LEFT);
let span_add_test = (span_add, add_button, del_button) let span_add_test = (span_add, add_button, del_button)
.stack() .stack()
@@ -105,18 +105,18 @@ impl Client {
let btext = |content| text(content).size(30); let btext = |content| text(content).size(30);
let text_test = ( let text_test = (
btext("this is a").align(Align::Left), btext("this is a").align(Align::LEFT),
btext("teeeeeeeest").align(Align::Right), btext("teeeeeeeest").align(Align::RIGHT),
btext("okkk\nokkkkkk!").align(Align::Left), btext("okkk\nokkkkkk!").align(Align::LEFT),
btext("hmm"), btext("hmm"),
btext("a"), btext("a"),
( (
btext("'").family(Family::Monospace).align(Align::Top), btext("'").family(Family::Monospace).align(Align::TOP),
btext("'").family(Family::Monospace), btext("'").family(Family::Monospace),
btext(":gamer mode").family(Family::Monospace), btext(":gamer mode").family(Family::Monospace),
rect(Color::CYAN).sized((10, 10)).center(), rect(Color::CYAN).sized((10, 10)).center(),
rect(Color::RED).sized((100, 100)).center(), rect(Color::RED).sized((100, 100)).center(),
rect(Color::PURPLE).sized((50, 50)).align(Align::Top), rect(Color::PURPLE).sized((50, 50)).align(Align::TOP),
) )
.span(Dir::RIGHT) .span(Dir::RIGHT)
.center(), .center(),
@@ -129,7 +129,7 @@ impl Client {
let msg_area = (Rect::new(Color::SKY), texts.scroll().masked()).stack(); let msg_area = (Rect::new(Color::SKY), texts.scroll().masked()).stack();
let add_text = text("add") let add_text = text("add")
.editable() .editable()
.text_align(Align::Left) .text_align(Align::LEFT)
.size(30) .size(30)
.id_on(CursorSense::click(), |id, client: &mut Client, ctx| { .id_on(CursorSense::click(), |id, client: &mut Client, ctx| {
client.ui.text(id).select(ctx.cursor, ctx.size); client.ui.text(id).select(ctx.cursor, ctx.size);
@@ -140,7 +140,7 @@ impl Client {
let text = text(content) let text = text(content)
.editable() .editable()
.size(30) .size(30)
.text_align(Align::Left) .text_align(Align::LEFT)
.wrap(true) .wrap(true)
.id_on(CursorSense::click(), |id, client: &mut Client, ctx| { .id_on(CursorSense::click(), |id, client: &mut Client, ctx| {
client.ui.text(id).select(ctx.cursor, ctx.size); client.ui.text(id).select(ctx.cursor, ctx.size);
@@ -171,7 +171,7 @@ impl Client {
.stack() .stack()
.size(StackSize::Child(1)) .size(StackSize::Child(1))
.offset_layer(1) .offset_layer(1)
.align(Align::Bot), .align(Align::BOT),
) )
.span(Dir::DOWN) .span(Dir::DOWN)
.add_static(&mut ui); .add_static(&mut ui);
@@ -208,7 +208,7 @@ impl Client {
.span(Dir::RIGHT); .span(Dir::RIGHT);
let info = text("").add(&mut ui); let info = text("").add(&mut ui);
let info_sect = info.clone().pad(10).align(Align::Right); let info_sect = info.clone().pad(10).align(Align::RIGHT);
((tabs.height(40), main).span(Dir::DOWN), info_sect) ((tabs.height(40), main).span(Dir::DOWN), info_sect)
.stack() .stack()