feat: color: add channel properties to color

Add extra properties to the `color` type.
- `red`
- `green`
- `blue`
- `alpha`
This commit is contained in:
Luke D. Jones 2024-03-05 17:37:22 +13:00 committed by Olivier Goffart
parent 0409cb0140
commit 8c60cc74be
8 changed files with 73 additions and 3 deletions

View file

@ -22,6 +22,7 @@ All notable changes to this project are documented in this file.
- Image: Added support for 9 slice scaling
- Image: Added `horizontal-` and `vertical-tiling`
- Flickable: Added `flicked` callback
- Slint: Expose `.red`, `.green`, `.blue`, and `.alpha` properties on `color`
### Widgets

View file

@ -66,6 +66,17 @@ draw the outline.
CSS Color names are only in scope in expressions of type `color` or `brush`. Otherwise, you can access
colors from the `Colors` namespace.
### Properties
The following properties are exposed:
- **`red`**
- **`green`**
- **`blue`**
- **`alpha`**
All properties are in the range 0-255.
### Methods
All colors and brushes define the following methods:

View file

@ -47,6 +47,7 @@ pub enum BuiltinFunction {
StringToFloat,
/// the "42".is_float()
StringIsFloat,
ColorRgbaStruct,
ColorBrighter,
ColorDarker,
ColorTransparentize,
@ -153,6 +154,21 @@ impl BuiltinFunction {
return_type: Box::new(crate::layout::layout_info_type()),
args: vec![Type::ElementReference],
},
BuiltinFunction::ColorRgbaStruct => Type::Function {
return_type: Box::new(Type::Struct {
fields: IntoIterator::into_iter([
("red".to_string(), Type::Int32),
("green".to_string(), Type::Int32),
("blue".to_string(), Type::Int32),
("alpha".to_string(), Type::Int32),
])
.collect(),
name: Some("Color".into()),
node: None,
rust_attributes: None,
}),
args: vec![Type::Color],
},
BuiltinFunction::ColorBrighter => Type::Function {
return_type: Box::new(Type::Brush),
args: vec![Type::Brush, Type::Float32],
@ -256,7 +272,8 @@ impl BuiltinFunction {
BuiltinFunction::SetSelectionOffsets => false,
BuiltinFunction::ItemMemberFunction(..) => false,
BuiltinFunction::StringToFloat | BuiltinFunction::StringIsFloat => true,
BuiltinFunction::ColorBrighter
BuiltinFunction::ColorRgbaStruct
| BuiltinFunction::ColorBrighter
| BuiltinFunction::ColorDarker
| BuiltinFunction::ColorTransparentize
| BuiltinFunction::ColorMix
@ -310,7 +327,8 @@ impl BuiltinFunction {
BuiltinFunction::SetSelectionOffsets => false,
BuiltinFunction::ItemMemberFunction(..) => false,
BuiltinFunction::StringToFloat | BuiltinFunction::StringIsFloat => true,
BuiltinFunction::ColorBrighter
BuiltinFunction::ColorRgbaStruct
| BuiltinFunction::ColorBrighter
| BuiltinFunction::ColorDarker
| BuiltinFunction::ColorTransparentize
| BuiltinFunction::ColorMix

View file

@ -3048,6 +3048,9 @@ fn compile_builtin_function_call(
ctx.generator_state.conditional_includes.cstdlib.set(true);
format!("[](const auto &a){{ auto e1 = std::end(a); auto e2 = const_cast<char*>(e1); auto r = std::strtod(std::begin(a), &e2); return e1 == e2 ? r : 0; }}({})", a.next().unwrap())
}
BuiltinFunction::ColorRgbaStruct => {
format!("{}.to_argb_u8()", a.next().unwrap())
}
BuiltinFunction::ColorBrighter => {
format!("{}.brighter({})", a.next().unwrap(), a.next().unwrap())
}

View file

@ -2492,6 +2492,7 @@ fn compile_builtin_function_call(
quote!(#(#a)*.as_str().parse::<f64>().unwrap_or_default())
}
BuiltinFunction::StringIsFloat => quote!(#(#a)*.as_str().parse::<f64>().is_ok()),
BuiltinFunction::ColorRgbaStruct => quote!( #(#a)*.to_argb_u8()),
BuiltinFunction::ColorBrighter => {
let x = a.next().unwrap();
let factor = a.next().unwrap();

View file

@ -87,6 +87,7 @@ fn builtin_function_cost(function: &BuiltinFunction) -> isize {
BuiltinFunction::ItemMemberFunction(..) => isize::MAX,
BuiltinFunction::StringToFloat => 50,
BuiltinFunction::StringIsFloat => 50,
BuiltinFunction::ColorRgbaStruct => 50,
BuiltinFunction::ColorBrighter => 50,
BuiltinFunction::ColorDarker => 50,
BuiltinFunction::ColorTransparentize => 50,

View file

@ -996,7 +996,24 @@ impl<'a> LookupObject for ColorExpression<'a> {
)),
})
};
None.or_else(|| f("brighter", member_function(BuiltinFunction::ColorBrighter)))
let field_access = |f: &str| {
LookupResult::from(Expression::StructFieldAccess {
base: Box::new(Expression::FunctionCall {
function: Box::new(Expression::BuiltinFunctionReference(
BuiltinFunction::ColorRgbaStruct,
ctx.current_token.as_ref().map(|t| t.to_source_location()),
)),
source_location: ctx.current_token.as_ref().map(|t| t.to_source_location()),
arguments: vec![self.0.clone()],
}),
name: f.into(),
})
};
None.or_else(|| f("red", field_access("red")))
.or_else(|| f("green", field_access("green")))
.or_else(|| f("blue", field_access("blue")))
.or_else(|| f("alpha", field_access("alpha")))
.or_else(|| f("brighter", member_function(BuiltinFunction::ColorBrighter)))
.or_else(|| f("darker", member_function(BuiltinFunction::ColorDarker)))
.or_else(|| f("transparentize", member_function(BuiltinFunction::ColorTransparentize)))
.or_else(|| f("with-alpha", member_function(BuiltinFunction::ColorWithAlpha)))

View file

@ -739,6 +739,24 @@ fn call_builtin_function(
panic!("Argument not a string");
}
}
BuiltinFunction::ColorRgbaStruct => {
if arguments.len() != 1 {
panic!("internal error: incorrect argument count to ColorRGBAComponents")
}
if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
let color = brush.color();
let values = IntoIterator::into_iter([
("red".to_string(), Value::Number(color.red().into())),
("green".to_string(), Value::Number(color.green().into())),
("blue".to_string(), Value::Number(color.blue().into())),
("alpha".to_string(), Value::Number(color.alpha().into())),
])
.collect();
Value::Struct(values)
} else {
panic!("First argument not a color");
}
}
BuiltinFunction::ColorBrighter => {
if arguments.len() != 2 {
panic!("internal error: incorrect argument count to ColorBrighter")