diff --git a/api/sixtyfps-node/native/lib.rs b/api/sixtyfps-node/native/lib.rs index 487270817..1b7731598 100644 --- a/api/sixtyfps-node/native/lib.rs +++ b/api/sixtyfps-node/native/lib.rs @@ -150,6 +150,7 @@ fn to_js_value<'cx>( } js_object.as_value(cx) } + Value::Color(c) => JsNumber::new(cx, c.as_argb_encoded()).as_value(cx), }) } diff --git a/api/sixtyfps-rs/lib.rs b/api/sixtyfps-rs/lib.rs index 571268ee0..37b16b044 100644 --- a/api/sixtyfps-rs/lib.rs +++ b/api/sixtyfps-rs/lib.rs @@ -83,6 +83,7 @@ pub mod re_exports { pub use sixtyfps_corelib::layout::{ solve_grid_layout, Constraint, GridLayoutCellData, GridLayoutData, }; + pub use sixtyfps_corelib::Color; pub use sixtyfps_corelib::ComponentVTable_static; pub use sixtyfps_corelib::EvaluationContext; pub use sixtyfps_corelib::Resource; diff --git a/sixtyfps_compiler/generator/cpp.rs b/sixtyfps_compiler/generator/cpp.rs index 8fbf1ea3b..3b5a95606 100644 --- a/sixtyfps_compiler/generator/cpp.rs +++ b/sixtyfps_compiler/generator/cpp.rs @@ -140,7 +140,7 @@ impl CppType for Type { Type::Float32 => Some("float".to_owned()), Type::Int32 => Some("int".to_owned()), Type::String => Some("sixtyfps::SharedString".to_owned()), - Type::Color => Some("uint32_t".to_owned()), + Type::Color => Some("sixtyfps::internal::Color".to_owned()), Type::Bool => Some("bool".to_owned()), Type::Model => Some("std::shared_ptr".to_owned()), Type::Object(o) => { @@ -646,6 +646,14 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc({})", f) } (Type::Array(_), Type::Model) => f, + (Type::Float32, Type::Color) => { + let val = f.parse::().unwrap(); + let red = (val >> 16) as u8; + let green = (val >> 8) as u8; + let blue = val as u8; + let alpha = (val >> 24) as u8; + format!("sixtyfps::internal::Color{{{}, {}, {}, {}}}", red, green, blue, alpha) + } _ => f, } } diff --git a/sixtyfps_compiler/generator/rust.rs b/sixtyfps_compiler/generator/rust.rs index 53b433f9e..e5091b23b 100644 --- a/sixtyfps_compiler/generator/rust.rs +++ b/sixtyfps_compiler/generator/rust.rs @@ -18,7 +18,7 @@ fn rust_type( Type::Int32 => Ok(quote!(i32)), Type::Float32 => Ok(quote!(f32)), Type::String => Ok(quote!(sixtyfps::re_exports::SharedString)), - Type::Color => Ok(quote!(u32)), + Type::Color => Ok(quote!(sixtyfps::re_exports::Color)), Type::Bool => Ok(quote!(bool)), Type::Object(o) => { let elem = o.values().map(|v| rust_type(v, span)).collect::, _>>()?; @@ -459,6 +459,9 @@ fn compile_expression(e: &Expression, component: &Rc) -> TokenStream } (Type::Float32, Type::Model) | (Type::Int32, Type::Model) => quote!((0..#f as i32)), (Type::Array(_), Type::Model) => quote!(#f.iter().cloned()), + (Type::Float32, Type::Color) => { + quote!(sixtyfps::re_exports::Color::from(#f as u32)) + } _ => f, } } diff --git a/sixtyfps_runtime/corelib/abi/datastructures.rs b/sixtyfps_runtime/corelib/abi/datastructures.rs index bf994c919..7d93d8940 100644 --- a/sixtyfps_runtime/corelib/abi/datastructures.rs +++ b/sixtyfps_runtime/corelib/abi/datastructures.rs @@ -146,7 +146,7 @@ impl Default for LayoutInfo { } /// RGBA color -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug, Default)] #[repr(C)] pub struct Color { red: u8, @@ -190,12 +190,26 @@ impl Color { (self.red, self.green, self.blue, self.alpha) } + /// Returns `(alpha, red, green, blue)` encoded as u32 + pub fn as_argb_encoded(&self) -> u32 { + ((self.red as u32) << 16) + | ((self.green as u32) << 8) + | (self.blue as u32) + | ((self.alpha as u32) << 24) + } + /// A constant for the black color pub const BLACK: Color = Color::from_rgb(0, 0, 0); /// A constant for the white color pub const WHITE: Color = Color::from_rgb(255, 255, 255); } +impl From for Color { + fn from(encoded: u32) -> Self { + Color::from_argb_encoded(encoded) + } +} + /// A resource is a reference to binary data, for example images. They can be accessible on the file /// system or embedded in the resulting binary. Or they might be URLs to a web server and a downloaded /// is necessary before they can be used. diff --git a/sixtyfps_runtime/corelib/abi/primitives.rs b/sixtyfps_runtime/corelib/abi/primitives.rs index e85b3589c..14197343a 100644 --- a/sixtyfps_runtime/corelib/abi/primitives.rs +++ b/sixtyfps_runtime/corelib/abi/primitives.rs @@ -30,8 +30,7 @@ use corelib_macro::*; #[pin] /// The implementation of the `Rectangle` element pub struct Rectangle { - /// FIXME: make it a color - pub color: Property, + pub color: Property, pub x: Property, pub y: Property, pub width: Property, @@ -60,9 +59,7 @@ impl Item for Rectangle { y: Self::field_offsets().y.apply_pin(self).get(context), width, height, - color: Color::from_argb_encoded( - Self::field_offsets().color.apply_pin(self).get(context), - ), + color: Self::field_offsets().color.apply_pin(self).get(context), } } else { RenderingPrimitive::NoContents @@ -153,7 +150,7 @@ pub struct Text { pub text: Property, pub font_family: Property, pub font_pixel_size: Property, - pub color: Property, + pub color: Property, pub x: Property, pub y: Property, pub cached_rendering_data: CachedRenderingData, @@ -179,9 +176,7 @@ impl Item for Text { text: Self::field_offsets().text.apply_pin(self).get(context), font_family: Self::field_offsets().font_family.apply_pin(self).get(context), font_pixel_size: Self::field_offsets().font_pixel_size.apply_pin(self).get(context), - color: Color::from_argb_encoded( - Self::field_offsets().color.apply_pin(self).get(context), - ), + color: Self::field_offsets().color.apply_pin(self).get(context), } } diff --git a/sixtyfps_runtime/corelib/lib.rs b/sixtyfps_runtime/corelib/lib.rs index 42fe27854..11ab6c9fa 100644 --- a/sixtyfps_runtime/corelib/lib.rs +++ b/sixtyfps_runtime/corelib/lib.rs @@ -45,6 +45,9 @@ pub use abi::properties::{EvaluationContext, Property}; #[doc(inline)] pub use abi::signals::Signal; +#[doc(inline)] +pub use abi::datastructures::Color; + /// Type alias to the commonly use `Pin>>` pub type ComponentRefPin<'a> = core::pin::Pin>; diff --git a/sixtyfps_runtime/corelib/rtti.rs b/sixtyfps_runtime/corelib/rtti.rs index b863c3bec..d8ce00c80 100644 --- a/sixtyfps_runtime/corelib/rtti.rs +++ b/sixtyfps_runtime/corelib/rtti.rs @@ -12,7 +12,18 @@ macro_rules! declare_ValueType { pub trait ValueType: 'static $(+ TryInto<$ty> + TryFrom<$ty>)* {} }; } -declare_ValueType![bool, u32, u64, i32, i64, f32, f64, crate::SharedString, crate::Resource]; +declare_ValueType![ + bool, + u32, + u64, + i32, + i64, + f32, + f64, + crate::SharedString, + crate::Resource, + crate::Color +]; pub trait PropertyInfo { fn get(&self, item: Pin<&Item>, context: &crate::EvaluationContext) -> Result; diff --git a/sixtyfps_runtime/interpreter/dynamic_component.rs b/sixtyfps_runtime/interpreter/dynamic_component.rs index b6bd4ee02..60d4a3608 100644 --- a/sixtyfps_runtime/interpreter/dynamic_component.rs +++ b/sixtyfps_runtime/interpreter/dynamic_component.rs @@ -13,7 +13,7 @@ use sixtyfps_corelib::abi::primitives::PropertyAnimation; use sixtyfps_corelib::abi::slice::Slice; use sixtyfps_corelib::rtti::PropertyInfo; use sixtyfps_corelib::ComponentRefPin; -use sixtyfps_corelib::{rtti, EvaluationContext, Property, SharedString, Signal}; +use sixtyfps_corelib::{rtti, Color, EvaluationContext, Property, SharedString, Signal}; use std::collections::HashMap; use std::{pin::Pin, rc::Rc}; @@ -269,7 +269,7 @@ fn generate_component( Type::Float32 => animated_property_info::(), Type::Int32 => animated_property_info::(), Type::String => property_info::(), - Type::Color => property_info::(), + Type::Color => property_info::(), Type::Resource => property_info::(), Type::Bool => property_info::(), Type::Signal => { diff --git a/sixtyfps_runtime/interpreter/eval.rs b/sixtyfps_runtime/interpreter/eval.rs index 0f3d52e9e..13da92e39 100644 --- a/sixtyfps_runtime/interpreter/eval.rs +++ b/sixtyfps_runtime/interpreter/eval.rs @@ -4,8 +4,8 @@ use sixtyfps_compilerlib::expression_tree::{Expression, NamedReference}; use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type}; use sixtyfps_corelib as corelib; use sixtyfps_corelib::{ - abi::datastructures::ItemRef, abi::primitives::PropertyAnimation, EvaluationContext, Resource, - SharedString, + abi::datastructures::ItemRef, abi::primitives::PropertyAnimation, Color, EvaluationContext, + Resource, SharedString, }; use std::{collections::HashMap, rc::Rc}; @@ -62,6 +62,8 @@ pub enum Value { Array(Vec), /// An object Object(HashMap), + /// A color + Color(Color), } impl Default for Value { @@ -105,6 +107,7 @@ declare_value_conversion!(String => [SharedString] ); declare_value_conversion!(Bool => [bool] ); declare_value_conversion!(Resource => [Resource] ); declare_value_conversion!(Object => [HashMap] ); +declare_value_conversion!(Color => [Color] ); /// Evaluate an expression and return a Value as the result of this expression pub fn eval_expression( @@ -186,6 +189,7 @@ pub fn eval_expression( (Value::Number(n), Type::String) => { Value::String(SharedString::from(format!("{}", n).as_str())) } + (Value::Number(n), Type::Color) => Value::Color(Color::from(n as u32)), (v, _) => v, } }