From e8bcb9a31f039ea82c674a36154e5a55c426f666 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Thu, 19 Dec 2024 13:16:14 +0100 Subject: [PATCH] added input --- src/examples.rs | 46 +++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 33 ++++++++++++++++++++++++++------ src/main.rs | 4 ++-- src/rsx.rs | 4 ++-- src/ui/mod.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ui/styles.rs | 10 ++++++++++ src/utils.rs | 6 +++++- 7 files changed, 139 insertions(+), 13 deletions(-) diff --git a/src/examples.rs b/src/examples.rs index c775252..480b721 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -8,7 +8,7 @@ pub mod counter_example { @SetStyle(styling()) button { - class: "outline", + class: "btn", on_click: fn(_, _, _) @count { count += 1; @@ -21,7 +21,7 @@ pub mod counter_example { pub fn styling() -> Css { css! { - "outline" { + "btn" { outline: true, outline_color: Red } @@ -79,3 +79,45 @@ pub mod todo_example { } } } + +pub mod login_example { + use crate::prelude::*; + + pub fn second_screen(usr: String, psw: String) -> Element { + rsx! { + text { "Username: {usr}\nPassword: {psw}" } + } + } + + pub fn app() -> Element { + rsx! { + @SetStyle(styling()) + + input { class: "input", id: "usr", on_click: fn(_, _, document) { + let root = document.get_root::
(); + root.children.set_index(1); + }, "username: " } + input { class: "input", id: "psw", on_click: fn(psw: &mut Input, _, document) { + if let Some(usr) = document.get_element_by_id::("usr") { + document.draw(second_screen(usr.text.clone(), psw.text.clone())); + } + }, "password: " } + } + } + + pub fn styling() -> Css { + css! { + "input" { + width: 50 px, + outline: true, + y: Auto, + x: 0 px, + caret: String::new(), + } + "input": "hover" { + outline_color: Red, + caret: String::from("█"), + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 121eeb5..d131c3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ use std::{ }; use crossterm::event::Event; -use ui::Style; +use ui::{Style, StyleCore}; pub mod css; pub mod examples; @@ -138,6 +138,9 @@ impl Document { } } } + pub fn get_root(&self) -> &mut Box { + unsafe { &mut *(self.element as *mut Element as *mut Box) } + } pub fn get_element_by_id(&self, id: &str) -> Option<&mut Box> { if let Some(e) = self.get_element_by_id_raw(id) { Some(unsafe { &mut *(e as *mut Element as *mut Box) }) @@ -170,8 +173,10 @@ impl Document { pub fn set_css(&mut self, css: ui::Css) { self.css = css; } - pub fn draw(&mut self, element: &mut Element) { - self.element = element; + pub fn draw(&self, element: Element) { + unsafe { + *self.element = element; + } } pub fn run(&mut self) -> bool { unsafe { *self.running = None } @@ -275,7 +280,7 @@ impl Children { (None, 0) } } - pub fn set_child(&mut self, index: usize) { + pub fn set_index(&mut self, index: usize) { if let Children::Children(_, child) = self { *child = index; } @@ -337,10 +342,10 @@ impl Writer { for (i, line) in s.lines().enumerate() { if self.style.outline.1 { print!( - "\x1B[{};{}H{outline_ch}{}{outline_ch}", + "\x1B[{};{}H{outline_ch}{}", self.absolute.1 + 2 + i as u16, self.absolute.0 + 1, - self.style.write(line) + self.style.write(line), ); } else { print!( @@ -376,6 +381,14 @@ impl Writer { "─".repeat(self.get_size_root().0 as usize) )) ); + + for i in 0..self.written.1 { + print!( + "\x1B[{};{}H{outline_ch}", + self.absolute.1 + i + 2, + self.absolute.0 + self.get_size_root().0 + 2, + ); + } } } @@ -412,6 +425,14 @@ impl Writer { pub fn new_frame(&mut self) -> crate::utils::Frame { crate::utils::Frame::new(self.absolute, self.get_size(), unsafe { &*self.css }) } + + pub fn caret(&self) -> String { + format!( + "{}{}\x1b[0m", + self.style.cursor.1.ansi(), + self.style.caret.1 + ) + } } impl Default for Handler { diff --git a/src/main.rs b/src/main.rs index e7b091e..87b503d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ -use osui::{examples::counter_example::app, launch}; +use osui::{examples::*, launch}; fn main() { - launch!(app()); + launch!(login_example::app()); } diff --git a/src/rsx.rs b/src/rsx.rs index 7902c1d..18a0b9f 100644 --- a/src/rsx.rs +++ b/src/rsx.rs @@ -110,14 +110,14 @@ macro_rules! ersx { #[allow(unused_mut)] let mut elem = $elem(); $crate::parse_rsx_param!(elem, $($inner)*); - elem as $crate::Element + elem }}; ($elem:path as $t:ty { $($inner:tt)* }) => {{ #[allow(unused_mut)] let mut elem = paste::paste!{$elem::<$t>}(); $crate::parse_rsx_param!(elem, $($inner)*); - elem as $crate::Element + elem }}; } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index c77600e..68b170c 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -116,3 +116,52 @@ impl ElementWidget for Button<'_> { } } } + +#[element] +#[elem_fn] +#[derive(Default, Debug)] +pub struct Input { + pub on_click: Handler>, + pub text: String, + pub placeholder: &'a str, +} + +impl ElementWidget for Input<'_> { + fn render(&self, writer: &mut crate::Writer) { + if self.text.is_empty() { + writer.write(&format!( + "{}{}{}", + self.children.get_text(), + self.placeholder, + writer.caret() + )); + } else { + writer.write(&format!( + "{}{}{}", + self.children.get_text(), + self.text, + writer.caret() + )); + } + } + + fn event(&mut self, event: crossterm::event::Event, document: &Document) { + match event { + Event::Key(k) => match k.code { + KeyCode::Backspace => { + if self.text.len() > 0 { + self.text.remove(self.text.len() - 1); + } + } + KeyCode::Enter => { + self.on_click.clone().call(self, event, document); + } + KeyCode::Char(c) => { + self.text.push(c); + } + _ => {} + }, + _ => {} + } + } +} diff --git a/src/ui/styles.rs b/src/ui/styles.rs index 1ac029a..b6b6c1c 100644 --- a/src/ui/styles.rs +++ b/src/ui/styles.rs @@ -81,6 +81,8 @@ pub struct StyleElement { pub height: (bool, Number), pub visible: (bool, bool), pub outline: (bool, bool), + pub cursor: (bool, Color), + pub caret: (bool, String), } #[derive(Debug, Clone)] @@ -147,6 +149,7 @@ impl Default for StyleElement { StyleElement { color: (false, Color::NoColor), background: (false, Color::NoColor), + cursor: (false, Color::NoColor), font: (false, Vec::new()), outline_color: (false, Color::NoColor), x: (false, Number::Default), @@ -155,6 +158,7 @@ impl Default for StyleElement { height: (false, Number::Default), visible: (false, true), outline: (false, false), + caret: (false, String::from("█")), } } } @@ -191,6 +195,12 @@ impl StyleElement { if upper.outline.0 { self.outline = upper.outline.clone(); } + if upper.cursor.0 { + self.cursor = upper.cursor.clone(); + } + if upper.caret.0 { + self.caret = upper.caret.clone(); + } } } diff --git a/src/utils.rs b/src/utils.rs index e4b764e..38098e6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -62,7 +62,11 @@ impl<'a> Frame<'a> { self.css, ); element.render(&mut writer); - let (width, height) = writer.get_size_root(); + let (mut width, mut height) = writer.get_size_root(); + if style_element.outline.1 { + width += 2; + height += 2; + } for i in y..y + height { if let Some(o) = self.used.get_mut(i as usize) { *o += x + width;