mirror of
https://github.com/enso-org/enso.git
synced 2024-11-27 06:32:30 +03:00
Implementation of EnsoGL predefined Rectangle shape. (#6033)
This commit is contained in:
parent
dd009fd1af
commit
ca0779c46b
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -2751,6 +2751,15 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ensogl-example-built-in-shapes"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ensogl-core",
|
||||
"ensogl-hardcoded-theme",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ensogl-example-cached-shape"
|
||||
version = "0.1.0"
|
||||
@ -2976,6 +2985,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"ensogl-example-animation",
|
||||
"ensogl-example-auto-layout",
|
||||
"ensogl-example-built-in-shapes",
|
||||
"ensogl-example-cached-shape",
|
||||
"ensogl-example-complex-shape-system",
|
||||
"ensogl-example-custom-shape-system",
|
||||
|
@ -132,6 +132,13 @@ where for<'t> &'t Self: IntoOwned<Owned = Self> {
|
||||
Union(self, that)
|
||||
}
|
||||
|
||||
/// Unify two shapes, blending their colors based on the foreground shape's SDF value. This
|
||||
/// means that even if these shapes overlap and the foreground is semi-transparent, it will
|
||||
/// blend with the background only in the anti-aliased areas.
|
||||
fn union_exclusive<S: IntoOwned>(&self, that: S) -> UnionExclusive<Self, Owned<S>> {
|
||||
UnionExclusive(self, that)
|
||||
}
|
||||
|
||||
/// Subtracts the argument from this shape.
|
||||
fn difference<S: IntoOwned>(&self, that: S) -> Difference<Self, Owned<S>> {
|
||||
Difference(self, that)
|
||||
|
@ -115,17 +115,18 @@ macro_rules! _define_modifier {
|
||||
|
||||
pub use immutable::*;
|
||||
define_modifiers! {
|
||||
Translate translate (child) (v:Vector2<Pixels>)
|
||||
Rotation rotation (child) (angle:Radians)
|
||||
Scale scale (child) (value:f32)
|
||||
FlipY flip_y (child) ()
|
||||
Union union (child1,child2) ()
|
||||
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)
|
||||
Repeat repeat (child) (tile_size:Vector2<Pixels>)
|
||||
Translate translate (child) (v:Vector2<Pixels>)
|
||||
Rotation rotation (child) (angle:Radians)
|
||||
Scale scale (child) (value:f32)
|
||||
FlipY flip_y (child) ()
|
||||
Union union (child1,child2) ()
|
||||
UnionExclusive union_exclusive (child1,child2) ()
|
||||
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)
|
||||
Repeat repeat (child) (tile_size:Vector2<Pixels>)
|
||||
}
|
||||
|
@ -49,11 +49,15 @@ Color unpremultiply(PremultipliedColor c) {
|
||||
return color(rgb, alpha);
|
||||
}
|
||||
|
||||
PremultipliedColor blend_with_ratio(PremultipliedColor bg, PremultipliedColor fg, float ratio) {
|
||||
vec4 raw = fg.repr.raw + (1.0 - ratio) * bg.repr.raw;
|
||||
return PremultipliedColor(rgba(raw));
|
||||
}
|
||||
|
||||
/// Implements glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
|
||||
/// in the [`Color`]'s color space. See docs of [`Color`] to learn more.
|
||||
PremultipliedColor blend(PremultipliedColor bg, PremultipliedColor fg) {
|
||||
vec4 raw = fg.repr.raw + (1.0 - fg.repr.raw.a) * bg.repr.raw;
|
||||
return PremultipliedColor(rgba(raw));
|
||||
return blend_with_ratio(bg, fg, fg.repr.raw.a);
|
||||
}
|
||||
|
||||
Srgba srgba(PremultipliedColor color) {
|
||||
@ -370,7 +374,7 @@ Shape inverse (Shape s1) {
|
||||
return shape(s1.id, inverse(s1.sdf), s1.color);
|
||||
}
|
||||
|
||||
Shape unify (Shape s1, Shape s2) {
|
||||
Shape unify (Shape bg, Shape fg) {
|
||||
if (input_display_mode == DISPLAY_MODE_CACHED_SHAPES_TEXTURE) {
|
||||
// In DISPLAY_MODE_CACHED_SHAPES_TEXTURE the color has not [`alpha`] field applied (See
|
||||
// [`color`] documentation for explanation). That means, that even outside the
|
||||
@ -383,11 +387,19 @@ Shape unify (Shape s1, Shape s2) {
|
||||
// results ([`alpha`] field).
|
||||
// * We want to keep the color consistent near border of the both shapes.
|
||||
// The code below meets the both conditions.
|
||||
if (s2.sdf.distance > s1.sdf.distance) {
|
||||
s2.color.repr.raw *= s2.alpha;
|
||||
if (fg.sdf.distance > bg.sdf.distance) {
|
||||
fg.color.repr.raw *= fg.alpha;
|
||||
}
|
||||
}
|
||||
return shape(s1.id, unify(s1.sdf, s2.sdf), blend(s1.color, s2.color));
|
||||
return shape(bg.id, unify(bg.sdf, fg.sdf), blend(bg.color, fg.color));
|
||||
}
|
||||
|
||||
// Unify two shapes, blending their colors based on the foreground shape's SDF value. This means
|
||||
// that even if these shapes overlap and the foreground is semi-transparent, it will blend with
|
||||
// the background only in the anti-aliased areas.
|
||||
Shape unify_exclusive (Shape bg, Shape fg) {
|
||||
float ratio = render(fg.sdf);
|
||||
return shape(bg.id, unify(bg.sdf, fg.sdf), blend_with_ratio(bg.color, fg.color, ratio));
|
||||
}
|
||||
|
||||
Shape difference (Shape s1, Shape s2) {
|
||||
|
@ -176,6 +176,14 @@ impl Canvas {
|
||||
})
|
||||
}
|
||||
|
||||
/// Create an exclusive union shape from the provided shape components.
|
||||
pub fn union_exclusive(&mut self, num: usize, s1: Shape, s2: Shape) -> Shape {
|
||||
self.if_not_defined(num, |this| {
|
||||
let expr = format!("return unify_exclusive({},{});", s1.getter(), s2.getter());
|
||||
this.new_shape_from_expr(&expr)
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a difference shape from the provided shape components.
|
||||
pub fn difference(&mut self, num: usize, s1: Shape, s2: Shape) -> Shape {
|
||||
self.if_not_defined(num, |this| {
|
||||
|
@ -10,16 +10,17 @@ crate-type = ["cdylib", "rlib"]
|
||||
[dependencies]
|
||||
ensogl-example-animation = { path = "animation" }
|
||||
ensogl-example-auto-layout = { path = "auto-layout" }
|
||||
ensogl-example-built-in-shapes = { path = "built-in-shapes" }
|
||||
ensogl-example-cached-shape = { path = "cached-shape" }
|
||||
ensogl-example-complex-shape-system = { path = "complex-shape-system" }
|
||||
ensogl-example-custom-shape-system = { path = "custom-shape-system" }
|
||||
ensogl-example-dom-symbols = { path = "dom-symbols" }
|
||||
ensogl-example-drop-down = { path = "drop-down" }
|
||||
ensogl-example-drop-manager = { path = "drop-manager" }
|
||||
ensogl-example-focus-management = { path = "focus-management" }
|
||||
ensogl-example-easing-animator = { path = "easing-animator" }
|
||||
ensogl-example-list-view = { path = "list-view" }
|
||||
ensogl-example-focus-management = { path = "focus-management" }
|
||||
ensogl-example-grid-view = { path = "grid-view" }
|
||||
ensogl-example-list-view = { path = "list-view" }
|
||||
ensogl-example-mouse-events = { path = "mouse-events" }
|
||||
ensogl-example-profiling-run-graph = { path = "profiling-run-graph" }
|
||||
ensogl-example-render-profile-flamegraph = { path = "render-profile-flamegraph" }
|
||||
|
17
lib/rust/ensogl/examples/built-in-shapes/Cargo.toml
Normal file
17
lib/rust/ensogl/examples/built-in-shapes/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "ensogl-example-built-in-shapes"
|
||||
version = "0.1.0"
|
||||
authors = ["Enso Team <contact@enso.org>"]
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
ensogl-core = { path = "../../core" }
|
||||
wasm-bindgen = { workspace = true }
|
||||
ensogl-hardcoded-theme = { path = "../../../ensogl/app/theme/hardcoded" }
|
||||
|
||||
# Stop wasm-pack from running wasm-opt, because we run it from our build scripts in order to customize options.
|
||||
[package.metadata.wasm-pack.profile.release]
|
||||
wasm-opt = false
|
331
lib/rust/ensogl/examples/built-in-shapes/src/lib.rs
Normal file
331
lib/rust/ensogl/examples/built-in-shapes/src/lib.rs
Normal file
@ -0,0 +1,331 @@
|
||||
//! Example scene showing the usage of built-in high-level shapes.
|
||||
|
||||
// === Standard Linter Configuration ===
|
||||
#![deny(non_ascii_idents)]
|
||||
#![warn(unsafe_code)]
|
||||
#![allow(clippy::bool_to_int_with_if)]
|
||||
#![allow(clippy::let_and_return)]
|
||||
|
||||
use ensogl_core::display::shape::*;
|
||||
use ensogl_core::display::world::*;
|
||||
use ensogl_core::prelude::*;
|
||||
|
||||
use ensogl_core::data::color;
|
||||
use ensogl_core::display;
|
||||
use ensogl_core::display::navigation::navigator::Navigator;
|
||||
use ensogl_core::display::object::ObjectOps;
|
||||
|
||||
|
||||
|
||||
// ==============
|
||||
// === Shapes ===
|
||||
// ==============
|
||||
|
||||
mod rectangle {
|
||||
use super::*;
|
||||
ensogl_core::shape! {(
|
||||
style: Style,
|
||||
color: Vector4,
|
||||
corner_radius: f32,
|
||||
inset: f32,
|
||||
border: f32,
|
||||
border_color: Vector4,
|
||||
clip: Vector2,
|
||||
) {
|
||||
// === Canvas ===
|
||||
let canvas_width = Var::<Pixels>::from("input_size.x");
|
||||
let canvas_height = Var::<Pixels>::from("input_size.y");
|
||||
|
||||
// === Clip ===
|
||||
// Clipping scales the shape in such a way, that the visible part will occupy whole
|
||||
// canvas area. Thus, we need to recompute the new canvas size for the scaled shape.
|
||||
let canvas_clip_height_diff = &canvas_height * (clip.y() * 2.0);
|
||||
let canvas_clip_width_diff = &canvas_width * (clip.x() * 2.0);
|
||||
let canvas_height = canvas_height + &canvas_clip_height_diff;
|
||||
let canvas_width = canvas_width + &canvas_clip_width_diff;
|
||||
|
||||
// === Body ===
|
||||
let inset2 = (&inset * 2.0).px();
|
||||
let width = &canvas_width - &inset2;
|
||||
let height = &canvas_height - &inset2;
|
||||
let color = Var::<color::Rgba>::from(color);
|
||||
let body = Rect((&width, &height)).corners_radius(corner_radius.px());
|
||||
let body = body.fill(color);
|
||||
|
||||
// === Border ===
|
||||
let border = body.grow(border.px());
|
||||
let border_color = Var::<color::Rgba>::from(border_color);
|
||||
let border = border.fill(border_color);
|
||||
|
||||
// === Shape ===
|
||||
let shape = border.union_exclusive(&body);
|
||||
|
||||
// === Clip Adjustment ===
|
||||
let shape = shape.translate((-canvas_clip_width_diff/2.0, -canvas_clip_height_diff/2.0));
|
||||
shape.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A rectangle shape with the following configurable properties:
|
||||
/// - The body color of the shape.
|
||||
/// - The corner radius of the shape.
|
||||
/// - The inset, padding between edge of the frame and shape itself.
|
||||
/// - The border width and color.
|
||||
/// - The clipping of the shape (e.g. clipping bottom half of the shape).
|
||||
///
|
||||
/// # Performance
|
||||
/// This shape has been specifically designed to be utilized across various sections of the GUI. Its
|
||||
/// numerous parameters enable a highly adaptable approach to drawing a diverse range of shapes,
|
||||
/// such as circles, rings, or ring segments. The advantage of having a singular shape for these
|
||||
/// cases is that a single draw call can be used to render multiple GUI elements, which ultimately
|
||||
/// enhances performance.
|
||||
#[derive(Clone, CloneRef, Debug, Deref, Default)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Rectangle {
|
||||
pub view: rectangle::View,
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
fn modify_view(&self, f: impl FnOnce(&rectangle::View)) -> &Self {
|
||||
f(&self.view);
|
||||
self
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Builder-style modifier, allowing setting shape properties without creating a temporary
|
||||
/// variable after its construction.
|
||||
pub fn build(self, f: impl FnOnce(&Self)) -> Self {
|
||||
f(&self);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the color of the body of the shape.
|
||||
pub fn set_color(&self, color: color::Rgba) -> &Self {
|
||||
self.modify_view(|view| view.color.set(color.into()))
|
||||
}
|
||||
|
||||
/// Set the corner radius. If the corner radius will be larger than possible (e.g. larger than
|
||||
/// the shape dimension), it will be clamped to the highest possible value.
|
||||
pub fn set_corner_radius(&self, radius: f32) -> &Self {
|
||||
self.modify_view(|view| view.corner_radius.set(radius))
|
||||
}
|
||||
|
||||
/// Set the corner radius to maximum. If the width and height of the shape are equal, it will
|
||||
/// result in a circle.
|
||||
pub fn set_corner_radius_max(&self) -> &Self {
|
||||
// We are using here a value bigger than anything we will ever need. We are not using
|
||||
// biggest possible GLSL float value in order not to get rendering artifacts.
|
||||
let max_radius = 1000000.0;
|
||||
self.set_corner_radius(max_radius)
|
||||
}
|
||||
|
||||
/// Set the padding between edge of the frame and shape itself. If you want to use border, you
|
||||
/// should always set the inset at least of the size of the border. If you do not want the
|
||||
/// border to be animated, you can use [`Self::set_inset_border`] instead.
|
||||
pub fn set_inset(&self, inset: f32) -> &Self {
|
||||
self.modify_view(|view| view.inset.set(inset))
|
||||
}
|
||||
|
||||
/// Set the border size of the shape. If you want to use border, you should always set the inset
|
||||
/// at least of the size of the border. If you do not want the border to be animated, you can
|
||||
/// use [`Self::set_inset_border`] instead.
|
||||
pub fn set_border(&self, border: f32) -> &Self {
|
||||
self.modify_view(|view| view.border.set(border))
|
||||
}
|
||||
|
||||
/// Set both the inset and border at once. See documentation of [`Self::set_border`] and
|
||||
/// [`Self::set_inset`] to learn more.
|
||||
pub fn set_inset_border(&self, border: f32) -> &Self {
|
||||
self.set_inset(border).set_border(border)
|
||||
}
|
||||
|
||||
/// Set the border color.
|
||||
pub fn set_border_color(&self, color: color::Rgba) -> &Self {
|
||||
self.modify_view(|view| view.border_color.set(color.into()))
|
||||
}
|
||||
|
||||
/// Set clipping of the shape. The clipping is normalized, which means, that the value of 0.5
|
||||
/// means that we are clipping 50% of the shape. The clipping is performed always on the left
|
||||
/// and on the bottom of the shape. If you want to clip other sides of the shape, you can rotate
|
||||
/// it after clipping or use one of the predefined helper functions, such as
|
||||
/// [`Self::keep_bottom_half`].
|
||||
pub fn set_clip(&self, clip: Vector2) -> &Self {
|
||||
self.modify_view(|view| view.clip.set(clip))
|
||||
}
|
||||
|
||||
/// Keep only the top half of the shape.
|
||||
pub fn keep_top_half(&self) -> &Self {
|
||||
self.set_clip(Vector2(0.0, 0.5))
|
||||
}
|
||||
|
||||
/// Keep only the bottom half of the shape.
|
||||
pub fn keep_bottom_half(&self) -> &Self {
|
||||
self.keep_top_half().flip()
|
||||
}
|
||||
|
||||
/// Keep only the right half of the shape.
|
||||
pub fn keep_right_half(&self) -> &Self {
|
||||
self.set_clip(Vector2(0.5, 0.0))
|
||||
}
|
||||
|
||||
/// Keep only the left half of the shape.
|
||||
pub fn keep_left_half(&self) -> &Self {
|
||||
self.keep_right_half().flip()
|
||||
}
|
||||
|
||||
/// Keep only the top right quarter of the shape.
|
||||
pub fn keep_top_right_quarter(&self) -> &Self {
|
||||
self.set_clip(Vector2(0.5, 0.5))
|
||||
}
|
||||
|
||||
/// Keep only the bottom right quarter of the shape.
|
||||
pub fn keep_bottom_right_quarter(&self) -> &Self {
|
||||
self.keep_top_right_quarter().rotate_90()
|
||||
}
|
||||
|
||||
/// Keep only the bottom left quarter of the shape.
|
||||
pub fn keep_bottom_left_quarter(&self) -> &Self {
|
||||
self.keep_bottom_right_quarter().rotate_180()
|
||||
}
|
||||
|
||||
/// Keep only the top left quarter of the shape.
|
||||
pub fn keep_top_left_quarter(&self) -> &Self {
|
||||
self.keep_bottom_left_quarter().rotate_270()
|
||||
}
|
||||
|
||||
/// Flip the shape via its center. This is equivalent to rotating the shape by 180 degrees.
|
||||
pub fn flip(&self) -> &Self {
|
||||
self.rotate_180()
|
||||
}
|
||||
|
||||
/// Rotate the shape by 90 degrees.
|
||||
pub fn rotate_90(&self) -> &Self {
|
||||
self.modify_view(|view| view.set_rotation_z(-std::f32::consts::PI / 2.0))
|
||||
}
|
||||
|
||||
/// Counter rotate the shape by 90 degrees.
|
||||
pub fn counter_rotate_90(&self) -> &Self {
|
||||
self.modify_view(|view| view.set_rotation_z(std::f32::consts::PI / 2.0))
|
||||
}
|
||||
|
||||
/// Rotate the shape by 180 degrees.
|
||||
pub fn rotate_180(&self) -> &Self {
|
||||
self.modify_view(|view| view.set_rotation_z(-std::f32::consts::PI))
|
||||
}
|
||||
|
||||
/// Counter rotate the shape by 180 degrees.
|
||||
pub fn rotate_270(&self) -> &Self {
|
||||
self.modify_view(|view| view.set_rotation_z(-3.0 / 2.0 * std::f32::consts::PI))
|
||||
}
|
||||
|
||||
/// Counter rotate the shape by 270 degrees.
|
||||
pub fn counter_rotate_270(&self) -> &Self {
|
||||
self.modify_view(|view| view.set_rotation_z(3.0 / 2.0 * std::f32::consts::PI))
|
||||
}
|
||||
}
|
||||
|
||||
impl display::Object for Rectangle {
|
||||
fn display_object(&self) -> &display::object::Instance {
|
||||
self.view.display_object()
|
||||
}
|
||||
}
|
||||
|
||||
/// Rectangle constructor.
|
||||
#[allow(non_snake_case)]
|
||||
fn Rectangle() -> Rectangle {
|
||||
Rectangle::default()
|
||||
}
|
||||
|
||||
/// Rounded rectangle constructor. It is a wrapper around [`Rectangle`] with a corner radius set.
|
||||
#[allow(non_snake_case)]
|
||||
fn RoundedRectangle(radius: f32) -> Rectangle {
|
||||
let shape = Rectangle();
|
||||
shape.set_corner_radius(radius);
|
||||
shape
|
||||
}
|
||||
|
||||
/// Circle constructor. It is a wrapper around [`Rectangle`] with a corner radius set to maximum.
|
||||
#[allow(non_snake_case)]
|
||||
fn Circle() -> Rectangle {
|
||||
let shape = Rectangle();
|
||||
shape.set_corner_radius_max();
|
||||
shape
|
||||
}
|
||||
|
||||
|
||||
// ===================
|
||||
// === Entry Point ===
|
||||
// ===================
|
||||
|
||||
/// The example entry point.
|
||||
#[entry_point]
|
||||
#[allow(dead_code)]
|
||||
pub fn main() {
|
||||
let world = World::new().displayed_in("root");
|
||||
let scene = &world.default_scene;
|
||||
let camera = scene.camera().clone_ref();
|
||||
let navigator = Navigator::new(scene, &camera);
|
||||
|
||||
let shapes = [
|
||||
Circle().build(|t| {
|
||||
t.set_size(Vector2::new(100.0, 100.0))
|
||||
.set_color(color::Rgba::new(0.5, 0.0, 0.0, 0.3))
|
||||
.set_inset_border(5.0)
|
||||
.set_border_color(color::Rgba::new(0.0, 0.0, 1.0, 1.0))
|
||||
.keep_bottom_left_quarter();
|
||||
}),
|
||||
RoundedRectangle(10.0).build(|t| {
|
||||
t.set_size(Vector2::new(100.0, 100.0))
|
||||
.set_color(color::Rgba::new(0.5, 0.0, 0.0, 0.3))
|
||||
.set_inset_border(5.0)
|
||||
.set_border_color(color::Rgba::new(0.0, 0.0, 1.0, 1.0));
|
||||
}),
|
||||
RoundedRectangle(10.0).build(|t| {
|
||||
t.set_size(Vector2::new(100.0, 50.0))
|
||||
.set_color(color::Rgba::new(0.5, 0.0, 0.0, 0.3))
|
||||
.set_inset_border(5.0)
|
||||
.set_border_color(color::Rgba::new(0.0, 0.0, 1.0, 1.0))
|
||||
.keep_top_half();
|
||||
}),
|
||||
RoundedRectangle(10.0).build(|t| {
|
||||
t.set_size(Vector2::new(100.0, 50.0))
|
||||
.set_color(color::Rgba::new(0.5, 0.0, 0.0, 0.3))
|
||||
.set_inset_border(5.0)
|
||||
.set_border_color(color::Rgba::new(0.0, 0.0, 1.0, 1.0))
|
||||
.keep_bottom_half();
|
||||
}),
|
||||
RoundedRectangle(10.0).build(|t| {
|
||||
t.set_size(Vector2::new(50.0, 100.0))
|
||||
.set_color(color::Rgba::new(0.5, 0.0, 0.0, 0.3))
|
||||
.set_inset_border(5.0)
|
||||
.set_border_color(color::Rgba::new(0.0, 0.0, 1.0, 1.0))
|
||||
.keep_right_half();
|
||||
}),
|
||||
RoundedRectangle(10.0).build(|t| {
|
||||
t.set_size(Vector2::new(50.0, 100.0))
|
||||
.set_color(color::Rgba::new(0.5, 0.0, 0.0, 0.3))
|
||||
.set_inset_border(5.0)
|
||||
.set_border_color(color::Rgba::new(0.0, 0.0, 1.0, 1.0))
|
||||
.keep_left_half();
|
||||
}),
|
||||
];
|
||||
|
||||
let root = display::object::Instance::new();
|
||||
root.set_size(Vector2::new(300.0, 100.0));
|
||||
root.use_auto_layout().set_column_count(3).set_gap((10.0, 10.0));
|
||||
for shape in &shapes {
|
||||
root.add_child(shape);
|
||||
}
|
||||
world.add_child(&root);
|
||||
|
||||
world.keep_alive_forever();
|
||||
mem::forget(navigator);
|
||||
mem::forget(root);
|
||||
mem::forget(shapes);
|
||||
}
|
@ -31,6 +31,7 @@
|
||||
// ==============
|
||||
|
||||
pub use ensogl_example_animation as animation;
|
||||
pub use ensogl_example_built_in_shapes as built_in_shapes;
|
||||
pub use ensogl_example_cached_shape as cached_shape;
|
||||
pub use ensogl_example_complex_shape_system as complex_shape_system;
|
||||
pub use ensogl_example_dom_symbols as dom_symbols;
|
||||
|
Loading…
Reference in New Issue
Block a user