mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-09-18 05:16:44 +02:00
Compare commits
2 commits
4172fa2577
...
8e7286e409
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e7286e409 | ||
|
|
92f992e2e6 |
9 changed files with 240 additions and 69 deletions
84
Cargo.lock
generated
84
Cargo.lock
generated
|
|
@ -797,6 +797,21 @@ dependencies = [
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generator"
|
||||||
|
version = "0.8.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"rustversion",
|
||||||
|
"windows-link",
|
||||||
|
"windows-result",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.7"
|
||||||
|
|
@ -1178,6 +1193,19 @@ version = "0.4.33"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "loom"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"generator",
|
||||||
|
"scoped-tls",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lru"
|
name = "lru"
|
||||||
version = "0.18.2"
|
version = "0.18.2"
|
||||||
|
|
@ -1197,6 +1225,15 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.8.3"
|
version = "2.8.3"
|
||||||
|
|
@ -2615,6 +2652,7 @@ dependencies = [
|
||||||
"konst",
|
"konst",
|
||||||
"midly",
|
"midly",
|
||||||
"palette",
|
"palette",
|
||||||
|
"parking_lot",
|
||||||
"profiling",
|
"profiling",
|
||||||
"proptest",
|
"proptest",
|
||||||
"proptest-derive",
|
"proptest-derive",
|
||||||
|
|
@ -2625,6 +2663,7 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-flame",
|
"tracing-flame",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
"tracing-tracy",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
@ -2890,14 +2929,50 @@ version = "0.3.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
|
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex-automata",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-tracy"
|
||||||
|
version = "0.11.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eaa1852afa96e0fe9e44caa53dc0bd2d9d05e0f2611ce09f97f8677af56e4ba"
|
||||||
|
dependencies = [
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"tracy-client",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracy-client"
|
||||||
|
version = "0.18.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4f6fc3baeac5d86ab90c772e9e30620fc653bf1864295029921a15ef478e6a5"
|
||||||
|
dependencies = [
|
||||||
|
"loom",
|
||||||
|
"once_cell",
|
||||||
|
"tracy-client-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracy-client-sys"
|
||||||
|
version = "0.28.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c5f7c95348f20c1c913d72157b3c6dee6ea3e30b3d19502c5a7f6d3f160dacbf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ttf-parser"
|
name = "ttf-parser"
|
||||||
version = "0.25.1"
|
version = "0.25.1"
|
||||||
|
|
@ -3332,6 +3407,15 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ anyhow = { version = "1.0" }
|
||||||
atomic_float = { version = "1" }
|
atomic_float = { version = "1" }
|
||||||
better-panic = { version = "0.3.0" }
|
better-panic = { version = "0.3.0" }
|
||||||
konst = { version = "0.3.16", features = [ "rust_1_83" ] }
|
konst = { version = "0.3.16", features = [ "rust_1_83" ] }
|
||||||
|
parking_lot = { version = "0.12.5" }
|
||||||
|
|
||||||
bumpalo = { optional = true, version = "3.19.0" }
|
bumpalo = { optional = true, version = "3.19.0" }
|
||||||
crossterm = { optional = true, version = "0.29.0" }
|
crossterm = { optional = true, version = "0.29.0" }
|
||||||
|
|
@ -44,6 +45,8 @@ profiling = { version = "1.0.18", optional = true, features = ["profile
|
||||||
tracing = { version = "0.1", optional = true, default-features = false, features = [ "std" ] }
|
tracing = { version = "0.1", optional = true, default-features = false, features = [ "std" ] }
|
||||||
tracing-subscriber = { version = "0.3", optional = true }
|
tracing-subscriber = { version = "0.3", optional = true }
|
||||||
tracing-flame = { version = "0.2", optional = true }
|
tracing-flame = { version = "0.2", optional = true }
|
||||||
|
tracing-tracy = { version = "0.11.4", optional = true }
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
proptest = { version = "^1" }
|
proptest = { version = "^1" }
|
||||||
|
|
|
||||||
29
src/deps.rs
Normal file
29
src/deps.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
pub extern crate atomic_float;
|
||||||
|
pub extern crate palette;
|
||||||
|
pub extern crate better_panic;
|
||||||
|
pub extern crate unicode_width;
|
||||||
|
pub extern crate parking_lot;
|
||||||
|
pub(crate) use ::{
|
||||||
|
std::fmt::{Debug, Display},
|
||||||
|
std::ops::{Add, Sub, Mul, Div},
|
||||||
|
std::sync::Arc,
|
||||||
|
std::sync::atomic::{AtomicBool, AtomicUsize, Ordering::*},
|
||||||
|
std::marker::PhantomData
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) use ::parking_lot::RwLock;
|
||||||
|
|
||||||
|
#[cfg(feature = "lang")] pub use ::dizzle::*;
|
||||||
|
#[cfg(feature = "prof")] pub extern crate profiling;
|
||||||
|
#[cfg(feature = "prof")] pub extern crate tracing;
|
||||||
|
#[cfg(feature = "prof")] pub extern crate tracing_subscriber;
|
||||||
|
#[cfg(feature = "prof")] pub extern crate tracing_flame;
|
||||||
|
//#[cfg(feature = "prof")] pub extern crate tracing_tracy;
|
||||||
|
#[cfg(feature = "sing")] pub extern crate jack;
|
||||||
|
#[cfg(feature = "midi")] pub extern crate midly;
|
||||||
|
#[cfg(feature = "term")] pub extern crate ratatui;
|
||||||
|
#[cfg(feature = "term")] pub extern crate crossterm;
|
||||||
|
#[cfg(feature = "lang")] pub extern crate dizzle;
|
||||||
|
|
||||||
|
#[cfg(test)] #[macro_use] pub extern crate proptest;
|
||||||
|
#[cfg(test)] pub(crate) use proptest_derive::Arbitrary;
|
||||||
|
|
@ -19,6 +19,7 @@ pub struct Area<S: Screen, T>(
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<S>> Draw<S> for Area<S, T> {
|
impl<'a, S: Screen, T: Draw<S>> Draw<S> for Area<S, T> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("area_draw");
|
||||||
to.draw(self.0, &self.1)
|
to.draw(self.0, &self.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -297,6 +297,7 @@ where
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<S>> Draw<S> for Full<'a, S, I> {
|
impl <'a, S: Screen, I: Draw<S>> Draw<S> for Full<'a, S, I> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("full_draw");
|
||||||
let XYWH(x0, y0, w0, h0) = to.area();
|
let XYWH(x0, y0, w0, h0) = to.area();
|
||||||
let item = match self {
|
let item = match self {
|
||||||
Self::W(i) => i, Self::H(i) => i, Self::WH(i) => i, _ => unreachable!()
|
Self::W(i) => i, Self::H(i) => i, Self::WH(i) => i, _ => unreachable!()
|
||||||
|
|
@ -315,6 +316,7 @@ impl <'a, S: Screen, I: Draw<S>> Draw<S> for Full<'a, S, I> {
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Exact<'a, S, I, X> {
|
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Exact<'a, S, I, X> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("exact_draw");
|
||||||
let XYWH(x0, y0, w0, h0) = to.area();
|
let XYWH(x0, y0, w0, h0) = to.area();
|
||||||
let (item, w1, h1) = match self {
|
let (item, w1, h1) = match self {
|
||||||
Self::W(item, w1) => (item, (*w1).into(), None),
|
Self::W(item, w1) => (item, (*w1).into(), None),
|
||||||
|
|
@ -337,6 +339,7 @@ impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Ex
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Min<'a, S, I, X> {
|
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Min<'a, S, I, X> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("min_draw");
|
||||||
let XYWH(x0, y0, w0, h0) = to.area();
|
let XYWH(x0, y0, w0, h0) = to.area();
|
||||||
let (item, w1, h1) = match self {
|
let (item, w1, h1) = match self {
|
||||||
Self::W(item, w1) => (item, (*w1).into(), None),
|
Self::W(item, w1) => (item, (*w1).into(), None),
|
||||||
|
|
@ -358,6 +361,7 @@ impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Mi
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Max<'a, S, I, X> {
|
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Max<'a, S, I, X> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("max_draw");
|
||||||
let XYWH(x, y, w0, h0) = to.area();
|
let XYWH(x, y, w0, h0) = to.area();
|
||||||
let (item, w, h) = match self {
|
let (item, w, h) = match self {
|
||||||
Self::W(item, w) => (item, (*w).into().unwrap_or(w0), h0),
|
Self::W(item, w) => (item, (*w).into().unwrap_or(w0), h0),
|
||||||
|
|
@ -371,6 +375,7 @@ impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Ma
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Push<'a, S, I, X> {
|
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Push<'a, S, I, X> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("push_draw");
|
||||||
match self {
|
match self {
|
||||||
Self::__(_) => unreachable!(),
|
Self::__(_) => unreachable!(),
|
||||||
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => {
|
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => {
|
||||||
|
|
@ -389,6 +394,7 @@ impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Pu
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Pull<'a, S, I, X> {
|
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Pull<'a, S, I, X> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("pull_draw");
|
||||||
match self {
|
match self {
|
||||||
Self::__(_) => unreachable!(),
|
Self::__(_) => unreachable!(),
|
||||||
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => {
|
Self::X(item, x1) if let Some(XYWH(x, y, w, h)) = to.size(None, item)? => {
|
||||||
|
|
@ -413,6 +419,7 @@ impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Pu
|
||||||
|
|
||||||
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Pad<'a, S, I, X> {
|
impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Pad<'a, S, I, X> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("pad_draw");
|
||||||
let XYWH(x, y, w0, h0) = to.area();
|
let XYWH(x, y, w0, h0) = to.area();
|
||||||
let (item, w, h) = match self {
|
let (item, w, h) = match self {
|
||||||
Self::X(item, w) => (item, (*w).into().unwrap_or_default(), Default::default()),
|
Self::X(item, w) => (item, (*w).into().unwrap_or_default(), Default::default()),
|
||||||
|
|
|
||||||
|
|
@ -116,16 +116,17 @@ pub trait CanAlign<'a, S: Screen>: Draw<S> + Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Align<T>(
|
pub struct Align<T>(
|
||||||
pub(crate) Option<Azimuth>,
|
pub Option<Azimuth>,
|
||||||
pub(crate) T,
|
pub T,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'a, S: Screen, T: Draw<S>> Draw<S> for Align<T> {
|
impl<'a, S: Screen, T: Draw<S>> Draw<S> for Align<T> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("align_draw");
|
||||||
let Self(azimuth, item) = self;
|
let Self(azimuth, item) = self;
|
||||||
let area0 = to.area();
|
let area0 = to.area();
|
||||||
let size = to.size(area0, item)?;
|
let size = to.size(area0, item)?;
|
||||||
let area1 = align::<S>(area0, size, *azimuth);
|
let area1 = aligned::<S>(area0, size, *azimuth);
|
||||||
//println!("\n\r{azimuth:?} {area0:?} {size:?}=>{area1:?}");
|
//println!("\n\r{azimuth:?} {area0:?} {size:?}=>{area1:?}");
|
||||||
Ok(if let Some(area) = area1 {
|
Ok(if let Some(area) = area1 {
|
||||||
to.draw(area, &item)?
|
to.draw(area, &item)?
|
||||||
|
|
@ -135,9 +136,10 @@ impl<'a, S: Screen, T: Draw<S>> Draw<S> for Align<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn align <S: Screen> (
|
fn aligned <S: Screen> (
|
||||||
area0: XYWH<S::Unit>, area: Option<XYWH<S::Unit>>, azimuth: Option<Azimuth>
|
area0: XYWH<S::Unit>, area: Option<XYWH<S::Unit>>, azimuth: Option<Azimuth>
|
||||||
) -> Option<XYWH<S::Unit>> {
|
) -> Option<XYWH<S::Unit>> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("align");
|
||||||
area.map(|XYWH(x, y, w, h)|{
|
area.map(|XYWH(x, y, w, h)|{
|
||||||
let XYWH(x0, y0, w0, h0) = area0;
|
let XYWH(x0, y0, w0, h0) = area0;
|
||||||
match azimuth {
|
match azimuth {
|
||||||
|
|
@ -158,6 +160,7 @@ fn align <S: Screen> (
|
||||||
}
|
}
|
||||||
|
|
||||||
fn_kw_layout!(kw_split |state, output, expr| {
|
fn_kw_layout!(kw_split |state, output, expr| {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("kw_split");
|
||||||
let thunk_a = draw(move|screen|ok_flat(expr.nth(1)?.map(|x|state.interpret(screen, x))));
|
let thunk_a = draw(move|screen|ok_flat(expr.nth(1)?.map(|x|state.interpret(screen, x))));
|
||||||
let thunk_b = draw(move|screen|ok_flat(expr.nth(2)?.map(|x|state.interpret(screen, x))));
|
let thunk_b = draw(move|screen|ok_flat(expr.nth(2)?.map(|x|state.interpret(screen, x))));
|
||||||
Ok(match expr.head()? {
|
Ok(match expr.head()? {
|
||||||
|
|
@ -205,6 +208,7 @@ pub fn split <'a, S: Screen, A: Draw<S>, B: Draw<S>> (
|
||||||
|
|
||||||
impl<'a, S: Screen, A: Draw<S>, B: Draw<S>> Draw<S> for Pair<A, B> {
|
impl<'a, S: Screen, A: Draw<S>, B: Draw<S>> Draw<S> for Pair<A, B> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("pair_draw");
|
||||||
let Self(split, a, b, ..) = self;
|
let Self(split, a, b, ..) = self;
|
||||||
let (area_a, area_b) = stack_areas(split, to, a, b)?;
|
let (area_a, area_b) = stack_areas(split, to, a, b)?;
|
||||||
let (drawn_a, drawn_b) = draw_stacks(split, to, a, area_a, None, b, area_b, None)?;
|
let (drawn_a, drawn_b) = draw_stacks(split, to, a, area_a, None, b, area_b, None)?;
|
||||||
|
|
@ -222,6 +226,7 @@ fn draw_stacks <'a, S: Screen> (
|
||||||
area_b: impl Into<Option<XYWH<S::Unit>>>,
|
area_b: impl Into<Option<XYWH<S::Unit>>>,
|
||||||
origin_b: impl Into<Option<Azimuth>>,
|
origin_b: impl Into<Option<Azimuth>>,
|
||||||
) -> UsuallyRef<'a, (Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
|
) -> UsuallyRef<'a, (Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("draw_stacks");
|
||||||
let draw_a = |to: &mut S|Ok::<_, Box<dyn Error>>(match origin_a.into() {
|
let draw_a = |to: &mut S|Ok::<_, Box<dyn Error>>(match origin_a.into() {
|
||||||
Some(origin_a) => to.draw(area_a.into(), a.align(origin_a))?,
|
Some(origin_a) => to.draw(area_a.into(), a.align(origin_a))?,
|
||||||
None => to.draw(area_a.into(), a)?
|
None => to.draw(area_a.into(), a)?
|
||||||
|
|
@ -303,6 +308,7 @@ fn stack_drawn <S: Coord> (
|
||||||
drawn_a: Option<XYWH<S>>,
|
drawn_a: Option<XYWH<S>>,
|
||||||
drawn_b: Option<XYWH<S>>,
|
drawn_b: Option<XYWH<S>>,
|
||||||
) -> Option<XYWH<S>> {
|
) -> Option<XYWH<S>> {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("stack_drawn");
|
||||||
if let (Some(XYWH(xa, ya, wa, ha)), Some(XYWH(xb, yb, wb, hb))) = (drawn_a, drawn_b) {
|
if let (Some(XYWH(xa, ya, wa, ha)), Some(XYWH(xb, yb, wb, hb))) = (drawn_a, drawn_b) {
|
||||||
match split {
|
match split {
|
||||||
Split::South => Some(XYWH(xa.min(xb), ya, wa.max(wb), ha + hb)),
|
Split::South => Some(XYWH(xa.min(xb), ya, wa.max(wb), ha + hb)),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,28 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
fn_kw_layout!(kw_when |state, output, expr| {
|
pub struct When<T>(pub bool, pub T);
|
||||||
let thunk = draw(move|screen|ok_flat(expr.nth(2)?.map(|x|state.interpret(screen, x))));
|
|
||||||
ok_flat(matches!(expr.head()?, Some("when")).then(||{
|
impl<S: Screen, T: Draw<S>> Draw<S> for When<T> {
|
||||||
when(state.namespace(&expr.nth(1)?)?.unwrap(), thunk).draw(output)
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
}))
|
#[cfg(feature = "prof")] profiling::scope!("when");
|
||||||
});
|
if self.0 {
|
||||||
|
self.1.draw(to)
|
||||||
|
} else {
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> When<T> {
|
||||||
|
|
||||||
|
fn_kw_layout!(interpret |state, output, expr| {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("kw_when");
|
||||||
|
let thunk = draw(move|screen|ok_flat(expr.nth(2)?.map(|x|state.interpret(screen, x))));
|
||||||
|
ok_flat(matches!(expr.head()?, Some("when")).then(||{
|
||||||
|
when(state.namespace(&expr.nth(1)?)?.unwrap(), thunk).draw(output)
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Only render when condition is true.
|
/// Only render when condition is true.
|
||||||
///
|
///
|
||||||
|
|
@ -15,10 +32,11 @@ fn_kw_layout!(kw_when |state, output, expr| {
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn when <'a, T: Screen> (condition: bool, item: impl Draw<T>) -> impl Draw<T> {
|
pub const fn when <'a, T: Screen> (condition: bool, item: impl Draw<T>) -> impl Draw<T> {
|
||||||
draw(move|to: &mut T|if condition { item.draw(to) } else { Ok(Default::default()) })
|
When(condition, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn_kw_layout!(kw_either |state, output, expr| {
|
fn_kw_layout!(kw_either |state, output, expr| {
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("kw_layout");
|
||||||
let thunk_a = draw(move|screen|ok_flat(expr.nth(2)?.map(|x|state.interpret(screen, x))));
|
let thunk_a = draw(move|screen|ok_flat(expr.nth(2)?.map(|x|state.interpret(screen, x))));
|
||||||
let thunk_b = draw(move|screen|ok_flat(expr.nth(3)?.map(|x|state.interpret(screen, x))));
|
let thunk_b = draw(move|screen|ok_flat(expr.nth(3)?.map(|x|state.interpret(screen, x))));
|
||||||
ok_flat(matches!(expr.head()?, Some("either")).then(||{
|
ok_flat(matches!(expr.head()?, Some("either")).then(||{
|
||||||
|
|
@ -36,5 +54,8 @@ fn_kw_layout!(kw_either |state, output, expr| {
|
||||||
pub const fn either <'a, T: Screen> (
|
pub const fn either <'a, T: Screen> (
|
||||||
condition: bool, a: impl Draw<T>, b: impl Draw<T>
|
condition: bool, a: impl Draw<T>, b: impl Draw<T>
|
||||||
) -> impl Draw<T> {
|
) -> impl Draw<T> {
|
||||||
draw(move|to: &mut T|if condition { a.draw(to) } else { b.draw(to) })
|
draw(move|to: &mut T|{
|
||||||
|
#[cfg(feature = "prof")] profiling::scope!("either");
|
||||||
|
if condition { a.draw(to) } else { b.draw(to) }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
122
src/lib.rs
122
src/lib.rs
|
|
@ -9,28 +9,7 @@
|
||||||
//#![feature(trait_alias)]
|
//#![feature(trait_alias)]
|
||||||
//#![feature(type_alias_impl_trait)]
|
//#![feature(type_alias_impl_trait)]
|
||||||
//#![feature(type_changing_struct_update)]
|
//#![feature(type_changing_struct_update)]
|
||||||
pub extern crate atomic_float;
|
mod deps; pub use self::deps::*;
|
||||||
pub extern crate palette;
|
|
||||||
pub extern crate better_panic;
|
|
||||||
pub extern crate unicode_width;
|
|
||||||
#[cfg(feature = "sing")] pub extern crate jack;
|
|
||||||
#[cfg(feature = "midi")] pub extern crate midly;
|
|
||||||
#[cfg(feature = "term")] pub extern crate ratatui;
|
|
||||||
#[cfg(feature = "term")] pub extern crate crossterm;
|
|
||||||
#[cfg(feature = "lang")] pub extern crate dizzle;
|
|
||||||
#[cfg(test)] #[macro_use] pub extern crate proptest;
|
|
||||||
#[cfg(test)] pub(crate) use proptest_derive::Arbitrary;
|
|
||||||
|
|
||||||
pub(crate) use ::{
|
|
||||||
std::fmt::{Debug, Display},
|
|
||||||
std::ops::{Add, Sub, Mul, Div},
|
|
||||||
std::sync::{Arc, RwLock},
|
|
||||||
std::sync::atomic::{AtomicBool, AtomicUsize, Ordering::*},
|
|
||||||
std::marker::PhantomData
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "lang")] pub use ::dizzle::{Usually, Perhaps};
|
|
||||||
#[cfg(feature = "lang")] use ::dizzle::*;
|
|
||||||
|
|
||||||
/// Define a trait an implement it for various mutation-enabled wrapper types. */
|
/// Define a trait an implement it for various mutation-enabled wrapper types. */
|
||||||
#[macro_export] macro_rules! flex_trait_mut (
|
#[macro_export] macro_rules! flex_trait_mut (
|
||||||
|
|
@ -89,9 +68,32 @@ pub(crate) use ::{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implement [`Debug`] in bulk.
|
/// Implement [`Debug`] in bulk.
|
||||||
#[macro_export] macro_rules! impl_debug (($($S:ty|$self:ident,$w:ident|$body:block)*)=>{
|
#[macro_export] macro_rules! impl_debug (
|
||||||
$(impl std::fmt::Debug for $S { fn fmt (&$self, $w: &mut std::fmt::Formatter) -> std::fmt::Result $body })*
|
(<$($T:ident $(: $U:ident)?),+> $S:ty|$self:ident,$w:ident|$body:block)=>{
|
||||||
});
|
impl <$($T$(:$U)?),+> std::fmt::Debug for $S {
|
||||||
|
fn fmt (&$self, $w: &mut std::fmt::Formatter) -> std::fmt::Result $body
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($S:ty|$self:ident,$w:ident|$body:block)=>{
|
||||||
|
impl std::fmt::Debug for $S {
|
||||||
|
fn fmt (&$self, $w: &mut std::fmt::Formatter) -> std::fmt::Result $body
|
||||||
|
}
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Implement [`Display`] in bulk.
|
||||||
|
#[macro_export] macro_rules! impl_display (
|
||||||
|
(<$($T:ident $(: $U:ident)?),+> $S:ty|$self:ident,$w:ident|$body:block)=>{
|
||||||
|
impl <$($T$(:$U)?),+> std::fmt::Display for $S {
|
||||||
|
fn fmt (&$self, $w: &mut std::fmt::Formatter) -> std::fmt::Result $body
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($S:ty|$self:ident,$w:ident|$body:block)=>{
|
||||||
|
impl std::fmt::Display for $S {
|
||||||
|
fn fmt (&$self, $w: &mut std::fmt::Formatter) -> std::fmt::Result $body
|
||||||
|
}
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
/// Implement [`From`] in bulk.
|
/// Implement [`From`] in bulk.
|
||||||
#[macro_export] macro_rules! impl_from (
|
#[macro_export] macro_rules! impl_from (
|
||||||
|
|
@ -301,7 +303,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
}
|
}
|
||||||
/// Run something with the client.
|
/// Run something with the client.
|
||||||
pub fn with_client <T> (&self, op: impl FnOnce(&Client)->T) -> T {
|
pub fn with_client <T> (&self, op: impl FnOnce(&Client)->T) -> T {
|
||||||
match &*self.0.read().unwrap() {
|
match &*self.0.try_read().unwrap() {
|
||||||
Inert => panic!("jack client not activated"),
|
Inert => panic!("jack client not activated"),
|
||||||
Inactive(client) => op(client),
|
Inactive(client) => op(client),
|
||||||
Activating => panic!("jack client has not finished activation"),
|
Activating => panic!("jack client has not finished activation"),
|
||||||
|
|
@ -314,14 +316,14 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
let client_state = self.0.clone();
|
let client_state = self.0.clone();
|
||||||
let app: Arc<RwLock<T>> = Arc::new(RwLock::new(init(self)?));
|
let app: Arc<RwLock<T>> = Arc::new(RwLock::new(init(self)?));
|
||||||
let mut state = Activating;
|
let mut state = Activating;
|
||||||
std::mem::swap(&mut*client_state.write().unwrap(), &mut state);
|
std::mem::swap(&mut*client_state.try_write().unwrap(), &mut state);
|
||||||
if let Inactive(client) = state {
|
if let Inactive(client) = state {
|
||||||
// This is the misc notifications handler. It's a struct that wraps a [Box]
|
// This is the misc notifications handler. It's a struct that wraps a [Box]
|
||||||
// which performs type erasure on a callback that takes [JackEvent], which is
|
// which performs type erasure on a callback that takes [JackEvent], which is
|
||||||
// one of the available misc notifications.
|
// one of the available misc notifications.
|
||||||
let notify = JackNotify(Box::new({
|
let notify = JackNotify(Box::new({
|
||||||
let app = app.clone();
|
let app = app.clone();
|
||||||
move|event|(&mut*app.write().unwrap()).handle(event)
|
move|event|(&mut*app.try_write().unwrap()).handle(event)
|
||||||
}) as BoxedJackEventHandler);
|
}) as BoxedJackEventHandler);
|
||||||
// This is the main processing handler. It's a struct that wraps a [Box]
|
// This is the main processing handler. It's a struct that wraps a [Box]
|
||||||
// which performs type erasure on a callback that takes [Client] and [ProcessScope]
|
// which performs type erasure on a callback that takes [Client] and [ProcessScope]
|
||||||
|
|
@ -329,14 +331,14 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
// implements audio and MIDI input and output on a realtime basis.
|
// implements audio and MIDI input and output on a realtime basis.
|
||||||
let process = ::jack::contrib::ClosureProcessHandler::new(Box::new({
|
let process = ::jack::contrib::ClosureProcessHandler::new(Box::new({
|
||||||
let app = app.clone();
|
let app = app.clone();
|
||||||
move|c: &_, s: &_|if let Ok(mut app) = app.write() {
|
move|c: &_, s: &_|if let Some(mut app) = app.try_write() {
|
||||||
app.process(c, s)
|
app.process(c, s)
|
||||||
} else {
|
} else {
|
||||||
Control::Quit
|
Control::Quit
|
||||||
}
|
}
|
||||||
}) as BoxedAudioHandler);
|
}) as BoxedAudioHandler);
|
||||||
// Launch a client with the two handlers.
|
// Launch a client with the two handlers.
|
||||||
*client_state.write().unwrap() = Active(
|
*client_state.try_write().unwrap() = Active(
|
||||||
client.activate_async(notify, process)?
|
client.activate_async(notify, process)?
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -466,7 +468,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
fn callback (
|
fn callback (
|
||||||
state: &Arc<RwLock<Self>>, client: &Client, scope: &ProcessScope
|
state: &Arc<RwLock<Self>>, client: &Client, scope: &ProcessScope
|
||||||
) -> Control where Self: Sized {
|
) -> Control where Self: Sized {
|
||||||
if let Ok(mut state) = state.write() {
|
if let Some(mut state) = state.try_write() {
|
||||||
state.process(client, scope)
|
state.process(client, scope)
|
||||||
} else {
|
} else {
|
||||||
Control::Quit
|
Control::Quit
|
||||||
|
|
@ -633,10 +635,10 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
for connect in self.connections().iter() {
|
for connect in self.connections().iter() {
|
||||||
match &connect.name {
|
match &connect.name {
|
||||||
Some(Exact(name)) => {
|
Some(Exact(name)) => {
|
||||||
*connect.status.write().unwrap() = self.connect_exact(name)?;
|
*connect.status.try_write().unwrap() = self.connect_exact(name)?;
|
||||||
},
|
},
|
||||||
Some(RegExp(re)) => {
|
Some(RegExp(re)) => {
|
||||||
*connect.status.write().unwrap() = self.connect_regexp(re, connect.scope)?;
|
*connect.status.try_write().unwrap() = self.connect_regexp(re, connect.scope)?;
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
};
|
};
|
||||||
|
|
@ -943,7 +945,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
self.output_buffer[sample].push(self.note_buffer.clone());
|
self.output_buffer[sample].push(self.note_buffer.clone());
|
||||||
// Update the list of currently held notes.
|
// Update the list of currently held notes.
|
||||||
if let LiveEvent::Midi { ref message, .. } = event {
|
if let LiveEvent::Midi { ref message, .. } = event {
|
||||||
update_keys(&mut*self.held.write().unwrap(), message);
|
update_keys(&mut*self.held.try_write().unwrap(), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Write a chunk of MIDI data from the output buffer to the output port.
|
/// Write a chunk of MIDI data from the output buffer to the output port.
|
||||||
|
|
@ -1100,7 +1102,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
|
|
||||||
pub fn info (&self) -> Arc<str> {
|
pub fn info (&self) -> Arc<str> {
|
||||||
format!(" ({}) {} {}", {
|
format!(" ({}) {} {}", {
|
||||||
let status = self.status.read().unwrap();
|
let status = self.status.try_read().unwrap();
|
||||||
let mut ok = 0;
|
let mut ok = 0;
|
||||||
for (_, _, state) in status.iter() {
|
for (_, _, state) in status.iter() {
|
||||||
if *state == Connected {
|
if *state == Connected {
|
||||||
|
|
@ -1188,6 +1190,8 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
use crate::time::PerfModel;
|
use crate::time::PerfModel;
|
||||||
|
|
||||||
#[derive(Debug)] pub struct Task {
|
#[derive(Debug)] pub struct Task {
|
||||||
|
/// Human-friendly name
|
||||||
|
pub name: Arc<str>,
|
||||||
/// Exit flag.
|
/// Exit flag.
|
||||||
pub exit: Arc<AtomicBool>,
|
pub exit: Arc<AtomicBool>,
|
||||||
/// Performance counter.
|
/// Performance counter.
|
||||||
|
|
@ -1198,30 +1202,37 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
/// Spawn a TUI thread that runs `callt least one, then repeats until `exit`.
|
/// Spawn a TUI thread that runs `callt least one, then repeats until `exit`.
|
||||||
pub fn new <F> (exit: Arc<AtomicBool>, mut call: F) -> Result<Self, std::io::Error>
|
pub fn new <F: FnMut(&PerfModel)->() + Send + Sync + 'static> (
|
||||||
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
name: Option<impl AsRef<str>>,
|
||||||
{
|
exit: Arc<AtomicBool>,
|
||||||
|
mut call: F
|
||||||
|
) -> Result<Self, std::io::Error> {
|
||||||
let perf = Arc::new(PerfModel::default());
|
let perf = Arc::new(PerfModel::default());
|
||||||
|
let name: Arc<str> = name.map(|x|x.as_ref().into()).unwrap_or_else(||"tengri".into());
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
exit: exit.clone(),
|
exit: exit.clone(),
|
||||||
perf: perf.clone(),
|
perf: perf.clone(),
|
||||||
join: Builder::new().name("tengri task".into()).spawn(move || {
|
join: Builder::new().name(name.as_ref().into()).spawn(move || {
|
||||||
#[cfg(feature = "prof")] profiling::register_thread!();
|
#[cfg(feature = "prof")] profiling::register_thread!();
|
||||||
while !exit.fetch_and(true, Relaxed) {
|
while !exit.fetch_and(true, Relaxed) {
|
||||||
let _ = perf.cycle(&mut call);
|
let _ = perf.cycle(&mut call);
|
||||||
}
|
}
|
||||||
})?.into()
|
})?.into(),
|
||||||
|
name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawn a thread that runs `call` least one, then repeats
|
/// Spawn a thread that runs `call` least one, then repeats
|
||||||
/// until `exit`, sleeping for `time` msec after every iteration.
|
/// until `exit`, sleeping for `time` msec after every iteration.
|
||||||
pub fn new_sleep <F> (
|
pub fn new_sleep <F> (
|
||||||
exit: Arc<AtomicBool>, time: Duration, mut call: F
|
name: Option<impl AsRef<str>>,
|
||||||
|
exit: Arc<AtomicBool>,
|
||||||
|
time: Duration,
|
||||||
|
mut call: F
|
||||||
) -> Result<Self, std::io::Error>
|
) -> Result<Self, std::io::Error>
|
||||||
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
||||||
{
|
{
|
||||||
Self::new(exit, move |perf| {
|
Self::new(name, exit, move |perf| {
|
||||||
let _ = call(perf);
|
let _ = call(perf);
|
||||||
sleep(time);
|
sleep(time);
|
||||||
})
|
})
|
||||||
|
|
@ -1230,11 +1241,14 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
/// Spawn a thread that uses [crossterm::event::poll]
|
/// Spawn a thread that uses [crossterm::event::poll]
|
||||||
/// to run `call` every `time` msec.
|
/// to run `call` every `time` msec.
|
||||||
#[cfg(feature = "term")] pub fn new_poll <F> (
|
#[cfg(feature = "term")] pub fn new_poll <F> (
|
||||||
exit: Arc<AtomicBool>, time: Duration, mut call: F
|
name: Option<impl AsRef<str>>,
|
||||||
|
exit: Arc<AtomicBool>,
|
||||||
|
time: Duration,
|
||||||
|
mut call: F
|
||||||
) -> Result<Self, std::io::Error>
|
) -> Result<Self, std::io::Error>
|
||||||
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
||||||
{
|
{
|
||||||
Self::new(exit, move |perf| {
|
Self::new(name, exit, move |perf| {
|
||||||
if poll(time).is_ok() {
|
if poll(time).is_ok() {
|
||||||
let _ = call(perf);
|
let _ = call(perf);
|
||||||
}
|
}
|
||||||
|
|
@ -1387,7 +1401,19 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S: Screen, D: Draw<S>> Draw<S> for Option<D> {
|
impl<S: Screen, D: Draw<S>> Draw<S> for Arc<D> {
|
||||||
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
(**self).draw(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Screen, D: Draw<S>> Draw<S> for Box<D> {
|
||||||
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
|
(**self).draw(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Screen, D: Draw<S>> Draw<S> for Option<D> {
|
||||||
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
|
||||||
self.as_ref().map(|it|it.draw(to)).transpose().map(Option::unwrap_or_default)
|
self.as_ref().map(|it|it.draw(to)).transpose().map(Option::unwrap_or_default)
|
||||||
}
|
}
|
||||||
|
|
@ -1399,12 +1425,6 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//impl<T: Screen, D: Draw<T>> Draw<T> for Arc<D> {
|
|
||||||
//fn draw (&self, __: &mut T) -> Perhaps<XYWH<T::Unit>> {
|
|
||||||
//todo!()
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
impl<'a, T: Screen, V: Draw<T>> Draw<T> for &V {
|
impl<'a, T: Screen, V: Draw<T>> Draw<T> for &V {
|
||||||
fn draw (&self, to: &mut T) -> Drawn<T::Unit> {
|
fn draw (&self, to: &mut T) -> Drawn<T::Unit> {
|
||||||
(*self).draw(to)
|
(*self).draw(to)
|
||||||
|
|
|
||||||
12
src/term.rs
12
src/term.rs
|
|
@ -162,11 +162,11 @@ impl Tui {
|
||||||
) -> Result<Task, std::io::Error> {
|
) -> Result<Task, std::io::Error> {
|
||||||
let exited = exited.clone();
|
let exited = exited.clone();
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
Task::new_poll(exited.clone(), poll, move |_| {
|
Task::new_poll(Some("tengri input"), exited.clone(), poll, move |_| {
|
||||||
let event = read().unwrap();
|
let event = read().unwrap();
|
||||||
if Exit::is(&event) {
|
if Exit::is(&event) {
|
||||||
exited.store(true, Relaxed);
|
exited.store(true, Relaxed);
|
||||||
} else if let Err(e) = state.write().unwrap().apply(&TuiEvent(event)) {
|
} else if let Err(e) = state.write().apply(&TuiEvent(event)) {
|
||||||
panic!("{e}")
|
panic!("{e}")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -268,15 +268,15 @@ impl Tui {
|
||||||
let Size { width, height } = backend.size().expect("get size failed");
|
let Size { width, height } = backend.size().expect("get size failed");
|
||||||
let mut prev = Tui::new(width, height);
|
let mut prev = Tui::new(width, height);
|
||||||
let mut next = Tui::new(width, height);
|
let mut next = Tui::new(width, height);
|
||||||
Ok(Task::new_sleep(exited.clone(), sleep, move |perf| {
|
Ok(Task::new_sleep(Some("tengri output"), exited.clone(), sleep, move |perf| {
|
||||||
let Size { width, height } = backend.size().expect("get size failed");
|
let Size { width, height } = backend.size().expect("get size failed");
|
||||||
if let Ok(state) = state.try_read() {
|
if let Some(state) = state.try_read() {
|
||||||
prev.resize(&mut backend, width, height);
|
prev.resize(&mut backend, width, height);
|
||||||
state.draw(&mut next).expect("draw failed"); // TODO draw error
|
state.draw(&mut next).expect("draw failed"); // TODO draw error
|
||||||
prev.redraw(&mut backend, &mut next);
|
prev.redraw(&mut backend, &mut next);
|
||||||
}
|
}
|
||||||
let timer = format!("{:>3.3}ms", perf.used.load(Relaxed));
|
//let timer = format!("{:>3.3}ms", perf.used.load(Relaxed));
|
||||||
prev.blit(&timer, 0, 0, Some(Style::default()));
|
//prev.blit(&timer, 0, 0, Some(Style::default()));
|
||||||
})?)
|
})?)
|
||||||
}
|
}
|
||||||
/// Draw TUI content or its error message.
|
/// Draw TUI content or its error message.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue