mirror of
https://github.com/enso-org/enso.git
synced 2024-12-24 04:24:01 +03:00
Filling cached shapes with a different color. (#5752)
Fixes #5188 Added a new method `ShapeOps::recolorize` which changes color depending on values on r, g, b channels. It should be explained more in the docs. It will allow us using colored cached icons in the Component Browser.
This commit is contained in:
parent
6dfbde5afd
commit
d1a0f5a543
@ -81,7 +81,7 @@ define_icons! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Four rounded rectangles in different colors aranged in a grid.
|
||||
/// Four rounded rectangles in different colors arranged in a grid.
|
||||
pub mod libraries(Libraries) {
|
||||
ensogl_core::shape! {
|
||||
above = [grid_view::selectable::highlight::shape, crate::entry::background];
|
||||
|
@ -142,6 +142,41 @@ where for<'t> &'t Self: IntoOwned<Owned = Self> {
|
||||
Fill(self, color)
|
||||
}
|
||||
|
||||
/// Change the shape color depending on RGB components.
|
||||
///
|
||||
/// ### How The New Color Is Defined
|
||||
///
|
||||
/// Assuming `s.color` is a previous shape premultiplied color (i.e. the alpha component is
|
||||
/// applied to each channel), a new color is defined as:
|
||||
/// `r * s.color.r + b * s.color.b + g * s.color.g`.
|
||||
///
|
||||
/// ### Usage
|
||||
///
|
||||
/// The main case for this function is coloring a complex shape serving as a
|
||||
/// template - the best example are [cached
|
||||
/// shapes](crate::display::shape::primitive::system::cached), which cannot be
|
||||
/// parameterized.
|
||||
///
|
||||
/// When the only colors in that template are [full red](color::Rgba::red),
|
||||
/// [full green](color::Rgba::green), or [full blue](color::Rgba::blue), this method will
|
||||
/// replace the template colors with the specialized ones.
|
||||
///
|
||||
/// A real-world example is an icon (cached in the texture) which should change color on mouse
|
||||
/// hover or click.
|
||||
fn recolorize<RColor, GColor, BColor>(
|
||||
&self,
|
||||
r: RColor,
|
||||
g: GColor,
|
||||
b: BColor,
|
||||
) -> Recolorize<Self>
|
||||
where
|
||||
RColor: Into<Var<color::Rgba>>,
|
||||
GColor: Into<Var<color::Rgba>>,
|
||||
BColor: Into<Var<color::Rgba>>,
|
||||
{
|
||||
Recolorize(self, r, g, b)
|
||||
}
|
||||
|
||||
/// Makes the borders of the shape crisp. Please note that it removes any form of antialiasing
|
||||
/// and can cause distortions especially with round surfaces.
|
||||
fn pixel_snap(&self) -> PixelSnap<Self> {
|
||||
|
@ -122,6 +122,7 @@ define_modifiers! {
|
||||
Difference difference (child1,child2) ()
|
||||
Intersection intersection (child1,child2) ()
|
||||
Fill fill (child) (color:Rgba)
|
||||
Recolorize recolorize (child) (r: Rgba, g: Rgba, b: Rgba)
|
||||
PixelSnap pixel_snap (child) ()
|
||||
Grow grow (child) (value:f32)
|
||||
Shrink shrink (child) (value:f32)
|
||||
|
@ -403,6 +403,8 @@ Shape intersection_no_blend (Shape s1, Shape s2) {
|
||||
}
|
||||
|
||||
Shape set_color(Shape shape, Rgba t) {
|
||||
// The [`alpha`] field is applied on [`color`] only if we are not in
|
||||
// `DISPLAY_MODE_CACHED_SHAPES_TEXTURE`. See [`color`] docs for explanation.
|
||||
if (input_display_mode != DISPLAY_MODE_CACHED_SHAPES_TEXTURE) {
|
||||
t.raw.a *= shape.alpha;
|
||||
}
|
||||
@ -410,6 +412,24 @@ Shape set_color(Shape shape, Rgba t) {
|
||||
return shape;
|
||||
}
|
||||
|
||||
/// Change the shape color depending on RGB components.
|
||||
///
|
||||
/// See documentation of [`ShapeOps::colorize`] for detailed explanation and
|
||||
/// usage examples.
|
||||
Shape recolorize(Shape shape, Rgba r, Rgba g, Rgba b) {
|
||||
PremultipliedColor r_prem = premultiply(Color(r));
|
||||
PremultipliedColor g_prem = premultiply(Color(g));
|
||||
PremultipliedColor b_prem = premultiply(Color(b));
|
||||
vec4 r_component = premultiply(Color(r)).repr.raw * shape.color.repr.raw.r;
|
||||
vec4 g_component = premultiply(Color(g)).repr.raw * shape.color.repr.raw.g;
|
||||
vec4 b_component = premultiply(Color(b)).repr.raw * shape.color.repr.raw.b;
|
||||
Rgba new = rgba(r_component + g_component + b_component);
|
||||
// The original shape's color components had the [`alpha`] field already applied, so we don't need to apply it
|
||||
// again here.
|
||||
shape.color = PremultipliedColor(new);
|
||||
return shape;
|
||||
}
|
||||
|
||||
Shape with_infinite_bounds (Shape s) {
|
||||
BoundSdf sdf = s.sdf;
|
||||
sdf.bounds = infinite();
|
||||
|
@ -240,8 +240,42 @@ impl Canvas {
|
||||
self.if_not_defined(num, |this| {
|
||||
let color: Glsl = color.into().glsl();
|
||||
this.add_current_function_code_line(format!("Shape shape = {};", s.getter()));
|
||||
this.add_current_function_code_line(format!("Srgba color = srgba({color});"));
|
||||
this.new_shape_from_expr("return set_color(shape,rgba(color));")
|
||||
this.add_current_function_code_line(format!("Rgba color = rgba({color});"));
|
||||
this.new_shape_from_expr("return set_color(shape, color);")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/// Change the shape color depending on RGB components.
|
||||
///
|
||||
/// Assuming `s.color` is a previous shape premultiplied color (i.e. the alpha component is
|
||||
/// applied to each channel), a new color is defined as:
|
||||
/// `r * s.color.r + b * s.color.b + g * s.color.g`.
|
||||
///
|
||||
/// See [`ShapeOps` counterpart
|
||||
/// documentation](crate::display::shape::class::ShapeOps::recolorize) for usage examples.
|
||||
pub fn recolorize<RColor, GColor, BColor>(
|
||||
&mut self,
|
||||
num: usize,
|
||||
s: Shape,
|
||||
r: RColor,
|
||||
g: GColor,
|
||||
b: BColor,
|
||||
) -> Shape
|
||||
where
|
||||
RColor: Into<Var<color::Rgba>>,
|
||||
GColor: Into<Var<color::Rgba>>,
|
||||
BColor: Into<Var<color::Rgba>>,
|
||||
{
|
||||
self.if_not_defined(num, |this| {
|
||||
let r: Glsl = r.into().glsl();
|
||||
let g: Glsl = g.into().glsl();
|
||||
let b: Glsl = b.into().glsl();
|
||||
this.add_current_function_code_line(format!("Shape shape = {};", s.getter()));
|
||||
this.add_current_function_code_line(format!("Rgba r = rgba({r});"));
|
||||
this.add_current_function_code_line(format!("Rgba g = rgba({g});"));
|
||||
this.add_current_function_code_line(format!("Rgba b = rgba({b});"));
|
||||
this.new_shape_from_expr("return recolorize(shape, r, g, b);")
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#![allow(clippy::bool_to_int_with_if)]
|
||||
#![allow(clippy::let_and_return)]
|
||||
|
||||
use ensogl_core::data::color;
|
||||
use ensogl_core::display::shape::*;
|
||||
use ensogl_core::display::world::*;
|
||||
use ensogl_core::prelude::*;
|
||||
@ -24,8 +25,8 @@ mod icon1 {
|
||||
use super::*;
|
||||
ensogl_core::cached_shape! { 32 x 32;
|
||||
(_style: Style) {
|
||||
let shape = Circle(16.px()).fill(color::Rgba::green());
|
||||
shape.into()
|
||||
let shape = Circle(16.px()).fill(color::Rgba::red());
|
||||
shape.recolorize(color::Rgba::green(), color::Rgba::red(), color::Rgba::blue()).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,9 +88,12 @@ pub mod data_input {
|
||||
mod shape {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
(_style: Style, shape: cached::AnyCachedShape) {
|
||||
(_style: Style, shape: cached::AnyCachedShape, color: Vector4) {
|
||||
let bg = Rect((100.px(), 100.px())).fill(color::Rgba::white());
|
||||
let with_bg = &bg + &shape;
|
||||
let vivid_color: Var<color::Rgba> = color.into();
|
||||
let dull_color = vivid_color.clone().multiply_alpha(&Var::Static(0.5));
|
||||
let colored = shape.recolorize(vivid_color, dull_color, color::Rgba::default());
|
||||
let with_bg = &bg + &colored;
|
||||
with_bg.into()
|
||||
}
|
||||
}
|
||||
@ -174,18 +178,27 @@ pub fn main() {
|
||||
world.default_scene.add_child(&texture_preview);
|
||||
world.default_scene.layers.main.add(&texture_preview);
|
||||
|
||||
let shapes = [shape::View::new(), shape::View::new(), shape::View::new()];
|
||||
for shape in &shapes {
|
||||
shape.set_size(Vector2(100.0, 100.0));
|
||||
let shapes = [
|
||||
shape::View::new(),
|
||||
shape::View::new(),
|
||||
shape::View::new(),
|
||||
shape::View::new(),
|
||||
shape::View::new(),
|
||||
];
|
||||
for (index, shape) in shapes.iter().enumerate() {
|
||||
shape.set_x(-100.0 + 50.0 * index as f32);
|
||||
shape.set_size(Vector2(40.0, 40.0));
|
||||
shape.color.set(color::Rgba::black().into());
|
||||
world.default_scene.add_child(shape);
|
||||
world.default_scene.layers.main.add(shape);
|
||||
}
|
||||
shapes[0].set_xy((-60.0, 0.0));
|
||||
shapes[0].shape.set(icon1::Shape::any_cached_shape_parameter());
|
||||
shapes[1].set_xy((60.0, 0.0));
|
||||
shapes[1].shape.set(icon2::Shape::any_cached_shape_parameter());
|
||||
shapes[2].set_xy((180.0, 0.0));
|
||||
shapes[2].shape.set(data_input::Shape::any_cached_shape_parameter());
|
||||
shapes[3].shape.set(data_input::Shape::any_cached_shape_parameter());
|
||||
shapes[3].color.set(color::Rgb::from_base_255(43.0, 117.0, 239.0).with_alpha(1.0).into());
|
||||
shapes[4].shape.set(data_input::Shape::any_cached_shape_parameter());
|
||||
shapes[4].color.set(color::Rgb::from_base_255(134.0, 135.0, 43.0).with_alpha(1.0).into());
|
||||
|
||||
let icon1 = icon1::View::new();
|
||||
icon1.set_size(Vector2(100.0, 100.0));
|
||||
|
Loading…
Reference in New Issue
Block a user