fix rendering

This commit is contained in:
Evan Almloff 2022-04-13 11:39:38 -05:00
parent 628638b9af
commit 3b06059834
11 changed files with 509 additions and 65 deletions

View file

@ -10,50 +10,64 @@ fn tui_update(c: &mut Criterion) {
let mut group = c.benchmark_group("Update boxes");
// We can also use loops to define multiple benchmarks, even over multiple dimensions.
for size in 1..=6 {
let parameter_string = format!("{}", 5 * size);
for size in 1..=8u32 {
let parameter_string = format!("{}", (3 * size).pow(2));
group.bench_with_input(
BenchmarkId::new("size", parameter_string),
&size,
|b, size| {
b.iter(|| match size {
1 => dioxus::tui::launch_cfg(
app5,
app3,
Config {
headless: true,
..Default::default()
},
),
2 => dioxus::tui::launch_cfg(
app10,
app6,
Config {
headless: true,
..Default::default()
},
),
3 => dioxus::tui::launch_cfg(
app15,
app9,
Config {
headless: true,
..Default::default()
},
),
4 => dioxus::tui::launch_cfg(
app20,
app12,
Config {
headless: true,
..Default::default()
},
),
5 => dioxus::tui::launch_cfg(
app25,
app15,
Config {
headless: true,
..Default::default()
},
),
6 => dioxus::tui::launch_cfg(
app30,
app18,
Config {
headless: true,
..Default::default()
},
),
7 => dioxus::tui::launch_cfg(
app21,
Config {
headless: true,
..Default::default()
},
),
8 => dioxus::tui::launch_cfg(
app24,
Config {
headless: true,
..Default::default()
@ -157,25 +171,49 @@ fn Grid(cx: Scope<GridProps>) -> Element {
})
}
fn app5(cx: Scope) -> Element {
fn app3(cx: Scope) -> Element {
cx.render(rsx! {
div{
width: "100%",
height: "100%",
Grid{
size: 5,
size: 3,
}
}
})
}
fn app10(cx: Scope) -> Element {
fn app6(cx: Scope) -> Element {
cx.render(rsx! {
div{
width: "100%",
height: "100%",
Grid{
size: 10,
size: 6,
}
}
})
}
fn app9(cx: Scope) -> Element {
cx.render(rsx! {
div{
width: "100%",
height: "100%",
Grid{
size: 9,
}
}
})
}
fn app12(cx: Scope) -> Element {
cx.render(rsx! {
div{
width: "100%",
height: "100%",
Grid{
size: 12,
}
}
})
@ -193,37 +231,37 @@ fn app15(cx: Scope) -> Element {
})
}
fn app20(cx: Scope) -> Element {
fn app18(cx: Scope) -> Element {
cx.render(rsx! {
div{
width: "100%",
height: "100%",
Grid{
size: 20,
size: 18,
}
}
})
}
fn app25(cx: Scope) -> Element {
fn app21(cx: Scope) -> Element {
cx.render(rsx! {
div{
width: "100%",
height: "100%",
Grid{
size: 25,
size: 21,
}
}
})
}
fn app30(cx: Scope) -> Element {
fn app24(cx: Scope) -> Element {
cx.render(rsx! {
div{
width: "100%",
height: "100%",
Grid{
size: 30,
size: 24,
}
}
})

View file

@ -4,12 +4,35 @@ use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{
self,
parse::{Parse, ParseStream},
parse::{Parse, ParseStream, Result},
punctuated::Punctuated,
token::Paren,
Field, Ident, Token, Type, TypeTuple,
Field, Ident, LitStr, Token, Type, TypeTuple,
};
// struct StrSlice {
// init: LitStr,
// }
// impl Parse for StrSlice {
// fn parse(input: ParseStream) -> Result<Self> {
// input.parse::<Token![[]>()?;
// let str: LitStr = input.parse()?;
// let name: Ident = input.parse()?;
// input.parse::<Token![,]>()?;
// input.parse::<Token![]]>()?;
// Ok(LazyStatic {
// visibility,
// name,
// ty,
// init,
// })
// }
// }
// #[proc_macro]
// pub fn sorted_str_slice(input: TokenStream) -> TokenStream {}
#[derive(PartialEq)]
enum DepKind {
NodeDepState,
@ -105,7 +128,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
let gen = quote! {
impl State for #type_name{
fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, ctx: &anymap::AnyMap) -> bool{
fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::state::NodeDepState as _;
// println!("called update_node_dep_state with ty: {:?}", ty);
if false {
@ -117,7 +140,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
}
}
fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{
fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::state::ParentDepState as _;
// println!("called update_parent_dep_state with ty: {:?}", ty);
if false {
@ -129,7 +152,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
}
}
fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, children: &[&Self], ctx: &anymap::AnyMap) -> bool{
fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, children: &[&Self], ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::state::ChildDepState as _;
// println!("called update_child_dep_state with ty: {:?}", ty);
if false {
@ -205,7 +228,7 @@ struct DepTypes {
}
impl Parse for DepTypes {
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
fn parse(input: ParseStream) -> Result<Self> {
let dep_ty = input.parse().ok();
let comma: Option<Token![,]> = input.parse().ok();
let ctx_ty = input.parse().ok();
@ -221,7 +244,7 @@ struct NodeDepTypes {
}
impl Parse for NodeDepTypes {
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
fn parse(input: ParseStream) -> Result<Self> {
let ctx_ty = input.parse().ok();
Ok(Self { ctx_ty })
}
@ -307,7 +330,7 @@ impl<'a> StateMember<'a> {
quote! {&()}
};
let ty = &self.mem.ty;
let node_view = quote!(NodeView::new(node, #ty::NODE_MASK));
let node_view = quote!(NodeView::new(node, #ty::NODE_MASK, vdom));
if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) {
match self.dep_kind {
DepKind::NodeDepState => {

View file

@ -0,0 +1,368 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{
self,
parse::{Parse, ParseStream, Result},
punctuated::Punctuated,
token::Paren,
Field, Ident, LitStr, Token, Type, TypeTuple,
};
// struct StrSlice {
// init: LitStr,
// }
// impl Parse for StrSlice {
// fn parse(input: ParseStream) -> Result<Self> {
// input.parse::<Token![[]>()?;
// let str: LitStr = input.parse()?;
// let name: Ident = input.parse()?;
// input.parse::<Token![,]>()?;
// input.parse::<Token![]]>()?;
// Ok(LazyStatic {
// visibility,
// name,
// ty,
// init,
// })
// }
// }
// #[proc_macro]
// pub fn sorted_str_slice(input: TokenStream) -> TokenStream {}
#[derive(PartialEq)]
enum DepKind {
NodeDepState,
ChildDepState,
ParentDepState,
}
// macro that streams data from the State for any attributes that end with _
#[proc_macro_derive(State, attributes(node_dep_state, child_dep_state, parent_dep_state))]
pub fn state_macro_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_derive_macro(&ast)
}
fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
let type_name = &ast.ident;
let fields: Vec<_> = match &ast.data {
syn::Data::Struct(data) => match &data.fields {
syn::Fields::Named(e) => &e.named,
syn::Fields::Unnamed(_) => todo!("unnamed fields"),
syn::Fields::Unit => todo!("unit fields"),
}
.iter()
.collect(),
_ => unimplemented!(),
};
let strct = Struct::parse(&fields);
let state_strct = StateStruct::parse(&fields, &strct);
let node_dep_state_fields = quote::__private::TokenStream::from_iter(
state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::NodeDepState)
.map(|f| {
let ty_id = &f.type_id();
let reduce = &f.reduce_self();
quote! {
else if ty == #ty_id {
#reduce
}
}
}),
);
let child_dep_state_fields = quote::__private::TokenStream::from_iter(
state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::ChildDepState)
.map(|f| {
let ty_id = &f.type_id();
let reduce = &f.reduce_self();
quote! {
else if ty == #ty_id {
#reduce
}
}
}),
);
let parent_dep_state_fields = quote::__private::TokenStream::from_iter(
state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::ParentDepState)
.map(|f| {
let ty_id = &f.type_id();
let reduce = &f.reduce_self();
quote! {
else if ty == #ty_id {
#reduce
}
}
}),
);
let node_types = state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::NodeDepState)
.map(|f| &f.mem.ty);
let child_types = state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::ChildDepState)
.map(|f| &f.mem.ty);
let parent_types = state_strct
.state_members
.iter()
.filter(|f| f.dep_kind == DepKind::ParentDepState)
.map(|f| &f.mem.ty);
let type_name_str = type_name.to_string();
let gen = quote! {
impl State for #type_name{
fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::state::NodeDepState as _;
// println!("called update_node_dep_state with ty: {:?}", ty);
if false {
unreachable!();
}
#node_dep_state_fields
else{
panic!("{:?} not in {}", ty, #type_name_str)
}
}
fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::state::ParentDepState as _;
// println!("called update_parent_dep_state with ty: {:?}", ty);
if false {
unreachable!();
}
#parent_dep_state_fields
else{
panic!("{:?} not in {}", ty, #type_name_str)
}
}
fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, children: &[&Self], ctx: &anymap::AnyMap) -> bool{
use dioxus_native_core::state::ChildDepState as _;
// println!("called update_child_dep_state with ty: {:?}", ty);
if false {
unreachable!()
}
#child_dep_state_fields
else{
panic!("{:?} not in {}", ty, #type_name_str)
}
}
fn child_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
let mut dep_types = Vec::new();
#(if #child_types::NODE_MASK.overlaps(mask) {
dep_types.push(std::any::TypeId::of::<#child_types>());
})*
dep_types
}
fn parent_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
let mut dep_types = Vec::new();
#(if #parent_types::NODE_MASK.overlaps(mask) {
dep_types.push(std::any::TypeId::of::<#parent_types>());
})*
dep_types
}
fn node_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
let mut dep_types = Vec::new();
#(if #node_types::NODE_MASK.overlaps(mask) {
dep_types.push(std::any::TypeId::of::<#node_types>());
})*
dep_types
}
}
};
gen.into()
}
struct Struct {
members: Vec<Member>,
}
impl Struct {
fn parse(fields: &[&Field]) -> Self {
let members = fields.iter().filter_map(|f| Member::parse(f)).collect();
Self { members }
}
}
struct StateStruct<'a> {
state_members: Vec<StateMember<'a>>,
}
impl<'a> StateStruct<'a> {
fn parse(fields: &[&'a Field], strct: &'a Struct) -> Self {
let state_members = strct
.members
.iter()
.zip(fields.iter())
.filter_map(|(m, f)| StateMember::parse(f, m, &strct))
.collect();
// todo: sort members
Self { state_members }
}
}
struct DepTypes {
ctx_ty: Option<Type>,
dep_ty: Option<Type>,
}
impl Parse for DepTypes {
fn parse(input: ParseStream) -> Result<Self> {
let dep_ty = input.parse().ok();
let comma: Option<Token![,]> = input.parse().ok();
let ctx_ty = input.parse().ok();
Ok(Self {
ctx_ty: comma.and(ctx_ty),
dep_ty,
})
}
}
struct NodeDepTypes {
ctx_ty: Option<Type>,
}
impl Parse for NodeDepTypes {
fn parse(input: ParseStream) -> Result<Self> {
let ctx_ty = input.parse().ok();
Ok(Self { ctx_ty })
}
}
impl From<NodeDepTypes> for DepTypes {
fn from(node_dep_types: NodeDepTypes) -> Self {
Self {
ctx_ty: node_dep_types.ctx_ty,
dep_ty: None,
}
}
}
struct Member {
ty: Type,
ident: Ident,
}
impl Member {
fn parse(field: &Field) -> Option<Self> {
Some(Self {
ty: field.ty.clone(),
ident: field.ident.as_ref()?.clone(),
})
}
}
struct StateMember<'a> {
mem: &'a Member,
dep_kind: DepKind,
dep_mem: Option<&'a Member>,
ctx_ty: Option<Type>,
}
impl<'a> StateMember<'a> {
fn parse(field: &Field, mem: &'a Member, parent: &'a Struct) -> Option<StateMember<'a>> {
field.attrs.iter().find_map(|a| {
let dep_kind = a
.path
.get_ident()
.map(|i| match i.to_string().as_str() {
"node_dep_state" => Some(DepKind::NodeDepState),
"child_dep_state" => Some(DepKind::ChildDepState),
"parent_dep_state" => Some(DepKind::ParentDepState),
_ => None,
})
.flatten()?;
let deps: DepTypes = match dep_kind {
DepKind::NodeDepState => a.parse_args::<NodeDepTypes>().ok()?.into(),
_ => a.parse_args().ok()?,
};
Some(Self {
mem,
dep_kind,
dep_mem: deps
.dep_ty
.map(|ty| parent.members.iter().find(|m| m.ty == ty))
.flatten(),
ctx_ty: deps.ctx_ty,
})
})
}
fn reduce_self(&self) -> quote::__private::TokenStream {
let ident = &self.mem.ident;
let get_ctx = if let Some(ctx_ty) = &self.ctx_ty {
if ctx_ty
== &Type::Tuple(TypeTuple {
paren_token: Paren {
span: quote::__private::Span::call_site(),
},
elems: Punctuated::new(),
})
{
quote! {&()}
} else {
let msg = ctx_ty.to_token_stream().to_string() + " not found in context";
quote! {ctx.get().expect(#msg)}
}
} else {
quote! {&()}
};
let ty = &self.mem.ty;
let node_view = quote!(NodeView::new(node, #ty::NODE_MASK, vdom));
if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) {
match self.dep_kind {
DepKind::NodeDepState => {
quote!(self.#ident.reduce(#node_view, #get_ctx))
}
DepKind::ChildDepState => {
quote!(self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident), #get_ctx))
}
DepKind::ParentDepState => {
quote!(self.#ident.reduce(#node_view, parent.as_ref().map(|p| &p.#dep_ident), #get_ctx))
}
}
} else {
match self.dep_kind {
DepKind::NodeDepState => {
quote!(self.#ident.reduce(#node_view, #get_ctx))
}
DepKind::ChildDepState => {
quote!(self.#ident.reduce(#node_view, &(), #get_ctx))
}
DepKind::ParentDepState => {
quote!(self.#ident.reduce(#node_view, Some(&()), #get_ctx))
}
}
}
}
fn type_id(&self) -> quote::__private::TokenStream {
let ty = &self.mem.ty;
quote!({
let type_id = std::any::TypeId::of::<#ty>();
type_id
})
}
}

View file

@ -29,6 +29,8 @@
- [ ] pub aspect_ratio: Number,
*/
// align-content,align-items,align-self,animation,animation-delay,animation-direction,animation-duration,animation-fill-mode,animation-iteration-count,animation-name,animation-play-state,animation-timing-function,backface-visibility,border,border-bottom,border-bottom-color,border-bottom-left-radius,border-bottom-right-radius,border-bottom-style,border-bottom-width,border-collapse,border-color,border-image,border-image-outset,border-image-repeat,border-image-slice,border-image-source,border-image-width,border-left,border-left-color,border-left-style,border-left-width,border-radius,border-right,border-right-color,border-right-style,border-right-width,border-spacing,border-style,border-top,border-top-color,border-top-left-radius,border-top-right-radius,border-top-style,border-top-width,border-width,bottom,box-shadow,box-sizing,caption-side,clear,clip,column-count,column-fill,column-gap,column-rule,column-rule-color,column-rule-style,column-rule-width,column-span,column-width,columns,content,counter-increment,counter-reset,cursor,direction,ltr,rtl,display,empty-cells,flex,flex-basis,flex-direction,flex-flow,flex-grow,flex-shrink,flex-wrap,float,height,justify-content,flex-start,flex-end,center,space-between,space-around,space-evenly,left,letter-spacing,line-height,list-style,list-style-image,list-style-position,list-style-type,margin,margin-bottom,margin-left,margin-right,margin-top,max-height,max-width,min-height,min-width,opacity,order,outline,outline-color,outline-offset,outline-style,outline-width,overflow,overflow-x,overflow-y,padding,padding-bottom,padding-left,padding-right,padding-top,page-break-after,page-break-before,page-break-inside,perspective,perspective-origin,position,static,relative,fixed,absolute,sticky,pointer-events,quotes,resize,right,tab-size,table-layout,top,transform,transform-origin,transform-style,transition,transition-delay,transition-duration,transition-property,transition-timing-function,vertical-align,visibility,white-space,width,word-break,word-spacing,word-wrap,z-index
use stretch2::{prelude::*, style::PositionType};
/// applies the entire html namespace defined in dioxus-html

View file

@ -301,7 +301,7 @@ impl<S: State> RealDom<S> {
for ty in ids {
let node = &mut self[node_ref.id];
let vnode = node.element(vdom);
changed |= node.state.update_node_dep_state(ty, vnode, &ctx);
changed |= node.state.update_node_dep_state(ty, vnode, vdom, &ctx);
}
if changed {
to_rerender.insert(node_ref.id);
@ -328,7 +328,7 @@ impl<S: State> RealDom<S> {
let vnode = node.element(vdom);
if node
.state
.update_child_dep_state(ty, vnode, &children_state, &ctx)
.update_child_dep_state(ty, vnode, vdom, &children_state, &ctx)
{
changed.push(ty);
}
@ -387,6 +387,7 @@ impl<S: State> RealDom<S> {
if state.update_parent_dep_state(
ty,
vnode,
vdom,
parent.filter(|n| n.id.0 != 0).map(|n| &n.state),
&ctx,
) {

View file

@ -1,7 +1,7 @@
use std::{any::TypeId, fmt::Debug};
use anymap::AnyMap;
use dioxus_core::{Attribute, ElementId, VElement, VNode, VText};
use dioxus_core::{Attribute, ElementId, VElement, VNode, VText, VirtualDom};
pub(crate) fn union_ordered_iter<T: Ord + Debug>(
s_iter: impl Iterator<Item = T>,
@ -40,7 +40,11 @@ pub struct NodeView<'a> {
mask: NodeMask,
}
impl<'a> NodeView<'a> {
pub fn new(vnode: &'a VNode<'a>, view: NodeMask) -> Self {
pub fn new(mut vnode: &'a VNode<'a>, view: NodeMask, vdom: &'a VirtualDom) -> Self {
if let VNode::Component(sc) = vnode {
let scope = vdom.get_scope(sc.scope.get().unwrap()).unwrap();
vnode = scope.root_node();
}
Self {
inner: vnode,
mask: view,
@ -284,6 +288,7 @@ pub trait State: Default + Clone {
&'a mut self,
ty: TypeId,
node: &'a VNode<'a>,
vdom: &'a dioxus_core::VirtualDom,
ctx: &AnyMap,
) -> bool;
/// This must be a valid resolution order. (no nodes updated before a state they rely on)
@ -293,6 +298,7 @@ pub trait State: Default + Clone {
&'a mut self,
ty: TypeId,
node: &'a VNode<'a>,
vdom: &'a dioxus_core::VirtualDom,
parent: Option<&Self>,
ctx: &AnyMap,
) -> bool;
@ -303,6 +309,7 @@ pub trait State: Default + Clone {
&'a mut self,
ty: TypeId,
node: &'a VNode<'a>,
vdom: &'a dioxus_core::VirtualDom,
children: &[&Self],
ctx: &AnyMap,
) -> bool;

View file

@ -14,12 +14,6 @@ struct Z {
z: C,
}
// struct Z {
// x: A,
// y: B,
// z: C,
// }
use dioxus_native_core::state::NodeDepState;
#[derive(Default, Clone)]

View file

@ -28,11 +28,13 @@ impl ChildDepState for StretchLayout {
where
Self::DepState: 'a,
{
let mut changed = false;
let mut stretch = ctx.borrow_mut();
let mut style = Style::default();
if let Some(text) = node.text() {
let char_len = text.chars().count();
let style = Style {
style = Style {
size: Size {
// characters are 1 point tall
height: Dimension::Points(1.0),
@ -42,7 +44,6 @@ impl ChildDepState for StretchLayout {
},
..Default::default()
};
if let Some(n) = self.node {
if self.style != style {
stretch.set_style(n, style).unwrap();
@ -50,12 +51,8 @@ impl ChildDepState for StretchLayout {
} else {
self.node = Some(stretch.new_node(style, &[]).unwrap());
}
self.style = style;
} else {
// gather up all the styles from the attribute list
let mut style = Style::default();
for &Attribute { name, value, .. } in node.attributes() {
apply_layout_attributes(name, value, &mut style);
}
@ -73,18 +70,27 @@ impl ChildDepState for StretchLayout {
}
if let Some(n) = self.node {
if stretch.children(n).unwrap() != child_layout {
stretch.set_children(n, &child_layout).unwrap();
}
if self.style != style {
stretch.set_style(n, style).unwrap();
}
} else {
self.node = Some(stretch.new_node(style, &child_layout).unwrap());
self.node = Some(stretch.new_node(style, &[]).unwrap());
}
if let Some(n) = self.node {
if self.style != style {
stretch.set_style(n, style).unwrap();
}
if stretch.children(n).unwrap() != child_layout {
stretch.set_children(n, &child_layout).unwrap();
}
} else {
self.node = Some(stretch.new_node(style, &[]).unwrap());
}
}
if self.style != style {
changed = true;
self.style = style;
}
true
changed
}
}

View file

@ -148,8 +148,7 @@ fn render_vdom(
fn resize(dims: Rect, stretch: &mut Stretch, rdom: &Dom) {
let width = dims.width;
let height = dims.height;
let root_id = rdom.root_id();
let root_node = rdom[root_id].state.layout.node.unwrap();
let root_node = rdom[0].state.layout.node.unwrap();
stretch
.compute_layout(
@ -165,7 +164,7 @@ fn render_vdom(
terminal.draw(|frame| {
// size is guaranteed to not change when rendering
resize(frame.size(), &mut stretch.borrow_mut(), &rdom);
let root = &rdom[rdom.root_id()];
let root = &rdom[0];
render::render_vnode(frame, &stretch.borrow(), &rdom, &root, cfg);
})?;
} else {

View file

@ -30,6 +30,7 @@ pub(crate) fn render_vnode(
}
let Layout { location, size, .. } = layout.layout(node.state.layout.node.unwrap()).unwrap();
// println!("rendering {node:?} {location:?} {size:?}");
let Point { x, y } = location;
let Size { width, height } = size;

View file

@ -50,22 +50,22 @@ impl ParentDepState for StyleModifier {
const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, true, true, false);
fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, _: &Self::Ctx) -> bool {
*self = StyleModifier::default();
let mut new = StyleModifier::default();
if parent.is_some() {
self.style.fg = None;
new.style.fg = None;
}
// handle text modifier elements
if node.namespace().is_none() {
if let Some(tag) = node.tag() {
match tag {
"b" => apply_style_attributes("font-weight", "bold", self),
"strong" => apply_style_attributes("font-weight", "bold", self),
"u" => apply_style_attributes("text-decoration", "underline", self),
"ins" => apply_style_attributes("text-decoration", "underline", self),
"del" => apply_style_attributes("text-decoration", "line-through", self),
"i" => apply_style_attributes("font-style", "italic", self),
"em" => apply_style_attributes("font-style", "italic", self),
"b" => apply_style_attributes("font-weight", "bold", &mut new),
"strong" => apply_style_attributes("font-weight", "bold", &mut new),
"u" => apply_style_attributes("text-decoration", "underline", &mut new),
"ins" => apply_style_attributes("text-decoration", "underline", &mut new),
"del" => apply_style_attributes("text-decoration", "line-through", &mut new),
"i" => apply_style_attributes("font-style", "italic", &mut new),
"em" => apply_style_attributes("font-style", "italic", &mut new),
"mark" => {
apply_style_attributes("background-color", "rgba(241, 231, 64, 50%)", self)
}
@ -76,16 +76,21 @@ impl ParentDepState for StyleModifier {
// gather up all the styles from the attribute list
for &Attribute { name, value, .. } in node.attributes() {
apply_style_attributes(name, value, self);
apply_style_attributes(name, value, &mut new);
}
// keep the text styling from the parent element
if let Some(parent) = parent {
let mut new_style = self.style.merge(parent.style);
new_style.bg = self.style.bg;
self.style = new_style;
let mut new_style = new.style.merge(parent.style);
new_style.bg = new.style.bg;
new.style = new_style;
}
if &mut new != self {
*self = new;
true
} else {
false
}
true
}
}