mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-29 05:14:48 +00:00
Implement property declarations for the C++ backend
This commit is contained in:
parent
5a7a95dbc8
commit
0932953ac8
4 changed files with 88 additions and 13 deletions
|
@ -77,7 +77,8 @@ Hello := Rectangle {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
counter := Text { x: 100; y: 300; text: "0"; color: black; }
|
property<int32> counter;
|
||||||
|
counter_label := Text { x: 100; y: 300; text: "0"; color: black; }
|
||||||
ButtonRectangle {
|
ButtonRectangle {
|
||||||
color: 4289374890;
|
color: 4289374890;
|
||||||
x: 50;
|
x: 50;
|
||||||
|
|
|
@ -4,24 +4,24 @@
|
||||||
int main() {
|
int main() {
|
||||||
static Hello component;
|
static Hello component;
|
||||||
|
|
||||||
static int counter = 0;
|
|
||||||
|
|
||||||
component._foobar.set_handler([](auto...){
|
component._foobar.set_handler([](auto...){
|
||||||
std::cout << "Hello from C++" << std::endl;
|
std::cout << "Hello from C++" << std::endl;
|
||||||
});
|
});
|
||||||
|
|
||||||
component._plus_clicked.set_handler([](auto...){
|
component._plus_clicked.set_handler([](auto...){
|
||||||
counter += 1;
|
auto &counter = component.property_0_counter;
|
||||||
|
counter.set(counter.get() + 1);
|
||||||
// FIXME: this _13 is an internal detail and should be private anyway. We muse use some
|
// FIXME: this _13 is an internal detail and should be private anyway. We muse use some
|
||||||
// alias or way to expose the property (same for the _ before signals)
|
// alias or way to expose the property (same for the _ before signals)
|
||||||
component.counter_13.text.set(std::string_view(std::to_string(counter)));
|
component.counter_label_13.text.set(std::string_view(std::to_string(counter.get())));
|
||||||
std::cout << "PLUS: " << std::string_view(component.counter_13.text.get()) << std::endl;
|
std::cout << "PLUS: " << std::string_view(component.counter_label_13.text.get()) << std::endl;
|
||||||
});
|
});
|
||||||
|
|
||||||
component._minus_clicked.set_handler([](auto...){
|
component._minus_clicked.set_handler([](auto...){
|
||||||
counter -= 1;
|
auto &counter = component.property_0_counter;
|
||||||
component.counter_13.text.set(std::string_view(std::to_string(counter)));
|
counter.set(counter.get() - 1);
|
||||||
std::cout << "MINUS: " << std::string_view(component.counter_13.text.get()) << std::endl;
|
component.counter_label_13.text.set(std::string_view(std::to_string(counter.get())));
|
||||||
|
std::cout << "MINUS: " << std::string_view(component.counter_label_13.text.get()) << std::endl;
|
||||||
});
|
});
|
||||||
|
|
||||||
sixtyfps::run(&component);
|
sixtyfps::run(&component);
|
||||||
|
|
|
@ -121,12 +121,35 @@ mod cpp_ast {
|
||||||
writeln!(f, ";")
|
writeln!(f, ";")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait CppType {
|
||||||
|
fn cpp_type(&self) -> Option<&str>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::lower::{LoweredComponent, LoweredItem};
|
use crate::lower::{LoweredComponent, LoweredItem};
|
||||||
|
use crate::typeregister::Type;
|
||||||
use cpp_ast::*;
|
use cpp_ast::*;
|
||||||
|
|
||||||
fn handle_item(item: &LoweredItem, main_struct: &mut Struct, init: &mut Vec<String>) {
|
impl CppType for Type {
|
||||||
|
fn cpp_type(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Type::Float32 => Some("float"),
|
||||||
|
Type::Int32 => Some("int"),
|
||||||
|
Type::String => Some("sixtyfps::SharedString"),
|
||||||
|
Type::Color => Some("uint32_t"),
|
||||||
|
Type::Bool => Some("bool"),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_item(
|
||||||
|
item: &LoweredItem,
|
||||||
|
global_properties: &Vec<String>,
|
||||||
|
main_struct: &mut Struct,
|
||||||
|
init: &mut Vec<String>,
|
||||||
|
) {
|
||||||
main_struct.members.push(Declaration::Var(Var {
|
main_struct.members.push(Declaration::Var(Var {
|
||||||
ty: format!("sixtyfps::{}", item.native_type.class_name),
|
ty: format!("sixtyfps::{}", item.native_type.class_name),
|
||||||
name: item.id.clone(),
|
name: item.id.clone(),
|
||||||
|
@ -135,13 +158,19 @@ fn handle_item(item: &LoweredItem, main_struct: &mut Struct, init: &mut Vec<Stri
|
||||||
|
|
||||||
let id = &item.id;
|
let id = &item.id;
|
||||||
init.extend(item.init_properties.iter().map(|(s, i)| {
|
init.extend(item.init_properties.iter().map(|(s, i)| {
|
||||||
|
let cpp_prop = item
|
||||||
|
.property_declarations
|
||||||
|
.get(s)
|
||||||
|
.map(|idx| global_properties[*idx].clone())
|
||||||
|
.unwrap_or_else(|| format!("{id}.{prop}", id = id, prop = s.clone()));
|
||||||
|
|
||||||
use crate::expression_tree::Expression::*;
|
use crate::expression_tree::Expression::*;
|
||||||
let init = match &i {
|
let init = match &i {
|
||||||
StringLiteral(s) => format!(r#"sixtyfps::SharedString("{}")"#, s.escape_default()),
|
StringLiteral(s) => format!(r#"sixtyfps::SharedString("{}")"#, s.escape_default()),
|
||||||
NumberLiteral(n) => n.to_string(),
|
NumberLiteral(n) => n.to_string(),
|
||||||
_ => format!("\n#error: unsupported expression {:?}\n", i),
|
_ => format!("\n#error: unsupported expression {:?}\n", i),
|
||||||
};
|
};
|
||||||
format!("{id}.{prop}.set({init});", id = id, prop = s, init = init)
|
format!("{cpp_prop}.set({init});", cpp_prop = cpp_prop, init = init)
|
||||||
}));
|
}));
|
||||||
init.extend(item.connect_signals.iter().map(|(s, fwd)| {
|
init.extend(item.connect_signals.iter().map(|(s, fwd)| {
|
||||||
format!(
|
format!(
|
||||||
|
@ -151,7 +180,7 @@ fn handle_item(item: &LoweredItem, main_struct: &mut Struct, init: &mut Vec<Stri
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for i in &item.children {
|
for i in &item.children {
|
||||||
handle_item(i, main_struct, init)
|
handle_item(i, global_properties, main_struct, init)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +192,31 @@ pub fn generate(component: &LoweredComponent) -> impl std::fmt::Display {
|
||||||
|
|
||||||
let mut main_struct = Struct { name: component.id.clone(), ..Default::default() };
|
let mut main_struct = Struct { name: component.id.clone(), ..Default::default() };
|
||||||
|
|
||||||
|
let (declared_property_members, declared_property_vars): (Vec<String>, Vec<Declaration>) =
|
||||||
|
component
|
||||||
|
.property_declarations
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, property)| {
|
||||||
|
let cpp_name: String = format!("property_{}_{}", index, property.name_hint).into();
|
||||||
|
(
|
||||||
|
cpp_name.clone(),
|
||||||
|
Declaration::Var(Var {
|
||||||
|
ty: format!(
|
||||||
|
"sixtyfps::Property<{}>",
|
||||||
|
property.property_type.cpp_type().expect("cannot convert type to C++")
|
||||||
|
),
|
||||||
|
name: cpp_name,
|
||||||
|
init: None,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unzip();
|
||||||
|
|
||||||
|
main_struct.members.extend(declared_property_vars);
|
||||||
|
|
||||||
let mut init = Vec::new();
|
let mut init = Vec::new();
|
||||||
handle_item(&component.root_item, &mut main_struct, &mut init);
|
handle_item(&component.root_item, &declared_property_members, &mut main_struct, &mut init);
|
||||||
|
|
||||||
main_struct.members.extend(component.signals_declarations.iter().map(|s| {
|
main_struct.members.extend(component.signals_declarations.iter().map(|s| {
|
||||||
Declaration::Var(Var { ty: "sixtyfps::Signal".into(), name: s.clone(), init: None })
|
Declaration::Var(Var { ty: "sixtyfps::Signal".into(), name: s.clone(), init: None })
|
||||||
|
|
|
@ -15,6 +15,8 @@ pub struct NativeItemType {
|
||||||
pub class_name: String,
|
pub class_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type LoweredPropertyDeclarationIndex = usize;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct LoweredItem {
|
pub struct LoweredItem {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
@ -22,6 +24,7 @@ pub struct LoweredItem {
|
||||||
pub init_properties: HashMap<String, Expression>,
|
pub init_properties: HashMap<String, Expression>,
|
||||||
/// Right now we only allow forwarding and this connect with the signal in the root
|
/// Right now we only allow forwarding and this connect with the signal in the root
|
||||||
pub connect_signals: HashMap<String, String>,
|
pub connect_signals: HashMap<String, String>,
|
||||||
|
pub property_declarations: HashMap<String, LoweredPropertyDeclarationIndex>,
|
||||||
pub children: Vec<LoweredItem>,
|
pub children: Vec<LoweredItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +34,7 @@ pub struct LoweredComponent {
|
||||||
pub root_item: LoweredItem,
|
pub root_item: LoweredItem,
|
||||||
|
|
||||||
pub signals_declarations: Vec<String>,
|
pub signals_declarations: Vec<String>,
|
||||||
|
pub property_declarations: Vec<LoweredPropertyDeclaration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoweredComponent {
|
impl LoweredComponent {
|
||||||
|
@ -40,6 +44,7 @@ impl LoweredComponent {
|
||||||
id: component.id.clone(),
|
id: component.id.clone(),
|
||||||
root_item: LoweredComponent::lower_item(&*component.root_element.borrow(), &mut state),
|
root_item: LoweredComponent::lower_item(&*component.root_element.borrow(), &mut state),
|
||||||
signals_declarations: state.signals,
|
signals_declarations: state.signals,
|
||||||
|
property_declarations: state.property_declarations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +77,16 @@ impl LoweredComponent {
|
||||||
let current_component_id = state.current_component_id.clone();
|
let current_component_id = state.current_component_id.clone();
|
||||||
let format_signal = |name| format!("{}_{}", current_component_id, name);
|
let format_signal = |name| format!("{}_{}", current_component_id, name);
|
||||||
state.signals.extend(element.signals_declaration.iter().map(format_signal));
|
state.signals.extend(element.signals_declaration.iter().map(format_signal));
|
||||||
|
|
||||||
|
for (prop_name, property_type) in element.property_declarations.iter() {
|
||||||
|
let component_global_index = state.property_declarations.len();
|
||||||
|
lowered.property_declarations.insert(prop_name.clone(), component_global_index);
|
||||||
|
state.property_declarations.push(LoweredPropertyDeclaration {
|
||||||
|
property_type: property_type.clone(),
|
||||||
|
name_hint: prop_name.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (k, e) in element.bindings.iter() {
|
for (k, e) in element.bindings.iter() {
|
||||||
if let Expression::SignalReference { name, .. } = e {
|
if let Expression::SignalReference { name, .. } = e {
|
||||||
lowered.connect_signals.insert(
|
lowered.connect_signals.insert(
|
||||||
|
@ -89,6 +104,12 @@ impl LoweredComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LoweredPropertyDeclaration {
|
||||||
|
pub property_type: Type,
|
||||||
|
pub name_hint: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct LowererState {
|
struct LowererState {
|
||||||
/// The count of item to create the ids
|
/// The count of item to create the ids
|
||||||
|
@ -97,4 +118,5 @@ struct LowererState {
|
||||||
current_component_id: String,
|
current_component_id: String,
|
||||||
|
|
||||||
signals: Vec<String>,
|
signals: Vec<String>,
|
||||||
|
property_declarations: Vec<LoweredPropertyDeclaration>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue