mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 03:36:42 +01:00
This commit is contained in:
parent
ff4d0c9db5
commit
74b3af2212
6 changed files with 301 additions and 11 deletions
|
|
@ -13,17 +13,23 @@ pub(crate) use std::sync::{Arc, atomic::{AtomicUsize, Ordering::Relaxed}};
|
||||||
pub(crate) use tengri_core::*;
|
pub(crate) use tengri_core::*;
|
||||||
#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*;
|
#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*;
|
||||||
|
|
||||||
mod output; pub use self::output::*;
|
mod output; pub use self::output::*;
|
||||||
mod output_render; pub use self::output_render::*;
|
mod output_render; pub use self::output_render::*;
|
||||||
mod output_content; pub use self::output_content::*;
|
mod output_content; pub use self::output_content::*;
|
||||||
mod output_thunk; pub use self::output_thunk::*;
|
mod output_thunk; pub use self::output_thunk::*;
|
||||||
mod space; pub use self::space::*;
|
mod space_area; pub use self::space_area::*;
|
||||||
mod layout_align; pub use self::layout_align::*;
|
mod space_coordinate; pub use self::space_coordinate::*;
|
||||||
mod layout_bsp; pub use self::layout_bsp::*;
|
mod space_direction; pub use self::space_direction::*;
|
||||||
mod layout_cond; pub use self::layout_cond::*;
|
mod space_measure; pub use self::space_measure::*;
|
||||||
mod layout_map; pub use self::layout_map::*;
|
mod space_size; pub use self::space_size::*;
|
||||||
mod layout_stack; pub use self::layout_stack::*;
|
mod layout_align; pub use self::layout_align::*;
|
||||||
mod layout_xy; pub use self::layout_xy::*;
|
mod layout_bsp; pub use self::layout_bsp::*;
|
||||||
|
mod layout_cond; pub use self::layout_cond::*;
|
||||||
|
mod layout_map; pub use self::layout_map::*;
|
||||||
|
mod layout_stack; pub use self::layout_stack::*;
|
||||||
|
mod layout_xy; pub use self::layout_xy::*;
|
||||||
|
|
||||||
|
pub(crate) use self::Direction::*;
|
||||||
|
|
||||||
#[cfg(test)] mod test;
|
#[cfg(test)] mod test;
|
||||||
#[cfg(test)] pub(crate) use proptest_derive::Arbitrary;
|
#[cfg(test)] pub(crate) use proptest_derive::Arbitrary;
|
||||||
|
|
|
||||||
97
output/src/space_area.rs
Normal file
97
output/src/space_area.rs
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub trait Area<N: Coordinate>: From<[N;4]> + Debug + Copy {
|
||||||
|
fn x (&self) -> N;
|
||||||
|
fn y (&self) -> N;
|
||||||
|
fn w (&self) -> N;
|
||||||
|
fn h (&self) -> N;
|
||||||
|
fn zero () -> [N;4] {
|
||||||
|
[N::zero(), N::zero(), N::zero(), N::zero()]
|
||||||
|
}
|
||||||
|
fn from_position (pos: impl Size<N>) -> [N;4] {
|
||||||
|
let [x, y] = pos.wh();
|
||||||
|
[x, y, 0.into(), 0.into()]
|
||||||
|
}
|
||||||
|
fn from_size (size: impl Size<N>) -> [N;4] {
|
||||||
|
let [w, h] = size.wh();
|
||||||
|
[0.into(), 0.into(), w, h]
|
||||||
|
}
|
||||||
|
fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
|
||||||
|
if self.w() < w || self.h() < h {
|
||||||
|
Err(format!("min {w}x{h}").into())
|
||||||
|
} else {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn xy (&self) -> [N;2] {
|
||||||
|
[self.x(), self.y()]
|
||||||
|
}
|
||||||
|
fn wh (&self) -> [N;2] {
|
||||||
|
[self.w(), self.h()]
|
||||||
|
}
|
||||||
|
fn xywh (&self) -> [N;4] {
|
||||||
|
[self.x(), self.y(), self.w(), self.h()]
|
||||||
|
}
|
||||||
|
fn clip_h (&self, h: N) -> [N;4] {
|
||||||
|
[self.x(), self.y(), self.w(), self.h().min(h)]
|
||||||
|
}
|
||||||
|
fn clip_w (&self, w: N) -> [N;4] {
|
||||||
|
[self.x(), self.y(), self.w().min(w), self.h()]
|
||||||
|
}
|
||||||
|
fn clip (&self, wh: impl Size<N>) -> [N;4] {
|
||||||
|
[self.x(), self.y(), wh.w(), wh.h()]
|
||||||
|
}
|
||||||
|
fn set_w (&self, w: N) -> [N;4] {
|
||||||
|
[self.x(), self.y(), w, self.h()]
|
||||||
|
}
|
||||||
|
fn set_h (&self, h: N) -> [N;4] {
|
||||||
|
[self.x(), self.y(), self.w(), h]
|
||||||
|
}
|
||||||
|
fn x2 (&self) -> N {
|
||||||
|
self.x().plus(self.w())
|
||||||
|
}
|
||||||
|
fn y2 (&self) -> N {
|
||||||
|
self.y().plus(self.h())
|
||||||
|
}
|
||||||
|
fn lrtb (&self) -> [N;4] {
|
||||||
|
[self.x(), self.x2(), self.y(), self.y2()]
|
||||||
|
}
|
||||||
|
fn center (&self) -> [N;2] {
|
||||||
|
[self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into())]
|
||||||
|
}
|
||||||
|
fn center_x (&self, n: N) -> [N;4] {
|
||||||
|
let [x, y, w, h] = self.xywh();
|
||||||
|
[(x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into()]
|
||||||
|
}
|
||||||
|
fn center_y (&self, n: N) -> [N;4] {
|
||||||
|
let [x, y, w, h] = self.xywh();
|
||||||
|
[x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n]
|
||||||
|
}
|
||||||
|
fn center_xy (&self, [n, m]: [N;2]) -> [N;4] {
|
||||||
|
let [x, y, w, h] = self.xywh();
|
||||||
|
[(x.plus(w / 2.into())).minus(n / 2.into()), (y.plus(h / 2.into())).minus(m / 2.into()), n, m]
|
||||||
|
}
|
||||||
|
fn centered (&self) -> [N;2] {
|
||||||
|
[self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())]
|
||||||
|
}
|
||||||
|
fn iter_x (&self) -> impl Iterator<Item = N> where N: std::iter::Step {
|
||||||
|
self.x()..(self.x()+self.w())
|
||||||
|
}
|
||||||
|
fn iter_y (&self) -> impl Iterator<Item = N> where N: std::iter::Step {
|
||||||
|
self.y()..(self.y()+self.h())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coordinate> Area<N> for (N, N, N, N) {
|
||||||
|
fn x (&self) -> N { self.0 }
|
||||||
|
fn y (&self) -> N { self.1 }
|
||||||
|
fn w (&self) -> N { self.2 }
|
||||||
|
fn h (&self) -> N { self.3 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coordinate> Area<N> for [N;4] {
|
||||||
|
fn x (&self) -> N { self[0] }
|
||||||
|
fn y (&self) -> N { self[1] }
|
||||||
|
fn w (&self) -> N { self[2] }
|
||||||
|
fn h (&self) -> N { self[3] }
|
||||||
|
}
|
||||||
30
output/src/space_coordinate.rs
Normal file
30
output/src/space_coordinate.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// A linear coordinate.
|
||||||
|
pub trait Coordinate: Send + Sync + Copy
|
||||||
|
+ Add<Self, Output=Self>
|
||||||
|
+ Sub<Self, Output=Self>
|
||||||
|
+ Mul<Self, Output=Self>
|
||||||
|
+ Div<Self, Output=Self>
|
||||||
|
+ Ord + PartialEq + Eq
|
||||||
|
+ Debug + Display + Default
|
||||||
|
+ From<u16> + Into<u16>
|
||||||
|
+ Into<usize>
|
||||||
|
+ Into<f64>
|
||||||
|
{
|
||||||
|
fn zero () -> Self { 0.into() }
|
||||||
|
fn plus (self, other: Self) -> Self;
|
||||||
|
fn minus (self, other: Self) -> Self {
|
||||||
|
if self >= other {
|
||||||
|
self - other
|
||||||
|
} else {
|
||||||
|
0.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Coordinate for u16 {
|
||||||
|
fn plus (self, other: Self) -> Self {
|
||||||
|
self.saturating_add(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
21
output/src/space_direction.rs
Normal file
21
output/src/space_direction.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// A cardinal direction.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
|
pub enum Direction {
|
||||||
|
North, South, East, West, Above, Below
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
pub fn split_fixed <N: Coordinate> (self, area: impl Area<N>, a: N) -> ([N;4],[N;4]) {
|
||||||
|
let [x, y, w, h] = area.xywh();
|
||||||
|
match self {
|
||||||
|
North => ([x, y.plus(h).minus(a), w, a], [x, y, w, h.minus(a)]),
|
||||||
|
South => ([x, y, w, a], [x, y.plus(a), w, h.minus(a)]),
|
||||||
|
East => ([x, y, a, h], [x.plus(a), y, w.minus(a), h]),
|
||||||
|
West => ([x.plus(w).minus(a), y, a, h], [x, y, w.minus(a), h]),
|
||||||
|
Above | Below => (area.xywh(), area.xywh())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
81
output/src/space_measure.rs
Normal file
81
output/src/space_measure.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// A widget that tracks its render width and height
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Measure<E: Output> {
|
||||||
|
_engine: PhantomData<E>,
|
||||||
|
pub x: Arc<AtomicUsize>,
|
||||||
|
pub y: Arc<AtomicUsize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Output> PartialEq for Measure<E> {
|
||||||
|
fn eq (&self, other: &Self) -> bool {
|
||||||
|
self.x.load(Relaxed) == other.x.load(Relaxed) &&
|
||||||
|
self.y.load(Relaxed) == other.y.load(Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small
|
||||||
|
impl<E: Output> Content<E> for Measure<E> {
|
||||||
|
fn render (&self, to: &mut E) {
|
||||||
|
self.x.store(to.area().w().into(), Relaxed);
|
||||||
|
self.y.store(to.area().h().into(), Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Output> Clone for Measure<E> {
|
||||||
|
fn clone (&self) -> Self {
|
||||||
|
Self {
|
||||||
|
_engine: Default::default(),
|
||||||
|
x: self.x.clone(),
|
||||||
|
y: self.y.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Output> std::fmt::Debug for Measure<E> {
|
||||||
|
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||||
|
f.debug_struct("Measure")
|
||||||
|
.field("width", &self.x)
|
||||||
|
.field("height", &self.y)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Output> Measure<E> {
|
||||||
|
pub fn new () -> Self {
|
||||||
|
Self {
|
||||||
|
_engine: PhantomData::default(),
|
||||||
|
x: Arc::new(0.into()),
|
||||||
|
y: Arc::new(0.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn set_w (&self, w: impl Into<usize>) -> &Self {
|
||||||
|
self.x.store(w.into(), Relaxed);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn set_h (&self, h: impl Into<usize>) -> &Self {
|
||||||
|
self.y.store(h.into(), Relaxed);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn set_wh (&self, w: impl Into<usize>, h: impl Into<usize>) -> &Self {
|
||||||
|
self.set_w(w);
|
||||||
|
self.set_h(h);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn w (&self) -> usize {
|
||||||
|
self.x.load(Relaxed)
|
||||||
|
}
|
||||||
|
pub fn h (&self) -> usize {
|
||||||
|
self.y.load(Relaxed)
|
||||||
|
}
|
||||||
|
pub fn wh (&self) -> [usize;2] {
|
||||||
|
[self.w(), self.h()]
|
||||||
|
}
|
||||||
|
pub fn format (&self) -> Arc<str> {
|
||||||
|
format!("{}x{}", self.w(), self.h()).into()
|
||||||
|
}
|
||||||
|
pub fn of <T: Render<E>> (&self, item: T) -> Bsp<Fill<&Self>, T> {
|
||||||
|
Bsp::b(Fill::xy(self), item)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
output/src/space_size.rs
Normal file
55
output/src/space_size.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub trait Size<N: Coordinate>: From<[N;2]> + Debug + Copy {
|
||||||
|
fn x (&self) -> N;
|
||||||
|
fn y (&self) -> N;
|
||||||
|
fn w (&self) -> N { self.x() }
|
||||||
|
fn h (&self) -> N { self.y() }
|
||||||
|
fn wh (&self) -> [N;2] { [self.x(), self.y()] }
|
||||||
|
fn clip_w (&self, w: N) -> [N;2] { [self.w().min(w), self.h()] }
|
||||||
|
fn clip_h (&self, h: N) -> [N;2] { [self.w(), self.h().min(h)] }
|
||||||
|
fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
|
||||||
|
if self.w() < w || self.h() < h {
|
||||||
|
Err(format!("min {w}x{h}").into())
|
||||||
|
} else {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn zero () -> [N;2] {
|
||||||
|
[N::zero(), N::zero()]
|
||||||
|
}
|
||||||
|
fn to_area_pos (&self) -> [N;4] {
|
||||||
|
let [x, y] = self.wh();
|
||||||
|
[x, y, 0.into(), 0.into()]
|
||||||
|
}
|
||||||
|
fn to_area_size (&self) -> [N;4] {
|
||||||
|
let [w, h] = self.wh();
|
||||||
|
[0.into(), 0.into(), w, h]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coordinate> Size<N> for (N, N) {
|
||||||
|
fn x (&self) -> N { self.0 }
|
||||||
|
fn y (&self) -> N { self.1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coordinate> Size<N> for [N;2] {
|
||||||
|
fn x (&self) -> N { self[0] }
|
||||||
|
fn y (&self) -> N { self[1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasSize<E: Output> {
|
||||||
|
fn size (&self) -> &Measure<E>;
|
||||||
|
fn width (&self) -> usize {
|
||||||
|
self.size().w()
|
||||||
|
}
|
||||||
|
fn height (&self) -> usize {
|
||||||
|
self.size().h()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Output, T: Has<Measure<E>>> HasSize<E> for T {
|
||||||
|
fn size (&self) -> &Measure<E> {
|
||||||
|
self.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue