mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
wip: compiles and runs (not enabled yet)
This commit is contained in:
parent
ac3827b8f3
commit
98d2107e4e
15 changed files with 440 additions and 357 deletions
50
Cargo.lock
generated
50
Cargo.lock
generated
|
|
@ -262,6 +262,12 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const_panic"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53857514f72ee4a2b583de67401e3ff63a5472ca4acf289d09a9ea7636dfec17"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
|
|
@ -557,6 +563,33 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "konst"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4381b9b00c55f251f2ebe9473aef7c117e96828def1a7cb3bd3f0f903c6894e9"
|
||||
dependencies = [
|
||||
"const_panic",
|
||||
"konst_kernel",
|
||||
"konst_proc_macros",
|
||||
"typewit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "konst_kernel"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4b1eb7788f3824c629b1116a7a9060d6e898c358ebff59070093d51103dcc3c"
|
||||
dependencies = [
|
||||
"typewit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "konst_proc_macros"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00af7901ba50898c9e545c24d5c580c96a982298134e8037d8978b6594782c07"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
|
|
@ -1389,6 +1422,8 @@ name = "tek_edn"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clojure-reader",
|
||||
"konst",
|
||||
"tek_layout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1461,6 +1496,21 @@ dependencies = [
|
|||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typewit"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb77c29baba9e4d3a6182d51fa75e3215c7fd1dab8f4ea9d107c716878e55fc0"
|
||||
dependencies = [
|
||||
"typewit_proc_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typewit_proc_macros"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36a83ea2b3c704935a01b4642946aadd445cea40b10935e3f8bd8052b8193d6"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
|
|
|
|||
45
edn/src/edn_context.rs
Normal file
45
edn/src/edn_context.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use crate::*;
|
||||
|
||||
#[macro_export] macro_rules! edn_context {
|
||||
($Struct:ident |$l:lifetime, $state:ident| {
|
||||
$($key:literal = $field:ident: $Type:ty => $expr:expr,)*
|
||||
}) => {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EdnView<$l> { $($field: Option<$Type>),* }
|
||||
|
||||
impl<$l> EdnView<$l> {
|
||||
pub fn parse <'e> (edn: &[Edn<'e>]) -> impl Fn(&$Struct) + use<'e> {
|
||||
let imports = Self::imports_all(edn);
|
||||
move |state| {
|
||||
let mut context = EdnView::default();
|
||||
for import in imports.iter() {
|
||||
context.import(state, import)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn imports_all <'e> (edn: &[Edn<'e>]) -> Vec<&'e str> {
|
||||
let mut imports = vec![];
|
||||
for edn in edn.iter() {
|
||||
for import in Self::imports_one(edn) {
|
||||
imports.push(import);
|
||||
}
|
||||
}
|
||||
imports
|
||||
}
|
||||
fn imports_one <'e> (edn: &Edn<'e>) -> Vec<&'e str> {
|
||||
match edn {
|
||||
Edn::Symbol(import) => vec![import],
|
||||
Edn::List(edn) => Self::imports_all(edn.as_slice()),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
pub fn import (&mut self, $state: &$l$Struct, key: &str) {
|
||||
match key {
|
||||
$($key => self.$field = Some($expr),)*
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
edn/src/edn_item.rs
Normal file
60
edn/src/edn_item.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
use crate::*;
|
||||
|
||||
fn number (digits: &str) -> usize {
|
||||
let mut value = 0;
|
||||
for c in digits.chars() {
|
||||
value = 10 * value + digit(c);
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
const fn digit (c: char) -> usize {
|
||||
match c { '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4,
|
||||
'5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, _ => unreachable!() }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
Empty,
|
||||
Unexpected(char),
|
||||
Incomplete
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
pub enum Item<T: AsRef<str>> {
|
||||
#[default] Nil,
|
||||
Num(usize),
|
||||
Sym(T),
|
||||
Key(T),
|
||||
Exp(Vec<Item<T>>),
|
||||
}
|
||||
|
||||
impl Item<String> {
|
||||
pub fn read_all <'a> (mut source: &'a str) -> Result<Vec<Self>, ParseError> {
|
||||
let mut items = vec![];
|
||||
loop {
|
||||
if source.len() == 0 {
|
||||
break
|
||||
}
|
||||
let (remaining, token) = Token::chomp(source)?;
|
||||
match Item::read(token)? { Item::Nil => {}, item => items.push(item) };
|
||||
source = remaining
|
||||
}
|
||||
Ok(items)
|
||||
}
|
||||
pub fn read <'a> (token: Token<'a>) -> Result<Self, ParseError> {
|
||||
use Token::*;
|
||||
Ok(match token {
|
||||
Nil => Item::Nil,
|
||||
Num(chars, index, length) =>
|
||||
Self::Num(number(&chars[index..index+length])),
|
||||
Sym(chars, index, length) =>
|
||||
Self::Sym(chars[index..index+length].to_string()),
|
||||
Key(chars, index, length) =>
|
||||
Self::Key(chars[index..index+length].to_string()),
|
||||
Exp(chars, index, length, 0) =>
|
||||
Self::Exp(Self::read_all(&chars[index+1..(index+length).saturating_sub(1)])?),
|
||||
_ => panic!("unclosed delimiter")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -18,10 +18,10 @@ impl<'a, E, T: AsRef<str>> From<&'a [Item<T>]> for EdnContent<'a, E, T> {
|
|||
//pub struct EdnContent<'a, T>(T, &'a [Item]);
|
||||
|
||||
pub trait EdnLayout<E: Engine + 'static> {
|
||||
fn get_bool (&self, item: &Item<&str>) -> bool { todo!() }
|
||||
fn get_unit (&self, item: &Item<&str>) -> E::Unit { todo!() }
|
||||
fn get_usize (&self, key: &str) -> usize { todo!() }
|
||||
fn get_content (&self, item: &Item<&str>) -> &dyn Render<E> { todo!() }
|
||||
fn get_bool (&self, item: &Item<&str>) -> bool { false }
|
||||
fn get_unit (&self, item: &Item<&str>) -> E::Unit { 0.into() }
|
||||
fn get_usize (&self, key: &str) -> usize { 0 }
|
||||
fn get_content (&self, item: &Item<&str>) -> Box<dyn Render<E> + '_> { Box::new(()) }
|
||||
fn parse <'a: 'static> (&'a self, items: &[Item<&str>]) -> Box<dyn Render<E> + 'a> {
|
||||
match items {
|
||||
[Key("when"), c, a, ..] =>
|
||||
|
|
@ -71,50 +71,6 @@ pub trait EdnLayout<E: Engine + 'static> {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! edn_context {
|
||||
($Struct:ident |$l:lifetime, $state:ident| {
|
||||
$($key:literal = $field:ident: $Type:ty => $expr:expr,)*
|
||||
}) => {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EdnView<$l> { $($field: Option<$Type>),* }
|
||||
|
||||
impl<$l> EdnView<$l> {
|
||||
pub fn parse <'e> (edn: &[Edn<'e>]) -> impl Fn(&$Struct) + use<'e> {
|
||||
let imports = Self::imports_all(edn);
|
||||
move |state| {
|
||||
let mut context = EdnView::default();
|
||||
for import in imports.iter() {
|
||||
context.import(state, import)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn imports_all <'e> (edn: &[Edn<'e>]) -> Vec<&'e str> {
|
||||
let mut imports = vec![];
|
||||
for edn in edn.iter() {
|
||||
for import in Self::imports_one(edn) {
|
||||
imports.push(import);
|
||||
}
|
||||
}
|
||||
imports
|
||||
}
|
||||
fn imports_one <'e> (edn: &Edn<'e>) -> Vec<&'e str> {
|
||||
match edn {
|
||||
Edn::Symbol(import) => vec![import],
|
||||
Edn::List(edn) => Self::imports_all(edn.as_slice()),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
pub fn import (&mut self, $state: &$l$Struct, key: &str) {
|
||||
match key {
|
||||
$($key => self.$field = Some($expr),)*
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//edn_ns! { EdnLayout |context, item| {
|
||||
|
||||
//[Key("when"), Sym(condition), Sym(template)] => When(
|
||||
|
|
|
|||
|
|
@ -2,122 +2,6 @@ use std::sync::{Arc, RwLock};
|
|||
use std::collections::BTreeMap;
|
||||
pub use clojure_reader::edn::Edn;
|
||||
|
||||
fn number (digits: &str) -> usize {
|
||||
let mut value = 0;
|
||||
for c in digits.chars() {
|
||||
value = 10 * value + digit(c);
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
const fn digit (c: char) -> usize {
|
||||
match c { '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4,
|
||||
'5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, _ => unreachable!() }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
Empty,
|
||||
Unexpected(char),
|
||||
Incomplete
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
pub enum Item<T: AsRef<str>> {
|
||||
#[default] Nil,
|
||||
Num(usize),
|
||||
Sym(T),
|
||||
Key(T),
|
||||
Exp(Vec<Item<T>>),
|
||||
}
|
||||
|
||||
impl Item<String> {
|
||||
pub fn read_all <'a> (mut source: &'a str) -> Result<Vec<Self>, ParseError> {
|
||||
let mut items = vec![];
|
||||
loop {
|
||||
if source.len() == 0 {
|
||||
break
|
||||
}
|
||||
let (remaining, token) = Token::chomp(source)?;
|
||||
match Item::read(token)? { Item::Nil => {}, item => items.push(item) };
|
||||
source = remaining
|
||||
}
|
||||
Ok(items)
|
||||
}
|
||||
pub fn read <'a> (token: Token<'a>) -> Result<Self, ParseError> {
|
||||
use Token::*;
|
||||
Ok(match token {
|
||||
Nil => Item::Nil,
|
||||
Num(chars, index, length) =>
|
||||
Self::Num(number(&chars[index..index+length])),
|
||||
Sym(chars, index, length) =>
|
||||
Self::Sym(chars[index..index+length].to_string()),
|
||||
Key(chars, index, length) =>
|
||||
Self::Key(chars[index..index+length].to_string()),
|
||||
Exp(chars, index, length, 0) =>
|
||||
Self::Exp(Self::read_all(&chars[index+1..(index+length).saturating_sub(1)])?),
|
||||
_ => panic!("unclosed delimiter")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)]
|
||||
pub enum Token<'a> {
|
||||
#[default] Nil,
|
||||
Num(&'a str, usize, usize),
|
||||
Sym(&'a str, usize, usize),
|
||||
Key(&'a str, usize, usize),
|
||||
Exp(&'a str, usize, usize, usize),
|
||||
}
|
||||
|
||||
impl<'a> Token<'a> {
|
||||
fn chomp (source: &'a str) -> Result<(&'a str, Self), ParseError> {
|
||||
use Token::*;
|
||||
let mut state = Self::default();
|
||||
for (index, c) in source.char_indices() {
|
||||
state = match state {
|
||||
// must begin expression
|
||||
Nil => match c {
|
||||
' '|'\n'|'\r'|'\t' => Nil,
|
||||
'(' => Exp(source, index, 1, 1),
|
||||
':' => Sym(source, index, 1),
|
||||
'0'..='9' => Num(source, index, 1),
|
||||
'a'..='z' => Key(source, index, 1),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Num(_, _, 0) => unreachable!(),
|
||||
Sym(_, _, 0) => unreachable!(),
|
||||
Key(_, _, 0) => unreachable!(),
|
||||
Num(source, index, length) => match c {
|
||||
'0'..='9' => Num(source, index, length + 1),
|
||||
' '|'\n'|'\r'|'\t' => return Ok((&source[index+length..], Num(source, index, length))),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Sym(source, index, length) => match c {
|
||||
'a'..='z'|'0'..='9'|'-' => Sym(source, index, length + 1),
|
||||
' '|'\n'|'\r'|'\t' => return Ok((&source[index+length..], Sym(source, index, length))),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Key(source, index, length) => match c {
|
||||
'a'..='z'|'0'..='9'|'-'|'/' => Key(source, index, length + 1),
|
||||
' '|'\n'|'\r'|'\t' => return Ok((&source[index+length..], Key(source, index, length))),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Exp(source, index, length, 0) => match c {
|
||||
' '|'\n'|'\r'|'\t' => return Ok((&source[index+length..], Exp(source, index, length, 0))),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Exp(source, index, length, depth) => match c {
|
||||
')' => Exp(source, index, length + 1, depth - 1),
|
||||
'(' => Exp(source, index, length + 1, depth + 1),
|
||||
_ => Exp(source, index, length + 1, depth)
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(("", state))
|
||||
}
|
||||
}
|
||||
|
||||
//#[derive(Debug, Copy, Clone, Default, PartialEq)]
|
||||
//pub struct Items<'a>(&'a [Item<'a>]);
|
||||
|
|
|
|||
58
edn/src/edn_token.rs
Normal file
58
edn/src/edn_token.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use crate::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)]
|
||||
pub enum Token<'a> {
|
||||
#[default] Nil,
|
||||
Num(&'a str, usize, usize),
|
||||
Sym(&'a str, usize, usize),
|
||||
Key(&'a str, usize, usize),
|
||||
Exp(&'a str, usize, usize, usize),
|
||||
}
|
||||
|
||||
impl<'a> Token<'a> {
|
||||
pub fn chomp (source: &'a str) -> Result<(&'a str, Self), ParseError> {
|
||||
use Token::*;
|
||||
let mut state = Self::default();
|
||||
for (index, c) in source.char_indices() {
|
||||
state = match state {
|
||||
// must begin expression
|
||||
Nil => match c {
|
||||
' '|'\n'|'\r'|'\t' => Nil,
|
||||
'(' => Exp(source, index, 1, 1),
|
||||
':' => Sym(source, index, 1),
|
||||
'0'..='9' => Num(source, index, 1),
|
||||
'a'..='z' => Key(source, index, 1),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Num(_, _, 0) => unreachable!(),
|
||||
Sym(_, _, 0) => unreachable!(),
|
||||
Key(_, _, 0) => unreachable!(),
|
||||
Num(source, index, length) => match c {
|
||||
'0'..='9' => Num(source, index, length + 1),
|
||||
' '|'\n'|'\r'|'\t' => return Ok((&source[index+length..], Num(source, index, length))),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Sym(source, index, length) => match c {
|
||||
'a'..='z'|'0'..='9'|'-' => Sym(source, index, length + 1),
|
||||
' '|'\n'|'\r'|'\t' => return Ok((&source[index+length..], Sym(source, index, length))),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Key(source, index, length) => match c {
|
||||
'a'..='z'|'0'..='9'|'-'|'/' => Key(source, index, length + 1),
|
||||
' '|'\n'|'\r'|'\t' => return Ok((&source[index+length..], Key(source, index, length))),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Exp(source, index, length, 0) => match c {
|
||||
' '|'\n'|'\r'|'\t' => return Ok((&source[index+length..], Exp(source, index, length, 0))),
|
||||
_ => return Err(ParseError::Unexpected(c))
|
||||
},
|
||||
Exp(source, index, length, depth) => match c {
|
||||
')' => Exp(source, index, length + 1, depth - 1),
|
||||
'(' => Exp(source, index, length + 1, depth + 1),
|
||||
_ => Exp(source, index, length + 1, depth)
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(("", state))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_fn_trait_return)]
|
||||
|
||||
mod edn_lib; pub use self::edn_lib::*;
|
||||
mod edn_context; pub use self::edn_context::*;
|
||||
mod edn_item; pub use self::edn_item::*;
|
||||
mod edn_layout; pub use self::edn_layout::*;
|
||||
mod edn_token; pub use self::edn_token::*;
|
||||
|
||||
#[cfg(test)] #[test] fn test_edn () -> Result<(), ParseError> {
|
||||
use Item::*;
|
||||
|
|
@ -28,7 +30,7 @@ mod edn_layout; pub use self::edn_layout::*;
|
|||
#[cfg(test)] #[test] fn test_edn_layout () -> Result<(), ParseError> {
|
||||
let source = include_str!("example.edn");
|
||||
let layout = Item::read_all(source)?;
|
||||
panic!("{layout:?}");
|
||||
let content = EdnLayout::from(&layout);
|
||||
//panic!("{layout:?}");
|
||||
//let content = <dyn EdnLayout<::tek_engine::tui::Tui>>::from(&layout);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use crate::*;
|
||||
use std::marker::PhantomData;
|
||||
//use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
/// Rendering target
|
||||
pub trait Output<E: Engine> {
|
||||
/// Current output area
|
||||
|
|
@ -10,31 +8,37 @@ pub trait Output<E: Engine> {
|
|||
fn area_mut (&mut self) -> &mut E::Area;
|
||||
/// Render widget in area
|
||||
fn place (&mut self, area: E::Area, content: &impl Render<E>);
|
||||
|
||||
#[inline] fn x (&self) -> E::Unit { self.area().x() }
|
||||
#[inline] fn y (&self) -> E::Unit { self.area().y() }
|
||||
#[inline] fn w (&self) -> E::Unit { self.area().w() }
|
||||
#[inline] fn h (&self) -> E::Unit { self.area().h() }
|
||||
#[inline] fn wh (&self) -> E::Size { self.area().wh().into() }
|
||||
}
|
||||
pub struct Thunk<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync>(F, PhantomData<E>);
|
||||
impl<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync> Thunk<E, T, F> {
|
||||
pub fn new (thunk: F) -> Self { Self(thunk, Default::default()) }
|
||||
}
|
||||
impl<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync> Content<E> for Thunk<E, T, F> {
|
||||
fn content (&self) -> impl Content<E> { (self.0)() }
|
||||
}
|
||||
pub trait Render<E: Engine>: Send + Sync {
|
||||
fn layout (&self, area: E::Area) -> E::Area { area }
|
||||
fn render (&self, output: &mut E::Output) {}
|
||||
fn layout (&self, area: E::Area) -> E::Area;
|
||||
fn render (&self, output: &mut E::Output);
|
||||
}
|
||||
pub trait Content<E: Engine>: Send + Sync + Sized {
|
||||
fn content (&self) -> impl Render<E> { () }
|
||||
fn layout (&self, area: E::Area) -> E::Area { self.content().layout(area) }
|
||||
fn render (&self, output: &mut E::Output) { self.content().render(output) }
|
||||
}
|
||||
impl<E: Engine, C: Content<E>> Render<E> for C {
|
||||
fn layout (&self, area: E::Area) -> E::Area { Content::layout(self, area) }
|
||||
fn render (&self, output: &mut E::Output) { Content::render(self, output) }
|
||||
}
|
||||
impl<E: Engine> Content<E> for Box<dyn Render<E>> {
|
||||
fn content (&self) -> impl Content<E> { self }
|
||||
fn content (&self) -> impl Render<E> { self }
|
||||
}
|
||||
impl<E: Engine> Content<E> for &dyn Render<E> {
|
||||
fn content (&self) -> impl Content<E> { self }
|
||||
}
|
||||
pub trait Content<E: Engine>: Send + Sync + Sized {
|
||||
fn content (&self) -> impl Content<E> { () }
|
||||
fn layout (&self, area: E::Area) -> E::Area { area }
|
||||
fn render (&self, output: &mut E::Output) {}
|
||||
fn content (&self) -> impl Render<E> { self }
|
||||
}
|
||||
/// The platonic ideal unit of [Content]: total emptiness at dead center.
|
||||
impl<E: Engine> Content<E> for () {
|
||||
|
|
@ -46,7 +50,7 @@ impl<E: Engine> Content<E> for () {
|
|||
}
|
||||
|
||||
impl<E: Engine, T: Content<E>> Content<E> for &T {
|
||||
fn content (&self) -> impl Content<E> {
|
||||
fn content (&self) -> impl Render<E> {
|
||||
(*self).content()
|
||||
}
|
||||
fn layout (&self, area: E::Area) -> E::Area {
|
||||
|
|
@ -58,9 +62,8 @@ impl<E: Engine, T: Content<E>> Content<E> for &T {
|
|||
}
|
||||
|
||||
impl<E: Engine, T: Content<E>> Content<E> for Option<T> {
|
||||
fn content (&self) -> impl Content<E> {
|
||||
fn content (&self) -> impl Render<E> {
|
||||
self.as_ref()
|
||||
.map(|content|content.content())
|
||||
}
|
||||
fn layout (&self, area: E::Area) -> E::Area {
|
||||
self.as_ref()
|
||||
|
|
@ -73,18 +76,6 @@ impl<E: Engine, T: Content<E>> Content<E> for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Thunk<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync>(F, PhantomData<E>);
|
||||
|
||||
impl<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync> Thunk<E, T, F> {
|
||||
pub fn new (thunk: F) -> Self {
|
||||
Self(thunk, Default::default())
|
||||
}
|
||||
}
|
||||
impl<E: Engine, T: Content<E>, F: Fn()->T + Send + Sync> Content<E> for Thunk<E, T, F> {
|
||||
fn content (&self) -> impl Content<E> {
|
||||
(self.0)()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! render {
|
||||
(($self:ident:$Struct:ty) => $content:expr) => {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl<T> Align<T> {
|
|||
}
|
||||
|
||||
impl<E: Engine, T: Content<E>> Content<E> for Align<T> {
|
||||
fn content (&self) -> impl Content<E> {
|
||||
fn content (&self) -> impl Render<E> {
|
||||
&self.1
|
||||
}
|
||||
fn layout (&self, on: E::Area) -> E::Area {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ macro_rules! transform_xy {
|
|||
pub fn xy (item: T) -> Self { Self::XY(item) }
|
||||
}
|
||||
impl<E: Engine, T: Content<E>> Content<E> for $Enum<T> {
|
||||
fn content (&self) -> impl Content<E> {
|
||||
fn content (&self) -> impl Render<E> {
|
||||
match self {
|
||||
Self::X(item) => item,
|
||||
Self::Y(item) => item,
|
||||
|
|
@ -31,7 +31,7 @@ macro_rules! transform_xy {
|
|||
|
||||
transform_xy!(self: Fill |to|{
|
||||
let [x0, y0, wmax, hmax] = to.xywh();
|
||||
let [x, y, w, h] = Content::layout(&self.content(), to).xywh();
|
||||
let [x, y, w, h] = self.content().layout(to).xywh();
|
||||
match self {
|
||||
X(_) => [x0, y, wmax, h],
|
||||
Y(_) => [x, y0, w, hmax],
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ macro_rules! transform_xy_unit {
|
|||
}
|
||||
}
|
||||
impl<E: Engine, T: Content<E>> Content<E> for $Enum<E::Unit, T> {
|
||||
fn content (&self) -> impl Content<E> {
|
||||
fn content (&self) -> impl Render<E> {
|
||||
Some(match self {
|
||||
Self::X(_, content) => content,
|
||||
Self::Y(_, content) => content,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use crate::*;
|
|||
use ClockCommand::{Play, Pause, SetBpm, SetQuant, SetSync};
|
||||
use FocusCommand::{Next, Prev};
|
||||
use KeyCode::{Enter, Left, Right, Char};
|
||||
|
||||
/// Transport clock app.
|
||||
pub struct TransportTui {
|
||||
pub jack: Arc<RwLock<JackConnection>>,
|
||||
|
|
@ -10,48 +9,13 @@ pub struct TransportTui {
|
|||
}
|
||||
has_clock!(|self: TransportTui|&self.clock);
|
||||
audio!(|self: TransportTui, client, scope|ClockAudio(self).process(client, scope));
|
||||
handle!(<Tui>|self: TransportTui, input|ClockCommand::execute_with_state(self, input.event()));
|
||||
keymap!(TRANSPORT_KEYS = |state: TransportTui, input: Event| ClockCommand {
|
||||
key(Char(' ')) =>
|
||||
if state.clock().is_stopped() { Play(None) } else { Pause(None) },
|
||||
shift(key(Char(' '))) =>
|
||||
if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }
|
||||
});
|
||||
// TODO:
|
||||
//keymap!(TRANSPORT_BPM_KEYS = |state: Clock, input: Event| ClockCommand {
|
||||
//key(Char(',')) => SetBpm(state.bpm().get() - 1.0),
|
||||
//key(Char('.')) => SetBpm(state.bpm().get() + 1.0),
|
||||
//key(Char('<')) => SetBpm(state.bpm().get() - 0.001),
|
||||
//key(Char('>')) => SetBpm(state.bpm().get() + 0.001),
|
||||
//});
|
||||
//keymap!(TRANSPORT_QUANT_KEYS = |state: Clock, input: Event| ClockCommand {
|
||||
//key(Char(',')) => SetQuant(state.quant.prev()),
|
||||
//key(Char('.')) => SetQuant(state.quant.next()),
|
||||
//key(Char('<')) => SetQuant(state.quant.prev()),
|
||||
//key(Char('>')) => SetQuant(state.quant.next()),
|
||||
//});
|
||||
//keymap!(TRANSPORT_SYNC_KEYS = |sync: Clock, input: Event | ClockCommand {
|
||||
//key(Char(',')) => SetSync(state.sync.prev()),
|
||||
//key(Char('.')) => SetSync(state.sync.next()),
|
||||
//key(Char('<')) => SetSync(state.sync.prev()),
|
||||
//key(Char('>')) => SetSync(state.sync.next()),
|
||||
//});
|
||||
//keymap!(TRANSPORT_SEEK_KEYS = |state: Clock, input: Event| ClockCommand {
|
||||
//key(Char(',')) => todo!("transport seek bar"),
|
||||
//key(Char('.')) => todo!("transport seek bar"),
|
||||
//key(Char('<')) => todo!("transport seek beat"),
|
||||
//key(Char('>')) => todo!("transport seek beat"),
|
||||
//});
|
||||
render!(Tui: (self: TransportTui) => TransportView {
|
||||
compact: false,
|
||||
clock: &self.clock
|
||||
});
|
||||
impl TransportTui {
|
||||
pub fn new (jack: &Arc<RwLock<JackConnection>>) -> Usually<Self> {
|
||||
Ok(Self {
|
||||
jack: jack.clone(),
|
||||
clock: Clock::from(jack),
|
||||
})
|
||||
Ok(Self { jack: jack.clone(), clock: Clock::from(jack) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,3 +100,35 @@ render!(Tui: (self: OutputStats) => Either(self.compact,
|
|||
Bsp::e(Tui::fg(TuiTheme::g(255), format!("{:.3}ms", self.latency)), " latency"),
|
||||
)));
|
||||
|
||||
handle!(<Tui>|self: TransportTui, input|ClockCommand::execute_with_state(self, input.event()));
|
||||
keymap!(TRANSPORT_KEYS = |state: TransportTui, input: Event| ClockCommand {
|
||||
key(Char(' ')) =>
|
||||
if state.clock().is_stopped() { Play(None) } else { Pause(None) },
|
||||
shift(key(Char(' '))) =>
|
||||
if state.clock().is_stopped() { Play(Some(0)) } else { Pause(Some(0)) }
|
||||
});
|
||||
// TODO:
|
||||
//keymap!(TRANSPORT_BPM_KEYS = |state: Clock, input: Event| ClockCommand {
|
||||
//key(Char(',')) => SetBpm(state.bpm().get() - 1.0),
|
||||
//key(Char('.')) => SetBpm(state.bpm().get() + 1.0),
|
||||
//key(Char('<')) => SetBpm(state.bpm().get() - 0.001),
|
||||
//key(Char('>')) => SetBpm(state.bpm().get() + 0.001),
|
||||
//});
|
||||
//keymap!(TRANSPORT_QUANT_KEYS = |state: Clock, input: Event| ClockCommand {
|
||||
//key(Char(',')) => SetQuant(state.quant.prev()),
|
||||
//key(Char('.')) => SetQuant(state.quant.next()),
|
||||
//key(Char('<')) => SetQuant(state.quant.prev()),
|
||||
//key(Char('>')) => SetQuant(state.quant.next()),
|
||||
//});
|
||||
//keymap!(TRANSPORT_SYNC_KEYS = |sync: Clock, input: Event | ClockCommand {
|
||||
//key(Char(',')) => SetSync(state.sync.prev()),
|
||||
//key(Char('.')) => SetSync(state.sync.next()),
|
||||
//key(Char('<')) => SetSync(state.sync.prev()),
|
||||
//key(Char('>')) => SetSync(state.sync.next()),
|
||||
//});
|
||||
//keymap!(TRANSPORT_SEEK_KEYS = |state: Clock, input: Event| ClockCommand {
|
||||
//key(Char(',')) => todo!("transport seek bar"),
|
||||
//key(Char('.')) => todo!("transport seek bar"),
|
||||
//key(Char('<')) => todo!("transport seek beat"),
|
||||
//key(Char('>')) => todo!("transport seek beat"),
|
||||
//});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,48 @@
|
|||
use crate::*;
|
||||
use super::*;
|
||||
use std::marker::ConstParamTy;
|
||||
use tek_engine::Render;
|
||||
use Item::*;
|
||||
|
||||
impl EdnLayout<Tui> for Groovebox {
|
||||
fn get_bool (&self, item: &Item<&str>) -> bool { todo!() }
|
||||
fn get_unit (&self, item: &Item<&str>) -> u16 {
|
||||
match item {
|
||||
Sym(":sample-h") => if self.compact { 0 } else { 5 },
|
||||
Sym(":samples-w") => if self.compact { 4 } else { 11 },
|
||||
Sym(":samples-y") => if self.compact { 1 } else { 0 },
|
||||
Sym(":pool-w") => if self.compact { 5 } else {
|
||||
let w = self.size.w();
|
||||
if w > 60 { 20 } else if w > 40 { 15 } else { 10 }
|
||||
},
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
fn get_content (&self, item: &Item<&str>) -> Box<dyn Render<Tui> + '_> {
|
||||
match item {
|
||||
Sym(":input-meter-l") => Box::new(Meter("L/", self.sampler.input_meter[0])),
|
||||
Sym(":input-meter-r") => Box::new(Meter("R/", self.sampler.input_meter[1])),
|
||||
|
||||
Sym(":transport") => Box::new(TransportView::new(true, &self.player.clock)),
|
||||
Sym(":clip-play") => Box::new(ClipSelected::play_phrase(&self.player)),
|
||||
Sym(":clip-next") => Box::new(ClipSelected::next_phrase(&self.player)),
|
||||
Sym(":clip-edit") => Box::new(MidiEditClip(&self.editor)),
|
||||
Sym(":edit-stat") => Box::new(MidiEditStatus(&self.editor)),
|
||||
Sym(":pool-view") => Box::new(PoolView(self.compact, &self.pool)),
|
||||
Sym(":midi-view") => Box::new(&self.editor),
|
||||
|
||||
Sym(":sample-view") => Box::new(SampleViewer::from_sampler(
|
||||
&self.sampler, self.editor.note_point())),
|
||||
Sym(":sample-stat") => Box::new(SamplerStatus(
|
||||
&self.sampler, self.editor.note_point())),
|
||||
Sym(":samples-view") => Box::new(SampleList::new(
|
||||
self.compact, &self.sampler, &self.editor)),
|
||||
|
||||
_ => Box::new(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render!(Tui: (self: Groovebox) => self.size.of(
|
||||
Bsp::s(self.toolbar_view(),
|
||||
Bsp::n(self.selector_view(),
|
||||
|
|
@ -8,109 +50,120 @@ render!(Tui: (self: Groovebox) => self.size.of(
|
|||
Bsp::n(self.status_view(),
|
||||
Bsp::w(self.pool_view(), Fill::xy(Bsp::e(self.sampler_view(), &self.editor)))))))));
|
||||
|
||||
const GROOVEBOX_EDN: &'static str = include_str!("groovebox.edn");
|
||||
|
||||
impl Content<Tui> for Groovebox {
|
||||
fn content (&self) -> impl Content<Tui> {
|
||||
EdnView::parse(self.edn.as_slice())
|
||||
impl Groovebox {
|
||||
fn toolbar_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
Fill::x(Fixed::y(2, lay!(
|
||||
Align::w(Meter("L/", self.sampler.input_meter[0])),
|
||||
Align::e(Meter("R/", self.sampler.input_meter[1])),
|
||||
Align::x(TransportView::new(true, &self.player.clock)),
|
||||
)))
|
||||
}
|
||||
fn selector_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
row!(
|
||||
ClipSelected::play_phrase(&self.player),
|
||||
ClipSelected::next_phrase(&self.player),
|
||||
MidiEditClip(&self.editor),
|
||||
MidiEditStatus(&self.editor),
|
||||
)
|
||||
}
|
||||
fn sample_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
let note_pt = self.editor.note_point();
|
||||
let sample_h = if self.compact { 0 } else { 5 };
|
||||
Max::y(sample_h, Fill::xy(
|
||||
SampleViewer::from_sampler(&self.sampler, note_pt)))
|
||||
}
|
||||
fn status_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
let note_pt = self.editor.note_point();
|
||||
Align::w(Fixed::y(1, SamplerStatus(&self.sampler, note_pt)))
|
||||
}
|
||||
fn pool_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
let w = self.size.w();
|
||||
let pool_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
||||
Fixed::x(if self.compact { 5 } else { pool_w },
|
||||
PoolView(self.compact, &self.pool))
|
||||
}
|
||||
fn sampler_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
let sampler_w = if self.compact { 4 } else { 11 };
|
||||
let sampler_y = if self.compact { 1 } else { 0 };
|
||||
Fixed::x(sampler_w, Push::y(sampler_y, Fill::y(
|
||||
SampleList::new(self.compact, &self.sampler, &self.editor))))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! edn_context {
|
||||
($Struct:ident |$l:lifetime, $state:ident| {
|
||||
$($key:literal = $field:ident: $Type:ty => $expr:expr,)*
|
||||
}) => {
|
||||
//render!(Tui: (self: Groovebox) => self.size.of(
|
||||
//Bsp::s(self.toolbar_view(),
|
||||
//Bsp::n(self.selector_view(),
|
||||
//Bsp::n(self.sample_view(),
|
||||
//Bsp::n(self.status_view(),
|
||||
//Bsp::w(self.pool_view(), Fill::xy(Bsp::e(self.sampler_view(), &self.editor)))))))));
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EdnView<$l> { $($field: Option<$Type>),* }
|
||||
//const GROOVEBOX_EDN: &'static str = include_str!("groovebox.edn");
|
||||
|
||||
impl<$l> EdnView<$l> {
|
||||
pub fn parse <'e> (edn: &[Edn<'e>]) -> impl Fn(&$Struct) + use<'e> {
|
||||
let imports = Self::imports_all(edn);
|
||||
move |state| {
|
||||
let mut context = EdnView::default();
|
||||
for import in imports.iter() {
|
||||
context.import(state, import)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn imports_all <'e> (edn: &[Edn<'e>]) -> Vec<&'e str> {
|
||||
let mut imports = vec![];
|
||||
for edn in edn.iter() {
|
||||
for import in Self::imports_one(edn) {
|
||||
imports.push(import);
|
||||
}
|
||||
}
|
||||
imports
|
||||
}
|
||||
fn imports_one <'e> (edn: &Edn<'e>) -> Vec<&'e str> {
|
||||
match edn {
|
||||
Edn::Symbol(import) => vec![import],
|
||||
Edn::List(edn) => Self::imports_all(edn.as_slice()),
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
pub fn import (&mut self, $state: &$l$Struct, key: &str) {
|
||||
match key {
|
||||
$($key => self.$field = Some($expr),)*
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
edn_context!(Groovebox |'a, state| {
|
||||
":input-meter-l" = input_meter_l: Meter<'a> =>
|
||||
Meter("L/", state.sampler.input_meter[0]),
|
||||
":input-meter-r" = input_meter_r: Meter<'a> =>
|
||||
Meter("R/", state.sampler.input_meter[1]),
|
||||
":transport" = transport: TransportView<'a> =>
|
||||
TransportView::new(true, &state.player.clock),
|
||||
":clip-play" = clip_play: ClipSelected =>
|
||||
ClipSelected::play_phrase(&state.player),
|
||||
":clip-next" = clip_next: ClipSelected =>
|
||||
ClipSelected::next_phrase(&state.player),
|
||||
":clip-edit" = clip_edit: MidiEditClip<'a> =>
|
||||
MidiEditClip(&state.editor),
|
||||
":edit-stat" = edit_stat: MidiEditStatus<'a> =>
|
||||
MidiEditStatus(&state.editor),
|
||||
":sample-h" = sample_h: u16 =>
|
||||
if state.compact { 0 } else { 5 },
|
||||
":sample-view" = sample_view: SampleViewer =>
|
||||
SampleViewer::from_sampler(&state.sampler, state.editor.note_point()),
|
||||
":sample-stat" = sample_stat: SamplerStatus<'a> =>
|
||||
SamplerStatus(&state.sampler, state.editor.note_point()),
|
||||
":pool-w" = pool_w: u16 => if state.compact { 5 } else {
|
||||
let w = state.size.w();
|
||||
if w > 60 { 20 } else if w > 40 { 15 } else { 10 } },
|
||||
":pool-view" = pool_view: PoolView<'a> =>
|
||||
PoolView(state.compact, &state.pool),
|
||||
":samples-w" = samples_w: u16 =>
|
||||
if state.compact { 4 } else { 11 },
|
||||
":samples-y" = samples_y: u16 =>
|
||||
if state.compact { 1 } else { 0 },
|
||||
":samples-view" = samples_view: SampleList<'a> => SampleList::new(
|
||||
state.compact, &state.sampler, &state.editor),
|
||||
":midi-view" = midi_view: &'a MidiEditor =>
|
||||
&state.editor,
|
||||
});
|
||||
|
||||
//impl Groovebox {
|
||||
//fn status_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
//let note_pt = self.editor.note_point();
|
||||
//Align::w(Fixed::y(1, ))
|
||||
//}
|
||||
//fn pool_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
//let w = self.size.w();
|
||||
//let pool_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
||||
//Fixed::x(if self.compact { 5 } else { pool_w },
|
||||
//)
|
||||
//}
|
||||
//fn sampler_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
//let sampler_w = if self.compact { 4 } else { 11 };
|
||||
//let sampler_y = if self.compact { 1 } else { 0 };
|
||||
//Fixed::x(sampler_w, Push::y(sampler_y, Fill::y(
|
||||
//SampleList::new(self.compact, &self.sampler, &self.editor))))
|
||||
//impl Content<Tui> for Groovebox {
|
||||
//fn content (&self) -> impl Content<Tui> {
|
||||
//EdnView::parse(self.edn.as_slice())
|
||||
//}
|
||||
//}
|
||||
|
||||
//macro_rules! edn_context {
|
||||
//($Struct:ident |$l:lifetime, $state:ident| {
|
||||
//$($key:literal = $field:ident: $Type:ty => $expr:expr,)*
|
||||
//}) => {
|
||||
|
||||
//#[derive(Default)]
|
||||
//pub struct EdnView<$l> { $($field: Option<$Type>),* }
|
||||
|
||||
//impl<$l> EdnView<$l> {
|
||||
//pub fn parse <'e> (edn: &[Edn<'e>]) -> impl Fn(&$Struct) + use<'e> {
|
||||
//let imports = Self::imports_all(edn);
|
||||
//move |state| {
|
||||
//let mut context = EdnView::default();
|
||||
//for import in imports.iter() {
|
||||
//context.import(state, import)
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//fn imports_all <'e> (edn: &[Edn<'e>]) -> Vec<&'e str> {
|
||||
//let mut imports = vec![];
|
||||
//for edn in edn.iter() {
|
||||
//for import in Self::imports_one(edn) {
|
||||
//imports.push(import);
|
||||
//}
|
||||
//}
|
||||
//imports
|
||||
//}
|
||||
//fn imports_one <'e> (edn: &Edn<'e>) -> Vec<&'e str> {
|
||||
//match edn {
|
||||
//Edn::Symbol(import) => vec![import],
|
||||
//Edn::List(edn) => Self::imports_all(edn.as_slice()),
|
||||
//_ => vec![],
|
||||
//}
|
||||
//}
|
||||
//pub fn import (&mut self, $state: &$l$Struct, key: &str) {
|
||||
//match key {
|
||||
//$($key => self.$field = Some($expr),)*
|
||||
//_ => {}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
////impl Groovebox {
|
||||
////fn status_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
////let note_pt = self.editor.note_point();
|
||||
////Align::w(Fixed::y(1, ))
|
||||
////}
|
||||
////fn pool_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
////let w = self.size.w();
|
||||
////let pool_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
||||
////Fixed::x(if self.compact { 5 } else { pool_w },
|
||||
////)
|
||||
////}
|
||||
////fn sampler_view (&self) -> impl Content<Tui> + use<'_> {
|
||||
////let sampler_w = if self.compact { 4 } else { 11 };
|
||||
////let sampler_y = if self.compact { 1 } else { 0 };
|
||||
////Fixed::x(sampler_w, Push::y(sampler_y, Fill::y(
|
||||
////SampleList::new(self.compact, &self.sampler, &self.editor))))
|
||||
////}
|
||||
////}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub(crate) use ::tek_layout::{
|
|||
tek_engine::{
|
||||
Usually, Perhaps,
|
||||
Engine, Size, Area,
|
||||
Output, Content, Thunk, render,
|
||||
Output, Content, Render, Thunk, render,
|
||||
Input, Handle, handle,
|
||||
kexp, kpat,
|
||||
tui::{
|
||||
|
|
|
|||
30
src/style.rs
30
src/style.rs
|
|
@ -21,11 +21,8 @@ pub trait TuiStyle {
|
|||
impl TuiStyle for Tui {}
|
||||
|
||||
pub struct Bold<W: Content<Tui>>(pub bool, W);
|
||||
|
||||
impl<W: Content<Tui>> Content<Tui> for Bold<W> {
|
||||
fn content (&self) -> impl Content<Tui> {
|
||||
Some(&self.1)
|
||||
}
|
||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.fill_bold(to.area(), self.0);
|
||||
self.1.render(to)
|
||||
|
|
@ -33,11 +30,8 @@ impl<W: Content<Tui>> Content<Tui> for Bold<W> {
|
|||
}
|
||||
|
||||
pub struct Foreground<W: Content<Tui>>(pub Color, W);
|
||||
|
||||
impl<W: Content<Tui>> Content<Tui> for Foreground<W> {
|
||||
fn content (&self) -> impl Content<Tui> {
|
||||
Some(&self.1)
|
||||
}
|
||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.fill_fg(to.area(), self.0);
|
||||
self.1.render(to)
|
||||
|
|
@ -45,11 +39,8 @@ impl<W: Content<Tui>> Content<Tui> for Foreground<W> {
|
|||
}
|
||||
|
||||
pub struct Background<W: Content<Tui>>(pub Color, W);
|
||||
|
||||
impl<W: Content<Tui>> Content<Tui> for Background<W> {
|
||||
fn content (&self) -> impl Content<Tui> {
|
||||
Some(&self.1)
|
||||
}
|
||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.fill_bg(to.area(), self.0);
|
||||
self.1.render(to)
|
||||
|
|
@ -57,11 +48,8 @@ impl<W: Content<Tui>> Content<Tui> for Background<W> {
|
|||
}
|
||||
|
||||
pub struct Styled<T: Content<Tui>>(pub Option<Style>, pub T);
|
||||
|
||||
impl Content<Tui> for Styled<&str> {
|
||||
fn content (&self) -> impl Content<Tui> {
|
||||
Some(&self.1)
|
||||
}
|
||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
// FIXME
|
||||
let [x, y, ..] = to.area();
|
||||
|
|
@ -71,16 +59,16 @@ impl Content<Tui> for Styled<&str> {
|
|||
}
|
||||
|
||||
//pub trait TuiStyle: Content<Tui> + Sized {
|
||||
//fn fg (self, color: Color) -> impl Content<Tui> {
|
||||
//fn fg (self, color: Color) -> impl Render<Tui> {
|
||||
//Layers::new(move |add|{ add(&Foreground(color))?; add(&self) })
|
||||
//}
|
||||
//fn bg (self, color: Color) -> impl Content<Tui> {
|
||||
//fn bg (self, color: Color) -> impl Render<Tui> {
|
||||
//Layers::new(move |add|{ add(&Background(color))?; add(&self) })
|
||||
//}
|
||||
//fn bold (self, on: bool) -> impl Content<Tui> {
|
||||
//fn bold (self, on: bool) -> impl Render<Tui> {
|
||||
//Layers::new(move |add|{ add(&Bold(on))?; add(&self) })
|
||||
//}
|
||||
//fn border <S: BorderStyle> (self, style: S) -> impl Content<Tui> {
|
||||
//fn border <S: BorderStyle> (self, style: S) -> impl Render<Tui> {
|
||||
//Bordered(style, self)
|
||||
//}
|
||||
//}
|
||||
|
|
@ -91,7 +79,7 @@ impl Content<Tui> for Styled<&str> {
|
|||
//}
|
||||
|
||||
//impl<S: BorderStyle, W: Content<Tui>> Content<Tui> for Bordered<S, W> {
|
||||
//fn content (&self) -> impl Content<Tui> {
|
||||
//fn content (&self) -> impl Render<Tui> {
|
||||
//let content: &dyn Content<Tui> = &self.1;
|
||||
//lay! { content.padding_xy(1, 1), Border(self.0) }.fill_xy()
|
||||
//}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue