added positioning in rsx

This commit is contained in:
2025-01-18 15:04:09 +01:00
parent bde4438663
commit 9ecf8de501
6 changed files with 196 additions and 80 deletions
+2
View File
@@ -10,6 +10,8 @@ documentation = "https://osui.netlify.app/docs/"
[features] [features]
rsx = [] rsx = []
frontend = ["rsx"]
portable = []
[lib] [lib]
name = "osui" name = "osui"
+7 -7
View File
@@ -26,20 +26,20 @@ pub fn end() -> crate::Result<()> {
} }
impl Console { impl Console {
pub fn draw(&self, f: Element) -> crate::Result<()> { pub fn draw(&mut self, ui: Element, event: Option<Event>) -> crate::Result<()> {
crate::utils::clear()?; self.0.clear()?;
f(&self.0) ui(&mut self.0, event)
} }
pub fn run(&mut self, ui: Element) -> crate::Result<()> { pub fn run(&mut self, ui: Element) -> crate::Result<()> {
self.draw(ui.clone(), None)?;
loop { loop {
self.draw(ui.clone())?;
let event = read()?; let event = read()?;
if let Event::Resize(w, h) = event { if let Event::Resize(w, h) = event {
self.0.area.width = w; self.0.width = w;
self.0.area.height = h; self.0.height = h;
} }
self.draw(ui.clone(), Some(event))?;
} }
} }
} }
+102 -57
View File
@@ -12,7 +12,7 @@ pub mod prelude {
pub use std::io::Result; pub use std::io::Result;
pub type Element = std::sync::Arc<dyn Fn(&Frame) -> crate::Result<()>>; pub type Element = std::sync::Arc<dyn Fn(&mut Frame, Option<console::Event>) -> crate::Result<()>>;
pub trait Widget { pub trait Widget {
fn render(&self) -> String; fn render(&self) -> String;
@@ -21,25 +21,59 @@ pub trait Widget {
} }
} }
#[derive(Debug, Clone, Copy)]
pub enum Pos {
Auto,
Center,
Num(u16),
}
impl Pos {
pub fn get(self, auto: u16, width: u16, frame: u16) -> u16 {
match self {
Self::Auto => auto,
Self::Center => (frame - width) / 2,
Self::Num(n) => n,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Size {
Auto,
Num(u16),
}
impl Size {
fn get_(self, written: u16) -> u16 {
match self {
Self::Auto => written,
Self::Num(n) => n,
}
}
pub fn get(self, written: u16, _frame: u16) -> u16 {
self.get_(written)
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Area { pub struct Area {
width: u16, pub width: Size,
height: u16, pub height: Size,
x: u16, pub x: Pos,
y: u16, pub y: Pos,
center_x: bool,
center_y: bool,
width_auto: bool,
height_auto: bool,
} }
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
pub struct Frame { pub struct Frame {
pub area: Area, pub width: u16,
pub height: u16,
last_elem: (u16, u16),
} }
impl Frame { impl Frame {
pub fn draw<W>(&self, w: &W, mut props: Area) -> Result<()> pub fn draw<W>(&mut self, w: &W, props: Area) -> Result<()>
where where
W: Widget, W: Widget,
{ {
@@ -47,49 +81,47 @@ impl Frame {
let (ww, wh) = utils::str_size(&written); let (ww, wh) = utils::str_size(&written);
if props.width_auto { let (width, height) = (
props.width = ww; props.width.get(ww, self.width),
} props.height.get(wh, self.height),
if props.height_auto { );
props.height = wh;
}
if props.width > self.area.width { let (x, y) = (
props.width -= props.width - self.area.width; props.x.get(self.last_elem.0, width, self.width),
} props.y.get(self.last_elem.1, height, self.height),
);
if props.width > self.area.width {
props.width -= props.width - self.area.width;
}
if props.center_x {
props.x = (self.area.width - ww) / 2;
}
if props.center_y {
props.y = (self.area.height - wh) / 2;
}
for (i, line) in written.lines().enumerate() { for (i, line) in written.lines().enumerate() {
if i as u16 > props.height { if i as u16 > height {
break; break;
} }
println!( println!(
"\x1b[{};{}H{}", "\x1b[{};{}H{}",
props.y + (i as u16) + 1, y + (i as u16) + 1,
props.x + 1, x + 1,
line.chars().take(props.width as usize).collect::<String>() line.chars().take(width as usize).collect::<String>()
); );
} }
self.last_elem.0 = x + width;
self.last_elem.1 = y + height;
Ok(()) Ok(())
} }
pub fn clear(&mut self) -> Result<()> {
self.last_elem.0 = 0;
self.last_elem.1 = 0;
utils::clear()
}
pub fn new((width, height): (u16, u16)) -> Self { pub fn new((width, height): (u16, u16)) -> Self {
let mut f = Self::default(); Self {
f.area.width(width); width,
f.area.height(height); height,
f last_elem: (0, 0),
}
} }
} }
@@ -98,59 +130,72 @@ impl Area {
Self::default() Self::default()
} }
#[cfg(feature = "portable")]
pub fn center_x() -> Self { pub fn center_x() -> Self {
let mut s = Self::default(); let mut s = Self::default();
s.center_x = true; s.x = Pos::Center;
s s
} }
#[cfg(feature = "portable")]
pub fn center_y() -> Self { pub fn center_y() -> Self {
let mut s = Self::default(); let mut s = Self::default();
s.center_y = true; s.y = Pos::Center;
s s
} }
#[cfg(feature = "portable")]
pub fn center() -> Self { pub fn center() -> Self {
let mut s = Self::default(); let mut s = Self::default();
s.center_x = true; s.x = Pos::Center;
s.center_y = true; s.y = Pos::Center;
s s
} }
pub fn width(&mut self, w: u16) -> Self { #[cfg(feature = "portable")]
pub fn set_width(&mut self, w: Size) -> Self {
self.width = w; self.width = w;
self.width_auto = false;
*self *self
} }
pub fn height(&mut self, h: u16) -> Self { #[cfg(feature = "portable")]
pub fn set_height(&mut self, h: Size) -> Self {
self.height = h; self.height = h;
self.height_auto = false;
*self *self
} }
pub fn x(&mut self, x: u16) -> Self { #[cfg(feature = "portable")]
pub fn set_x(&mut self, x: Pos) -> Self {
self.x = x; self.x = x;
*self *self
} }
pub fn y(&mut self, y: u16) -> Self { #[cfg(feature = "portable")]
pub fn set_y(&mut self, y: Pos) -> Self {
self.y = y; self.y = y;
*self *self
} }
#[cfg(feature = "portable")]
pub fn x_auto(&mut self) -> Self {
self.x = Pos::Auto;
*self
}
#[cfg(feature = "portable")]
pub fn y_zero(&mut self) -> Self {
self.y = Pos::Num(0);
*self
}
} }
impl Default for Area { impl Default for Area {
fn default() -> Self { fn default() -> Self {
Self { Self {
width: 0, width: Size::Auto,
height: 0, height: Size::Auto,
x: 0, x: Pos::Num(0),
y: 0, y: Pos::Auto,
center_x: false,
center_y: false,
width_auto: true,
height_auto: true,
} }
} }
} }
+7 -11
View File
@@ -3,20 +3,16 @@ use osui::prelude::*;
fn main() -> osui::Result<()> { fn main() -> osui::Result<()> {
let mut con = console::init()?; let mut con = console::init()?;
let (ui, _count) = app(); con.run(app())?;
con.run(ui).unwrap();
console::end() console::end()
} }
pub fn app() -> (Element, state::State<i32>) { pub fn app() -> Element {
let count = use_state(0); rsx! {
let count1 = count.copy_state(); "X" (x-Center)
"Y" (y-Center)
( "Hello, World" (x-Center, y-Center)
rsx! { }
"{count}"
},
count1,
)
} }
+77 -5
View File
@@ -1,13 +1,85 @@
#[macro_export] #[macro_export]
macro_rules! rsx { macro_rules! rsx {
($($e:literal)*) => { ($($inner:tt)*) => {
std::sync::Arc::new( std::sync::Arc::new(
move |frame: &$crate::Frame| -> $crate::Result<()> { move |frame: &mut $crate::Frame, event: Option<$crate::console::Event>| -> $crate::Result<()> {
$( $crate::rsx_inner!(frame, event; $($inner)*);
frame.draw(&format!($e), Area::center())?;
)*
Ok(()) Ok(())
} }
) )
}; };
} }
#[macro_export]
macro_rules! rsx_inner {
($frame:expr, $event:expr;
$elem:literal ($($inner:tt)*)
$($rest:tt)*) => {
let mut area = $crate::Area::new();
$crate::tw_area!(area, $($inner)*);
$frame.draw(&format!($elem), area)?;
$crate::rsx_inner!($frame, $event; $($rest)*);
};
($frame:expr, $event:expr;
$elem:literal
$($rest:tt)*) => {
$frame.draw(&format!($elem), Area::new())?;
$crate::rsx_inner!($frame, $event; $($rest)*);
};
($frame:expr, $event:expr;) => {};
}
#[macro_export]
macro_rules! tw_area {
($a:expr, $n:ident) => {
$a.$n;
};
// X
($a:expr, x-$v:ident $(, $($rest:tt)*)?) => {
$a.x = $crate::Pos::$v;
$crate::tw_area!($a, $($($rest)*)?);
};
($a:expr, x-$v:literal $(, $($rest:tt)*)?) => {
$a.x = $crate::Pos::Num($v);
$crate::tw_area!($a, $($($rest)*)?);
};
// Y
($a:expr, y-$v:ident $(, $($rest:tt)*)?) => {
$a.y = $crate::Pos::$v;
$crate::tw_area!($a, $($($rest)*)?);
};
($a:expr, y-$v:literal $(, $($rest:tt)*)?) => {
$a.y = $crate::Pos::Num($v);
$crate::tw_area!($a, $($($rest)*)?);
};
// Width
($a:expr, width-$v:ident $(, $($rest:tt)*)?) => {
$a.width = $crate::Size::$v;
$crate::tw_area!($a, $($($rest)*)?);
};
($a:expr, width-$v:literal $(, $($rest:tt)*)?) => {
$a.width = $crate::Size::Num($v);
$crate::tw_area!($a, $($($rest)*)?);
};
// Height
($a:expr, height-$v:ident $(, $($rest:tt)*)?) => {
$a.height = $crate::Size::$v;
$crate::tw_area!($a, $($($rest)*)?);
};
($a:expr, height-$v:literal $(, $($rest:tt)*)?) => {
$a.height = $crate::Size::Num($v);
$crate::tw_area!($a, $($($rest)*)?);
};
($a:expr,) => {};
}
+1
View File
@@ -1,3 +1,4 @@
#[derive(Clone, Copy)]
pub struct State<T>(pub(crate) *mut T); pub struct State<T>(pub(crate) *mut T);
impl<T: std::fmt::Display> std::fmt::Display for State<T> { impl<T: std::fmt::Display> std::fmt::Display for State<T> {