alignment!!!
This commit is contained in:
17
src/core/align.rs
Normal file
17
src/core/align.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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
16
src/core/sized.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"),
|
||||
|
||||
Reference in New Issue
Block a user