alignment!!!

This commit is contained in:
2025-08-28 21:55:34 -04:00
parent 46c7d8ba26
commit 1204e3728e
11 changed files with 190 additions and 86 deletions

17
src/core/align.rs Normal file
View File

@@ -0,0 +1,17 @@
use crate::prelude::*;
pub struct Aligned {
pub inner: WidgetId,
pub align: Align,
}
impl Widget for Aligned {
fn draw(&mut self, painter: &mut Painter) {
let region = UiRegion::from_size_align(painter.size(&self.inner), self.align);
painter.draw_within(&self.inner, region);
}
fn size(&mut self, ctx: &mut SizeCtx) -> Vec2 {
ctx.size(&self.inner)
}
}

View File

@@ -1,16 +1,20 @@
mod align;
mod frame;
mod image;
mod rect;
mod sense;
mod sized;
mod span;
mod stack;
mod text;
mod trait_fns;
pub use align::*;
pub use frame::*;
pub use image::*;
pub use rect::*;
pub use sense::*;
pub use sized::*;
pub use span::*;
pub use stack::*;
pub use text::*;

16
src/core/sized.rs Normal file
View File

@@ -0,0 +1,16 @@
use crate::prelude::*;
pub struct Sized {
pub inner: WidgetId,
pub size: Vec2,
}
impl Widget for Sized {
fn draw(&mut self, painter: &mut Painter) {
painter.draw(&self.inner);
}
fn size(&mut self, _: &mut SizeCtx) -> Vec2 {
self.size
}
}

View File

@@ -33,9 +33,7 @@ impl Widget for Span {
let offset = size.axis(self.dir.axis);
start.offset += offset;
*axis.bot_right.offset = start.offset;
child_region.bot_right.anchor = child_region.top_left.anchor;
let opposite = !self.dir.axis;
*child_region.bot_right.offset.axis_mut(opposite) += size.axis(opposite);
*axis.bot_right.anchor = *axis.top_left.anchor;
}
}
if self.dir.sign == Sign::Neg {

View File

@@ -1,13 +1,13 @@
use super::*;
use crate::layout::{
Dir, UiPos, UiRegion, Vec2, WidgetArrLike, WidgetFnRet, WidgetIdFnRet, WidgetLike,
};
use crate::prelude::*;
pub trait CoreWidget<W, Tag> {
fn pad(self, padding: impl Into<Padding>) -> WidgetFnRet!(Regioned);
fn center(self, size: impl Into<Vec2>) -> WidgetFnRet!(Regioned);
fn align(self, align: Align) -> WidgetFnRet!(Aligned);
fn center(self) -> WidgetFnRet!(Aligned);
fn region(self, region: UiRegion) -> WidgetFnRet!(Regioned);
fn label(self, label: impl Into<String>) -> WidgetIdFnRet!(W);
fn sized(self, size: impl Into<Vec2>) -> WidgetFnRet!(Sized);
}
impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
@@ -18,13 +18,17 @@ impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
}
}
fn center(self, size: impl Into<Vec2>) -> WidgetFnRet!(Regioned) {
|ui| Regioned {
region: UiPos::center().expand(size.into()),
fn align(self, align: Align) -> WidgetFnRet!(Aligned) {
move |ui| Aligned {
inner: self.add(ui).erase_type(),
align,
}
}
fn center(self) -> WidgetFnRet!(Aligned) {
self.align(Align::Center)
}
fn region(self, region: UiRegion) -> WidgetFnRet!(Regioned) {
move |ui| Regioned {
region,
@@ -39,19 +43,26 @@ impl<W: WidgetLike<Tag>, Tag> CoreWidget<W::Widget, Tag> for W {
id
}
}
fn sized(self, size: impl Into<Vec2>) -> WidgetFnRet!(Sized) {
move |ui| Sized {
inner: self.add(ui).erase_type(),
size: size.into(),
}
}
}
pub trait CoreWidgetArr<const LEN: usize, Tag> {
fn span(self, dir: Dir, lengths: [impl Into<SpanLen>; LEN]) -> WidgetFnRet!(Span);
fn span(self, dir: Dir, lengths: impl IntoSpanLens<LEN>) -> WidgetFnRet!(Span);
fn stack(self) -> WidgetFnRet!(Stack);
}
impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> CoreWidgetArr<LEN, Tag> for Wa {
fn span(self, dir: Dir, lengths: [impl Into<SpanLen>; LEN]) -> WidgetFnRet!(Span) {
let lengths = lengths.map(Into::into);
fn span(self, dir: Dir, lengths: impl IntoSpanLens<LEN>) -> WidgetFnRet!(Span) {
let lengths = lengths.into_lens();
move |ui| Span {
dir,
children: self.ui(ui).arr.into_iter().zip(lengths).collect(),
dir,
}
}
fn stack(self) -> WidgetFnRet!(Stack) {
@@ -60,3 +71,37 @@ impl<const LEN: usize, Wa: WidgetArrLike<LEN, Tag>, Tag> CoreWidgetArr<LEN, Tag>
}
}
}
// pub struct SpanBuilder<const LEN: usize, Tag, Wa: WidgetArrLike<LEN, Tag>> {
// children: Wa,
// dir: Dir,
// align: Align,
// }
//
// impl WidgetLike<FnTag> for SpanBuilder {
// type Widget = Span;
//
// fn add(self, ui: &mut Ui) -> WidgetId<Self::Widget> {
// ui.add_widget(Span {
// children: self.children,
// dir: self.dir,
// align: self.align,
// })
// }
// }
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]
}
}

