dynamic text and styling,
This commit is contained in:
+19
-18
@@ -1,31 +1,32 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn todo_app() -> Element {
|
pub fn todo_app() -> Element {
|
||||||
let count = State::new(0);
|
let todo = vec!["Foo", "Bar"];
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
styling: Some(styling()),
|
for (t in todo) {
|
||||||
|
ersx!( button{ class: "todo", on_click: fn(btn: &mut Button, _, _) {
|
||||||
button { on_click: fn(_, _, _) @count {
|
btn.class = if btn.class == "todo" {
|
||||||
let mut count = count.use_state();
|
"complete"
|
||||||
*count += 1;
|
} else {
|
||||||
}, class: "btn", "Count: {count}" }
|
"todo"
|
||||||
|
};
|
||||||
|
}, "{t}" } )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn styling() -> Css {
|
pub fn todo_styling() -> Css {
|
||||||
css! {
|
css! {
|
||||||
"title" {
|
"todo" {
|
||||||
|
x: 0 px,
|
||||||
|
y: Auto,
|
||||||
|
color: Red,
|
||||||
|
}
|
||||||
|
"complete" {
|
||||||
|
x: 0 px,
|
||||||
|
y: Auto,
|
||||||
color: Green,
|
color: Green,
|
||||||
x: Center,
|
|
||||||
}
|
|
||||||
|
|
||||||
"container" {
|
|
||||||
width: 50%,
|
|
||||||
}
|
|
||||||
|
|
||||||
"btn": "clicked" {
|
|
||||||
color: Red
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-30
@@ -80,6 +80,7 @@ pub struct Handler<T>(pub Arc<Mutex<dyn FnMut(&mut T, crossterm::event::Event, &
|
|||||||
pub struct Document {
|
pub struct Document {
|
||||||
element: *mut Element,
|
element: *mut Element,
|
||||||
running: *mut Option<bool>,
|
running: *mut Option<bool>,
|
||||||
|
css: ui::Css,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -98,6 +99,7 @@ pub struct Writer {
|
|||||||
pub enum Children {
|
pub enum Children {
|
||||||
None,
|
None,
|
||||||
Text(Arc<dyn Fn() -> String>),
|
Text(Arc<dyn Fn() -> String>),
|
||||||
|
StaticText(String),
|
||||||
Children(Vec<Element>, usize),
|
Children(Vec<Element>, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +109,7 @@ impl std::fmt::Debug for Children {
|
|||||||
Self::None => String::new(),
|
Self::None => String::new(),
|
||||||
Self::Children(a, b) => format!("({b}, {a:?})"),
|
Self::Children(a, b) => format!("({b}, {a:?})"),
|
||||||
Self::Text(a) => format!("{:?}", a()),
|
Self::Text(a) => format!("{:?}", a()),
|
||||||
|
Self::StaticText(a) => format!("{a:?}"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,6 +119,13 @@ impl std::fmt::Debug for Children {
|
|||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
impl Document {
|
impl Document {
|
||||||
|
pub fn with_elem(element: &mut Element) -> Document {
|
||||||
|
Document {
|
||||||
|
element,
|
||||||
|
running: &mut None,
|
||||||
|
css: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
if !self.running.is_null() {
|
if !self.running.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -151,7 +161,10 @@ impl Document {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn render(&self) {
|
pub fn render(&self) {
|
||||||
if !self.running.is_null() {
|
if !self.element.is_null() {
|
||||||
|
unsafe {
|
||||||
|
(*self.element).set_styling(&self.css);
|
||||||
|
}
|
||||||
let (width, height) = crossterm::terminal::size().unwrap();
|
let (width, height) = crossterm::terminal::size().unwrap();
|
||||||
let mut frame = utils::Frame::new((0, 0), (width, height));
|
let mut frame = utils::Frame::new((0, 0), (width, height));
|
||||||
utils::clear();
|
utils::clear();
|
||||||
@@ -159,9 +172,34 @@ impl Document {
|
|||||||
utils::flush();
|
utils::flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn set_css(&mut self, css: ui::Css) {
|
||||||
|
self.css = css;
|
||||||
|
}
|
||||||
pub fn draw(&mut self, element: &mut Element) {
|
pub fn draw(&mut self, element: &mut Element) {
|
||||||
self.element = element;
|
self.element = element;
|
||||||
}
|
}
|
||||||
|
pub fn run(&self) -> bool {
|
||||||
|
unsafe { *self.running = None }
|
||||||
|
let element = unsafe { &mut *self.element };
|
||||||
|
|
||||||
|
// Send initial event
|
||||||
|
element.event(crossterm::event::Event::FocusGained, self);
|
||||||
|
|
||||||
|
utils::hide_cursor();
|
||||||
|
crossterm::terminal::enable_raw_mode().unwrap();
|
||||||
|
utils::clear();
|
||||||
|
|
||||||
|
while unsafe { *self.running } == None {
|
||||||
|
self.render();
|
||||||
|
element.event(crossterm::event::read().unwrap(), self);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::show_cursor();
|
||||||
|
crossterm::terminal::disable_raw_mode().unwrap();
|
||||||
|
utils::clear();
|
||||||
|
|
||||||
|
unsafe { (*self.running).unwrap() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Children {
|
impl Default for Children {
|
||||||
@@ -180,6 +218,7 @@ impl Children {
|
|||||||
pub fn get_text(&self) -> String {
|
pub fn get_text(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Children::Text(text) => text(),
|
Children::Text(text) => text(),
|
||||||
|
Children::StaticText(text) => text.clone(),
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,16 +240,51 @@ impl Children {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn set_static_force(&mut self, text: String) {
|
||||||
|
*self = Children::StaticText(text);
|
||||||
|
}
|
||||||
pub fn add_child(&mut self, element: Element) {
|
pub fn add_child(&mut self, element: Element) {
|
||||||
if let Children::Children(children, _) = self {
|
if let Children::Children(children, _) = self {
|
||||||
children.push(element);
|
children.push(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_child(&mut self) -> Option<&mut Element> {
|
pub fn get_child(&mut self) -> (Option<&mut Element>, usize) {
|
||||||
if let Children::Children(children, child) = self {
|
if let Children::Children(children, child) = self {
|
||||||
children.get_mut(*child)
|
let l = children.len();
|
||||||
|
(children.get_mut(*child), l)
|
||||||
} else {
|
} else {
|
||||||
None
|
(None, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get_child_idx(&mut self) -> (Option<(&mut Element, &mut usize)>, usize) {
|
||||||
|
if let Children::Children(children, child) = self {
|
||||||
|
let l = children.len();
|
||||||
|
if let Some(d) = children.get_mut(*child) {
|
||||||
|
(Some((d, child)), l)
|
||||||
|
} else {
|
||||||
|
(None, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(None, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn set_child(&mut self, index: usize) {
|
||||||
|
if let Children::Children(_, child) = self {
|
||||||
|
*child = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
if let Children::Children(children, _) = self {
|
||||||
|
children.len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
if let Children::Children(_, c) = self {
|
||||||
|
*c
|
||||||
|
} else {
|
||||||
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,7 +310,7 @@ impl Writer {
|
|||||||
focused,
|
focused,
|
||||||
size,
|
size,
|
||||||
absolute,
|
absolute,
|
||||||
written: (0, 1),
|
written: (0, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,31 +375,6 @@ impl<T> std::fmt::Debug for Handler<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(element: &mut Element) -> bool {
|
|
||||||
let document = Document {
|
|
||||||
element: element,
|
|
||||||
running: &mut None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send initial event
|
|
||||||
element.event(crossterm::event::Event::FocusGained, &document);
|
|
||||||
|
|
||||||
utils::hide_cursor();
|
|
||||||
crossterm::terminal::enable_raw_mode().unwrap();
|
|
||||||
utils::clear();
|
|
||||||
|
|
||||||
while unsafe { *document.running } == None {
|
|
||||||
document.render();
|
|
||||||
element.event(crossterm::event::read().unwrap(), &document);
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::show_cursor();
|
|
||||||
crossterm::terminal::disable_raw_mode().unwrap();
|
|
||||||
utils::clear();
|
|
||||||
|
|
||||||
unsafe { (*document.running).unwrap() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct State<T>(Arc<Mutex<T>>);
|
pub struct State<T>(Arc<Mutex<T>>);
|
||||||
impl<T> State<T> {
|
impl<T> State<T> {
|
||||||
pub fn new<'a>(v: T) -> State<T> {
|
pub fn new<'a>(v: T) -> State<T> {
|
||||||
|
|||||||
+13
-1
@@ -13,6 +13,18 @@ macro_rules! call {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! launch {
|
macro_rules! launch {
|
||||||
($expr:expr) => {
|
($expr:expr) => {
|
||||||
while $crate::run(&mut $expr) {}
|
let mut element = $expr;
|
||||||
|
let mut document = $crate::Document::with_elem(&mut element);
|
||||||
|
while document.run() {
|
||||||
|
element = $expr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($expr:expr, $css:expr) => {
|
||||||
|
let mut element = $expr;
|
||||||
|
let mut document = $crate::Document::with_elem(&mut element);
|
||||||
|
document.set_css($css);
|
||||||
|
while document.run() {
|
||||||
|
element = $expr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -1,5 +1,8 @@
|
|||||||
use osui::{examples::todo_app, launch};
|
use osui::{
|
||||||
|
examples::{todo_app, todo_styling},
|
||||||
|
launch,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
launch!(todo_app());
|
launch!(todo_app(), todo_styling());
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-8
@@ -12,17 +12,12 @@ use osui_element::{elem_fn, element};
|
|||||||
#[element]
|
#[element]
|
||||||
#[elem_fn]
|
#[elem_fn]
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Text {
|
pub struct Text {}
|
||||||
pub on_event: Handler<Text<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElementWidget for Text<'_> {
|
impl ElementWidget for Text<'_> {
|
||||||
fn render(&self, writer: &mut crate::Writer) {
|
fn render(&self, writer: &mut crate::Writer) {
|
||||||
writer.write(&self.children.get_text());
|
writer.write(&self.children.get_text());
|
||||||
}
|
}
|
||||||
fn event(&mut self, event: Event, document: &Document) {
|
|
||||||
call!(self.on_event(event, document));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[element]
|
#[element]
|
||||||
@@ -49,8 +44,31 @@ impl ElementWidget for Div<'_> {
|
|||||||
self.set_styling(&styling);
|
self.set_styling(&styling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(child) = self.children.get_child() {
|
if let (Some((child, i)), l) = self.children.get_child_idx() {
|
||||||
child.event(event, document);
|
match event {
|
||||||
|
Event::Key(k) => match k.code {
|
||||||
|
KeyCode::Tab => {
|
||||||
|
child.event(Event::FocusLost, document);
|
||||||
|
if *i < l - 1 {
|
||||||
|
*i += 1;
|
||||||
|
} else {
|
||||||
|
*i = 0;
|
||||||
|
}
|
||||||
|
child.event(Event::FocusGained, document);
|
||||||
|
}
|
||||||
|
KeyCode::BackTab => {
|
||||||
|
child.event(Event::FocusLost, document);
|
||||||
|
if *i > 0 {
|
||||||
|
*i -= 1;
|
||||||
|
} else {
|
||||||
|
*i = l - 1;
|
||||||
|
}
|
||||||
|
child.event(Event::FocusGained, document);
|
||||||
|
}
|
||||||
|
_ => child.event(event, document),
|
||||||
|
},
|
||||||
|
_ => child.event(event, document),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-7
@@ -25,14 +25,11 @@ impl Frame {
|
|||||||
if style.visible {
|
if style.visible {
|
||||||
let y = style.y.as_position(
|
let y = style.y.as_position(
|
||||||
&{
|
&{
|
||||||
let mut y_ = 0;
|
let mut y = 0;
|
||||||
for n in self.used.iter().rev() {
|
while y < self.used.len() && self.used[y] != 0 {
|
||||||
if *n == 0 {
|
y += 1;
|
||||||
break;
|
|
||||||
}
|
|
||||||
y_ += 1;
|
|
||||||
}
|
}
|
||||||
y_
|
y as u16
|
||||||
},
|
},
|
||||||
self.height,
|
self.height,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user