diff --git a/examples/simple_window.rs b/examples/simple_window.rs index 1f43975..d9cbbc4 100644 --- a/examples/simple_window.rs +++ b/examples/simple_window.rs @@ -95,12 +95,6 @@ impl App { Rectangle { force_color <= color.to_wire(), force_height <= force_height.clone(), - @style: style! { - in window_backend::sty { - Width: 50px; - Height: 70px + 40px * *index.read() as f32; - } - }, @on_create: move |access| { access.listen().spawn(move |_: PointerMove| { force_height.set(Some(rand::thread_rng().gen_range(50.0..200.0))); diff --git a/examples/window_backend.rs b/examples/window_backend.rs index 6918097..11a36a3 100644 --- a/examples/window_backend.rs +++ b/examples/window_backend.rs @@ -9,21 +9,6 @@ use irisia::{ user_props, Event, Result, WriteStyle, }; -pub mod sty { - use irisia::{primitive::Length, Style}; - - #[derive(Style, Clone, Copy, PartialEq)] - pub struct Color(pub irisia::skia_safe::Color); - - #[derive(Style, Clone, Copy, PartialEq)] - #[style(all)] - pub struct Width(pub Length); - - #[derive(Style, Clone, Copy, PartialEq)] - #[style(all)] - pub struct Height(pub Length); -} - pub struct Rectangle { is_force: bool, props: RectProps, @@ -39,13 +24,6 @@ pub struct RectProps { pub force_height: Option, } -#[derive(Default, WriteStyle)] -struct RectStyles { - width: Option, - height: Option, - color: Option, -} - impl ElementInterfaces for Rectangle { type Props<'a> = RectProps; const REQUIRE_INDEPENDENT_LAYER: bool = false; diff --git a/irisia-macros/src/derive_read_style.rs b/irisia-macros/src/derive_read_style.rs deleted file mode 100644 index df2d534..0000000 --- a/irisia-macros/src/derive_read_style.rs +++ /dev/null @@ -1,76 +0,0 @@ -use proc_macro2::{Span, TokenStream}; -use quote::{quote, ToTokens}; -use syn::{ - punctuated::Punctuated, Data, DeriveInput, Error, Field, Fields, Index, Member, Result, Token, -}; - -pub fn derive( - DeriveInput { - ident, - generics, - data, - .. - }: DeriveInput, -) -> Result { - let fields = match data { - Data::Struct(s) => s.fields, - Data::Enum(_) | Data::Union(_) => { - return Err(Error::new(Span::call_site(), "only struct is support")) - } - }; - - let inner = match fields { - Fields::Named(named) => { - let inner = fields_iter(named.named); - quote! {{#inner}} - } - Fields::Unnamed(unnamed) => { - let inner = fields_iter(unnamed.unnamed); - quote! {(#inner)} - } - Fields::Unit => quote! {}, - }; - - let mut generics = generics; - add_trait_bounds(&mut generics); - - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - let output = quote! { - impl #impl_generics irisia::style::ReadStyle for #ident #ty_generics - #where_clause - { - fn read_style_into(&self, buf: &mut irisia::style::StyleBuffer) { - #inner - } - } - }; - - Ok(output) -} - -fn add_trait_bounds(generics: &mut syn::Generics) { - for param in &mut generics.params { - if let syn::GenericParam::Type(type_param) = param { - type_param - .bounds - .push(syn::parse_quote!(irisia::style::ReadStyle)); - } - } -} - -fn fields_iter(fields: Punctuated) -> TokenStream { - let mut tokens = TokenStream::new(); - for (i, Field { ident, .. }) in fields.iter().enumerate() { - let member = match ident { - Some(ident) => Member::Named(ident.clone()), - None => Member::Unnamed(Index::from(i)), - }; - - quote! { - irisia::style::ReadStyle::read_style_into(&self.#member, buf); - } - .to_tokens(&mut tokens); - } - tokens -} diff --git a/irisia-macros/src/derive_style/mod.rs b/irisia-macros/src/derive_style/mod.rs deleted file mode 100644 index 9cf67a7..0000000 --- a/irisia-macros/src/derive_style/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -use proc_macro2::{Span, TokenStream}; -use quote::{quote, ToTokens}; -use syn::{Data, DataEnum, DataStruct, DeriveInput, Error, Result}; - -mod parse_attr; -mod style_path; - -pub fn derive_style( - DeriveInput { - attrs, - ident, - generics, - data, - .. - }: DeriveInput, -) -> Result { - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let mut tokens = quote! { - impl #impl_generics ::irisia::Style - for #ident #ty_generics #where_clause - {} - }; - - match &data { - Data::Struct(DataStruct { fields, .. }) => { - parse_attr::derive_for(&attrs, &ident, None, &generics, fields)?.to_tokens(&mut tokens); - } - Data::Enum(DataEnum { variants, .. }) => { - for variant in variants { - tokens.extend(parse_attr::derive_for( - &variant.attrs, - &ident, - Some(&variant.ident), - &generics, - &variant.fields, - )?); - } - } - Data::Union(_) => return Err(Error::new(Span::call_site(), "union is unsupported")), - } - - Ok(tokens) -} diff --git a/irisia-macros/src/derive_style/parse_attr.rs b/irisia-macros/src/derive_style/parse_attr.rs deleted file mode 100644 index 01b468f..0000000 --- a/irisia-macros/src/derive_style/parse_attr.rs +++ /dev/null @@ -1,319 +0,0 @@ -use std::{collections::HashMap, fmt::Display}; - -use attr_parser_fn::{ - find_attr, - meta::{conflicts, key_value, list, path_only, ParseMetaExt}, - ParseArgs, ParseAttrTrait, -}; -use proc_macro2::TokenStream; -use quote::{quote, ToTokens}; -use syn::{ - Attribute, Error, Expr, Field, Fields, Generics, Ident, Index, LitStr, Member, Path, Result, - Type, -}; - -use super::style_path; - -pub enum FieldInit { - AlwaysRequired, - Optional, - OptionalWith(Expr), -} - -struct FieldInfo<'a> { - origin: &'a Field, - init: FieldInit, - map: Option<(Type, Path)>, -} - -struct PathDef { - from_tuple_order: Vec, - defined_len: usize, -} - -pub struct StyleDefinition<'a> { - all_fields: HashMap>, - paths: Vec, - empty_path: PathDef, - derive_default: bool, -} - -pub fn derive_for( - top_attrs: &[Attribute], - ident: &Ident, - variant_name: Option<&Ident>, - generics: &Generics, - fields: &Fields, -) -> Result { - let def = StyleDefinition::parse_fields(top_attrs, fields)?; - Ok(def.compile(ident, variant_name, generics)) -} - -impl<'a> StyleDefinition<'a> { - fn parse_fields(top_attrs: &[Attribute], fields: &'a Fields) -> Result { - let mut this = Self { - all_fields: HashMap::with_capacity(fields.len()), - paths: Vec::new(), - empty_path: PathDef { - from_tuple_order: Vec::new(), - defined_len: 0, - }, - derive_default: false, - }; - - for (member, field) in fields.members().zip(fields.iter()) { - if let Some(info) = this - .all_fields - .insert(member.clone(), Self::extract_field_init(field)?) - { - return Err(Error::new_spanned(info.origin, "duplicate field")); - } - - this.empty_path.from_tuple_order.push(member.clone()); - } - - this.load_paths(top_attrs)?; - Ok(this) - } - - fn extract_field_init(field: &'a Field) -> Result { - let (default, map_args) = if let Some(attr) = find_attr::only(&field.attrs, "style")? { - let (default, map_args) = ParseArgs::new() - .meta(( - conflicts(( - ("default", path_only()).map(|_| FieldInit::Optional), - ("default", key_value::()).map(FieldInit::OptionalWith), - )) - .optional(), - ("map", list(ParseArgs::new().args::<(Type, Path)>())).optional(), - )) - .parse_attr(attr)? - .meta; - ( - default.unwrap_or(FieldInit::AlwaysRequired), - map_args.map(|a| a.args), - ) - } else { - (FieldInit::AlwaysRequired, None) - }; - - Ok(FieldInfo { - origin: field, - init: default, - map: map_args, - }) - } - - fn load_paths(&mut self, attrs: &[Attribute]) -> Result<()> { - let ParseArgs { - rest_args: path_exprs, - meta: (add_path_all, derive_default), - .. - } = ParseArgs::new() - .rest_args::>() - .meta((("all", path_only()), ("derive_default", path_only()))) - .parse_concat_attrs(find_attr::all(attrs, "style"))?; - - if derive_default { - self.derive_default = true; - for (ident, field) in &self.all_fields { - if let FieldInit::AlwaysRequired = &field.init { - return Err(Error::new_spanned( - ident, - "all fields should have default value if `derive_default` is specified", - )); - } - } - } - - let mut unused_fields = HashMap::new(); - - if add_path_all { - Self::load_one_path( - &self.all_fields, - self.empty_path.from_tuple_order.clone(), - &mut self.paths, - &mut unused_fields, - )?; - } - - for path_expr in path_exprs { - let raw_paths = path_expr.parse_with(style_path::parse)?; - for path in raw_paths { - Self::load_one_path(&self.all_fields, path, &mut self.paths, &mut unused_fields)?; - } - } - - Ok(()) - } - - fn load_one_path<'b>( - all_fields: &'b HashMap>, - mut path: Vec, - path_vec: &mut Vec, - unused_fields: &mut HashMap<&'b Member, &'b FieldInfo<'a>>, - ) -> Result<()> { - debug_assert!(unused_fields.is_empty()); - unused_fields.extend(all_fields.iter()); - - for member in &path { - if unused_fields.remove(member).is_none() { - return Err(Error::new_spanned( - member, - format!( - "field `{}` {}", - display_member(member), - if all_fields.contains_key(member) { - "already used" - } else { - "not found" - } - ), - )); - } - } - - let defined_len = path.len(); - path.reserve(unused_fields.len()); - - for (unused, fi) in unused_fields.drain() { - if let FieldInit::AlwaysRequired = &fi.init { - return Err(Error::new_spanned( - unused, - format!( - "field `{}` should always be initialized, \ - but is not initialized in at least one style path. \ - if it is explicitly not required, \ - use `#[style(default = ...)]` to specify a default value", - display_member(unused) - ), - )); - } - path.push(unused.clone()); - } - - path_vec.push(PathDef { - from_tuple_order: path, - defined_len, - }); - Ok(()) - } - - fn compile( - &self, - ident: &Ident, - variant_name: Option<&Ident>, - generics: &Generics, - ) -> TokenStream { - let mut tokens = TokenStream::new(); - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let init_path = if let Some(variant_name) = variant_name { - quote! { Self::#variant_name } - } else { - quote! { Self } - }; - - for path_def @ &PathDef { - ref from_tuple_order, - defined_len, - } in &self.paths - { - let tuple_type = from_tuple_order.iter().take(defined_len).map(|member| { - let field = &self.all_fields[member]; - match &field.map { - Some((ty, _)) => ty, - None => &field.origin.ty, - } - }); - let tuple_type = quote! { (#(#tuple_type,)*) }; - - let body = self.compile_body(path_def); - quote! { - impl #impl_generics ::irisia::style::StyleFn<#tuple_type> - for #ident #ty_generics #where_clause - { - fn from(__irisia_from: #tuple_type) -> Self { - #init_path #body - } - } - } - .to_tokens(&mut tokens); - } - - if self.derive_default { - let body = self.compile_body(&self.empty_path); - quote! { - impl #impl_generics ::std::default::Default - for #ident #ty_generics #where_clause - { - fn default() -> Self { - #init_path #body - } - } - } - .to_tokens(&mut tokens); - } - - tokens - } - - fn compile_body( - &self, - &PathDef { - ref from_tuple_order, - defined_len, - }: &PathDef, - ) -> TokenStream { - let defined_fields = - (0..defined_len) - .zip(from_tuple_order.iter()) - .map(|(index, member)| { - let index = Index::from(index); - let value = quote! { __irisia_from.#index }; - self.compile_mapped_field(member, value) - }); - - let undefined_fields = from_tuple_order - .iter() - .skip(defined_len) - .map(|member| self.all_fields[member].init.compile()); - - let field_idents = from_tuple_order.iter(); - let field_values = defined_fields.chain(undefined_fields); - quote! { - { - #(#field_idents: #field_values,)* - } - } - } - - fn compile_mapped_field(&self, field: &Member, value: TokenStream) -> TokenStream { - match &self.all_fields[field].map { - Some((_, path)) => { - quote! { - (#path)(#value) - } - } - None => value, - } - } -} - -fn display_member(member: &Member) -> &dyn Display { - match member { - Member::Named(name) => name, - Member::Unnamed(index) => &index.index, - } -} - -impl FieldInit { - fn compile(&self) -> TokenStream { - match self { - Self::AlwaysRequired => unreachable!(), - Self::Optional => quote! { - ::std::default::Default::default() - }, - Self::OptionalWith(expr) => expr.to_token_stream(), - } - } -} diff --git a/irisia-macros/src/derive_style/style_path.rs b/irisia-macros/src/derive_style/style_path.rs deleted file mode 100644 index d96e4b5..0000000 --- a/irisia-macros/src/derive_style/style_path.rs +++ /dev/null @@ -1,65 +0,0 @@ -use syn::{bracketed, parse::ParseStream, token::Bracket, Member, Result}; - -pub fn parse(input: ParseStream) -> Result>> { - let mut template_path = Vec::new(); - parse_style_path(input, &mut template_path)?; - - let mut out = Vec::new(); - flatten_path_recursive(&template_path, vec![], &mut out); - Ok(out) -} - -fn flatten_path_recursive( - mut template_path: &[Seg], - mut current_path: Vec, - out: &mut Vec>, -) { - loop { - match template_path.split_first() { - Some((first, rest)) => { - template_path = rest; - match first { - Seg::Field(field) => { - current_path.push(field.clone()); - } - Seg::Optional { span } => { - flatten_path_recursive(&template_path[*span..], current_path.clone(), out); - flatten_path_recursive(template_path, current_path, out); - return; - } - } - } - None => { - out.push(current_path); - return; - } - } - } -} - -#[derive(Clone)] -enum Seg { - Field(Member), - Optional { span: usize }, -} - -fn parse_style_path(input: ParseStream, out: &mut Vec) -> Result<()> { - while !input.is_empty() { - if input.peek(Bracket) { - let content; - bracketed!(content in input); - out.push(Seg::Optional { span: 0 }); - let old_len = out.len(); - parse_style_path(&content, out)?; - out[old_len - 1] = Seg::Optional { - span: out.len() - old_len, - }; - continue; - } - - let member = input.parse()?; - out.push(Seg::Field(member)); - } - - Ok(()) -} diff --git a/irisia-macros/src/derive_write_style.rs b/irisia-macros/src/derive_write_style.rs deleted file mode 100644 index adb9612..0000000 --- a/irisia-macros/src/derive_write_style.rs +++ /dev/null @@ -1,43 +0,0 @@ -use proc_macro2::{Span, TokenStream}; -use quote::quote; -use syn::{spanned::Spanned, Data, DeriveInput, Error, Index, Member, Result}; - -pub fn derive( - DeriveInput { - ident: struct_name, - generics, - data, - .. - }: DeriveInput, -) -> Result { - let fields = match data { - Data::Struct(data) => data.fields, - _ => return Err(Error::new(Span::call_site(), "only struct is support")), - }; - - let members = fields.iter().enumerate().map(|(index, f)| match &f.ident { - Some(id) => Member::Named(id.clone()), - None => Member::Unnamed(Index { - index: index as _, - span: f.ty.span(), - }), - }); - - let (impl_gen, type_gen, where_clause) = generics.split_for_impl(); - - Ok(quote! { - impl #impl_gen ::irisia::style::WriteStyle for #struct_name #type_gen - #where_clause - { - fn write_style(&mut self, _read: &T) - where - T: ::irisia::style::ReadStyle + ?::std::marker::Sized, - { - #(::irisia::style::WriteStyle::write_style( - &mut self.#members, - _read - );)* - } - } - }) -} diff --git a/irisia-macros/src/lib.rs b/irisia-macros/src/lib.rs index b882bc3..1222e12 100644 --- a/irisia-macros/src/lib.rs +++ b/irisia-macros/src/lib.rs @@ -8,9 +8,6 @@ use syn::{ mod build_macro; mod derive_props; -mod derive_read_style; -mod derive_style; -mod derive_write_style; mod inner_impl_listen; mod main_macro; mod parse_incomplete; @@ -44,27 +41,6 @@ pub fn derive_event(input: TokenStream) -> TokenStream { .into() } -#[proc_macro_derive(Style, attributes(style))] -pub fn derive_style_trait(input: TokenStream) -> TokenStream { - result_into_stream(derive_style::derive_style(parse_macro_input!( - input as DeriveInput - ))) -} - -#[proc_macro_derive(WriteStyle, attributes(style))] -pub fn derive_write_style(input: TokenStream) -> TokenStream { - result_into_stream(derive_write_style::derive(parse_macro_input!( - input as DeriveInput - ))) -} - -#[proc_macro_derive(ReadStyle)] -pub fn derive_read_style(input: TokenStream) -> TokenStream { - result_into_stream(derive_read_style::derive(parse_macro_input!( - input as DeriveInput - ))) -} - #[proc_macro_attribute] pub fn user_props(attr: TokenStream, input: TokenStream) -> TokenStream { result_into_stream( diff --git a/irisia/src/application/backend.rs b/irisia/src/application/backend.rs index c65e510..3a97ca8 100644 --- a/irisia/src/application/backend.rs +++ b/irisia/src/application/backend.rs @@ -8,8 +8,8 @@ use irisia_backend::{ }; use crate::{ - el_model::{EMCreateCtx, SharedEM}, - element::ElementInterfaces, + el_model::{EMCreateCtx, ElementModel}, + element::{ElementInterfaces, OneStructureCreate}, event::{standard::WindowDestroyed, EventDispatcher}, primitive::{Point, Region}, structure::StructureCreate, @@ -26,7 +26,7 @@ use super::{ pub(super) struct BackendRuntime { gem: GlobalEventMgr, gc: Rc, - root: SharedEM, + root: ElementModel, } impl AppWindow for BackendRuntime @@ -72,13 +72,12 @@ fn window_size_to_draw_region(size: PhysicalSize) -> Region { ) } -pub(super) async fn new_window( +pub(super) async fn new_window( window_attributes: WindowAttributes, root_creator: F, ) -> Result where - F: StructureCreate> + Send + 'static, - El: ElementInterfaces, + F: OneStructureCreate + Send + 'static, { let ev_disp = EventDispatcher::new(); @@ -99,7 +98,6 @@ where let root = root_creator.create(&EMCreateCtx { global_content: gc.clone(), - parent_layer: None, }); root.set_draw_region(window_size_to_draw_region(gc.window().inner_size())); diff --git a/irisia/src/application/content.rs b/irisia/src/application/content.rs index 5639b86..6a61f0d 100644 --- a/irisia/src/application/content.rs +++ b/irisia/src/application/content.rs @@ -4,10 +4,7 @@ use irisia_backend::{window_handle::CloseHandle, WinitWindow}; use crate::event::EventDispatcher; -use super::{ - event_comp::global::focusing::Focusing, - redraw_scheduler::{RedrawScheduler, StandaloneRender}, -}; +use super::{event_comp::global::focusing::Focusing, redraw_scheduler::RedrawScheduler}; pub struct GlobalContent { pub(super) focusing: Focusing, diff --git a/irisia/src/application/mod.rs b/irisia/src/application/mod.rs index 0c9baa1..826d9f4 100644 --- a/irisia/src/application/mod.rs +++ b/irisia/src/application/mod.rs @@ -3,10 +3,8 @@ use std::sync::Weak; use irisia_backend::{winit::window::WindowAttributes, WinitWindow}; use crate::{ - el_model::SharedEM, - element::ElementInterfaces, + element::OneStructureCreate, event::{standard::WindowDestroyed, EventDispatcher}, - structure::StructureCreate, Result, }; @@ -28,10 +26,9 @@ pub struct Window { } impl Window { - pub async fn new(wa: WindowAttributes, dom: T) -> Result + pub async fn new(wa: WindowAttributes, dom: T) -> Result where - T: StructureCreate> + Send + 'static, - El: ElementInterfaces, + T: OneStructureCreate + Send + 'static, { new_window(wa, dom).await } diff --git a/irisia/src/application/redraw_scheduler.rs b/irisia/src/application/redraw_scheduler.rs index efc9e6a..52b33fe 100644 --- a/irisia/src/application/redraw_scheduler.rs +++ b/irisia/src/application/redraw_scheduler.rs @@ -85,7 +85,3 @@ fn fmt_errors(errors: &[anyhow::Error]) -> Result<()> { msg )) } - -pub(crate) trait StandaloneRender { - fn standalone_render(&self, canvas: &Canvas, interval: Duration) -> Result<()>; -} diff --git a/irisia/src/data_flow/trace_cell.rs b/irisia/src/data_flow/trace_cell.rs index 4e20af3..7759af0 100644 --- a/irisia/src/data_flow/trace_cell.rs +++ b/irisia/src/data_flow/trace_cell.rs @@ -14,8 +14,8 @@ pub struct TraceCell { } struct BorrowTraces { - table: HashMap, - next_id: usize, + table: HashMap, + next_id: u32, } impl TraceCell { @@ -42,29 +42,28 @@ impl TraceCell { } pub fn borrow(&self) -> Result>> { - let bt = Backtrace::capture(); Ok(TraceRef { inner_ref: self.value.try_borrow().map_err(|_| self.get_error())?, - trace: DropTrace::record(&self.borrow_traces, bt), + trace: DropTrace::record(&self.borrow_traces), }) } pub fn borrow_mut(&self) -> Result>> { - let bt = Backtrace::capture(); Ok(TraceRef { inner_ref: self.value.try_borrow_mut().map_err(|_| self.get_error())?, - trace: DropTrace::record(&self.borrow_traces, bt), + trace: DropTrace::record(&self.borrow_traces), }) } } struct DropTrace<'a> { trace_table: &'a RefCell, - id: usize, + id: u32, } impl<'a> DropTrace<'a> { - fn record(borrow_traces: &'a RefCell, bt: Backtrace) -> Self { + fn record(borrow_traces: &'a RefCell) -> Self { + let backtrace = Backtrace::capture(); let mut borrowed_r = borrow_traces.borrow_mut(); let borrowed = &mut *borrowed_r; @@ -72,7 +71,7 @@ impl<'a> DropTrace<'a> { let this_id = borrowed.next_id; borrowed.next_id = borrowed.next_id.wrapping_add(1); if let Entry::Vacant(vac) = borrowed.table.entry(this_id) { - vac.insert(bt); + vac.insert(backtrace); break this_id; } }; @@ -84,17 +83,16 @@ impl<'a> DropTrace<'a> { } } -pub struct TraceRef<'a, R> { - inner_ref: R, +pub struct TraceRef<'a, T> { + inner_ref: Ref<'a, T>, trace: DropTrace<'a>, } -impl<'a, T: ?Sized> TraceRef<'a, Ref<'a, T>> { +impl<'a, T: ?Sized> TraceRef<'a, T> { pub fn clone(this: &Self) -> Self { - let bt = Backtrace::capture(); Self { inner_ref: Ref::clone(&this.inner_ref), - trace: DropTrace::record(&this.trace.trace_table, bt), + trace: DropTrace::record(&this.trace.trace_table), } } @@ -110,35 +108,42 @@ impl<'a, T: ?Sized> TraceRef<'a, Ref<'a, T>> { } } -impl<'a, T: ?Sized> TraceRef<'a, RefMut<'a, T>> { - pub fn map_mut(orig: Self, f: F) -> TraceRef<'a, RefMut<'a, U>> +pub struct TraceMut<'a, T> { + inner_ref: RefMut<'a, T>, + trace: DropTrace<'a>, +} + +impl<'a, T: ?Sized> TraceMut<'a, RefMut<'a, T>> { + pub fn map(orig: Self, f: F) -> TraceRef<'a, RefMut<'a, U>> where F: FnOnce(&mut T) -> &mut U, U: ?Sized, { - TraceRef { + TraceMut { inner_ref: RefMut::map(orig.inner_ref, f), trace: orig.trace, } } } -impl<'a, R> Deref for TraceRef<'a, R> -where - R: Deref, -{ - type Target = R::Target; +impl Deref for TraceRef<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.inner_ref + } +} + +impl Deref for TraceMut<'_, T> { + type Target = T; - fn deref(&self) -> &Self::Target { + fn deref(&self) -> &T { &self.inner_ref } } -impl<'a, R> DerefMut for TraceRef<'a, R> -where - R: DerefMut, -{ - fn deref_mut(&mut self) -> &mut Self::Target { +impl DerefMut for TraceMut<'_, T> { + fn deref_mut(&mut self) -> &mut T { &mut self.inner_ref } } diff --git a/irisia/src/el_model/element_model.rs b/irisia/src/el_model/element_model.rs index 08f1758..7583b89 100644 --- a/irisia/src/el_model/element_model.rs +++ b/irisia/src/el_model/element_model.rs @@ -1,10 +1,8 @@ use std::{ - borrow::Cow, - cell::{Cell, RefCell}, + cell::Cell, future::Future, ops::{Deref, DerefMut}, - rc::{Rc, Weak}, - time::Duration, + rc::Rc, }; use tokio::task::JoinHandle; @@ -13,69 +11,37 @@ use crate::{ application::{ content::GlobalContent, event_comp::{IncomingPointerEvent, NodeEventMgr}, - redraw_scheduler::StandaloneRender, }, data_flow::observer::{Observer, RcObserver}, + element::Render, event::{standard::ElementAbandoned, EventDispatcher, Listen}, primitive::Region, structure::StructureCreate, - style::StyleFn, ElementInterfaces, Result, }; -use super::{ - layer::{LayerCompositer, SharedLayerCompositer}, - ElInputWatcher, LayerRebuilder, SharedEM, -}; - #[derive(Clone)] -pub struct ElementAccess(Rc>); +pub struct ElementAccess(Rc); -pub struct ElementModel { - pub(crate) el: RefCell>, - pub(crate) event_mgr: RefCell, - pub(crate) shared: Rc>, // TODO: 双Rc优化 +pub struct ElementModel { + pub(crate) el: El, + pub(crate) event_mgr: NodeEventMgr, + pub(crate) shared: Rc, pub(crate) redraw_hook: RcObserver, + pub(crate) child_props: Cp, } -pub(crate) struct Shared { +pub(crate) struct Shared { pub interact_region: Cell>, pub draw_region: Cell, pub redraw_signal_sent: Cell, - pub render_on: RenderOn, pub ed: EventDispatcher, pub gc: Rc, - pub styles: Sty, -} - -pub(crate) enum RenderOn { - ParentLayer(Weak), - NewLayer { - this: Weak, - layer: SharedLayerCompositer, - }, -} - -impl RenderOn { - fn get_layer(&self) -> &Weak { - let (Self::NewLayer { this, .. } | Self::ParentLayer(this)) = self; - this - } - - pub(crate) fn expect_independent(&self) -> &SharedLayerCompositer { - match self { - Self::NewLayer { layer, .. } => layer, - Self::ParentLayer(_) => { - panic!("this element did not require a independent layer, it cannot be rendered independently") - } - } - } } #[derive(Clone)] pub struct EMCreateCtx { pub(crate) global_content: Rc, - pub(crate) parent_layer: Option>, } impl ElementAccess { @@ -98,7 +64,6 @@ impl ElementAccess { pub fn context(&self) -> EMCreateCtx { EMCreateCtx { global_content: self.0.gc.clone(), - parent_layer: Some(self.0.render_on.get_layer().clone()), } } @@ -113,16 +78,12 @@ impl ElementAccess { self.0.request_redraw() } - pub fn styles(&self) -> &dyn StyleFn { - &self.0.styles - } - pub fn draw_region(&self) -> Region { self.0.draw_region.get() } } -impl Shared { +impl Shared { fn request_redraw(&self) { if self.redraw_signal_sent.get() { return; @@ -139,69 +100,37 @@ impl Shared { } } -impl ElementModel { +impl ElementModel { pub(crate) fn new( context: &EMCreateCtx, props: El::Props<'_>, - styles: Sty, + child_props: Cp, slot: Slt, - ) -> SharedEM + ) -> Self where El: ElementInterfaces, - Sty: StyleFn + 'static, Slt: StructureCreate, { let ed = EventDispatcher::new(); - let rc = Rc::new_cyclic(|weak: &Weak>| { - let render_on = match &context.parent_layer { - Some(layer) if !El::REQUIRE_INDEPENDENT_LAYER => { - RenderOn::ParentLayer(layer.clone()) - } - _ => RenderOn::NewLayer { - this: weak.clone(), - layer: LayerCompositer::new(), - }, - }; - - let shared = Rc::new(Shared { - interact_region: Cell::new(None), - draw_region: Default::default(), - redraw_signal_sent: Cell::new(false), - ed: ed.clone(), - render_on, - gc: context.global_content.clone(), - styles, - }); - - ElementModel { - el: RefCell::new(InitLater(None)), - event_mgr: NodeEventMgr::new(ed.clone()).into(), - redraw_hook: { - let shared = shared.clone(); - Observer::new(move || shared.request_redraw()) - }, - shared, - } + let shared = Rc::new(Shared { + interact_region: Cell::new(None), + draw_region: Default::default(), + redraw_signal_sent: Cell::new(false), + ed: ed.clone(), + gc: context.global_content.clone(), }); - let new_ctx = match &rc.shared.render_on { - RenderOn::ParentLayer(_) => Cow::Borrowed(context), - RenderOn::NewLayer { this, .. } => Cow::Owned(EMCreateCtx { - global_content: context.global_content.clone(), - parent_layer: Some(this.clone()), - }), - }; - - rc.el.borrow_mut().0 = Some(El::create( - props, - slot, - ElementAccess(rc.shared.clone() as _), - ElInputWatcher::new(Rc::downgrade(&rc)), - &new_ctx, - )); - - rc + ElementModel { + el: El::create(props, slot, ElementAccess(shared.clone()), &context), + event_mgr: NodeEventMgr::new(ed.clone()).into(), + redraw_hook: { + let shared = shared.clone(); + Observer::new(move || shared.request_redraw()) + }, + shared, + child_props, + } } pub(crate) fn set_draw_region(&self, region: Region) @@ -237,7 +166,7 @@ impl ElementModel { &self.shared.gc } - pub fn set_interact_region(&mut self, region: Option) { + pub fn set_interact_region(&self, region: Option) { self.shared.interact_region.set(region); } @@ -271,53 +200,33 @@ impl ElementModel { } /// returns whether this element is logically entered - pub fn on_pointer_event(&self, ipe: &IncomingPointerEvent) -> bool + pub fn on_pointer_event(&mut self, ipe: &IncomingPointerEvent) -> bool where El: ElementInterfaces, { let children_logically_entered = self.el.borrow_mut().children_emit_event(ipe); - self.event_mgr.borrow_mut().update_and_emit( + self.event_mgr.update_and_emit( ipe, self.shared.interact_region.get(), children_logically_entered, ) } - pub(crate) fn monitoring_render( - &self, - lr: &mut LayerRebuilder, - interval: Duration, - ) -> Result<()> + pub(crate) fn monitoring_render(&mut self, args: Render) -> Result<()> where El: ElementInterfaces, { self.redraw_hook - .invoke(|| self.el.borrow_mut().render(lr, interval)) + .invoke(|| self.el.get_mut().unwrap().render(args)) } } -impl Drop for ElementModel { +impl Drop for ElementModel { fn drop(&mut self) { self.shared.ed.emit_trusted(ElementAbandoned) } } -impl StandaloneRender for ElementModel -where - El: ElementInterfaces, -{ - fn standalone_render( - &self, - canvas: &irisia_backend::skia_safe::Canvas, - interval: std::time::Duration, - ) -> Result<()> { - self.shared.redraw_signal_sent.set(false); - let layer = self.shared.render_on.expect_independent(); - - self.monitoring_render(&mut LayerCompositer::rebuild(layer, canvas), interval) - } -} - pub(crate) struct InitLater(pub(super) Option); impl Deref for InitLater { diff --git a/irisia/src/el_model/layer/mod.rs b/irisia/src/el_model/layer/mod.rs deleted file mode 100644 index 19cb2d1..0000000 --- a/irisia/src/el_model/layer/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::{cell::RefCell, rc::Rc}; - -use anyhow::anyhow; -use irisia_backend::skia_safe::{ - canvas::{SaveLayerFlags, SaveLayerRec}, - BlendMode, Canvas, Paint, -}; - -use self::queue::{Layer, Queue}; -use crate::Result; -pub use rebuild::LayerRebuilder; - -mod queue; -pub(crate) mod rebuild; - -pub(crate) type SharedLayerCompositer = Rc>; - -pub(crate) struct LayerCompositer { - layers: Queue, -} - -impl LayerCompositer { - pub fn new() -> SharedLayerCompositer { - Rc::new(RefCell::new(Self { - layers: Queue::new(), - })) - } - - pub fn rebuild<'a>(this: &'a SharedLayerCompositer, canvas: &'a Canvas) -> LayerRebuilder<'a> { - LayerRebuilder::new(this, canvas) - } - - pub fn composite(&self, canvas: &Canvas) -> Result<()> { - let mut paint = Paint::default(); - paint.set_blend_mode(BlendMode::DstOver); - let rec = SaveLayerRec::default() - .flags(SaveLayerFlags::INIT_WITH_PREVIOUS) - .paint(&paint); - - for layer in self.layers.iter() { - match layer { - Layer::Bitmap { bitmap, offset } => { - canvas.save_layer(&rec); - if !canvas.write_pixels_from_bitmap(bitmap, *offset) { - return Err(anyhow!("cannot write bitmap to canvas")); - } - canvas.restore(); - } - Layer::CacheLayer { layer, matrix } => { - canvas.save(); - canvas.set_matrix(matrix); - layer.borrow().composite(canvas)?; - canvas.restore(); - } - } - } - Ok(()) - } -} diff --git a/irisia/src/el_model/layer/queue.rs b/irisia/src/el_model/layer/queue.rs deleted file mode 100644 index 928a048..0000000 --- a/irisia/src/el_model/layer/queue.rs +++ /dev/null @@ -1,89 +0,0 @@ -use irisia_backend::skia_safe::{Bitmap, IPoint, ImageInfo, M44}; -use smallvec::SmallVec; - -use super::SharedLayerCompositer; - -pub(super) enum Layer { - Bitmap { - bitmap: Bitmap, - offset: IPoint, - }, - CacheLayer { - layer: SharedLayerCompositer, - matrix: M44, - }, -} - -pub(super) struct Queue { - buffer: SmallVec<[Layer; 1]>, - len: usize, -} - -impl Queue { - pub fn new() -> Self { - Self { - buffer: SmallVec::new(), - len: 0, - } - } - - pub fn clear(&mut self) { - self.len = 0; - } - - pub fn add_bitmap(&mut self, image_info: &ImageInfo, offset: IPoint) -> &mut Bitmap { - loop { - match self.buffer.get_mut(self.len) { - None => { - let mut bitmap = Bitmap::new(); - assert!(bitmap.set_info(image_info, None)); - self.buffer.push(Layer::Bitmap { bitmap, offset }); - break; - } - Some(Layer::Bitmap { - bitmap, - offset: old_offset, - }) => { - assert!(bitmap.set_info(image_info, None)); - *old_offset = offset; - break; - } - Some(Layer::CacheLayer { .. }) => { - self.buffer.swap_remove(self.len); - } - } - } - - self.len += 1; - match self.buffer.last_mut() { - Some(Layer::Bitmap { bitmap, .. }) => bitmap, - _ => unreachable!(), - } - } - - pub fn add_layer(&mut self, layer: SharedLayerCompositer, matrix: M44) { - let layer = Layer::CacheLayer { layer, matrix }; - - match self.buffer.get_mut(self.len) { - Some(ext @ Layer::CacheLayer { .. }) => *ext = layer, - Some(normal @ Layer::Bitmap { .. }) => { - let bitmap = std::mem::replace(normal, layer); - self.buffer.push(bitmap); - } - None => { - self.buffer.push(layer); - } - } - self.len += 1; - } - - pub fn iter(&self) -> impl Iterator { - self.buffer.iter().take(self.len) - } - - pub fn pop(&mut self) { - if let Some(len) = self.len.checked_sub(1) { - self.len = len; - } - } -} diff --git a/irisia/src/el_model/layer/rebuild.rs b/irisia/src/el_model/layer/rebuild.rs deleted file mode 100644 index f67a49c..0000000 --- a/irisia/src/el_model/layer/rebuild.rs +++ /dev/null @@ -1,141 +0,0 @@ -use std::cell::RefMut; - -use anyhow::anyhow; -use irisia_backend::skia_safe::{colors::TRANSPARENT, Canvas, ColorType, IPoint, ISize, Pixmap}; - -use super::{LayerCompositer, SharedLayerCompositer}; -use crate::Result; - -pub struct LayerRebuilder<'a> { - lc: RefMut<'a, LayerCompositer>, - canvas: &'a Canvas, - dirty: bool, -} - -impl<'a> LayerRebuilder<'a> { - pub(super) fn new(lc: &'a SharedLayerCompositer, canvas: &'a Canvas) -> Self { - canvas.save(); - canvas.clear(TRANSPARENT); - canvas.reset_matrix(); - - let mut lc = lc.borrow_mut(); - lc.layers.clear(); - - Self { - lc, - canvas, - dirty: false, - } - } - - pub fn canvas(&mut self) -> &Canvas { - self.dirty = true; - self.canvas - } - - pub(crate) fn append_layer(&mut self, custom_layer: &SharedLayerCompositer) -> Result<()> { - self.flush()?; - let matrix = self.canvas.local_to_device(); - self.lc.layers.add_layer(custom_layer.clone(), matrix); - Ok(()) - } - - fn flush(&mut self) -> Result<()> { - if !self.dirty { - return Ok(()); - } - - let (rect_start, rect_size) = { - /*self.canvas - .peek_pixels() - .map(min_opaque_rect) - .unwrap_or_else(|| ((0, 0).into(), self.canvas.image_info().dimensions()))*/ - ((0, 0).into(), self.canvas.image_info().dimensions()) - }; - - let bitmap = self.lc.layers.add_bitmap( - &self.canvas.image_info().with_dimensions(rect_size), - rect_start, - ); - bitmap.alloc_pixels(); - - if !self.canvas.read_pixels_to_bitmap(bitmap, rect_start) { - self.lc.layers.pop(); - return Err(anyhow!("cannot flush canvas content")); - } - self.dirty = false; - - Ok(()) - } -} - -fn _min_opaque_rect(pixmap: Pixmap) -> (IPoint, ISize) { - debug_assert_eq!(pixmap.color_type(), ColorType::RGBA8888); - let mut pixels = pixmap.pixels::<[u8; 4]>().unwrap(); - let row_length = pixmap.row_bytes_as_pixels(); - let column_length = pixels.len() / row_length; - - let mut start = (0usize, 0i32); - let mut end = (row_length, column_length as i32); - - // move start Y dimension - while !pixels.is_empty() { - let (row, rest) = pixels.split_at(row_length); - if row.iter().any(|arr| arr[3] != 0) { - break; - } - start.1 += 1; - pixels = rest; - } - - // move end Y dimension - while !pixels.is_empty() { - let (rest, row) = pixels.split_at(pixels.len() - row_length); - if row.iter().any(|arr| arr[3] != 0) { - break; - } - end.1 -= 1; - pixels = rest; - } - - // move start X dimension - while !pixels.is_empty() { - if pixels - .chunks_exact(row_length) - .any(|chunk| chunk[start.0][3] != 0) - { - break; - } - start.0 += 1; - } - - // move end X dimension - while !pixels.is_empty() { - if pixels - .chunks_exact(row_length) - .any(|chunk| chunk[end.0 - 1][3] != 0) - { - break; - } - end.0 -= 1 - } - - if pixels.is_empty() { - ((0, 0).into(), (0, 0).into()) - } else { - let width = (end.0 - start.0) as i32; - let height = end.1 - start.1; - ( - IPoint::new(start.0 as i32, start.1), - ISize::new(width, height), - ) - } -} - -impl Drop for LayerRebuilder<'_> { - fn drop(&mut self) { - self.flush().expect("flush at drop time failed"); - self.canvas.clear(TRANSPARENT); - self.canvas.restore(); - } -} diff --git a/irisia/src/el_model/mod.rs b/irisia/src/el_model/mod.rs index 3d27f64..995b0aa 100644 --- a/irisia/src/el_model/mod.rs +++ b/irisia/src/el_model/mod.rs @@ -1,21 +1,10 @@ -use std::rc::Rc; - use anyhow::anyhow; use crate::Result; -pub(crate) use self::element_model::RenderOn; -pub use self::{ - element_model::{EMCreateCtx, ElementAccess, ElementModel}, - layer::LayerRebuilder, - watcher::ElInputWatcher, -}; +pub use self::element_model::{EMCreateCtx, ElementAccess, ElementModel}; mod element_model; -pub(crate) mod layer; -mod watcher; - -pub type SharedEM = Rc>; #[allow(unused)] fn panic_on_debug(msg: &str) -> Result<()> { diff --git a/irisia/src/el_model/watcher.rs b/irisia/src/el_model/watcher.rs deleted file mode 100644 index 3fa3a00..0000000 --- a/irisia/src/el_model/watcher.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::rc::Weak; - -use crate::{ - data_flow::{ReadWire, ReadableExt}, - ElementInterfaces, -}; - -use super::ElementModel; - -pub struct ElInputWatcher(Weak>); - -impl Clone for ElInputWatcher { - fn clone(&self) -> Self { - ElInputWatcher(self.0.clone()) - } -} - -impl ElInputWatcher { - pub(crate) fn new(em: Weak>) -> Self { - ElInputWatcher(em) - } - - pub fn invoke(&self, f: F) -> R - where - F: FnOnce(&El) -> R, - { - let Some(rc) = self.0.upgrade() else { - panic!("cannot invoke function on a dropped element"); - }; - - let r = f(&rc.el.borrow()); - r - } - - pub fn invoke_mut(&self, f: F) -> R - where - F: FnOnce(&mut El) -> R, - { - let Some(rc) = self.0.upgrade() else { - panic!("cannot invoke function on a dropped element"); - }; - - let r = f(&mut rc.el.borrow_mut()); - r - } - - pub fn watch(&self, watch: ReadWire, mut func: F) - where - U: 'static, - F: FnMut(&mut El, &U) + 'static, - { - let em = self.0.clone(); - watch.watch( - move |wire, handle| { - let Some(em) = em.upgrade() else { - handle.discard(); - return; - }; - - if let Some(el) = &mut em.el.borrow_mut().0 { - func(el, &wire.read()); - }; - }, - false, - ); - } -} diff --git a/irisia/src/element/component.rs b/irisia/src/element/component.rs index 4ccfe96..5fdcd05 100644 --- a/irisia/src/element/component.rs +++ b/irisia/src/element/component.rs @@ -1,15 +1,12 @@ -use std::time::Duration; - use crate::{ application::event_comp::IncomingPointerEvent, - data_flow::ReadWire, - el_model::{layer::LayerRebuilder, EMCreateCtx, ElInputWatcher, ElementAccess, SharedEM}, + el_model::{EMCreateCtx, ElementAccess, ElementModel}, primitive::Region, structure::{ChildBox, StructureCreate}, ElementInterfaces, }; -use super::FromUserProps; +use super::{FromUserProps, Render}; pub trait ComponentTemplate: Sized + 'static { type Props<'a>: FromUserProps; @@ -18,15 +15,13 @@ pub trait ComponentTemplate: Sized + 'static { props: Self::Props<'_>, slot: Slt, access: ElementAccess, - watch_input: CompInputWatcher, - ) -> (Self, impl OneStructureCreate) + ) -> impl OneStructureCreate where Slt: StructureCreate; } -pub struct Component { - inner: T, - slot: ChildBox, +pub struct Component { + slot: ChildBox, } impl ElementInterfaces for Component @@ -39,23 +34,18 @@ where props: Self::Props<'_>, slot: Slt, access: ElementAccess, - watch_input: ElInputWatcher, ctx: &EMCreateCtx, ) -> Self where Slt: StructureCreate, { - let (inner, slot) = - ::create(props, slot, access, CompInputWatcher(watch_input)); - Component { - inner, - slot: ChildBox::new(slot, ctx), + slot: ChildBox::new(T::create(props, slot, access), ctx), } } - fn render(&mut self, lr: &mut LayerRebuilder, interval: Duration) -> crate::Result<()> { - self.slot.render(lr, interval) + fn render(&mut self, args: Render) -> crate::Result<()> { + self.slot.render(args) } fn children_emit_event(&mut self, ipe: &IncomingPointerEvent) -> bool { @@ -70,48 +60,18 @@ where } } -pub struct CompInputWatcher(ElInputWatcher>); - -impl Clone for CompInputWatcher { - fn clone(&self) -> Self { - CompInputWatcher(self.0.clone()) - } -} - -impl CompInputWatcher { - pub fn watch(&self, watch: ReadWire, mut func: F) - where - U: 'static, - F: FnMut(&mut El, &U) + 'static, - { - self.0.watch(watch, move |comp, watch_data| { - func(&mut comp.inner, watch_data) - }); - } - - pub fn invoke(&self, f: F) -> R - where - F: FnOnce(&El) -> R, - { - self.0.invoke(|comp| f(&comp.inner)) - } - - pub fn invoke_mut(&self, f: F) -> R - where - F: FnOnce(&mut El) -> R, - { - self.0.invoke_mut(|comp| f(&mut comp.inner)) - } -} - -pub trait OneStructureCreate: StructureCreate> { +pub trait OneStructureCreate: + StructureCreate> +{ type Element: ElementInterfaces; + type OneChildProps; } -impl OneStructureCreate for T +impl OneStructureCreate for T where - T: StructureCreate>, + T: StructureCreate>, El: ElementInterfaces, { type Element = El; + type OneChildProps = Cp; } diff --git a/irisia/src/element/mod.rs b/irisia/src/element/mod.rs index 00fbb30..43ebf32 100644 --- a/irisia/src/element/mod.rs +++ b/irisia/src/element/mod.rs @@ -3,16 +3,24 @@ use std::time::Duration; use crate::{ application::event_comp::IncomingPointerEvent, data_flow::{const_wire, ReadWire}, - el_model::{layer::LayerRebuilder, EMCreateCtx, ElInputWatcher, ElementAccess}, + el_model::{EMCreateCtx, ElementAccess}, primitive::Region, structure::StructureCreate, Result, }; -pub use component::{CompInputWatcher, Component, ComponentTemplate, OneStructureCreate}; +pub use component::{Component, ComponentTemplate, OneStructureCreate}; +use irisia_backend::skia_safe::Canvas; mod component; +#[derive(Clone, Copy)] +pub struct Render<'a> { + pub canvas: &'a Canvas, + pub dirty_zone: Region, + pub interval: Duration, +} + /// Element is a thing can draw itself on the given canvas, /// according to its properties, styles and given drawing region. /// This trait is close to the native rendering, if you are not a @@ -26,13 +34,12 @@ pub trait ElementInterfaces: Sized + 'static { props: Self::Props<'_>, slot: Slt, access: ElementAccess, - watch_input: ElInputWatcher, ctx: &EMCreateCtx, ) -> Self where Slt: StructureCreate; - fn render(&mut self, lr: &mut LayerRebuilder, interval: Duration) -> Result<()>; + fn render(&mut self, args: Render) -> Result<()>; fn set_draw_region(&mut self, dr: Region); fn children_emit_event(&mut self, ipe: &IncomingPointerEvent) -> bool; } diff --git a/irisia/src/lib.rs b/irisia/src/lib.rs index 543e39f..013222a 100644 --- a/irisia/src/lib.rs +++ b/irisia/src/lib.rs @@ -22,11 +22,10 @@ pub mod event; pub mod log; pub mod primitive; pub mod structure; -pub mod style; pub use application::Window; pub use element::ElementInterfaces; pub use event::Event; pub use irisia_backend::{runtime::exit_app, skia_safe, start_runtime, winit, WinitWindow}; -pub use irisia_macros::{build, main, style, user_props, Event, ReadStyle, Style, WriteStyle}; +pub use irisia_macros::{build, main, style, user_props, Event}; //pub use style::{ReadStyle, Style, WriteStyle}; diff --git a/irisia/src/primitive/mod.rs b/irisia/src/primitive/mod.rs index a768173..26c83bf 100644 --- a/irisia/src/primitive/mod.rs +++ b/irisia/src/primitive/mod.rs @@ -1,7 +1,7 @@ -pub use self::{length::Length, point::Point}; +pub use self::{length::Length, point::Point, region::Region}; pub mod length; pub mod point; +pub mod region; pub type Result = anyhow::Result; -pub type Region = (Point, Point); diff --git a/irisia/src/primitive/region.rs b/irisia/src/primitive/region.rs new file mode 100644 index 0000000..b09e5c9 --- /dev/null +++ b/irisia/src/primitive/region.rs @@ -0,0 +1,20 @@ +use super::Point; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Region { + pub left_top: Point, + pub right_bottom: Point, +} + +impl Region { + pub const fn contains(&self, rhs: Self) -> bool { + self.left_top.abs_le(rhs.left_top) && self.right_bottom.abs_ge(rhs.right_bottom) + } + + pub const fn intersects(&self, rhs: Self) -> bool { + !(self.left_top.0 >= rhs.right_bottom.0 + || self.left_top.1 >= rhs.right_bottom.1 + || self.right_bottom.0 <= rhs.left_top.0 + || self.right_bottom.1 <= rhs.left_top.1) + } +} diff --git a/irisia/src/structure/chain.rs b/irisia/src/structure/chain.rs index c26c2e1..a1bb6aa 100644 --- a/irisia/src/structure/chain.rs +++ b/irisia/src/structure/chain.rs @@ -16,17 +16,25 @@ impl_variadics! { } } - impl<#(#T0),*> VisitBy for (#(#T0,)*) + impl VisitBy for (#(#T0,)*) where - #(#T0: VisitBy,)* + #(#T0: VisitBy,)* { fn visit(&self, _v: &mut V) -> crate::Result<()> where - V: super::Visitor + V: super::Visitor { #(self.#index.visit(_v)?;)* Ok(()) } + + fn visit_mut(&mut self, _v: &mut V) -> crate::Result<()> + where + V: super::VisitorMut + { + #(self.#index.visit_mut(_v)?;)* + Ok(()) + } } } } diff --git a/irisia/src/structure/child_box.rs b/irisia/src/structure/child_box.rs index c9640d4..4307953 100644 --- a/irisia/src/structure/child_box.rs +++ b/irisia/src/structure/child_box.rs @@ -1,14 +1,12 @@ -use std::time::Duration; - use super::{RenderMultiple, StructureCreate}; use crate::{ - application::event_comp::IncomingPointerEvent, el_model::layer::LayerRebuilder, - primitive::Region, structure::EMCreateCtx, style::StyleFn, Result, + application::event_comp::IncomingPointerEvent, element::Render, primitive::Region, + structure::EMCreateCtx, Result, }; -pub struct ChildBox(Box); +pub struct ChildBox(Box>); -impl ChildBox { +impl ChildBox { pub fn new(updater: T, ctx: &EMCreateCtx) -> Self where T: StructureCreate, @@ -16,25 +14,25 @@ impl ChildBox { ChildBox(Box::new(updater.create(ctx))) } - pub fn render(&mut self, lr: &mut LayerRebuilder, interval: Duration) -> Result<()> { - self.0.render(lr, interval) + pub fn render(&mut self, args: Render) -> Result<()> { + self.0.render(args) } - pub fn peek_styles(&self, mut f: F) + pub fn props(&self, mut f: F) where - F: FnMut(&dyn StyleFn), + F: FnMut(&Cp), { - self.0.peek_styles(&mut f) + self.0.props(&mut f); } pub fn layout(&mut self, mut f: F) -> Result<()> where - F: FnMut(&dyn StyleFn) -> Option, + F: FnMut(&Cp) -> Option, { self.0.layout(&mut f) } - pub fn emit_event(&self, ipe: &IncomingPointerEvent) -> bool { + pub fn emit_event(&mut self, ipe: &IncomingPointerEvent) -> bool { self.0.emit_event(ipe) } diff --git a/irisia/src/structure/cond.rs b/irisia/src/structure/cond.rs index 69e1dbc..11680be 100644 --- a/irisia/src/structure/cond.rs +++ b/irisia/src/structure/cond.rs @@ -7,10 +7,10 @@ pub struct Conditional { or_else: S2, } -impl VisitBy for Conditional +impl VisitBy for Conditional where - S1: VisitBy, - S2: VisitBy, + S1: VisitBy, + S2: VisitBy, { fn visit(&self, v: &mut V) -> crate::Result<()> where @@ -22,6 +22,17 @@ where self.or_else.visit(v) } } + + fn visit_mut(&mut self, v: &mut V) -> crate::Result<()> + where + V: super::VisitorMut, + { + if *self.cond.read() { + self.if_selected.visit_mut(v) + } else { + self.or_else.visit_mut(v) + } + } } pub fn conditional( diff --git a/irisia/src/structure/mod.rs b/irisia/src/structure/mod.rs index a9b07eb..2c5648c 100644 --- a/irisia/src/structure/mod.rs +++ b/irisia/src/structure/mod.rs @@ -1,12 +1,10 @@ -use std::time::Duration; - use anyhow::anyhow; use crate::{ application::event_comp::IncomingPointerEvent, - el_model::{layer::LayerRebuilder, EMCreateCtx, RenderOn, SharedEM}, + el_model::{EMCreateCtx, ElementModel}, + element::Render, primitive::Region, - style::StyleFn, ElementInterfaces, Result, }; @@ -25,94 +23,100 @@ mod pat_match; mod repeat; mod single; -pub trait VisitBy: 'static { +pub trait VisitBy: 'static { fn visit(&self, v: &mut V) -> Result<()> where - V: Visitor; + V: Visitor; + + fn visit_mut(&mut self, v: &mut V) -> Result<()> + where + V: VisitorMut; } -pub trait RenderMultiple: 'static { - fn render(&mut self, lr: &mut LayerRebuilder, interval: Duration) -> Result<()>; +type PropsFn<'a, Cp> = &'a mut dyn FnMut(&Cp); +type LayoutFn<'a, Cp> = &'a mut dyn FnMut(&Cp) -> Option; - fn peek_styles(&self, f: &mut dyn FnMut(&dyn StyleFn)); +pub trait RenderMultiple: 'static { + fn render(&mut self, args: Render) -> Result<()>; - fn layout(&mut self, f: &mut dyn FnMut(&dyn StyleFn) -> Option) -> Result<()>; + fn props(&self, f: PropsFn); + + fn layout(&mut self, f: LayoutFn) -> Result<()>; fn emit_event(&self, ipe: &IncomingPointerEvent) -> bool; fn len(&self) -> usize; } -pub trait Visitor { - fn visit(&mut self, em: &SharedEM) -> Result<()> +pub trait Visitor { + fn visit(&mut self, em: &ElementModel) -> Result<()> + where + El: ElementInterfaces; +} + +pub trait VisitorMut { + fn visit_mut(&mut self, em: &mut ElementModel) -> Result<()> where El: ElementInterfaces; } -impl RenderMultiple for T +impl RenderMultiple for T where - T: VisitBy, + T: VisitBy, { - fn render(&mut self, lr: &mut LayerRebuilder, interval: Duration) -> Result<()> { - struct Render<'a, 'b> { - lr: &'a mut LayerRebuilder<'b>, - interval: Duration, - } + fn render(&mut self, args: Render) -> Result<()> { + struct Vis<'a>(Render<'a>); - impl Visitor for Render<'_, '_> { - fn visit(&mut self, em: &SharedEM) -> Result<()> + impl VisitorMut for Vis<'_> { + fn visit_mut(&mut self, em: &mut ElementModel) -> Result<()> where El: ElementInterfaces, { em.shared.redraw_signal_sent.set(false); - match &em.shared.render_on { - RenderOn::NewLayer { layer, .. } => self.lr.append_layer(layer), - RenderOn::ParentLayer(_) => em.monitoring_render(self.lr, self.interval), + let draw_region = em.shared.draw_region.get(); + if draw_region.intersects(self.0.dirty_zone) { + em.render(self.0) + } else { + Ok(()) } } } - self.visit(&mut Render { lr, interval }) + self.visit_mut(&mut Vis(args)) } - fn peek_styles(&self, f: &mut dyn FnMut(&dyn StyleFn)) { - struct PeekStyles(F); + fn props(&self, f: PropsFn) { + struct Vis<'a, Cp>(PropsFn<'a, Cp>); - impl Visitor for PeekStyles - where - F: FnMut(&dyn StyleFn), - { - fn visit(&mut self, em: &SharedEM) -> Result<()> + impl Visitor for Vis<'_, Cp> { + fn visit(&mut self, em: &ElementModel) -> Result<()> where El: ElementInterfaces, { - (self.0)(&em.shared.styles); + (self.0)(&em.child_props); Ok(()) } } - self.visit(&mut PeekStyles(f)).unwrap() + self.visit(&mut Vis(f)).unwrap() } - fn layout(&mut self, f: &mut dyn FnMut(&dyn StyleFn) -> Option) -> Result<()> { - struct Layout(F); + fn layout(&mut self, f: LayoutFn) -> Result<()> { + struct Vis<'a, Cp>(LayoutFn<'a, Cp>); - impl Visitor for Layout - where - F: FnMut(&dyn StyleFn) -> Option, - { - fn visit(&mut self, em: &SharedEM) -> Result<()> + impl VisitorMut for Vis<'_, Cp> { + fn visit_mut(&mut self, em: &ElementModel) -> Result<()> where El: ElementInterfaces, { - let option = (self.0)(&em.shared.styles); + let option = (self.0)(&em.child_props); match option { Some(region) => { let old_region = em.shared.draw_region.get(); if region != old_region { em.set_draw_region(region); - em.request_redraw(); + em.request_redraw(); // TODO: 是否需要重绘? } Ok(()) @@ -122,17 +126,17 @@ where } } - self.visit(&mut Layout(f)) + self.visit(&mut Vis(f)) } - fn emit_event(&self, ipe: &IncomingPointerEvent) -> bool { - struct EmitEvent<'a> { + fn emit_event(&mut self, ipe: &IncomingPointerEvent) -> bool { + struct Vis<'a> { children_entered: bool, ipe: &'a IncomingPointerEvent<'a>, } - impl Visitor for EmitEvent<'_> { - fn visit(&mut self, em: &SharedEM) -> Result<()> + impl VisitorMut for Vis<'_> { + fn visit_mut(&mut self, em: &ElementModel) -> Result<()> where El: ElementInterfaces, { @@ -141,20 +145,20 @@ where } } - let mut ee = EmitEvent { + let mut ee = Vis { children_entered: false, ipe, }; - self.visit(&mut ee).unwrap(); + self.visit_mut(&mut ee).unwrap(); ee.children_entered } fn len(&self) -> usize { - struct VisitLength(usize); + struct Vis(usize); - impl Visitor for VisitLength { - fn visit(&mut self, _: &SharedEM) -> Result<()> + impl Visitor for Vis { + fn visit(&mut self, _: &ElementModel) -> Result<()> where El: ElementInterfaces, { @@ -163,14 +167,14 @@ where } } - let mut visitor = VisitLength(0); + let mut visitor = Vis(0); self.visit(&mut visitor).unwrap(); visitor.0 } } pub trait StructureCreate { - type Target: VisitBy; + type Target; fn create(self, ctx: &EMCreateCtx) -> Self::Target; } @@ -178,9 +182,9 @@ pub trait StructureCreate { impl StructureCreate for F where F: FnOnce(&EMCreateCtx) -> R, - R: VisitBy, { type Target = R; + fn create(self, ctx: &EMCreateCtx) -> Self::Target { self(ctx) } diff --git a/irisia/src/structure/pat_match.rs b/irisia/src/structure/pat_match.rs index 06b4fd5..432da31 100644 --- a/irisia/src/structure/pat_match.rs +++ b/irisia/src/structure/pat_match.rs @@ -18,24 +18,11 @@ pub struct PatMatch { or_else: S2, } -impl VisitBy for PatMatch -where - T: Clone + 'static, - F1: FnOnce(ReadWire) -> S1 + 'static, - S1: VisitBy, - S2: VisitBy, -{ - fn visit(&self, v: &mut V) -> crate::Result<()> - where - V: super::Visitor, - { - if self.cond.read().is_none() { - return self.or_else.visit(v); - } - +impl PatMatch { + fn init_if_need(&self) { let borrowed = self.if_selected.borrow(); match &*borrowed { - IfSelected::Initialized(branch) => return branch.visit(v), + IfSelected::Initialized(_) => return, IfSelected::Intermediate => panic!( "thread was panicked during last updating, this structure should not be used anymore" ), @@ -66,10 +53,46 @@ where ) }; - let tree = creator(value_wire); - let result = tree.visit(v); - *borrow_mut = IfSelected::Initialized(tree); - result + *borrow_mut = IfSelected::Initialized(creator(value_wire)); + } +} + +impl VisitBy for PatMatch +where + T: Clone + 'static, + F1: FnOnce(ReadWire) -> S1 + 'static, + S1: VisitBy, + S2: VisitBy, +{ + fn visit(&self, v: &mut V) -> crate::Result<()> + where + V: super::Visitor, + { + if self.cond.read().is_none() { + return self.or_else.visit(v); + } + + self.init_if_need(); + if let IfSelected::Initialized(x) = &*self.if_selected.borrow() { + x.visit(v) + } else { + unreachable!(); + } + } + + fn visit_mut(&mut self, v: &mut V) -> crate::Result<()> + where + V: super::Visitor, + { + if self.cond.read().is_none() { + return self.or_else.visit_mut(v); + } + + if let IfSelected::Initialized(x) = &mut *self.if_selected.borrow_mut() { + x.visit_mut(v) + } else { + unreachable!(); + } } } diff --git a/irisia/src/structure/repeat.rs b/irisia/src/structure/repeat.rs index 2a4ae4b..c89caa0 100644 --- a/irisia/src/structure/repeat.rs +++ b/irisia/src/structure/repeat.rs @@ -16,12 +16,11 @@ use super::{StructureCreate, VisitBy}; const MAX_TIME_TO_LIVE: u8 = 3; -struct Repeat(ReadWire>); - -struct RepeatInner { +pub struct Repeat { + order: ReadWire>, + //dirty: map: HashMap>, ctx: EMCreateCtx, - order: Vec, } struct Item { @@ -30,11 +29,11 @@ struct Item { time_to_live: u8, } -impl VisitBy for Repeat +impl VisitBy for Repeat where K: Hash + Eq + 'static, T: 'static, - Tree: VisitBy, + Tree: VisitBy, { fn visit(&self, v: &mut V) -> crate::Result<()> where @@ -48,15 +47,30 @@ where Ok(()) } + + fn visit_mut(&mut self, v: &mut V) -> crate::Result<()> + where + V: super::Visitor, + { + let this = self.0.read(); + + for key in &this.order { + this.map.get_mut(key).unwrap().tree.visit_mut(v)?; + } + + Ok(()) + } } pub struct RepeatMutator<'a, K, T, Tree>(&'a mut RepeatInner); -impl<'a, K, Item, Tree> RepeatMutator<'a, K, Item, Tree> { +impl<'a, K, Item, Tree> RepeatMutator<'a, K, Item, Tree> +where + K: Hash + Eq + Clone, + Item: 'static, +{ pub fn update(self, iter: Iter, key_fn: Fk, content_fn: F) where - K: Hash + Eq + Clone, - Item: 'static, Iter: IntoIterator, Fk: Fn(&Item) -> K, F: Fn(ReadWire) -> Upd, diff --git a/irisia/src/structure/single.rs b/irisia/src/structure/single.rs index 1ad3c7a..3bf69bb 100644 --- a/irisia/src/structure/single.rs +++ b/irisia/src/structure/single.rs @@ -1,29 +1,28 @@ use super::{StructureCreate, VisitBy}; use crate::{ - el_model::{EMCreateCtx, ElementAccess, ElementModel, SharedEM}, + el_model::{EMCreateCtx, ElementAccess, ElementModel}, element::FromUserProps, - style::StyleFn, ElementInterfaces, }; -pub fn single<'a, El>( +pub fn single<'a, El, Cp>( props: as FromUserProps>::Props, - styles: impl StyleFn + 'static, + child_props: Cp, slot: impl StructureCreate + 'a, on_create: impl FnOnce(ElementAccess) + 'a, -) -> impl StructureCreate> + 'a +) -> impl StructureCreate> + 'a where El: ElementInterfaces, { move |context: &EMCreateCtx| { let props = as FromUserProps>::take(props); - let em = ElementModel::new(context, props, styles, slot); + let em = ElementModel::new(context, props, child_props, slot); on_create(em.access()); em } } -impl VisitBy for SharedEM +impl VisitBy for ElementModel where El: ElementInterfaces, { @@ -33,4 +32,11 @@ where { v.visit(self) } + + fn visit_mut(&mut self, v: &mut V) -> crate::Result<()> + where + V: super::VisitorMut, + { + v.visit_mut(self) + } } diff --git a/irisia/src/style/mod.rs b/irisia/src/style/mod.rs deleted file mode 100644 index c1a5f52..0000000 --- a/irisia/src/style/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -use reader::ParseRule; - -pub use value::StyleValue; - -mod reader; -pub mod value; - -pub type ReadStyleFn<'a> = &'a mut dyn FnMut(ParseRule); - -pub struct StyleBuffer<'a>(ReadStyleFn<'a>); - -impl StyleBuffer<'_> { - pub fn write(&mut self, rule_name: &str, body: &[StyleValue]) { - (self.0)(ParseRule::new(rule_name, body)) - } -} - -pub trait StyleFn { - fn read(&self, f: ReadStyleFn); -} - -impl StyleFn for F -where - F: Fn(StyleBuffer), -{ - fn read(&self, f: ReadStyleFn) { - self(StyleBuffer(f)) - } -} - -impl StyleFn for () { - fn read(&self, _: ReadStyleFn) {} -} diff --git a/irisia/src/style/reader.rs b/irisia/src/style/reader.rs deleted file mode 100644 index 69934ee..0000000 --- a/irisia/src/style/reader.rs +++ /dev/null @@ -1,62 +0,0 @@ -use anyhow::{anyhow, Result}; - -use crate::style::value::Eof; - -use super::{value::ParseStyleValue, StyleValue}; - -#[derive(Clone)] -#[must_use] -pub struct ParseRule<'a> { - rule_name: &'a str, - stream: &'a [StyleValue], -} - -impl<'a> ParseRule<'a> { - pub(super) fn new(rule_name: &'a str, stream: &'a [StyleValue]) -> Self { - Self { rule_name, stream } - } - - pub fn name(&self) -> &'a str { - self.rule_name - } - - pub fn try_parse(&mut self) -> Option { - let (result, rest) = T::try_parse(self.stream)?; - self.stream = rest; - Some(result) - } - - pub fn parse(&mut self) -> Result { - self.try_parse().ok_or_else(|| { - let found = if let Some(first) = self.stream.first() { - first.type_name() - } else { - Eof::type_name() - }; - anyhow!("expect {}, found {found}", T::type_name()) - }) - } - - pub fn peek(&self) -> Option { - T::try_parse(self.stream).map(|(x, _)| x) - } - - pub fn is_empty(&self) -> bool { - self.stream.is_empty() - } - - pub fn ignore_rest(mut self) { - self.stream = &[]; - } -} - -impl Drop for ParseRule<'_> { - fn drop(&mut self) { - if !self.is_empty() { - panic!( - "drop check failed: there still values remain in the stream. \ - if it is expected, call `Self::ignore_rest` explictly." - ); - } - } -} diff --git a/irisia/src/style/value.rs b/irisia/src/style/value.rs deleted file mode 100644 index 7629f85..0000000 --- a/irisia/src/style/value.rs +++ /dev/null @@ -1,227 +0,0 @@ -use std::{fmt::Write, ops::Deref, rc::Rc}; - -use crate::primitive::Length; -use anyhow::Error; -use irisia_backend::skia_safe::Color; - -#[derive(Clone)] -pub enum StyleValue { - Color(Color), - Length(Length), - Float(f32), - Bool(bool), - Ident(Ident), - Delimiter, - KeyEq(KeyEq), -} - -impl StyleValue { - pub const fn type_name(&self) -> &'static str { - match self { - Self::Color(_) => "color", - Self::Length(_) => "length", - Self::Float(_) => "float", - Self::Bool(_) => "bool", - Self::Ident(_) => "ident", - Self::Delimiter => "delimiter", - Self::KeyEq(_) => "key equal", - } - } -} - -#[derive(Clone, Copy)] -pub struct Delimiter; - -#[derive(Clone, Copy)] -pub struct Eof(()); - -pub trait ParseStyleValue: Clone { - fn try_parse(this: &[StyleValue]) -> Option<(Self, &[StyleValue])>; - fn type_name() -> &'static str; -} - -macro_rules! impl_psv { - ($($Var:ident $type_name:literal $Type:ty,)*) => { - $( - impl ParseStyleValue for $Type { - fn try_parse(this: &[StyleValue]) -> Option<(Self, &[StyleValue])> { - if let [StyleValue::$Var(val), ref rest @ ..] = this { - Some((val.clone(), rest)) - } else { - None - } - } - - fn type_name() -> &'static str { - $type_name - } - } - )* - }; -} - -impl_psv! { - Color "color" Color , - Length "length" Length, - Float "float" f32 , - Bool "bool" bool , - Ident "ident" Ident , -} - -impl ParseStyleValue for Delimiter { - fn try_parse(this: &[StyleValue]) -> Option<(Self, &[StyleValue])> { - if let [StyleValue::Delimiter, ref rest @ ..] = this { - Some((Delimiter, rest)) - } else { - None - } - } - - fn type_name() -> &'static str { - "delimiter" - } -} - -impl ParseStyleValue for Eof { - fn try_parse(this: &[StyleValue]) -> Option<(Self, &[StyleValue])> { - if this.is_empty() { - Some((Eof(()), this)) - } else { - None - } - } - - fn type_name() -> &'static str { - "end of stream" - } -} - -impl ParseStyleValue for StyleValue { - fn try_parse(this: &[StyleValue]) -> Option<(Self, &[StyleValue])> { - match this.split_first() { - Some((StyleValue::KeyEq(_), _)) | None => None, - Some((value, rest)) => Some((value.clone(), rest)), - } - } - - fn type_name() -> &'static str { - "any value" - } -} - -impl ParseStyleValue for (KeyEq, T) -where - T: ParseStyleValue, -{ - fn try_parse(this: &[StyleValue]) -> Option<(Self, &[StyleValue])> { - let [StyleValue::KeyEq(key), rest @ ..] = this else { - return None; - }; - - let (value, rest) = T::try_parse(rest)?; - Some(((key.clone(), value), rest)) - } - - fn type_name() -> &'static str { - "key-value" - } -} - -macro_rules! impl_from { - ($($Var:ident $Type:ty,)*) => { - $( - impl From<$Type> for StyleValue { - fn from(value: $Type) -> Self { - Self::$Var(value) - } - } - )* - }; -} - -impl_from! { - Color Color, - Length Length, - Float f32, - Bool bool, - KeyEq KeyEq, -} - -impl From<&'static str> for StyleValue { - fn from(value: &'static str) -> Self { - Self::Ident(Ident::new(value)) - } -} - -impl From for StyleValue { - fn from(_: Delimiter) -> Self { - Self::Delimiter - } -} - -#[derive(Clone)] -pub struct Ident(IdentInner); - -#[derive(Clone)] -enum IdentInner { - Borrowed(&'static str), - Rc(Rc), -} - -impl Ident { - pub const fn new(ident: &'static str) -> Self { - Self(IdentInner::Borrowed(ident)) - } - - /// Do not use this unless for debug usage - pub fn new_debug(ident: &str) -> Self { - Self(IdentInner::Rc(ident.into())) - } - - pub fn error(&self, expected: &[&str]) -> Error { - let mut s = "expected identifier".to_string(); - if let Some(last_index) = expected.len().checked_sub(1) { - for (index, &ident) in expected.iter().enumerate() { - let spliter = if index == 0 { - " " - } else if index == last_index { - " or " - } else { - ", " - }; - write!(&mut s, "{spliter}`{ident}`").unwrap(); - } - } else { - s += "matches nothing"; - }; - - write!(&mut s, ", found {}`", &**self).unwrap(); - Error::msg(s) - } -} - -impl Deref for Ident { - type Target = str; - fn deref(&self) -> &Self::Target { - match &self.0 { - &IdentInner::Borrowed(b) => b, - IdentInner::Rc(r) => r, - } - } -} - -#[derive(Clone)] -pub struct KeyEq(Ident); - -impl KeyEq { - pub const fn new(key: Ident) -> Self { - Self(key) - } -} - -impl Deref for KeyEq { - type Target = str; - fn deref(&self) -> &Self::Target { - &self.0 - } -}