View File

@@ -1,20 +1,21 @@
#[const_trait]
pub trait UiNum {
fn to_f32(self) -> f32;
}
impl UiNum for f32 {
impl const UiNum for f32 {
fn to_f32(self) -> f32 {
self
}
}
impl UiNum for u32 {
impl const UiNum for u32 {
fn to_f32(self) -> f32 {
self as f32
}
}
impl UiNum for i32 {
impl const UiNum for i32 {
fn to_f32(self) -> f32 {
self as f32
}

View File

@@ -2,25 +2,6 @@ use std::ops::Not;
use crate::layout::{Vec2, vec2};
#[derive(Clone, Copy, Debug)]
pub enum Corner {
TopLeft,
TopRight,
BotLeft,
BotRight,
}
impl Corner {
pub const fn anchor(&self) -> Vec2 {
match self {
Corner::TopLeft => vec2(0.0, 0.0),
Corner::TopRight => vec2(1.0, 0.0),
Corner::BotLeft => vec2(0.0, 1.0),
Corner::BotRight => vec2(1.0, 1.0),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Axis {
X,
@@ -89,3 +70,33 @@ impl Vec2 {
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Align {
TopLeft,
Top,
TopRight,
Left,
Center,
Right,
BotLeft,
Bot,
BotRight,
}
impl Align {
pub const fn anchor(&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),
}
}
}

View File

@@ -156,7 +156,7 @@ impl<'a> Painter<'a> {
.size(&mut self.size_ctx())
}
pub fn size_ctx(&mut self) -> SizeCtx {
pub fn size_ctx(&mut self) -> SizeCtx<'_> {
SizeCtx {
size: self.region().in_size(self.screen_size),
text: self.text,

View File

@@ -1,5 +1,5 @@
use crate::{
layout::{Axis, Corner, Vec2, vec2},
layout::{Align, Axis, Vec2},
util::{F32Util, impl_op},
};
@@ -20,10 +20,6 @@ impl UiPos {
}
}
pub const fn center() -> Self {
Self::anchor(vec2(0.5, 0.5))
}
pub const fn anchor(anchor: Vec2) -> Self {
Self {
anchor,
@@ -38,10 +34,6 @@ impl UiPos {
}
}
pub const fn corner(corner: Corner) -> Self {
Self::anchor(corner.anchor())
}
pub const fn shift(&mut self, offset: impl const Into<Vec2>) {
self.offset += offset.into();
}
@@ -90,6 +82,18 @@ impl UiPos {
}
}
impl const From<Align> for UiPos {
fn from(align: Align) -> Self {
Self::anchor(align.anchor())
}
}
impl Align {
pub fn pos(self) -> UiPos {
UiPos::from(self)
}
}
#[derive(Clone, Copy, Debug)]
pub struct UIScalar {
pub anchor: f32,
@@ -137,8 +141,8 @@ pub struct UiRegion {
impl UiRegion {
pub const fn full() -> Self {
Self {
top_left: UiPos::corner(Corner::TopLeft),
bot_right: UiPos::corner(Corner::BotRight),
top_left: Align::TopLeft.into(),
bot_right: Align::BotRight.into(),
}
}
pub fn anchor(anchor: Vec2) -> Self {
@@ -153,9 +157,6 @@ impl UiRegion {
bot_right: self.bot_right.within(parent),
}
}
pub fn select(&mut self, inner: &Self) {
*self = inner.within(self);
}
pub fn axis_mut(&mut self, axis: Axis) -> UIRegionAxisView<'_> {
UIRegionAxisView {
top_left: self.top_left.axis_mut(axis),
@@ -188,12 +189,27 @@ impl UiRegion {
}
pub fn center(&self) -> UiPos {
UiPos::center().within(self)
Align::Center.pos().within(self)
}
pub fn in_size(&self, size: Vec2) -> Vec2 {
self.bot_right.to_size(size) - self.top_left.to_size(size)
}
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 = UiPos::from(align);
top_left.offset -= size * align.anchor();
let mut bot_right = UiPos::from(align);
bot_right.offset += size * (Vec2::ONE - align.anchor());
Self {
top_left,
bot_right,
}
}
}
#[derive(Debug)]

View File

@@ -54,9 +54,12 @@ impl Vec2 {
}
}
impl const From<f32> for Vec2 {
fn from(v: f32) -> Self {
Self { x: v, y: v }
impl<T: const UiNum + Copy> const From<T> for Vec2 {
fn from(v: T) -> Self {
Self {
x: v.to_f32(),
y: v.to_f32(),
}
}
}

View File

@@ -39,7 +39,7 @@ impl Client {
(
rect.color(Color::BLUE),
(
rect.color(Color::RED).center((100.0, 100.0)),
rect.color(Color::RED).sized((100.0, 100.0)),
(rect.color(Color::ORANGE), rect.color(Color::LIME).pad(10.0))
.span(Dir::RIGHT, [1, 1]),
rect.color(Color::YELLOW),
@@ -91,62 +91,55 @@ impl Client {
let text_test = ui.add_static(
(
text("this is a").size(30),
text("teeeeeeeest").size(30),
text("okkk\nokkkkkk!").size(30),
text("this is a").size(30).align(Align::Left),
text("teeeeeeeest").size(30).align(Align::Left),
text("okkk\nokkkkkk!").size(30).align(Align::Left),
text("hmm").size(30),
text("a").size(30),
(
text("'").size(30).family(Family::Monospace),
text("'").size(30).family(Family::Monospace),
text(":gamer mode").size(30).family(Family::Monospace),
Rect::new(Color::BLUE).sized(100),
)
.span(Dir::RIGHT, [sized(); _]),
.span(Dir::RIGHT, sized())
.center(),
text("pretty cool right?").size(30),
)
.span(Dir::DOWN, [sized(); _]),
.span(Dir::DOWN, sized()),
);
let tabs = ui.add(
(
switch_button(Color::RED, pad_test, "pad test"),
switch_button(Color::GREEN, span_test, "span test"),
switch_button(Color::BLUE, span_add, "span add test"),
switch_button(Color::MAGENTA, text_test, "text test"),
)
.span(Dir::RIGHT, [1; _]),
);
let tabs = (
switch_button(Color::RED, pad_test, "pad test"),
switch_button(Color::GREEN, span_test, "span test"),
switch_button(Color::BLUE, span_add, "span add test"),
switch_button(Color::MAGENTA, text_test, "text test"),
)
.span(Dir::RIGHT, ratio(1));
let add_button = Rect::new(Color::LIME)
.radius(30)
.on(PRESS_START, move |ui| {
let child = ui
.add(image(include_bytes!("assets/sungals.png")))
.add(image(include_bytes!("assets/sungals.png")).center())
.erase_type();
ui[span_add].children.push((child, sized()));
})
.region(
UiPos::corner(Corner::BotRight)
.expand((150, 150))
.shifted((-75, -75)),
);
.sized(150)
.align(Align::BotRight);
let del_button = Rect::new(Color::RED)
.radius(30)
.on(PRESS_START, move |ui| {
ui[span_add].children.pop();
})
.region(
UiPos::corner(Corner::BotLeft)
.expand((150, 150))
.shifted((75, -75)),
);
.sized(150)
.align(Align::BotLeft);
let info = ui.add(text(""));
let info_sect = info.clone().region(
UiPos::corner(Corner::TopRight)
.expand((150, 150))
.shifted((-75, 0)),
);
let info_sect = info
.clone()
.region(Align::TopRight.pos().expand((150, 150)).shifted((-75, 0)));
ui.set_base(
(
tabs.label("tabs"),