diff --git a/.gitignore b/.gitignore index 7cfeab2..0728338 100644 --- a/.gitignore +++ b/.gitignore @@ -24,5 +24,3 @@ target # Added by cargo /target - -.mist diff --git a/Cargo.lock b/Cargo.lock index e7f4d2d..609c1a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,13 +2,366 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + [[package]] name = "pulse-trader" -version = "0.1.0" +version = "0.1.0-alpha.0" dependencies = [ "pulse-ui", + "tokio", ] [[package]] name = "pulse-ui" -version = "0.1.0-alpha.0" +version = "0.1.0" +dependencies = [ + "crossterm", + "tokio", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml index 610264a..772db70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,16 @@ [package] name = "pulse-trader" -version = "0.1.0" +version = "0.1.0-alpha.0" edition = "2024" +[dependencies] +pulse-ui = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } + [workspace] members = ["pulse-ui"] [workspace.dependencies] pulse-ui = { path = "pulse-ui", version = "0.1.0-alpha.0" } - -[dependencies] -pulse-ui = { workspace = true } - -[[bin]] -name = "pulse-trader" -path = ".mist/src/main.rs" +tokio = "1.52.3" +crossterm = "0.29.0" diff --git a/Mist.toml b/Mist.toml deleted file mode 100644 index 401c586..0000000 --- a/Mist.toml +++ /dev/null @@ -1,3 +0,0 @@ -package = "main.mist" -packages = [] -include = ["pulse-ui"] diff --git a/README.md b/README.md index 3938f59..17c62b0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # pulse-trader -A high-performance algorithmic crypto trading engine with backtesting, paper trading, and live execution support. Built with Mist +A high-performance algorithmic crypto trading engine with backtesting, paper trading, and live execution support. diff --git a/pulse-ui/Cargo.toml b/pulse-ui/Cargo.toml index 1890d49..5755de8 100644 --- a/pulse-ui/Cargo.toml +++ b/pulse-ui/Cargo.toml @@ -1,10 +1,9 @@ [package] name = "pulse-ui" -version = "0.1.0-alpha.0" +version = "0.1.0" edition = "2024" [dependencies] +tokio = { workspace = true, features = ["sync"] } +crossterm = { workspace = true } -[lib] -name = "pulse_ui" -path = ".mist/src/lib.rs" diff --git a/pulse-ui/Mist.toml b/pulse-ui/Mist.toml deleted file mode 100644 index a568ef1..0000000 --- a/pulse-ui/Mist.toml +++ /dev/null @@ -1,3 +0,0 @@ -package = "lib.mist" -packages = [] -include = [] diff --git a/pulse-ui/src/layout.rs b/pulse-ui/src/layout.rs new file mode 100644 index 0000000..f30f424 --- /dev/null +++ b/pulse-ui/src/layout.rs @@ -0,0 +1,100 @@ +use crate::unit::{Rect, Size}; + +#[derive(Debug, Clone)] +pub enum LayoutItem { + Rows { unit: Size, items: Vec }, + Columns { unit: Size, items: Vec }, + Widget(Size), +} + +#[derive(Debug, Clone)] +pub struct Allocation { + pub widget_alloc: Vec, + pub frame_alloc: Vec, +} + +impl LayoutItem { + pub fn allocate(&self, alloc: &Rect, frame: &mut Vec, widgets: &mut Vec) { + match self { + Self::Rows { items, .. } | Self::Columns { items, .. } => { + frame.push(*alloc); + + let is_row = matches!(self, Self::Rows { .. }); + + let allocation = if is_row { alloc.height } else { alloc.width }; + + let remaining = allocation + - items + .iter() + .map(|item| item.get_size().get_fixed(alloc.height)) + .sum::(); + + let total_weight = items + .iter() + .map(|item| item.get_size().get_flex()) + .sum::(); + + let mut curr = if is_row { alloc.y } else { alloc.x }; + + for item in items { + let size = item.get_size(); + + let unit_alloc = size.get(allocation, remaining, total_weight); + + let item_alloc = if is_row { + Rect { + width: alloc.width, + height: unit_alloc, + x: alloc.x, + y: curr, + } + } else { + Rect { + width: unit_alloc, + height: alloc.height, + x: curr, + y: alloc.y, + } + }; + + curr += unit_alloc; + + item.allocate(&item_alloc, frame, widgets); + } + } + + Self::Widget(_) => { + widgets.push(*alloc); + } + } + } + + pub fn get_size<'a>(&'a self) -> &'a Size { + match self { + Self::Rows { unit, .. } => unit, + Self::Columns { unit, .. } => unit, + Self::Widget(unit) => unit, + } + } +} + +impl Rect { + pub fn allocate(&self, layout: &LayoutItem) -> Allocation { + let mut widget_alloc = Vec::new(); + let mut frame_alloc = Vec::new(); + + layout.allocate(self, &mut frame_alloc, &mut widget_alloc); + + Allocation { + widget_alloc, + frame_alloc, + } + } +} + +pub fn layout(rows: Vec) -> LayoutItem { + LayoutItem::Rows { + unit: Size::Percent(100), + items: rows, + } +} diff --git a/pulse-ui/src/lib.mist b/pulse-ui/src/lib.mist deleted file mode 100644 index 083d0d9..0000000 --- a/pulse-ui/src/lib.mist +++ /dev/null @@ -1,3 +0,0 @@ -pub void test() { - println!("Hello, World"); -} diff --git a/pulse-ui/src/lib.rs b/pulse-ui/src/lib.rs new file mode 100644 index 0000000..fa13f10 --- /dev/null +++ b/pulse-ui/src/lib.rs @@ -0,0 +1,67 @@ +use std::any::Any; + +use tokio::sync::mpsc; + +pub mod layout; +pub mod render; +pub mod state; +pub mod unit; +pub mod widget; + +#[allow(async_fn_in_trait)] +pub trait App { + // State + async fn init(&mut self, ctx: state::Context); + async fn update(&mut self, event: Box); + + // Rendering + async fn layout(&self) -> layout::LayoutItem; + async fn render(&mut self, allocation: layout::Allocation); + + async fn refresh(&mut self) { + crossterm::execute!( + std::io::stdout(), + crossterm::terminal::Clear(crossterm::terminal::ClearType::All) + ) + .unwrap(); + + crossterm::execute!( + std::io::stdout(), + crossterm::terminal::Clear(crossterm::terminal::ClearType::Purge) + ) + .unwrap(); + + crossterm::execute!(std::io::stdout(), crossterm::cursor::Hide).unwrap(); + + self.render(get_screen().allocate(&self.layout().await)) + .await; + } +} + +pub async fn run(create_app: impl FnOnce(&state::Context) -> A) { + let (tx, mut rx) = mpsc::channel(100); + + let ctx = state::Context { tx }; + + let mut app = create_app(&ctx); + + app.init(ctx).await; + + app.refresh().await; + + while let Some(event) = rx.recv().await { + app.update(event).await; + app.refresh().await; + } +} + +pub fn get_screen() -> unit::Rect { + let (width, height) = crossterm::terminal::size().unwrap(); + + unit::Rect { + x: 0, + y: 0, + width, + height, + } +} diff --git a/pulse-ui/src/render.rs b/pulse-ui/src/render.rs new file mode 100644 index 0000000..8e458be --- /dev/null +++ b/pulse-ui/src/render.rs @@ -0,0 +1,93 @@ +use std::{fmt::Display, io::stdout}; + +use crate::{ + layout::Allocation, + unit::{Point, Rect}, + widget::Widget, +}; + +pub enum Instr { + DrawText(Point, String), + DrawOutline(Rect), +} + +pub struct RenderScope { + pub rect: Rect, + draw_instructions: Vec, +} + +impl RenderScope { + pub fn draw_text, T: Display>(&mut self, at: P, text: T) { + self.draw_instructions + .push(Instr::DrawText(at.into(), text.to_string())); + } + + pub fn draw_outline>(&mut self, rect: Rect) { + self.draw_instructions.push(Instr::DrawOutline(rect)); + } +} + +impl RenderScope { + pub fn new(rect: Rect) -> Self { + Self { + rect, + draw_instructions: Vec::new(), + } + } +} + +impl From<(u16, u16)> for Point { + fn from(value: (u16, u16)) -> Self { + Self { + x: value.0, + y: value.1, + } + } +} + +impl From for Point { + fn from(value: u16) -> Self { + Self { x: value, y: value } + } +} + +impl From for Point { + fn from(value: Rect) -> Self { + Self { + x: value.x, + y: value.y, + } + } +} + +impl Allocation { + pub fn draw(&self, index: usize, widget: W) { + let mut scope = RenderScope::new(self.widget_alloc[index]); + widget.render(&mut scope); + scope.draw(); + } +} + +impl RenderScope { + pub fn draw(self) { + for inst in self.draw_instructions { + match inst { + Instr::DrawText(point, text) => { + for (i, line) in text.lines().enumerate() { + print_at( + self.rect.x + point.x, + self.rect.y + point.y + i as u16, + line, + ); + } + } + Instr::DrawOutline(rect) => {} + } + } + } +} + +pub fn print_at(x: u16, y: u16, text: &str) { + crossterm::execute!(stdout(), crossterm::cursor::MoveTo(x, y)).unwrap(); + println!("{text}"); +} diff --git a/pulse-ui/src/render_scope.mist b/pulse-ui/src/render_scope.mist deleted file mode 100644 index 80a660b..0000000 --- a/pulse-ui/src/render_scope.mist +++ /dev/null @@ -1,31 +0,0 @@ -pub module render_scope; - -pub class RenderScope -{ - u16 x = 0; - u16 y = 0; - u16 width = 0; - u16 height = 0; - - pub constructor() {} -} - -pub class RenderStack -{ - pub Vec stack; - - pub constructor() - { - self.stack = Vec::new(); - } - - pub RenderScope pop(&mut self) - { - self.stack.pop().expect("Failed to pop, no more items in the stack") - } - - pub RenderScope mut'a& push<'a>(&'a mut self) - { - self.stack.push_mut(RenderScope::new()) - } -} diff --git a/pulse-ui/src/state.rs b/pulse-ui/src/state.rs new file mode 100644 index 0000000..279386c --- /dev/null +++ b/pulse-ui/src/state.rs @@ -0,0 +1,64 @@ +use std::{any::Any, sync::Arc}; + +use tokio::sync::{Mutex, MutexGuard, mpsc::Sender}; + +pub struct Refresh; + +#[derive(Debug, Clone)] +pub struct Context { + pub(crate) tx: Sender>, +} + +pub struct State { + pub value: Arc>, + tx: Sender>, +} + +pub struct StateGuard<'a, T> { + is_mutated: bool, + value: MutexGuard<'a, T>, + tx: &'a Sender>, +} + +impl Context { + pub fn use_state(&self, v: T) -> State { + State { + value: Arc::new(Mutex::new(v)), + tx: self.tx.clone(), + } + } +} + +impl State { + pub async fn lock<'a>(&'a self) -> StateGuard<'a, T> { + StateGuard { + value: self.value.lock().await, + is_mutated: false, + tx: &self.tx, + } + } +} + +impl<'a, T> std::ops::Deref for StateGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl<'a, T> std::ops::DerefMut for StateGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.is_mutated = true; + + &mut self.value + } +} + +impl<'a, T> Drop for StateGuard<'a, T> { + fn drop(&mut self) { + if self.is_mutated { + self.tx.blocking_send(Box::new(Refresh)).unwrap() + } + } +} diff --git a/pulse-ui/src/unit.rs b/pulse-ui/src/unit.rs new file mode 100644 index 0000000..83ff31d --- /dev/null +++ b/pulse-ui/src/unit.rs @@ -0,0 +1,51 @@ +#[derive(Debug, Clone, Copy)] +pub struct Point { + pub x: u16, + pub y: u16, +} + +#[derive(Debug, Clone, Copy)] +pub enum Size { + Fixed(u16), + Flex(u16), + Percent(u16), +} + +#[derive(Debug, Clone, Copy)] +pub struct Rect { + pub x: u16, + pub y: u16, + pub width: u16, + pub height: u16, +} + +impl Size { + pub fn get_fixed(&self, alloc: u16) -> u16 { + match self { + Self::Fixed(v) => *v, + Self::Percent(v) => alloc * (*v) / 100, + Self::Flex(_) => 0, + } + } + + pub fn get_flex(&self) -> u16 { + match self { + Self::Flex(f) => *f, + _ => 0, + } + } + + pub fn get(&self, alloc: u16, remaining: u16, total_weight: u16) -> u16 { + match self { + Self::Fixed(v) => *v, + Self::Percent(v) => alloc * (*v) / 100, + Self::Flex(v) => { + if total_weight == 0 { + 0 + } else { + remaining * v / total_weight + } + } + } + } +} diff --git a/pulse-ui/src/units.mist b/pulse-ui/src/units.mist deleted file mode 100644 index f55e633..0000000 --- a/pulse-ui/src/units.mist +++ /dev/null @@ -1,18 +0,0 @@ -pub module units; - -pub enum Position -{ - Char(u16); - ScreenUnits { u16 units; u16 div; }; - Percent(u16); - Center; - End; -} - -pub enum Size -{ - Char(u16); - ScreenUnits { u16 units; u16 div; }; - Percent(u16); - Full; -} diff --git a/pulse-ui/src/widget/mod.rs b/pulse-ui/src/widget/mod.rs new file mode 100644 index 0000000..8d37a34 --- /dev/null +++ b/pulse-ui/src/widget/mod.rs @@ -0,0 +1,11 @@ +use crate::render::RenderScope; + +pub trait Widget { + fn render(&self, scope: &mut RenderScope); +} + +impl Widget for &str { + fn render(&self, scope: &mut RenderScope) { + scope.draw_text(0, self); + } +} diff --git a/pulse-ui/src/widgets/text.mist b/pulse-ui/src/widgets/text.mist deleted file mode 100644 index ea36234..0000000 --- a/pulse-ui/src/widgets/text.mist +++ /dev/null @@ -1,19 +0,0 @@ -pub module text; - -use super::widget::Widget; -use crate::render_scope; - -pub class Text : Widget { - String text; - - pub constructor(str& text) - { - super = Super::new(); - self.text = text.to_string(); - } - - pub virtual void render(&self, render_scope::RenderStack mut& stack) override - { - render_scope::RenderScope mut& scope = stack.push(); - } -} diff --git a/pulse-ui/src/widgets/widget.mist b/pulse-ui/src/widgets/widget.mist deleted file mode 100644 index a2d8c59..0000000 --- a/pulse-ui/src/widgets/widget.mist +++ /dev/null @@ -1,21 +0,0 @@ -pub module widget; - -use crate::units; -use crate::render_scope; - -pub class Widget -{ - units::Position x = units::Position::Char(0); - units::Position y = units::Position::Char(0); - - units::Size width = units::Size::Full; - units::Size height = units::Size::Full; - - pub constructor() {} - - pub virtual void render(&self, render_scope::RenderStack mut& stack) { - let _ = stack; - } - - pub virtual void update(&self) {} -} diff --git a/src/main.mist b/src/main.mist deleted file mode 100644 index ff5fe30..0000000 --- a/src/main.mist +++ /dev/null @@ -1,5 +0,0 @@ -void main() { - println!("Hello, World!"); - - pulse_ui::test(); -} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..74f9a7f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,35 @@ +use pulse_ui::{ + App, + layout::{LayoutItem, layout}, + state::State, + unit::Size, +}; + +pub struct PulseTradeApp { + count: State, +} + +impl App for PulseTradeApp { + async fn init(&mut self, ctx: pulse_ui::state::Context) {} + + async fn update(&mut self, event: Box) {} + + async fn layout(&self) -> pulse_ui::layout::LayoutItem { + layout(vec![ + LayoutItem::Widget(Size::Flex(1)), + LayoutItem::Widget(Size::Flex(1)), + ]) + } + + async fn render(&mut self, layout: pulse_ui::layout::Allocation) { + layout.draw(1, "Yo"); + } +} + +#[tokio::main] +async fn main() { + pulse_ui::run(|ctx| PulseTradeApp { + count: ctx.use_state(0), + }) + .await; +}