Layout for rust

This commit is contained in:
Olivier Goffart 2020-06-10 18:26:00 +02:00
parent 96a372e45d
commit 907bea3d3b
7 changed files with 122 additions and 30 deletions

View file

@ -71,11 +71,15 @@ pub mod re_exports {
pub use const_field_offset::{self, FieldOffsets}; pub use const_field_offset::{self, FieldOffsets};
pub use once_cell::sync::Lazy; pub use once_cell::sync::Lazy;
pub use sixtyfps_corelib::abi::datastructures::{ pub use sixtyfps_corelib::abi::datastructures::{
Component, ComponentTO, ComponentVTable, ItemTreeNode, LayoutInfo, Component, ComponentRef, ComponentTO, ComponentVTable, ItemTreeNode, LayoutInfo,
}; };
pub use sixtyfps_corelib::abi::primitives::*; pub use sixtyfps_corelib::abi::primitives::*;
pub use sixtyfps_corelib::abi::properties::Property; pub use sixtyfps_corelib::abi::properties::Property;
pub use sixtyfps_corelib::abi::signals::Signal; pub use sixtyfps_corelib::abi::signals::Signal;
pub use sixtyfps_corelib::abi::slice::Slice;
pub use sixtyfps_corelib::layout::{
solve_grid_layout, Constraint, GridLayoutCellData, GridLayoutData,
};
pub use sixtyfps_corelib::ComponentVTable_static; pub use sixtyfps_corelib::ComponentVTable_static;
pub use sixtyfps_corelib::EvaluationContext; pub use sixtyfps_corelib::EvaluationContext;
pub use sixtyfps_corelib::Resource; pub use sixtyfps_corelib::Resource;

View file

@ -84,7 +84,7 @@ pub fn compile(path: impl AsRef<std::path::Path>) -> Result<(), CompileError> {
CompileError::CompileError(vec) CompileError::CompileError(vec)
})?; })?;
write!(file, "{}", generated).map_err(CompileError::SaveError)?; write!(file, "{}", generated).map_err(CompileError::SaveError)?;
println!("cargo:rerun-if-changed={}", path.to_string_lossy()); println!("cargo:rerun-if-changed={}", path.display());
println!("cargo:rustc-env=SIXTYFPS_INCLUDE_GENERATED={}", output_file_path.to_string_lossy()); println!("cargo:rustc-env=SIXTYFPS_INCLUDE_GENERATED={}", output_file_path.display());
Ok(()) Ok(())
} }

View file

@ -26,8 +26,8 @@ component ButtonRectangle := Rectangle {
height: 75; height: 75;
color: button_area.pressed ? red : button_color; color: button_area.pressed ? red : button_color;
button_area := TouchArea { button_area := TouchArea {
width: 100; width: root.width;
height: 75; height: root.height;
clicked => { root.clicked() } clicked => { root.clicked() }
} }
Text { Text {
@ -72,22 +72,34 @@ Hello := Rectangle {
source: img!"../graphicstest/logo.png"; source: img!"../graphicstest/logo.png";
} }
ButtonRectangle { property<int32> counter;
button_color: 4289374890;
Rectangle {
x: 50; x: 50;
y: 225; y: 225;
clicked => { counter += 1 } width: 100;
button_text: "+"; height: 225;
}
property<int32> counter;
counter_label := Text { x: 100; y: 300; text: counter; color: black; }
ButtonRectangle {
button_color: 4289374890;
x: 50;
y: 350;
clicked => { minus_clicked() }
button_text: "-";
}
GridLayout {
Row {
ButtonRectangle {
button_color: 4289374890;
clicked => { counter += 1 }
button_text: "+";
}
}
Row {
counter_label := Text { text: counter; color: black; }
}
Row {
ButtonRectangle {
button_color: 4289374890;
clicked => { minus_clicked() }
button_text: "-";
}
}
}
}
} }

View file

