finally fixed style merging

This commit is contained in:
2024-12-17 11:11:55 +01:00
parent f753a27bbc
commit 317542097c
7 changed files with 137 additions and 122 deletions
+25 -41
View File
@@ -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,54 +40,38 @@ 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)*);
$hm.insert(
name,
_style,
);
}
let mut _style = $crate::ui::StyleElement::default();
$crate::__css!(_style, $($inner)*);
$hm.insert(
$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);
$hm.insert(
name,
_style,
);
}
let mut _style = $crate::ui::StyleElement::default();
$crate::__css!(_style, $($inner)*);
$hm.insert(
$crate::ui::StyleName::ClassState(String::from($name), String::from($state)),
_style,
);
$crate::_css!($hm, $($rest)*);
}};
}
/// Creates a styling map `Css`
///
/// # Examples
/// # Example
/// ```
/// "btn" {
/// color: Red,
/// }
/// "btn": "clicked" {
/// color: Blue,
/// css! {
/// "btn" {
/// color: Red,
/// }
/// "btn": "clicked" {
/// color: Blue,
/// }
/// }
/// ```
///
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();