finally fixed style merging
This commit is contained in:
+1
-1
@@ -26,4 +26,4 @@ lazy_static = "1.4"
|
||||
paste = "1.0.15"
|
||||
dyn-clone = "1.0.17"
|
||||
flume = "=0.10.12"
|
||||
osui-element = "0.1.13"
|
||||
osui-element = "0.1.14"
|
||||
|
||||
+14
-30
@@ -5,7 +5,7 @@ macro_rules! __css {
|
||||
(
|
||||
$_style:expr, $name:ident: $value:literal% $(, $($rest:tt)*)?
|
||||
) => {{
|
||||
$_style.$name = Number::Pe($value);
|
||||
$_style.$name = (true, Number::Pe($value));
|
||||
$crate::__css!($_style, $($($rest)*)?);
|
||||
}};
|
||||
|
||||
@@ -13,7 +13,7 @@ macro_rules! __css {
|
||||
(
|
||||
$_style:expr, $name:ident: $value:literal px $(, $($rest:tt)*)?
|
||||
) => {{
|
||||
$_style.$name = Number::Px($value);
|
||||
$_style.$name = (true, Number::Px($value));
|
||||
$crate::__css!($_style, $($($rest)*)?);
|
||||
}};
|
||||
|
||||
@@ -21,7 +21,7 @@ macro_rules! __css {
|
||||
(
|
||||
$_style:expr, $name:ident: [$($inner:tt),*] $(, $($rest:tt)*)?
|
||||
) => {{
|
||||
$_style.$name = vec![$($inner),*];
|
||||
$_style.$name = (true, vec![$($inner),*]);
|
||||
$crate::__css!($_style, $($($rest)*)?);
|
||||
}};
|
||||
|
||||
@@ -29,7 +29,7 @@ macro_rules! __css {
|
||||
(
|
||||
$_style:expr, $name:ident: $value:expr $(, $($rest:tt)*)?
|
||||
) => {{
|
||||
$_style.$name = $value;
|
||||
$_style.$name = (true, $value);
|
||||
$crate::__css!($_style, $($($rest)*)?);
|
||||
}};
|
||||
}
|
||||
@@ -40,55 +40,39 @@ macro_rules! _css {
|
||||
(
|
||||
$hm:expr, $name:literal { $($inner:tt)* } $($rest:tt)*
|
||||
) => {{
|
||||
let name = $crate::ui::StyleName::Class(String::from($name));
|
||||
if let Some(_style) = $hm.get_mut(&name) {
|
||||
$crate::__css!(_style.0, $($inner)*);
|
||||
} else {
|
||||
let mut _style = $crate::ui::Style::default();
|
||||
|
||||
$crate::__css!(_style.0, $($inner)*);
|
||||
|
||||
let mut _style = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(_style, $($inner)*);
|
||||
$hm.insert(
|
||||
name,
|
||||
$crate::ui::StyleName::Class(String::from($name)),
|
||||
_style,
|
||||
);
|
||||
}
|
||||
$crate::_css!($hm, $($rest)*);
|
||||
}};
|
||||
(
|
||||
$hm:expr, $name:literal: $kind:literal { $($inner:tt)* } $($rest:tt)*
|
||||
$hm:expr, $name:literal: $state:literal { $($inner:tt)* } $($rest:tt)*
|
||||
) => {{
|
||||
let name = $crate::ui::StyleName::Class(String::from($name));
|
||||
if let Some(_style) = $hm.get_mut(&name) {
|
||||
let mut style_elem = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(style_elem, $($inner)*);
|
||||
_style.1.insert($kind.to_string(), style_elem);
|
||||
} else {
|
||||
let mut _style = $crate::ui::Style::default();
|
||||
|
||||
let mut style_elem = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(style_elem, $($inner)*);
|
||||
_style.1.insert($kind.to_string(), style_elem);
|
||||
|
||||
let mut _style = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(_style, $($inner)*);
|
||||
$hm.insert(
|
||||
name,
|
||||
$crate::ui::StyleName::ClassState(String::from($name), String::from($state)),
|
||||
_style,
|
||||
);
|
||||
}
|
||||
$crate::_css!($hm, $($rest)*);
|
||||
}};
|
||||
}
|
||||
|
||||
/// Creates a styling map `Css`
|
||||
///
|
||||
/// # Examples
|
||||
/// # Example
|
||||
/// ```
|
||||
/// css! {
|
||||
/// "btn" {
|
||||
/// color: Red,
|
||||
/// }
|
||||
/// "btn": "clicked" {
|
||||
/// color: Blue,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Returns
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ pub fn todo_app() -> Element {
|
||||
let todo = vec!["Foo", "Bar"];
|
||||
|
||||
rsx! {
|
||||
// text { class: "title", "Todo list app made with OSUI" }
|
||||
// text { class: "title", "{}", "-".repeat(crossterm::terminal::size().unwrap().0 as usize) }
|
||||
text { class: "title", "Todo list app made with OSUI" }
|
||||
text { class: "title", "{}", "-".repeat(crossterm::terminal::size().unwrap().0 as usize) }
|
||||
for (t in todo) {
|
||||
ersx!( button{ class: "todo", on_click: fn(btn: &mut Button, _, _) {
|
||||
btn.class = if btn.class == "todo" {
|
||||
|
||||
+17
-10
@@ -59,8 +59,8 @@ pub type Element = Box<dyn ElementWidget>;
|
||||
|
||||
pub trait ElementCore {
|
||||
fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element>;
|
||||
fn set_styling(&mut self, styling: &HashMap<crate::ui::StyleName, crate::ui::Style>);
|
||||
fn get_id(&self) -> String;
|
||||
fn get_class(&self) -> String;
|
||||
fn get_style(&self) -> &Style;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ pub struct Document {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Writer {
|
||||
css: *const ui::Css,
|
||||
style: ui::StyleElement,
|
||||
focused: bool,
|
||||
size: (u16, u16),
|
||||
@@ -162,11 +163,11 @@ impl Document {
|
||||
}
|
||||
pub fn render(&self) {
|
||||
if !self.element.is_null() {
|
||||
unsafe {
|
||||
(*self.element).set_styling(&self.css);
|
||||
}
|
||||
// unsafe {
|
||||
// (*self.element).set_styling(&self.css);
|
||||
// }
|
||||
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), &self.css);
|
||||
utils::clear();
|
||||
frame.render(true, unsafe { &*self.element });
|
||||
utils::flush();
|
||||
@@ -304,8 +305,10 @@ impl Writer {
|
||||
style: ui::StyleElement,
|
||||
absolute: (u16, u16),
|
||||
size: (u16, u16),
|
||||
css: &ui::Css,
|
||||
) -> Writer {
|
||||
Writer {
|
||||
css,
|
||||
style,
|
||||
focused,
|
||||
size,
|
||||
@@ -338,10 +341,12 @@ impl Writer {
|
||||
(
|
||||
self.style
|
||||
.width
|
||||
.as_size(self.size.0, self.size.0, self.style.outline),
|
||||
.1
|
||||
.as_size(self.size.0, self.size.0, self.style.outline.1),
|
||||
self.style
|
||||
.height
|
||||
.as_size(self.size.1, self.size.1, self.style.outline),
|
||||
.1
|
||||
.as_size(self.size.1, self.size.1, self.style.outline.1),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -349,15 +354,17 @@ impl Writer {
|
||||
(
|
||||
self.style
|
||||
.width
|
||||
.as_size(self.written.0, self.size.0, self.style.outline),
|
||||
.1
|
||||
.as_size(self.written.0, self.size.0, self.style.outline.1),
|
||||
self.style
|
||||
.height
|
||||
.as_size(self.written.1, self.size.1, self.style.outline),
|
||||
.1
|
||||
.as_size(self.written.1, self.size.1, self.style.outline.1),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_frame(&self) -> crate::utils::Frame {
|
||||
crate::utils::Frame::new(self.absolute, self.get_size())
|
||||
crate::utils::Frame::new(self.absolute, self.get_size(), unsafe { &*self.css })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -39,11 +39,6 @@ impl ElementWidget for Div<'_> {
|
||||
}
|
||||
|
||||
fn event(&mut self, event: Event, document: &Document) {
|
||||
if event == Event::FocusGained {
|
||||
if let Some(styling) = self.styling.clone() {
|
||||
self.set_styling(&styling);
|
||||
}
|
||||
}
|
||||
if let (Some((child, i)), l) = self.children.get_child_idx() {
|
||||
match event {
|
||||
Event::Key(k) => match k.code {
|
||||
@@ -78,6 +73,7 @@ impl ElementWidget for Div<'_> {
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Button {
|
||||
pub on_click: Handler<Button<'a>>,
|
||||
pub on_hover: Handler<Button<'a>>,
|
||||
}
|
||||
|
||||
impl ElementWidget for Button<'_> {
|
||||
@@ -97,6 +93,9 @@ impl ElementWidget for Button<'_> {
|
||||
self.style.set_state("");
|
||||
}
|
||||
}
|
||||
Event::FocusGained => {
|
||||
call!(self.on_hover(event, document));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
+56
-56
@@ -10,7 +10,7 @@ use dyn_clone::{clone_trait_object, DynClone};
|
||||
// Type aliases
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub type Css = HashMap<StyleName, Style>;
|
||||
pub type Css = HashMap<StyleName, StyleElement>;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Traits
|
||||
@@ -19,7 +19,6 @@ pub type Css = HashMap<StyleName, Style>;
|
||||
pub trait StyleCore: Debug + Send + Sync + DynClone {
|
||||
fn ansi(&self) -> String;
|
||||
fn ansi_bg(&self) -> String;
|
||||
fn is_null(&self) -> bool;
|
||||
}
|
||||
clone_trait_object!(StyleCore);
|
||||
|
||||
@@ -65,6 +64,7 @@ pub enum StyleName {
|
||||
Class(String),
|
||||
Id(String),
|
||||
Component(String),
|
||||
ClassState(String, String),
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -73,16 +73,16 @@ pub enum StyleName {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StyleElement {
|
||||
pub color: Color,
|
||||
pub background: Color,
|
||||
pub outline_color: Color,
|
||||
pub font: Vec<Font>,
|
||||
pub x: Number,
|
||||
pub y: Number,
|
||||
pub width: Number,
|
||||
pub height: Number,
|
||||
pub visible: bool,
|
||||
pub outline: bool,
|
||||
pub color: (bool, Color),
|
||||
pub background: (bool, Color),
|
||||
pub outline_color: (bool, Color),
|
||||
pub font: (bool, Vec<Font>),
|
||||
pub x: (bool, Number),
|
||||
pub y: (bool, Number),
|
||||
pub width: (bool, Number),
|
||||
pub height: (bool, Number),
|
||||
pub visible: (bool, bool),
|
||||
pub outline: (bool, bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -103,17 +103,19 @@ impl Default for Style {
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn get(&self, hover: bool) -> StyleElement {
|
||||
pub fn get(mut self, hover: bool) -> StyleElement {
|
||||
if let Some(style_element) = self.1.get(&self.2) {
|
||||
self.0.clone().prioritize(style_element)
|
||||
self.0.merge(style_element);
|
||||
self.0
|
||||
} else if hover {
|
||||
if let Some(style_element) = self.1.get("hover") {
|
||||
self.0.clone().prioritize(style_element)
|
||||
self.0.merge(style_element);
|
||||
self.0
|
||||
} else {
|
||||
self.0.clone()
|
||||
self.0
|
||||
}
|
||||
} else {
|
||||
self.0.clone()
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +131,9 @@ impl StyleElement {
|
||||
.map(|p| {
|
||||
format!(
|
||||
"{}{}{}{p}\x1b[0m",
|
||||
self.color.ansi(),
|
||||
self.background.ansi_bg(),
|
||||
self.font.ansi()
|
||||
self.color.1.ansi(),
|
||||
self.background.1.ansi_bg(),
|
||||
self.font.1.ansi()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
@@ -142,44 +144,52 @@ impl StyleElement {
|
||||
impl Default for StyleElement {
|
||||
fn default() -> Self {
|
||||
StyleElement {
|
||||
color: Color::NoColor,
|
||||
background: Color::NoColor,
|
||||
font: Vec::new(),
|
||||
outline_color: Color::NoColor,
|
||||
x: Number::Default,
|
||||
y: Number::Px(0),
|
||||
width: Number::Default,
|
||||
height: Number::Default,
|
||||
visible: true,
|
||||
outline: false,
|
||||
color: (false, Color::NoColor),
|
||||
background: (false, Color::NoColor),
|
||||
font: (false, Vec::new()),
|
||||
outline_color: (false, Color::NoColor),
|
||||
x: (false, Number::Default),
|
||||
y: (false, Number::Px(0)),
|
||||
width: (false, Number::Default),
|
||||
height: (false, Number::Default),
|
||||
visible: (false, true),
|
||||
outline: (false, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleElement {
|
||||
pub fn prioritize(mut self, other: &Self) -> StyleElement {
|
||||
if !other.color.is_null() {
|
||||
self.color = other.color.clone();
|
||||
pub fn merge(&mut self, upper: &Self) {
|
||||
if upper.color.0 {
|
||||
self.color = upper.color.clone();
|
||||
}
|
||||
if !other.background.is_null() {
|
||||
self.background = other.background.clone();
|
||||
if upper.background.0 {
|
||||
self.background = upper.background.clone();
|
||||
}
|
||||
if !other.font.is_null() {
|
||||
self.font = other.font.clone();
|
||||
if upper.font.0 {
|
||||
self.font = upper.font.clone();
|
||||
}
|
||||
if other.x != Number::Default {
|
||||
self.x = other.x.clone();
|
||||
if upper.outline_color.0 {
|
||||
self.outline_color = upper.outline_color.clone();
|
||||
}
|
||||
if other.y != Number::Default {
|
||||
self.y = other.y.clone();
|
||||
if upper.x.0 {
|
||||
self.x = upper.x.clone();
|
||||
}
|
||||
if other.width != Number::Default {
|
||||
self.width = other.width.clone();
|
||||
if upper.y.0 {
|
||||
self.y = upper.y.clone();
|
||||
}
|
||||
if other.height != Number::Default {
|
||||
self.height = other.height.clone();
|
||||
if upper.width.0 {
|
||||
self.width = upper.width.clone();
|
||||
}
|
||||
if upper.height.0 {
|
||||
self.height = upper.height.clone();
|
||||
}
|
||||
if upper.visible.0 {
|
||||
self.visible = upper.visible.clone();
|
||||
}
|
||||
if upper.outline.0 {
|
||||
self.outline = upper.outline.clone();
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,9 +235,6 @@ impl StyleCore for Color {
|
||||
Color::White => "\x1b[47m",
|
||||
})
|
||||
}
|
||||
fn is_null(&self) -> bool {
|
||||
*self == Self::NoColor
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Color {
|
||||
@@ -275,9 +282,6 @@ impl StyleCore for Font {
|
||||
fn ansi_bg(&self) -> String {
|
||||
self.ansi()
|
||||
}
|
||||
fn is_null(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleCore for Vec<Font> {
|
||||
@@ -296,10 +300,6 @@ impl StyleCore for Vec<Font> {
|
||||
}
|
||||
a
|
||||
}
|
||||
|
||||
fn is_null(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Number {
|
||||
|
||||
+32
-7
@@ -2,28 +2,52 @@ use std::io::{stdout, Write};
|
||||
|
||||
use crossterm::terminal::disable_raw_mode;
|
||||
|
||||
use crate::ui;
|
||||
|
||||
pub struct Frame {
|
||||
used: Vec<u16>,
|
||||
width: u16,
|
||||
height: u16,
|
||||
x: u16,
|
||||
y: u16,
|
||||
css: *const ui::Css,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new((x, y): (u16, u16), (width, height): (u16, u16)) -> Self {
|
||||
pub fn new((x, y): (u16, u16), (width, height): (u16, u16), css: &crate::ui::Css) -> Self {
|
||||
Frame {
|
||||
used: vec![0; height as usize],
|
||||
width,
|
||||
height,
|
||||
x,
|
||||
y,
|
||||
css,
|
||||
}
|
||||
}
|
||||
pub fn render(&mut self, focused: bool, element: &crate::Element) {
|
||||
let style = element.get_style().get(focused);
|
||||
if style.visible {
|
||||
let y = style.y.as_position(
|
||||
let style = element.get_style();
|
||||
let mut style_element = style.clone().get(focused);
|
||||
|
||||
if let Some(upper) = unsafe { (*self.css).get(&ui::StyleName::Class(element.get_class())) }
|
||||
{
|
||||
style_element.merge(upper);
|
||||
}
|
||||
|
||||
if let Some(upper) = unsafe {
|
||||
(*self.css).get(&ui::StyleName::ClassState(
|
||||
element.get_class(),
|
||||
if style.2 == "" && focused {
|
||||
"hover".to_string()
|
||||
} else {
|
||||
style.2.clone()
|
||||
},
|
||||
))
|
||||
} {
|
||||
style_element.merge(upper);
|
||||
}
|
||||
|
||||
if style_element.visible.1 {
|
||||
let y = style_element.y.1.as_position(
|
||||
&{
|
||||
let mut y = 0;
|
||||
while y < self.used.len() && self.used[y] != 0 {
|
||||
@@ -34,16 +58,17 @@ impl Frame {
|
||||
self.height,
|
||||
);
|
||||
if let Some(y_) = self.used.get(y as usize) {
|
||||
let x = style.x.as_position(y_, self.width);
|
||||
let x = style_element.x.1.as_position(y_, self.width);
|
||||
let mut writer = crate::Writer::new(
|
||||
focused,
|
||||
style.clone(),
|
||||
style_element.clone(),
|
||||
(x + self.x, y + self.y),
|
||||
(self.width, self.height),
|
||||
unsafe { &*self.css },
|
||||
);
|
||||
element.render(&mut writer);
|
||||
let (width, height) = writer.get_size_root();
|
||||
if style.outline {
|
||||
if style_element.outline.1 {
|
||||
clear();
|
||||
show_cursor();
|
||||
disable_raw_mode().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user