235 lines
5.7 KiB
Rust
235 lines
5.7 KiB
Rust
use crate::{
|
|
layout::{Axis, Corner, Vec2, vec2},
|
|
util::{F32Util, impl_op},
|
|
};
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, Default)]
|
|
pub struct UiPos {
|
|
pub anchor: Vec2,
|
|
pub offset: Vec2,
|
|
}
|
|
|
|
impl UiPos {
|
|
/// 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.shifted(-size / 2.0),
|
|
bot_right: self.shifted(size / 2.0),
|
|
}
|
|
}
|
|
|
|
pub const fn center() -> Self {
|
|
Self::anchor(vec2(0.5, 0.5))
|
|
}
|
|
|
|
pub const fn anchor(anchor: Vec2) -> Self {
|
|
Self {
|
|
anchor,
|
|
offset: Vec2::ZERO,
|
|
}
|
|
}
|
|
|
|
pub const fn offset(offset: Vec2) -> Self {
|
|
Self {
|
|
anchor: Vec2::ZERO,
|
|
offset,
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
pub const fn shifted(mut self, offset: Vec2) -> Self {
|
|
self.shift(offset);
|
|
self
|
|
}
|
|
|
|
pub const fn within(&self, region: &UiRegion) -> UiPos {
|
|
let anchor = self
|
|
.anchor
|
|
.lerp(region.top_left.anchor, region.bot_right.anchor);
|
|
let offset = self.offset
|
|
+ self
|
|
.anchor
|
|
.lerp(region.top_left.offset, region.bot_right.offset);
|
|
UiPos { anchor, offset }
|
|
}
|
|
|
|
pub fn axis_mut(&mut self, axis: Axis) -> UIScalarView<'_> {
|
|
match axis {
|
|
Axis::X => UIScalarView {
|
|
anchor: &mut self.anchor.x,
|
|
offset: &mut self.offset.x,
|
|
},
|
|
Axis::Y => UIScalarView {
|
|
anchor: &mut self.anchor.y,
|
|
offset: &mut self.offset.y,
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn flip(&mut self) {
|
|
self.anchor = 1.0 - self.anchor;
|
|
self.offset = -self.offset;
|
|
}
|
|
|
|
pub fn flipped(mut self) -> Self {
|
|
self.flip();
|
|
self
|
|
}
|
|
|
|
pub fn to_size(&self, size: Vec2) -> Vec2 {
|
|
self.anchor * size + self.offset
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct UIScalar {
|
|
pub anchor: f32,
|
|
pub offset: f32,
|
|
}
|
|
|
|
impl_op!(UIScalar Add add; anchor offset);
|
|
impl_op!(UIScalar Sub sub; anchor offset);
|
|
|
|
impl UIScalar {
|
|
pub fn new(anchor: f32, offset: f32) -> Self {
|
|
Self { anchor, offset }
|
|
}
|
|
pub fn min() -> Self {
|
|
Self::new(0.0, 0.0)
|
|
}
|
|
|
|
pub fn max() -> Self {
|
|
Self::new(1.0, 0.0)
|
|
}
|
|
|
|
pub fn from_anchor(anchor: f32) -> Self {
|
|
Self::new(anchor, 0.0)
|
|
}
|
|
|
|
pub fn offset(mut self, amt: f32) -> Self {
|
|
self.offset += amt;
|
|
self
|
|
}
|
|
|
|
pub fn within(&self, start: UIScalar, end: UIScalar) -> Self {
|
|
let anchor = self.anchor.lerp(start.anchor, end.anchor);
|
|
let offset = self.offset + self.anchor.lerp(start.offset, end.offset);
|
|
Self { anchor, offset }
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
|
pub struct UiRegion {
|
|
pub top_left: UiPos,
|
|
pub bot_right: UiPos,
|
|
}
|
|
|
|
impl UiRegion {
|
|
pub const fn full() -> Self {
|
|
Self {
|
|
top_left: UiPos::corner(Corner::TopLeft),
|
|
bot_right: UiPos::corner(Corner::BotRight),
|
|
}
|
|
}
|
|
pub fn anchor(anchor: Vec2) -> Self {
|
|
Self {
|
|
top_left: UiPos::anchor(anchor),
|
|
bot_right: UiPos::anchor(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 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),
|
|
bot_right: self.bot_right.axis_mut(axis),
|
|
}
|
|
}
|
|
|
|
pub fn flip(&mut self) {
|
|
self.top_left.flip();
|
|
self.bot_right.flip();
|
|
std::mem::swap(&mut self.top_left, &mut self.bot_right);
|
|
}
|
|
|
|
pub fn shift(&mut self, offset: impl Into<Vec2>) {
|
|
let offset = offset.into();
|
|
self.top_left.shift(offset);
|
|
self.bot_right.shift(offset);
|
|
}
|
|
|
|
pub fn shifted(mut self, offset: impl Into<Vec2>) -> Self {
|
|
self.shift(offset);
|
|
self
|
|
}
|
|
|
|
pub fn to_screen(&self, size: Vec2) -> ScreenRect {
|
|
ScreenRect {
|
|
top_left: self.top_left.anchor * size + self.top_left.offset,
|
|
bot_right: self.bot_right.anchor * size + self.bot_right.offset,
|
|
}
|
|
}
|
|
|
|
pub fn center(&self) -> UiPos {
|
|
UiPos::center().within(self)
|
|
}
|
|
|
|
pub fn in_size(&self, size: Vec2) -> Vec2 {
|
|
self.bot_right.to_size(size) - self.top_left.to_size(size)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ScreenRect {
|
|
top_left: Vec2,
|
|
bot_right: Vec2,
|
|
}
|
|
impl ScreenRect {
|
|
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 struct UIRegionAxisView<'a> {
|
|
pub top_left: UIScalarView<'a>,
|
|
pub bot_right: UIScalarView<'a>,
|
|
}
|
|
|
|
pub struct UIScalarView<'a> {
|
|
pub anchor: &'a mut f32,
|
|
pub offset: &'a mut f32,
|
|
}
|
|
|
|
impl UIScalarView<'_> {
|
|
pub fn set(&mut self, scalar: UIScalar) {
|
|
*self.anchor = scalar.anchor;
|
|
*self.offset = scalar.offset;
|
|
}
|
|
pub fn get(self) -> UIScalar {
|
|
UIScalar {
|
|
anchor: *self.anchor,
|
|
offset: *self.offset,
|
|
}
|
|
}
|
|
}
|