@ -124,6 +124,8 @@ pub fn generate(component: &Component, diag: &mut Diagnostics) -> Option<TokenSt
}) })
.collect(); .collect();
let layouts = compute_layout(component);
Some(quote!( Some(quote!(
#(#resource_symbols)* #(#resource_symbols)*
@ -158,11 +160,8 @@ pub fn generate(component: &Component, diag: &mut Diagnostics) -> Option<TokenSt
fn create() -> Self { fn create() -> Self {
Default::default() Default::default()
} }
fn layout_info(&self) -> sixtyfps::re_exports::LayoutInfo {
todo!("Implement in rust.rs")
}
fn compute_layout(&self) { todo!("Implement in rust.rs") }
#layouts
} }
impl #component_id{ impl #component_id{
@ -255,3 +254,71 @@ fn compile_expression(e: &Expression, component: &Component) -> TokenStream {
} }
} }
} }
fn compute_layout(component: &Component) -> TokenStream {
let mut layouts = vec![];
for x in component.layout_constraints.borrow().0.iter() {
let within = quote::format_ident!("{}", x.within.borrow().id);
let row_constraint = vec![quote!(Constraint::default()); x.row_count()];
let col_constraint = vec![quote!(Constraint::default()); x.col_count()];
let cells = x
.elems
.iter()
.map(|x| {
x.iter()
.map(|y| {
y.as_ref()
.map(|elem| {
let e = quote::format_ident!("{}", elem.borrow().id);
let p = |n: &str| {
if elem.borrow().lookup_property(n) == Type::Float32 {
let n = quote::format_ident!("{}", n);
quote! {&self.#e.#n}
} else {
quote! {&dummy}
}
};
let width = p("width");
let height = p("height");
let x = p("x");
let y = p("y");
quote!(Some(GridLayoutCellData {
x: #x,
y: #y,
width: #width,
height: #height,
}))
})
.unwrap_or_else(|| quote!(None))
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
layouts.push(quote! {
solve_grid_layout(&GridLayoutData {
row_constraint: Slice::from_slice(&[#(#row_constraint),*]),
col_constraint: Slice::from_slice(&[#(#col_constraint),*]),
width: self.#within.width.get(&eval_context),
height: self.#within.height.get(&eval_context),
x: 0.,
y: 0.,
cells: Slice::from_slice(&[#( Slice::from_slice(&[#( #cells ),*])),*]),
});
});
}
quote! {
fn layout_info(&self) -> sixtyfps::re_exports::LayoutInfo {
todo!("Implement in rust.rs")
}
fn compute_layout(&self) {
#![allow(unused)]
use sixtyfps::re_exports::*;
let eval_context = EvaluationContext{ component: ComponentRef::new(self) };
let dummy = Property::<f32>::default();
#(#layouts)*
}
}
}

View file

@ -17,3 +17,12 @@ pub struct GridLayout {
/// This is like a matrix of elements. /// This is like a matrix of elements.
pub elems: Vec<Vec<Option<Rc<RefCell<Element>>>>>, pub elems: Vec<Vec<Option<Rc<RefCell<Element>>>>>,
} }
impl GridLayout {
pub fn col_count(&self) -> usize {
self.elems.iter().map(|x| x.len()).max().unwrap_or(0)
}
pub fn row_count(&self) -> usize {
self.elems.len()
}
}

View file

@ -105,6 +105,9 @@ impl<GraphicsBackend: graphics::GraphicsBackend> MainWindow<GraphicsBackend> {
.. ..
} => *control_flow = winit::event_loop::ControlFlow::Exit, } => *control_flow = winit::event_loop::ControlFlow::Exit,
winit::event::Event::RedrawRequested(_) => { winit::event::Event::RedrawRequested(_) => {
// FIXME: we should do that only if some property change
component.compute_layout();
{ {
let mut rendering_primitives_builder = let mut rendering_primitives_builder =
graphics_backend.new_rendering_primitives_builder(); graphics_backend.new_rendering_primitives_builder();
@ -124,8 +127,6 @@ impl<GraphicsBackend: graphics::GraphicsBackend> MainWindow<GraphicsBackend> {
let context = EvaluationContext { component: component }; let context = EvaluationContext { component: component };
let mut frame = let mut frame =
graphics_backend.new_frame(size.width, size.height, &Color::WHITE); graphics_backend.new_frame(size.width, size.height, &Color::WHITE);
// FIXME: we should do that only if some property change
component.compute_layout();
render_function(component, &context, &mut frame, &mut rendering_cache); render_function(component, &context, &mut frame, &mut rendering_cache);
graphics_backend.present_frame(frame); graphics_backend.present_frame(frame);
} }

View file

@ -335,9 +335,8 @@ unsafe extern "C" fn compute_layout(component: ComponentRef) {
let mut col_constraint = vec![]; let mut col_constraint = vec![];
//let mut cells = vec![]; //let mut cells = vec![];
row_constraint.resize_with(it.elems.len(), Default::default); row_constraint.resize_with(it.row_count(), Default::default);
col_constraint col_constraint.resize_with(it.col_count(), Default::default);
.resize_with(it.elems.iter().map(|x| x.len()).max().unwrap_or(0), Default::default);
// Fixme: i guess we should use Option in the layout data // Fixme: i guess we should use Option in the layout data
let dummy = Property::<f32>::default(); let dummy = Property::<f32>::default();
@ -386,8 +385,8 @@ unsafe extern "C" fn compute_layout(component: ComponentRef) {
col_constraint: Slice::from(col_constraint.as_slice()), col_constraint: Slice::from(col_constraint.as_slice()),
width: within_prop("width"), width: within_prop("width"),
height: within_prop("height"), height: within_prop("height"),
x: within_prop("x"), x: 0.,
y: within_prop("y"), y: 0.,
cells: Slice::from(cells.as_slice()), cells: Slice::from(cells.as_slice()),
}); });
} }