mirror of
https://github.com/enso-org/enso.git
synced 2024-09-11 13:15:52 +03:00
Layer/Rectangle improvements (#6247)
* Use Rectangle for breadcrumbs background. * Use Rectangle for status bar bg. * Use Rectangle for dropdown bg. * Dirty global_element_depth_order invalidates sublayers * Setting new parent may invalidate depth order * Support per-instance pointer_events_enabled * Remove workaround for #6241
This commit is contained in:
parent
8c9c2d79cd
commit
bc4ed96d71
@ -1,3 +1,5 @@
|
|||||||
# .git-blame-ignore-revs
|
# .git-blame-ignore-revs
|
||||||
# Fix prettier config; run prettier
|
# Fix prettier config; run prettier
|
||||||
0aa7d7ee4d969ec8e8f9d376e72741dca324fdf6
|
0aa7d7ee4d969ec8e8f9d376e72741dca324fdf6
|
||||||
|
# Update code style to use rust fmt (#3131)
|
||||||
|
c822256e6c531e56e894f9f92654654f63cfd6bc
|
||||||
|
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -24,7 +24,7 @@ Cargo.toml
|
|||||||
/app/gui/ @MichaelMauderer @wdanilo @farmaazon @mwu-tow @kazcw
|
/app/gui/ @MichaelMauderer @wdanilo @farmaazon @mwu-tow @kazcw
|
||||||
/app/gui/view/ @MichaelMauderer @wdanilo @farmaazon @kazcw
|
/app/gui/view/ @MichaelMauderer @wdanilo @farmaazon @kazcw
|
||||||
/app/gui/view/graph-editor/src/builtin/visualization/java_script/ @MichaelMauderer @wdanilo @farmaazon @kazcw @jdunkerley
|
/app/gui/view/graph-editor/src/builtin/visualization/java_script/ @MichaelMauderer @wdanilo @farmaazon @kazcw @jdunkerley
|
||||||
/app/ide-desktop/ @MichaelMauderer @wdanilo @kazcw
|
/app/ide-desktop/ @MichaelMauderer @wdanilo
|
||||||
|
|
||||||
# Engine (old)
|
# Engine (old)
|
||||||
# This section should be removed once the engine moves to /app/engine
|
# This section should be removed once the engine moves to /app/engine
|
||||||
|
@ -203,8 +203,6 @@ impl component::Model for Model {
|
|||||||
scene.layers.panel.add(÷r);
|
scene.layers.panel.add(÷r);
|
||||||
|
|
||||||
dropdown.set_label_layer(&scene.layers.panel_text);
|
dropdown.set_label_layer(&scene.layers.panel_text);
|
||||||
dropdown.restore_shape_constraints(app);
|
|
||||||
|
|
||||||
|
|
||||||
Self { display_object, background, play_button, dropdown, inner_root, divider }
|
Self { display_object, background, play_button, dropdown, inner_root, divider }
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,6 @@ use ensogl::application::Application;
|
|||||||
use ensogl::display;
|
use ensogl::display;
|
||||||
use ensogl::display::camera::Camera2d;
|
use ensogl::display::camera::Camera2d;
|
||||||
use ensogl::display::object::ObjectOps;
|
use ensogl::display::object::ObjectOps;
|
||||||
use ensogl::display::style;
|
|
||||||
use ensogl::display::Scene;
|
|
||||||
use ensogl::gui::cursor;
|
use ensogl::gui::cursor;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
@ -50,12 +48,11 @@ pub const HEIGHT: f32 = VERTICAL_MARGIN
|
|||||||
+ breadcrumb::VERTICAL_MARGIN
|
+ breadcrumb::VERTICAL_MARGIN
|
||||||
+ VERTICAL_MARGIN;
|
+ VERTICAL_MARGIN;
|
||||||
|
|
||||||
// This should be as large as the shadow around the background.
|
|
||||||
const MAGIC_SHADOW_MARGIN: f32 = 25.0;
|
|
||||||
/// Text offset to make the text appear more centered.
|
/// Text offset to make the text appear more centered.
|
||||||
const TEXT_Y_OFFSET: f32 = 2.0;
|
const TEXT_Y_OFFSET: f32 = 2.0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// === RelativePosition ===
|
// === RelativePosition ===
|
||||||
// ========================
|
// ========================
|
||||||
@ -68,38 +65,6 @@ enum RelativePosition {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==================
|
|
||||||
// === Background ===
|
|
||||||
// ==================
|
|
||||||
|
|
||||||
/// A background shape.
|
|
||||||
pub mod background {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
ensogl::shape! {
|
|
||||||
alignment = center;
|
|
||||||
(style:Style) {
|
|
||||||
let theme = ensogl_hardcoded_theme::graph_editor::breadcrumbs::background;
|
|
||||||
let theme = style::Path::from(&theme);
|
|
||||||
let width = Var::<Pixels>::from("input_size.x");
|
|
||||||
let height = Var::<Pixels>::from("input_size.y");
|
|
||||||
|
|
||||||
let corner_radius = style.get_number(theme.sub("corner_radius"));
|
|
||||||
let shape_width = width - MAGIC_SHADOW_MARGIN.px() * 2.0;
|
|
||||||
let shape_height = height - MAGIC_SHADOW_MARGIN.px() * 2.0;
|
|
||||||
let shape = Rect((&shape_width,&shape_height));
|
|
||||||
let shape = shape.corners_radius(corner_radius.px());
|
|
||||||
|
|
||||||
let bg_color = style.get_color(&theme);
|
|
||||||
let bg = shape.fill(bg_color);
|
|
||||||
|
|
||||||
bg.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ===========
|
// ===========
|
||||||
// === Frp ===
|
// === Frp ===
|
||||||
// ===========
|
// ===========
|
||||||
@ -173,7 +138,7 @@ ensogl::define_endpoints! {
|
|||||||
pub struct BreadcrumbsModel {
|
pub struct BreadcrumbsModel {
|
||||||
/// The breadcrumbs panel display object.
|
/// The breadcrumbs panel display object.
|
||||||
display_object: display::object::Instance,
|
display_object: display::object::Instance,
|
||||||
background: background::View,
|
background: Rectangle,
|
||||||
project_name: ProjectName,
|
project_name: ProjectName,
|
||||||
root: display::object::Instance,
|
root: display::object::Instance,
|
||||||
/// A container for all the breadcrumbs after project name. This contained and all its
|
/// A container for all the breadcrumbs after project name. This contained and all its
|
||||||
@ -205,9 +170,13 @@ impl BreadcrumbsModel {
|
|||||||
let frp_inputs = frp.input.clone_ref();
|
let frp_inputs = frp.input.clone_ref();
|
||||||
let current_index = default();
|
let current_index = default();
|
||||||
let camera = scene.camera().clone_ref();
|
let camera = scene.camera().clone_ref();
|
||||||
let background = background::View::new();
|
let background: Rectangle = default();
|
||||||
let gap_width = default();
|
let gap_width = default();
|
||||||
|
|
||||||
|
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet);
|
||||||
|
use ensogl_hardcoded_theme::graph_editor::breadcrumbs;
|
||||||
|
background.set_style(breadcrumbs::background::HERE, &style);
|
||||||
|
|
||||||
scene.layers.panel_background.add(&background);
|
scene.layers.panel_background.add(&background);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -223,22 +192,15 @@ impl BreadcrumbsModel {
|
|||||||
camera,
|
camera,
|
||||||
gap_width,
|
gap_width,
|
||||||
}
|
}
|
||||||
.init(&scene)
|
.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(self, scene: &Scene) -> Self {
|
fn init(self) -> Self {
|
||||||
self.add_child(&self.root);
|
self.add_child(&self.root);
|
||||||
self.root.add_child(&self.project_name);
|
self.root.add_child(&self.project_name);
|
||||||
self.root.add_child(&self.breadcrumbs_container);
|
self.root.add_child(&self.breadcrumbs_container);
|
||||||
self.root.add_child(&self.background);
|
self.root.add_child(&self.background);
|
||||||
|
|
||||||
ensogl::shapes_order_dependencies! {
|
|
||||||
scene => {
|
|
||||||
background -> breadcrumb::background;
|
|
||||||
background -> project_name::background;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.update_layout();
|
self.update_layout();
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -275,11 +237,9 @@ impl BreadcrumbsModel {
|
|||||||
let background_width = width + 2.0 * BACKGROUND_PADDING;
|
let background_width = width + 2.0 * BACKGROUND_PADDING;
|
||||||
let background_height =
|
let background_height =
|
||||||
crate::MACOS_TRAFFIC_LIGHTS_CONTENT_HEIGHT + BACKGROUND_PADDING * 2.0;
|
crate::MACOS_TRAFFIC_LIGHTS_CONTENT_HEIGHT + BACKGROUND_PADDING * 2.0;
|
||||||
let width_with_shadow = background_width + MAGIC_SHADOW_MARGIN * 2.0;
|
self.background.set_size(Vector2(background_width, background_height));
|
||||||
let height_with_shadow = background_height + MAGIC_SHADOW_MARGIN * 2.0;
|
self.background.set_x(-BACKGROUND_PADDING);
|
||||||
self.background.set_size(Vector2(width_with_shadow, height_with_shadow));
|
self.background.set_y(-HEIGHT / 2.0 - background_height / 2.0);
|
||||||
self.background.set_x(width / 2.0);
|
|
||||||
self.background.set_y(-HEIGHT / 2.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_breadcrumb(&self, index: usize) -> Option<Breadcrumb> {
|
fn get_breadcrumb(&self, index: usize) -> Option<Breadcrumb> {
|
||||||
|
@ -15,8 +15,6 @@ use crate::graph_editor::component::node::input::area::TEXT_SIZE;
|
|||||||
use ensogl::application::Application;
|
use ensogl::application::Application;
|
||||||
use ensogl::display;
|
use ensogl::display;
|
||||||
use ensogl::display::camera::Camera2d;
|
use ensogl::display::camera::Camera2d;
|
||||||
use ensogl::display::style;
|
|
||||||
use ensogl_component::shadow;
|
|
||||||
use ensogl_hardcoded_theme as theme;
|
use ensogl_hardcoded_theme as theme;
|
||||||
use ensogl_text as text;
|
use ensogl_text as text;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@ -33,8 +31,6 @@ const HEIGHT: f32 = 28.0;
|
|||||||
pub const PADDING: f32 = 12.0;
|
pub const PADDING: f32 = 12.0;
|
||||||
/// Margin between status bar and edge of the screen
|
/// Margin between status bar and edge of the screen
|
||||||
const MARGIN: f32 = 12.0;
|
const MARGIN: f32 = 12.0;
|
||||||
/// This should be as large as the shadow around the background.
|
|
||||||
const MAGIC_SHADOW_MARGIN: f32 = 40.0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -85,40 +81,6 @@ pub mod process {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==================
|
|
||||||
// === Background ===
|
|
||||||
// ==================
|
|
||||||
|
|
||||||
mod background {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
ensogl::shape! {
|
|
||||||
alignment = center;
|
|
||||||
(style:Style) {
|
|
||||||
let theme = ensogl_hardcoded_theme::application::status_bar::background;
|
|
||||||
let theme = style::Path::from(theme);
|
|
||||||
let width = Var::<Pixels>::from("input_size.x");
|
|
||||||
let height = Var::<Pixels>::from("input_size.y");
|
|
||||||
|
|
||||||
let corner_radius = style.get_number(theme.sub("corner_radius"));
|
|
||||||
let shape_width = width - MAGIC_SHADOW_MARGIN.px() * 2.0;
|
|
||||||
let shape_height = height - MAGIC_SHADOW_MARGIN.px() * 2.0;
|
|
||||||
let shape = Rect((&shape_width,&shape_height));
|
|
||||||
let shape = shape.corners_radius(corner_radius.px());
|
|
||||||
|
|
||||||
let bg_color = style.get_color(&theme);
|
|
||||||
let bg = shape.fill(bg_color);
|
|
||||||
let shadow_parameters = shadow::parameters_from_style_path(style,theme.sub("shadow"));
|
|
||||||
let shadow = shadow::from_shape_with_parameters
|
|
||||||
(shape.into(),shadow_parameters);
|
|
||||||
|
|
||||||
(shadow + bg).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ===========
|
// ===========
|
||||||
// === FRP ===
|
// === FRP ===
|
||||||
// ===========
|
// ===========
|
||||||
@ -149,7 +111,7 @@ ensogl::define_endpoints! {
|
|||||||
struct Model {
|
struct Model {
|
||||||
display_object: display::object::Instance,
|
display_object: display::object::Instance,
|
||||||
root: display::object::Instance,
|
root: display::object::Instance,
|
||||||
background: background::View,
|
background: Rectangle,
|
||||||
label: text::Text,
|
label: text::Text,
|
||||||
events: Rc<RefCell<Vec<event::Label>>>,
|
events: Rc<RefCell<Vec<event::Label>>>,
|
||||||
processes: Rc<RefCell<HashMap<process::Id, process::Label>>>,
|
processes: Rc<RefCell<HashMap<process::Id, process::Label>>>,
|
||||||
@ -162,7 +124,7 @@ impl Model {
|
|||||||
let scene = &app.display.default_scene;
|
let scene = &app.display.default_scene;
|
||||||
let display_object = display::object::Instance::new();
|
let display_object = display::object::Instance::new();
|
||||||
let root = display::object::Instance::new();
|
let root = display::object::Instance::new();
|
||||||
let background = background::View::new();
|
let background: Rectangle = default();
|
||||||
let label = text::Text::new(app);
|
let label = text::Text::new(app);
|
||||||
let events = default();
|
let events = default();
|
||||||
let processes = default();
|
let processes = default();
|
||||||
@ -173,11 +135,14 @@ impl Model {
|
|||||||
scene.layers.main.remove(&label);
|
scene.layers.main.remove(&label);
|
||||||
label.add_to_scene_layer(&scene.layers.panel_text);
|
label.add_to_scene_layer(&scene.layers.panel_text);
|
||||||
|
|
||||||
let text_color_path = theme::application::status_bar::text;
|
use theme::application::status_bar;
|
||||||
|
let text_color_path = status_bar::text;
|
||||||
let style = StyleWatch::new(&app.display.default_scene.style_sheet);
|
let style = StyleWatch::new(&app.display.default_scene.style_sheet);
|
||||||
let text_color = style.get_color(text_color_path);
|
let text_color = style.get_color(text_color_path);
|
||||||
label.frp.set_property(.., text_color);
|
label.frp.set_property(.., text_color);
|
||||||
label.frp.set_property_default(text_color);
|
label.frp.set_property_default(text_color);
|
||||||
|
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet);
|
||||||
|
background.set_style(status_bar::background::HERE, &style);
|
||||||
|
|
||||||
Self { display_object, root, background, label, events, processes, next_process_id, camera }
|
Self { display_object, root, background, label, events, processes, next_process_id, camera }
|
||||||
.init()
|
.init()
|
||||||
@ -205,14 +170,11 @@ impl Model {
|
|||||||
self.label.set_x(-label_width / 2.0);
|
self.label.set_x(-label_width / 2.0);
|
||||||
self.label.set_y(-HEIGHT / 2.0 + TEXT_SIZE / 2.0);
|
self.label.set_y(-HEIGHT / 2.0 + TEXT_SIZE / 2.0);
|
||||||
|
|
||||||
let bg_width = if label_width > 0.0 {
|
let bg_width = if label_width > 0.0 { label_width + 2.0 * PADDING } else { 0.0 };
|
||||||
label_width + 2.0 * PADDING + 2.0 * MAGIC_SHADOW_MARGIN
|
let bg_height = HEIGHT;
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
let bg_height = HEIGHT + 2.0 * MAGIC_SHADOW_MARGIN;
|
|
||||||
self.background.set_size(Vector2(bg_width, bg_height));
|
self.background.set_size(Vector2(bg_width, bg_height));
|
||||||
self.background.set_y(-HEIGHT / 2.0);
|
self.background.set_x(-bg_width / 2.0);
|
||||||
|
self.background.set_y(-HEIGHT / 2.0 - bg_height / 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_event(&self, label: &event::Label) -> event::Id {
|
fn add_event(&self, label: &event::Label) -> event::Id {
|
||||||
|
@ -149,8 +149,6 @@ impl Model {
|
|||||||
|
|
||||||
ensogl::shapes_order_dependencies! {
|
ensogl::shapes_order_dependencies! {
|
||||||
app.display.default_scene => {
|
app.display.default_scene => {
|
||||||
ide_view_graph_editor::component::breadcrumbs::background -> close::shape;
|
|
||||||
ide_view_graph_editor::component::breadcrumbs::background -> fullscreen::shape;
|
|
||||||
shape -> close::shape;
|
shape -> close::shape;
|
||||||
shape -> fullscreen::shape;
|
shape -> fullscreen::shape;
|
||||||
}
|
}
|
||||||
|
@ -445,18 +445,9 @@ define_themes! { [light:0, dark:1]
|
|||||||
status_bar {
|
status_bar {
|
||||||
offset_y = -30.0, -30.0;
|
offset_y = -30.0, -30.0;
|
||||||
text = text, text;
|
text = text, text;
|
||||||
background = graph_editor::node::background , graph_editor::node::background;
|
|
||||||
background {
|
background {
|
||||||
|
color = graph_editor::node::background , graph_editor::node::background;
|
||||||
corner_radius = 14.0 , 14.0;
|
corner_radius = 14.0 , 14.0;
|
||||||
shadow = shadow , shadow;
|
|
||||||
shadow {
|
|
||||||
size = shadow::size , shadow::size;
|
|
||||||
spread = shadow::spread , shadow::spread;
|
|
||||||
fading = shadow::fading , shadow::fading;
|
|
||||||
exponent = shadow::exponent , shadow::exponent;
|
|
||||||
offset_x = shadow::offset_x , shadow::offset_x;
|
|
||||||
offset_y = shadow::offset_y , shadow::offset_y;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -617,18 +608,9 @@ define_themes! { [light:0, dark:1]
|
|||||||
right = Lcha(0.0,0.0,0.0,0.6) , Lcha(1.0,0.0,0.0,0.6);
|
right = Lcha(0.0,0.0,0.0,0.6) , Lcha(1.0,0.0,0.0,0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
background = application::background , application::background;
|
|
||||||
background {
|
background {
|
||||||
|
color = application::background , application::background;
|
||||||
corner_radius = 8.0 , 8.0;
|
corner_radius = 8.0 , 8.0;
|
||||||
shadow = shadow , shadow;
|
|
||||||
shadow {
|
|
||||||
size = shadow::size , shadow::size;
|
|
||||||
spread = shadow::spread , shadow::spread;
|
|
||||||
fading = shadow::fading , shadow::fading;
|
|
||||||
exponent = shadow::exponent , shadow::exponent;
|
|
||||||
offset_x = shadow::offset_x , shadow::offset_x;
|
|
||||||
offset_y = shadow::offset_y , shadow::offset_y;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
edge {
|
edge {
|
||||||
|
@ -431,17 +431,6 @@ impl DropDownMenu {
|
|||||||
self.model.selection_menu.set_label_layer(layer);
|
self.model.selection_menu.set_label_layer(layer);
|
||||||
self.model.label.add_to_scene_layer(layer);
|
self.model.label.add_to_scene_layer(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the correct order for the shapes. To be sued after moving the component to a different
|
|
||||||
/// layer. Workaround for #6241.
|
|
||||||
pub fn restore_shape_constraints(&self, app: &Application) {
|
|
||||||
let scene = &app.display.default_scene;
|
|
||||||
shapes_order_dependencies! {
|
|
||||||
scene => {
|
|
||||||
arrow -> chooser_hover_area;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl display::Object for DropDownMenu {
|
impl display::Object for DropDownMenu {
|
||||||
|
@ -37,27 +37,6 @@ const OPEN_ANIMATION_OFFSET: f32 = OPEN_ANIMATION_SCALE - 1.001;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =========================
|
|
||||||
// === Shape Definition ===
|
|
||||||
// =========================
|
|
||||||
|
|
||||||
mod rounded_rect {
|
|
||||||
use super::*;
|
|
||||||
ensogl_core::shape! {
|
|
||||||
alignment = center;
|
|
||||||
(style:Style, color_rgba: Vector4<f32>, corner_radius: f32) {
|
|
||||||
let color = Var::<color::Rgba>::from(color_rgba);
|
|
||||||
let rect = Rect(Var::canvas_size()).corners_radius(corner_radius.px());
|
|
||||||
let out = rect.fill(color);
|
|
||||||
out.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type RoundedRect = rounded_rect::View;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =============
|
// =============
|
||||||
// === Model ===
|
// === Model ===
|
||||||
// =============
|
// =============
|
||||||
@ -66,7 +45,7 @@ pub type RoundedRect = rounded_rect::View;
|
|||||||
#[derivative(Clone(bound = ""))]
|
#[derivative(Clone(bound = ""))]
|
||||||
pub struct Model<T> {
|
pub struct Model<T> {
|
||||||
display_object: display::object::Instance,
|
display_object: display::object::Instance,
|
||||||
background: RoundedRect,
|
background: Rectangle,
|
||||||
pub grid: Grid,
|
pub grid: Grid,
|
||||||
selected_entries: Rc<RefCell<HashSet<T>>>,
|
selected_entries: Rc<RefCell<HashSet<T>>>,
|
||||||
cache: Rc<RefCell<EntryCache<T>>>,
|
cache: Rc<RefCell<EntryCache<T>>>,
|
||||||
@ -81,7 +60,7 @@ impl<T> component::Model for Model<T> {
|
|||||||
fn new(app: &Application) -> Self {
|
fn new(app: &Application) -> Self {
|
||||||
let display_object = display::object::Instance::new();
|
let display_object = display::object::Instance::new();
|
||||||
|
|
||||||
let background = RoundedRect::new();
|
let background = default();
|
||||||
let grid = Grid::new(app);
|
let grid = Grid::new(app);
|
||||||
display_object.add_child(&background);
|
display_object.add_child(&background);
|
||||||
display_object.add_child(&grid);
|
display_object.add_child(&grid);
|
||||||
@ -132,7 +111,7 @@ impl<T: DropdownValue> Model<T> {
|
|||||||
|
|
||||||
self.background.set_size(outer_size);
|
self.background.set_size(outer_size);
|
||||||
// align the dropdown origin to its top left corner
|
// align the dropdown origin to its top left corner
|
||||||
self.background.set_xy(Vector2(outer_width, -outer_height) / 2.0);
|
self.background.set_y(-outer_height);
|
||||||
self.background.corner_radius.set(CORNER_RADIUS);
|
self.background.corner_radius.set(CORNER_RADIUS);
|
||||||
|
|
||||||
self.grid.set_xy(Vector2(CLIP_PADDING, -CLIP_PADDING));
|
self.grid.set_xy(Vector2(CLIP_PADDING, -CLIP_PADDING));
|
||||||
@ -280,7 +259,7 @@ impl<T: DropdownValue> Model<T> {
|
|||||||
|
|
||||||
/// Set the background color of the dropdown.
|
/// Set the background color of the dropdown.
|
||||||
pub fn set_color(&self, color: Lcha) {
|
pub fn set_color(&self, color: Lcha) {
|
||||||
self.background.color_rgba.set(color::Rgba::from(color).into());
|
self.background.color.set(color::Rgba::from(color).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,7 +599,7 @@ pub struct HardcodedLayers {
|
|||||||
pub label: Layer,
|
pub label: Layer,
|
||||||
pub above_nodes: Layer,
|
pub above_nodes: Layer,
|
||||||
pub above_nodes_text: Layer,
|
pub above_nodes_text: Layer,
|
||||||
/// Layer containing all panels with fixed position (not moving with the panned scene)
|
/// `panel` layer contains all panels with fixed position (not moving with the panned scene)
|
||||||
/// like status bar, breadcrumbs or similar.
|
/// like status bar, breadcrumbs or similar.
|
||||||
pub panel_background: Layer,
|
pub panel_background: Layer,
|
||||||
pub panel: Layer,
|
pub panel: Layer,
|
||||||
|
@ -641,7 +641,7 @@ impl LayerModel {
|
|||||||
/// Consume all dirty flags and update the ordering of elements if needed. Returns [`true`] if
|
/// Consume all dirty flags and update the ordering of elements if needed. Returns [`true`] if
|
||||||
/// the layer or its sub-layers were modified during this call.
|
/// the layer or its sub-layers were modified during this call.
|
||||||
pub fn update(&self) -> bool {
|
pub fn update(&self) -> bool {
|
||||||
self.update_internal(None)
|
self.update_internal(default(), default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume all dirty flags and update the ordering of elements if needed.
|
/// Consume all dirty flags and update the ordering of elements if needed.
|
||||||
@ -649,10 +649,11 @@ impl LayerModel {
|
|||||||
pub(crate) fn update_internal(
|
pub(crate) fn update_internal(
|
||||||
&self,
|
&self,
|
||||||
global_element_depth_order: Option<&DependencyGraph<LayerItem>>,
|
global_element_depth_order: Option<&DependencyGraph<LayerItem>>,
|
||||||
|
parent_depth_order_changed: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut was_dirty = false;
|
let mut was_dirty = false;
|
||||||
|
|
||||||
if self.depth_order_dirty.check() {
|
if self.depth_order_dirty.check() || parent_depth_order_changed {
|
||||||
was_dirty = true;
|
was_dirty = true;
|
||||||
self.depth_order_dirty.unset();
|
self.depth_order_dirty.unset();
|
||||||
self.depth_sort(global_element_depth_order);
|
self.depth_sort(global_element_depth_order);
|
||||||
@ -662,11 +663,13 @@ impl LayerModel {
|
|||||||
was_dirty = true;
|
was_dirty = true;
|
||||||
self.sublayers.element_depth_order_dirty.unset();
|
self.sublayers.element_depth_order_dirty.unset();
|
||||||
self.for_each_sublayer(|layer| {
|
self.for_each_sublayer(|layer| {
|
||||||
layer.update_internal(Some(&*self.global_element_depth_order.borrow()));
|
let global_order = self.global_element_depth_order.borrow();
|
||||||
|
layer.update_internal(Some(&*global_order), true);
|
||||||
});
|
});
|
||||||
if let Some(layer) = &*self.mask.borrow() {
|
if let Some(layer) = &*self.mask.borrow() {
|
||||||
if let Some(layer) = layer.upgrade() {
|
if let Some(layer) = layer.upgrade() {
|
||||||
layer.update_internal(Some(&*self.global_element_depth_order.borrow()));
|
let global_order = self.global_element_depth_order.borrow();
|
||||||
|
layer.update_internal(Some(&*global_order), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -777,7 +780,7 @@ impl LayerModel {
|
|||||||
fn remove_all_sublayers(&self) {
|
fn remove_all_sublayers(&self) {
|
||||||
for layer in self.sublayers.borrow().layers.iter() {
|
for layer in self.sublayers.borrow().layers.iter() {
|
||||||
if let Some(layer) = layer.upgrade() {
|
if let Some(layer) = layer.upgrade() {
|
||||||
layer.remove_parent()
|
layer.unset_parent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mem::take(&mut *self.sublayers.model.borrow_mut());
|
mem::take(&mut *self.sublayers.model.borrow_mut());
|
||||||
@ -788,15 +791,24 @@ impl LayerModel {
|
|||||||
if self.flags.contains(LayerFlags::INHERIT_PARENT_CAMERA) {
|
if self.flags.contains(LayerFlags::INHERIT_PARENT_CAMERA) {
|
||||||
self.set_camera(parent.camera());
|
self.set_camera(parent.camera());
|
||||||
}
|
}
|
||||||
|
// Parent's `global_element_depth_order` is an input to depth order computation.
|
||||||
|
self.depth_order_dirty.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_parent(&self) {
|
/// Clear the parent field. Note that this doesn't remove the layer from its parent's sublayer
|
||||||
|
/// list.
|
||||||
|
fn unset_parent(&self) {
|
||||||
*self.parent.borrow_mut() = None;
|
*self.parent.borrow_mut() = None;
|
||||||
|
// Recompute depth order, in case removing a parent resolved a cycle.
|
||||||
|
self.depth_order_dirty.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear the parent field and remove the layer from its parent's sublayer list.
|
||||||
fn remove_from_parent(&self) {
|
fn remove_from_parent(&self) {
|
||||||
if let Some(sublayers) = self.parent.borrow_mut().take() {
|
if let Some(parent) = self.parent.borrow_mut().take() {
|
||||||
sublayers.borrow_mut().remove(self.id());
|
parent.borrow_mut().remove(self.id());
|
||||||
|
// Recompute depth order, in case removing a parent resolved a cycle.
|
||||||
|
self.depth_order_dirty.set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,10 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
use crate::data::color;
|
use crate::data::color;
|
||||||
use crate::display;
|
use crate::display;
|
||||||
|
use crate::display::shape::StyleWatchFrp;
|
||||||
|
use crate::display::style::data::DataMatch;
|
||||||
|
use crate::display::style::Path;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==============
|
// ==============
|
||||||
@ -25,6 +29,7 @@ pub use shape::Shape;
|
|||||||
pub mod shape {
|
pub mod shape {
|
||||||
use super::*;
|
use super::*;
|
||||||
crate::shape! {
|
crate::shape! {
|
||||||
|
pointer_events_instanced = true,
|
||||||
(
|
(
|
||||||
style: Style,
|
style: Style,
|
||||||
color: Vector4,
|
color: Vector4,
|
||||||
@ -157,6 +162,15 @@ impl Rectangle {
|
|||||||
self.modify_view(|view| view.border_color.set(color.into()))
|
self.modify_view(|view| view.border_color.set(color.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set whether the shape interacts with the mouse.
|
||||||
|
pub fn set_pointer_events(&self, enabled: bool) -> &Self {
|
||||||
|
let disabled = match enabled {
|
||||||
|
true => 0.0,
|
||||||
|
false => 1.0,
|
||||||
|
};
|
||||||
|
self.modify_view(|view| view.disable_pointer_events.set(disabled))
|
||||||
|
}
|
||||||
|
|
||||||
/// Set clipping of the shape. The clipping is normalized, which means, that the value of 0.5
|
/// 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. For positive clip values, the clipping is
|
/// means that we are clipping 50% of the shape. For positive clip values, the clipping is
|
||||||
/// performed always on the left and on the bottom of the shape. For negative clip values, the
|
/// performed always on the left and on the bottom of the shape. For negative clip values, the
|
||||||
@ -205,6 +219,22 @@ impl Rectangle {
|
|||||||
pub fn keep_top_left_quarter(&self) -> &Self {
|
pub fn keep_top_left_quarter(&self) -> &Self {
|
||||||
self.set_clip(Vector2(-0.5, 0.5))
|
self.set_clip(Vector2(-0.5, 0.5))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the style properties from the given [`StyleWatchFrp`].
|
||||||
|
pub fn set_style(&self, path: impl Into<Path>, style: &StyleWatchFrp) {
|
||||||
|
let path = path.into();
|
||||||
|
macro_rules! set_property {
|
||||||
|
($name:ident: $ty:ident) => {{
|
||||||
|
let value = style.get(path.sub(stringify!($name))).value();
|
||||||
|
let value = value.and_then(|value| value.$ty());
|
||||||
|
if let Some(value) = value {
|
||||||
|
self.view.$name.set(value.into());
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
set_property!(corner_radius: number);
|
||||||
|
set_property!(color: color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl display::Object for Rectangle {
|
impl display::Object for Rectangle {
|
||||||
|
@ -37,10 +37,17 @@ const FRAGMENT_RUNNER: &str = include_str!("../glsl/fragment_runner.glsl");
|
|||||||
pub struct Builder {}
|
pub struct Builder {}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
/// Returns the final GLSL code. If `pointer_events_enabled` is set to false, the generated
|
/// Returns the final GLSL code.
|
||||||
/// shape will be transparent for pointer events and will pass them trough.
|
///
|
||||||
|
/// `disable_pointer_events` is a GLSL expression determining whether instances of the shader
|
||||||
|
/// are transparent to pointer events. It should be one of:
|
||||||
|
/// - "1.0": Pointer events pass through the object. (As GLSL attributes cannot be `bool`s, this
|
||||||
|
/// is a floating-point equivalent of `true`.)
|
||||||
|
/// - "0.0": The object receives pointer events.
|
||||||
|
/// - The name of an instance variable: The variable determines on a per-instance basis whether
|
||||||
|
/// pointer events are disabled.
|
||||||
#[profile(Detail)]
|
#[profile(Detail)]
|
||||||
pub fn run<S: canvas::Draw>(shape: &S, pointer_events_enabled: bool) -> CodeTemplate {
|
pub fn run<S: canvas::Draw>(shape: &S, disable_pointer_events: &str) -> CodeTemplate {
|
||||||
let mut canvas = Canvas::default();
|
let mut canvas = Canvas::default();
|
||||||
let shape_ref = shape.draw(&mut canvas);
|
let shape_ref = shape.draw(&mut canvas);
|
||||||
let shape_header = header("Shape Definition");
|
let shape_header = header("Shape Definition");
|
||||||
@ -48,8 +55,9 @@ impl Builder {
|
|||||||
canvas.submit_shape_constructor("run");
|
canvas.submit_shape_constructor("run");
|
||||||
let shape_def = overload::allow_overloading(&canvas.to_glsl());
|
let shape_def = overload::allow_overloading(&canvas.to_glsl());
|
||||||
let code = [GLSL_BOILERPLATE.as_str(), "", &shape_header, &shape_def].join("\n\n");
|
let code = [GLSL_BOILERPLATE.as_str(), "", &shape_header, &shape_def].join("\n\n");
|
||||||
let main =
|
let main = format!(
|
||||||
format!("bool pointer_events_enabled = {pointer_events_enabled};\n{FRAGMENT_RUNNER}");
|
"bool pointer_events_enabled = ({disable_pointer_events}) == 0.0;\n{FRAGMENT_RUNNER}"
|
||||||
|
);
|
||||||
|
|
||||||
CodeTemplate::new(code, main, "")
|
CodeTemplate::new(code, main, "")
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ pub trait Shape: 'static + Sized + AsRef<Self::InstanceParams> {
|
|||||||
type SystemData: CustomSystemData<Self>;
|
type SystemData: CustomSystemData<Self>;
|
||||||
type ShapeData: Debug;
|
type ShapeData: Debug;
|
||||||
fn definition_path() -> &'static str;
|
fn definition_path() -> &'static str;
|
||||||
fn pointer_events() -> bool;
|
fn pointer_events() -> PointerEvents;
|
||||||
/// The alignment of the drawn shape's origin position. When set to `center`, the shape's
|
/// The alignment of the drawn shape's origin position. When set to `center`, the shape's
|
||||||
/// origin will be at the center of its bounding box. The default value is `left_bottom`.
|
/// origin will be at the center of its bounding box. The default value is `left_bottom`.
|
||||||
fn default_alignment() -> alignment::Dim2 {
|
fn default_alignment() -> alignment::Dim2 {
|
||||||
@ -160,6 +160,17 @@ impl<S: Shape> CustomSystemData<S> for () {
|
|||||||
fn new(_data: &ShapeSystemStandardData<S>, _shape_data: &S::ShapeData) -> Self {}
|
fn new(_data: &ShapeSystemStandardData<S>, _shape_data: &S::ShapeData) -> Self {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies whether pointer events are enabled for a shader's instances.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum PointerEvents {
|
||||||
|
/// Enable pointer events for all instances.
|
||||||
|
Enabled,
|
||||||
|
/// Disable pointer events for all instances.
|
||||||
|
Disabled,
|
||||||
|
/// An instance attribute enables or disables pointer events.
|
||||||
|
PerInstance,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
@ -348,7 +359,7 @@ pub struct ShapeSystemModel {
|
|||||||
/// Enables or disables pointer events on this shape system. All shapes of a shape system which
|
/// Enables or disables pointer events on this shape system. All shapes of a shape system which
|
||||||
/// have pointer events disabled will be completely transparent for the mouse (they will pass
|
/// have pointer events disabled will be completely transparent for the mouse (they will pass
|
||||||
/// through all mouse events to shapes behind them).
|
/// through all mouse events to shapes behind them).
|
||||||
pub pointer_events: Immutable<bool>,
|
pub pointer_events: Immutable<PointerEvents>,
|
||||||
/// Do not use the provided shape definition to generate material's body. It is rarely needed,
|
/// Do not use the provided shape definition to generate material's body. It is rarely needed,
|
||||||
/// when a custom material is provided that does not require any additional shape definition
|
/// when a custom material is provided that does not require any additional shape definition
|
||||||
/// code. For example, the text system uses this field, as its material fully describes how to
|
/// code. For example, the text system uses this field, as its material fully describes how to
|
||||||
@ -363,7 +374,7 @@ impl ShapeSystemModel {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
shape: def::AnyShape,
|
shape: def::AnyShape,
|
||||||
alignment: alignment::Dim2,
|
alignment: alignment::Dim2,
|
||||||
pointer_events: bool,
|
pointer_events: PointerEvents,
|
||||||
definition_path: &'static str,
|
definition_path: &'static str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let sprite_system = SpriteSystem::new(definition_path, alignment);
|
let sprite_system = SpriteSystem::new(definition_path, alignment);
|
||||||
@ -478,8 +489,17 @@ impl ShapeSystemModel {
|
|||||||
warn!("No precompiled shader found for '{path}'. This will affect performance.");
|
warn!("No precompiled shader found for '{path}'. This will affect performance.");
|
||||||
}
|
}
|
||||||
if !self.do_not_use_shape_definition.get() {
|
if !self.do_not_use_shape_definition.get() {
|
||||||
|
let disable_pointer_events: Cow<_> = match *self.pointer_events {
|
||||||
|
PointerEvents::Enabled => "0.0".into(),
|
||||||
|
PointerEvents::Disabled => "1.0".into(),
|
||||||
|
PointerEvents::PerInstance => {
|
||||||
|
let var = "disable_pointer_events";
|
||||||
|
self.material.borrow_mut().add_input_def::<f32>(var);
|
||||||
|
format!("input_{var}").into()
|
||||||
|
}
|
||||||
|
};
|
||||||
let code =
|
let code =
|
||||||
shader::builder::Builder::run(&*self.shape.borrow(), *self.pointer_events);
|
shader::builder::Builder::run(&*self.shape.borrow(), &disable_pointer_events);
|
||||||
self.material.borrow_mut().set_code(code);
|
self.material.borrow_mut().set_code(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,6 +638,56 @@ macro_rules! shape {
|
|||||||
[$style] ($($gpu_param : $gpu_param_type),*){$($body)*}
|
[$style] ($($gpu_param : $gpu_param_type),*){$($body)*}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Recognize `pointer_events_instanced = true`; in addition to passing it to `_shape!`, insert
|
||||||
|
// a suitable instance attribute into the list of GPU parameters.
|
||||||
|
(
|
||||||
|
$(type SystemData = $system_data:ident;)?
|
||||||
|
$(type ShapeData = $shape_data:ident;)?
|
||||||
|
$(flavor = $flavor:path;)?
|
||||||
|
$(above = [$($always_above_1:tt $(::$always_above_2:tt)*),*];)?
|
||||||
|
$(below = [$($always_below_1:tt $(::$always_below_2:tt)*),*];)?
|
||||||
|
$(pointer_events = $pointer_events:tt;)?
|
||||||
|
pointer_events_instanced = true,
|
||||||
|
$(alignment = $alignment:tt;)?
|
||||||
|
($style:ident : Style $(,$gpu_param : ident : $gpu_param_type : ty)* $(,)?) {$($body:tt)*}
|
||||||
|
) => {
|
||||||
|
$crate::_shape! {
|
||||||
|
$(SystemData($system_data))?
|
||||||
|
$(ShapeData($shape_data))?
|
||||||
|
$(flavor = [$flavor];)?
|
||||||
|
$(alignment = $alignment;)?
|
||||||
|
$(above = [$($always_above_1 $(::$always_above_2)*),*];)?
|
||||||
|
$(below = [$($always_below_1 $(::$always_below_2)*),*];)?
|
||||||
|
$(pointer_events = $pointer_events;)?
|
||||||
|
pointer_events_instanced = true;
|
||||||
|
[$style] (disable_pointer_events : f32$(,$gpu_param : $gpu_param_type)*){$($body)*}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Recognize `pointer_events_instanced = false`. Only `true` and `false` are allowed, because
|
||||||
|
// if it were a computed value, we wouldn't know during macro expansion whether to create an
|
||||||
|
// instance parameter for it.
|
||||||
|
(
|
||||||
|
$(type SystemData = $system_data:ident;)?
|
||||||
|
$(type ShapeData = $shape_data:ident;)?
|
||||||
|
$(flavor = $flavor:path;)?
|
||||||
|
$(above = [$($always_above_1:tt $(::$always_above_2:tt)*),*];)?
|
||||||
|
$(below = [$($always_below_1:tt $(::$always_below_2:tt)*),*];)?
|
||||||
|
$(pointer_events = $pointer_events:tt;)?
|
||||||
|
pointer_events_instanced = false,
|
||||||
|
$(alignment = $alignment:tt;)?
|
||||||
|
($style:ident : Style $(,$gpu_param : ident : $gpu_param_type : ty)* $(,)?) {$($body:tt)*}
|
||||||
|
) => {
|
||||||
|
$crate::_shape! {
|
||||||
|
$(SystemData($system_data))?
|
||||||
|
$(ShapeData($shape_data))?
|
||||||
|
$(flavor = [$flavor];)?
|
||||||
|
$(alignment = $alignment;)?
|
||||||
|
$(above = [$($always_above_1 $(::$always_above_2)*),*];)?
|
||||||
|
$(below = [$($always_below_1 $(::$always_below_2)*),*];)?
|
||||||
|
$(pointer_events = $pointer_events;)?
|
||||||
|
[$style] ($($gpu_param : $gpu_param_type),*){$($body)*}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME[WD]: This macro was left in the code because glyphs are not able to use the shader
|
// FIXME[WD]: This macro was left in the code because glyphs are not able to use the shader
|
||||||
@ -708,10 +778,14 @@ macro_rules! _shape_old {
|
|||||||
root_call_path!()
|
root_call_path!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pointer_events() -> bool {
|
fn pointer_events() -> $crate::display::shape::primitive::system::PointerEvents {
|
||||||
|
use $crate::display::shape::primitive::system::PointerEvents;
|
||||||
let _out = true;
|
let _out = true;
|
||||||
$(let _out = $pointer_events;)?
|
$(let _out = $pointer_events;)?
|
||||||
_out
|
match _out {
|
||||||
|
true => PointerEvents::Enabled,
|
||||||
|
false => PointerEvents::Disabled,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_alignment() -> $crate::display::layout::alignment::Dim2 {
|
fn default_alignment() -> $crate::display::layout::alignment::Dim2 {
|
||||||
@ -818,6 +892,7 @@ macro_rules! _shape {
|
|||||||
$(above = [$($always_above_1:tt $(::$always_above_2:tt)*),*];)?
|
$(above = [$($always_above_1:tt $(::$always_above_2:tt)*),*];)?
|
||||||
$(below = [$($always_below_1:tt $(::$always_below_2:tt)*),*];)?
|
$(below = [$($always_below_1:tt $(::$always_below_2:tt)*),*];)?
|
||||||
$(pointer_events = $pointer_events:tt;)?
|
$(pointer_events = $pointer_events:tt;)?
|
||||||
|
$(pointer_events_instanced = $pointer_events_instanced:tt;)?
|
||||||
[$style:ident]
|
[$style:ident]
|
||||||
($($gpu_param : ident : $gpu_param_type : ty),* $(,)?)
|
($($gpu_param : ident : $gpu_param_type : ty),* $(,)?)
|
||||||
{$($body:tt)*}
|
{$($body:tt)*}
|
||||||
@ -869,10 +944,17 @@ macro_rules! _shape {
|
|||||||
root_call_path!()
|
root_call_path!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pointer_events() -> bool {
|
fn pointer_events() -> $crate::display::shape::primitive::system::PointerEvents {
|
||||||
let _out = true;
|
use $crate::display::shape::primitive::system::PointerEvents;
|
||||||
$(let _out = $pointer_events;)?
|
let _blanket = true;
|
||||||
_out
|
$(let _blanket = $pointer_events;)?
|
||||||
|
let _instanced = false;
|
||||||
|
$(let _instanced = $pointer_events_instanced;)?
|
||||||
|
match (_blanket, _instanced) {
|
||||||
|
(_, true) => PointerEvents::PerInstance,
|
||||||
|
(true, false) => PointerEvents::Enabled,
|
||||||
|
(false, false) => PointerEvents::Disabled,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(fn default_alignment() -> $crate::display::layout::alignment::Dim2 {
|
$(fn default_alignment() -> $crate::display::layout::alignment::Dim2 {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
//! Example scene showing simple shape component that logs all its mouse events.
|
//! Example scene showing simple shape component that logs all its mouse events.
|
||||||
|
//! A partially-transparent shape partially covering it is transparent to mouse events.
|
||||||
|
|
||||||
#![recursion_limit = "1024"]
|
#![recursion_limit = "1024"]
|
||||||
// === Features ===
|
// === Features ===
|
||||||
@ -28,31 +29,15 @@ use ensogl_core::prelude::*;
|
|||||||
use enso_frp as frp;
|
use enso_frp as frp;
|
||||||
use ensogl_core::application;
|
use ensogl_core::application;
|
||||||
use ensogl_core::application::Application;
|
use ensogl_core::application::Application;
|
||||||
|
use ensogl_core::data::color::Rgb;
|
||||||
|
use ensogl_core::data::color::Rgba;
|
||||||
use ensogl_core::display;
|
use ensogl_core::display;
|
||||||
use ensogl_core::display::navigation::navigator::Navigator;
|
use ensogl_core::display::navigation::navigator::Navigator;
|
||||||
use ensogl_core::display::object::ObjectOps;
|
use ensogl_core::display::object::ObjectOps;
|
||||||
use ensogl_core::shape;
|
|
||||||
use ensogl_text_msdf::run_once_initialized;
|
use ensogl_text_msdf::run_once_initialized;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==============
|
|
||||||
// === Shapes ===
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
mod shape {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
shape! {
|
|
||||||
alignment = center;
|
|
||||||
(style: Style) {
|
|
||||||
Circle(100.px()).fill(color::Rgb(1.0,0.0,0.0)).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =============
|
// =============
|
||||||
// === Model ===
|
// === Model ===
|
||||||
// =============
|
// =============
|
||||||
@ -61,17 +46,29 @@ mod shape {
|
|||||||
struct Model {
|
struct Model {
|
||||||
app: Application,
|
app: Application,
|
||||||
display_object: display::object::Instance,
|
display_object: display::object::Instance,
|
||||||
shape: shape::View,
|
shape: Rectangle,
|
||||||
|
cover: Rectangle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
fn new(app: &Application) -> Self {
|
fn new(app: &Application) -> Self {
|
||||||
let app = app.clone_ref();
|
let app = app.clone_ref();
|
||||||
let display_object = display::object::Instance::new();
|
let display_object = display::object::Instance::new();
|
||||||
let shape = shape::View::new();
|
let shape: Rectangle = default();
|
||||||
shape.set_size(Vector2::new(100.0, 100.0));
|
shape.set_size(Vector2(300.0, 300.0));
|
||||||
|
shape.set_color(Rgb(1.0, 0.0, 0.0).into());
|
||||||
|
shape.set_corner_radius_max();
|
||||||
display_object.add_child(&shape);
|
display_object.add_child(&shape);
|
||||||
Self { app, display_object, shape }
|
let cover: Rectangle = default();
|
||||||
|
// We need a value that will make the covering shape a bit smaller than the main shape.
|
||||||
|
// Euclid found a good one.
|
||||||
|
const INVERSE_PHI: f32 = 0.618_033;
|
||||||
|
cover.set_size(Vector2(300.0 * INVERSE_PHI, 300.0 * INVERSE_PHI));
|
||||||
|
cover.set_color(Rgba(0.0, 0.0, 0.0, 0.5));
|
||||||
|
cover.set_corner_radius_max();
|
||||||
|
cover.set_pointer_events(false);
|
||||||
|
display_object.add_child(&cover);
|
||||||
|
Self { app, display_object, shape, cover }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +159,6 @@ pub fn main() {
|
|||||||
run_once_initialized(|| {
|
run_once_initialized(|| {
|
||||||
let app = Application::new("root");
|
let app = Application::new("root");
|
||||||
let shape: View = app.new_view();
|
let shape: View = app.new_view();
|
||||||
shape.model.shape.set_size((300.0, 300.0));
|
|
||||||
app.display.add_child(&shape);
|
app.display.add_child(&shape);
|
||||||
|
|
||||||
let scene = &app.display.default_scene;
|
let scene = &app.display.default_scene;
|
||||||
|
Loading…
Reference in New Issue
Block a user