From d60e3835f2bc22de02d112f49ae801359bbde65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Dani=C5=82o?= Date: Fri, 25 Nov 2022 07:49:52 +0100 Subject: [PATCH] Display object refactoring (#3877) --- Cargo.lock | 1 + .../breadcrumbs/src/entry.rs | 2 +- .../breadcrumbs/src/lib.rs | 4 +- .../component-list-panel/grid/src/entry.rs | 11 +- .../component-list-panel/grid/src/lib.rs | 2 +- .../component-list-panel/src/lib.rs | 6 +- .../component-list-panel/src/navigator.rs | 4 +- app/gui/view/debug_scene/icons/src/lib.rs | 2 +- .../builtin/visualization/native/text_grid.rs | 6 +- .../src/component/add_node_button.rs | 4 +- .../graph-editor/src/component/breadcrumbs.rs | 10 +- .../src/component/breadcrumbs/breadcrumb.rs | 8 +- .../view/graph-editor/src/component/edge.rs | 34 +- .../view/graph-editor/src/component/node.rs | 26 +- .../src/component/node/action_bar.rs | 4 +- .../src/component/node/input/area.rs | 4 +- .../src/component/node/output/area.rs | 4 +- .../src/component/node/output/port.rs | 4 +- .../src/component/node/profiling.rs | 4 +- .../graph-editor/src/component/profiling.rs | 4 +- .../src/component/visualization/container.rs | 6 +- .../visualization/container/action_bar.rs | 4 +- app/gui/view/graph-editor/src/lib.rs | 14 +- app/gui/view/src/code_editor.rs | 4 +- app/gui/view/src/component_browser.rs | 4 +- app/gui/view/src/debug_mode_popup.rs | 7 +- app/gui/view/src/open_dialog.rs | 4 +- app/gui/view/src/open_dialog/project_list.rs | 4 +- app/gui/view/src/project.rs | 13 +- app/gui/view/src/searcher.rs | 8 +- app/gui/view/src/status_bar.rs | 11 +- app/gui/view/src/window_control_buttons.rs | 6 +- integration-test/tests/graph_editor.rs | 2 +- .../component/drop-down-menu/src/lib.rs | 10 +- .../ensogl/component/file-browser/src/lib.rs | 3 +- .../ensogl/component/flame-graph/src/lib.rs | 8 +- .../component/grid-view/src/entry/visible.rs | 4 +- .../ensogl/component/grid-view/src/header.rs | 4 +- .../component/grid-view/src/selectable.rs | 3 +- .../src/selectable/highlight/shape.rs | 2 +- .../ensogl/component/grid-view/src/simple.rs | 2 +- lib/rust/ensogl/component/label/src/lib.rs | 2 +- .../ensogl/component/list-view/src/entry.rs | 2 +- .../component/list-view/src/entry/list.rs | 2 +- .../ensogl/component/list-view/src/lib.rs | 6 +- .../ensogl/component/scroll-area/src/lib.rs | 16 +- .../component/selector/src/decimal_aligned.rs | 2 +- lib/rust/ensogl/component/selector/src/frp.rs | 18 +- .../ensogl/component/selector/src/model.rs | 18 +- .../component/sequence-diagram/src/lib.rs | 8 +- lib/rust/ensogl/component/slider/src/lib.rs | 16 +- .../component/text/src/component/line.rs | 4 +- .../component/text/src/component/selection.rs | 8 +- .../component/text/src/component/text.rs | 10 +- lib/rust/ensogl/component/tooltip/src/lib.rs | 2 +- lib/rust/ensogl/core/src/data/bounding_box.rs | 2 +- lib/rust/ensogl/core/src/data/dirty.rs | 414 ++- .../core/src/display/camera/camera2d.rs | 12 +- lib/rust/ensogl/core/src/display/object.rs | 27 +- .../ensogl/core/src/display/object/event.rs | 24 +- .../display/object/{class.rs => instance.rs} | 2252 ++++++++--------- .../{transform.rs => transformation.rs} | 82 +- lib/rust/ensogl/core/src/display/scene.rs | 104 +- lib/rust/ensogl/core/src/display/scene/dom.rs | 11 +- .../ensogl/core/src/display/scene/layer.rs | 43 +- .../core/src/display/scene/pointer_target.rs | 12 +- .../core/src/display/shape/primitive.rs | 1 + .../display/shape/primitive/def/primitive.rs | 2 +- .../src/display/shape/primitive/def/var.rs | 158 +- .../core/src/display/shape/primitive/glsl.rs | 8 + .../src/display/shape/primitive/glsl/codes.rs | 81 + .../display/shape/primitive/glsl/color.glsl | 326 +-- .../glsl/error_codes/id_encoding_overflow.txt | 1 - .../shape/primitive/glsl/fragment_runner.glsl | 96 +- .../display/shape/primitive/glsl/math.glsl | 2 +- .../display/shape/primitive/glsl/prelude.glsl | 20 + .../display/shape/primitive/glsl/shape.glsl | 319 ++- .../display/shape/primitive/shader/builder.rs | 48 +- .../display/shape/primitive/shader/canvas.rs | 16 +- .../src/display/shape/primitive/system.rs | 64 +- .../ensogl/core/src/display/symbol/dom.rs | 20 +- .../ensogl/core/src/display/symbol/gpu.rs | 23 +- .../symbol/gpu/geometry/compound/sprite.rs | 168 +- .../core/src/display/symbol/gpu/shader.rs | 2 +- lib/rust/ensogl/core/src/display/world.rs | 25 +- lib/rust/ensogl/core/src/gui/component.rs | 17 +- .../core/src/system/gpu/data/uniform.rs | 5 + .../example/complex-shape-system/src/lib.rs | 2 +- .../ensogl/example/dom-symbols/src/lib.rs | 96 +- .../example/focus-management/src/lib.rs | 26 +- lib/rust/ensogl/example/grid-view/src/lib.rs | 4 +- .../example/profiling-run-graph/src/lib.rs | 2 +- .../ensogl/example/scroll-area/src/lib.rs | 10 +- lib/rust/ensogl/example/slider/src/lib.rs | 6 +- lib/rust/ensogl/example/text-area/src/lib.rs | 12 +- lib/rust/types/Cargo.toml | 4 + lib/rust/types/build.rs | 177 ++ lib/rust/types/src/algebra.rs | 1381 +--------- lib/rust/types/src/dim.rs | 157 ++ lib/rust/types/src/dim_macros.rs | 441 ++++ lib/rust/types/src/lib.rs | 2 + 101 files changed, 3498 insertions(+), 3588 deletions(-) rename lib/rust/ensogl/core/src/display/object/{class.rs => instance.rs} (53%) rename lib/rust/ensogl/core/src/display/object/{transform.rs => transformation.rs} (81%) create mode 100644 lib/rust/ensogl/core/src/display/shape/primitive/glsl.rs create mode 100644 lib/rust/ensogl/core/src/display/shape/primitive/glsl/codes.rs delete mode 100644 lib/rust/ensogl/core/src/display/shape/primitive/glsl/error_codes/id_encoding_overflow.txt create mode 100644 lib/rust/ensogl/core/src/display/shape/primitive/glsl/prelude.glsl create mode 100644 lib/rust/types/build.rs create mode 100644 lib/rust/types/src/dim.rs create mode 100644 lib/rust/types/src/dim_macros.rs diff --git a/Cargo.lock b/Cargo.lock index 2b73f5a19eb..14e59101aac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2373,6 +2373,7 @@ dependencies = [ name = "enso-types" version = "0.1.0" dependencies = [ + "enso-prelude", "enso-reflect", "nalgebra", "num-traits", diff --git a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/entry.rs b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/entry.rs index 857e269f192..78b634f9b73 100644 --- a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/entry.rs +++ b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/entry.rs @@ -180,7 +180,7 @@ impl EntryData { fn update_layout(&self, contour: Contour, text_size: text::Size, text_padding: f32) { let size = contour.size; - self.text.set_position_xy(Vector2(text_padding - size.x / 2.0, text_size.value / 2.0)); + self.text.set_xy(Vector2(text_padding - size.x / 2.0, text_size.value / 2.0)); self.separator.size.set(size); self.ellipsis.size.set(size); } diff --git a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs index 3618dd1d79e..ba2a4897320 100644 --- a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs @@ -249,7 +249,7 @@ impl Model { fn update_layout(&self, content_size: Vector2, size: Vector2) { self.mask.size.set(size); let grid_view_center = Vector2(size.x / 2.0, -size.y / 2.0); - self.mask.set_position_xy(grid_view_center); + self.mask.set_xy(grid_view_center); let offset = self.offset(content_size, size); // Additional padding is added to the viewport width to avoid rare glitches when the last // entry is cropped because it is placed right on the border of the viewport. Even 1px seems @@ -505,7 +505,7 @@ impl Breadcrumbs { model.offset(*content_size, *size) }) ); - eval scroll_anim.value((offset) model.grid.set_position_x(-offset)); + eval scroll_anim.value((offset) model.grid.set_x(-offset)); eval_ input.move_up(model.move_up()); eval_ input.move_down(model.move_down()); entries_height <- all(&entries_height, &init)._0(); diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/entry.rs b/app/gui/view/component-browser/component-list-panel/grid/src/entry.rs index 8e8af7e0780..4208d1290e0 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/src/entry.rs +++ b/app/gui/view/component-browser/component-list-panel/grid/src/entry.rs @@ -18,7 +18,6 @@ use ensogl_core::data::color; use ensogl_core::display; use ensogl_core::display::scene::Layer; use ensogl_core::display::shape::StyleWatchFrp; -use ensogl_core::display::Scene; use ensogl_grid_view as grid_view; use ensogl_grid_view::entry::Contour; use ensogl_grid_view::entry::MovedHeaderPosition; @@ -267,7 +266,7 @@ impl CurrentIcon { } impl display::Object for CurrentIcon { - fn display_object(&self) -> &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { &self.display_object } } @@ -332,16 +331,16 @@ impl Data { let shadow_addition = self.background.size.get().y - self.background.height.get(); let bg_sprite_height = bg_height + shadow_addition; let bg_y = -gap_over_header / 2.0 + overlap / 2.0 + local_scope_offset; - self.background.set_position_y(bg_y); + self.background.set_y(bg_y); self.background.size.set(Vector2(bg_width, bg_sprite_height)); self.background.height.set(bg_height); let left = -entry_size.x / 2.0 + style.padding; let icon_x = left + style.icon_size / 2.0; let icon_y = local_scope_offset; - self.icon.borrow().set_position_xy(Vector2(icon_x, icon_y)); + self.icon.borrow().set_xy(Vector2(icon_x, icon_y)); let text_x = Self::text_x_position(kind, style, grid_style); let text_y = style.text_size / 2.0 + local_scope_offset; - self.label.set_position_xy(Vector2(text_x, text_y)); + self.label.set_xy(Vector2(text_x, text_y)); } fn contour(kind: Kind, grid_style: &GridStyle, entry_size: Vector2) -> Contour { @@ -517,7 +516,7 @@ impl grid_view::Entry for View { } impl display::Object for View { - fn display_object(&self) -> &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { &self.data.display_object } } diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/lib.rs b/app/gui/view/component-browser/component-list-panel/grid/src/lib.rs index 0a62e66ae8f..8ffbbb3d862 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/grid/src/lib.rs @@ -658,7 +658,7 @@ impl component::Frp for Frp { selection_entries_style.map(f!((input) model.selection_entries_params(input))); grid_scroll_frp.resize <+ style_and_content_size.map(Model::grid_size); grid_position <- style_and_content_size.map(Model::grid_position); - eval grid_position ((pos) model.grid.set_position_xy(*pos)); + eval grid_position ((pos) model.grid.set_xy(*pos)); grid_scroll_frp.set_corner_radius_bottom_right <+ all(&corners_radius, &style.init)._0(); grid.set_entries_size <+ style.update.map(|s| s.entry_size()); grid.set_column_width <+ style.update.map(|s| (column::CENTER, s.middle_column_width())); diff --git a/app/gui/view/component-browser/component-list-panel/src/lib.rs b/app/gui/view/component-browser/component-list-panel/src/lib.rs index 447c97d794a..97e3d28078a 100644 --- a/app/gui/view/component-browser/component-list-panel/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/src/lib.rs @@ -282,13 +282,13 @@ impl Model { self.section_navigator.update_layout(style); let navigator_shadow_x = -style.grid.width / 2.0; - self.navigator_shadow.set_position_x(navigator_shadow_x); + self.navigator_shadow.set_x(navigator_shadow_x); let section_navigator_shadow_size = Vector2(style.navigator.width, style.size().y); self.navigator_shadow.size.set(section_navigator_shadow_size); - self.breadcrumbs.set_position_xy(style.breadcrumbs_pos()); + self.breadcrumbs.set_xy(style.breadcrumbs_pos()); self.breadcrumbs.set_size(style.breadcrumbs_size()); - self.grid.set_position_xy(style.grid_pos()); + self.grid.set_xy(style.grid_pos()); } /// Set the navigator so it can be disabled on hover. diff --git a/app/gui/view/component-browser/component-list-panel/src/navigator.rs b/app/gui/view/component-browser/component-list-panel/src/navigator.rs index 043c162f194..708430902f1 100644 --- a/app/gui/view/component-browser/component-list-panel/src/navigator.rs +++ b/app/gui/view/component-browser/component-list-panel/src/navigator.rs @@ -220,8 +220,8 @@ impl Navigator { let x_pos = -style.grid.width / 2.0; let top_buttons_y = top - top_buttons_height / 2.0 - top_padding; let bottom_buttons_y = bottom + bottom_buttons_height / 2.0 + bottom_padding; - self.top_buttons.set_position_xy(Vector2(x_pos, top_buttons_y)); - self.bottom_buttons.set_position_xy(Vector2(x_pos, bottom_buttons_y)); + self.top_buttons.set_xy(Vector2(x_pos, top_buttons_y)); + self.bottom_buttons.set_xy(Vector2(x_pos, bottom_buttons_y)); } } diff --git a/app/gui/view/debug_scene/icons/src/lib.rs b/app/gui/view/debug_scene/icons/src/lib.rs index b64c29e4b56..a918277aea6 100644 --- a/app/gui/view/debug_scene/icons/src/lib.rs +++ b/app/gui/view/debug_scene/icons/src/lib.rs @@ -83,7 +83,7 @@ pub fn entry_point_searcher_icons() { let shape = id.create_shape(Vector2(icon::SIZE, icon::SIZE)); shape.set_vivid_color(color::Rgba(0.243, 0.541, 0.160, 1.0).into()); shape.set_dull_color(color::Rgba(0.655, 0.788, 0.624, 1.0).into()); - shape.set_position_x(x); + shape.set_x(x); x += 20.0; world.add_child(&shape); mem::forget(shape); diff --git a/app/gui/view/graph-editor/src/builtin/visualization/native/text_grid.rs b/app/gui/view/graph-editor/src/builtin/visualization/native/text_grid.rs index fe421d23a24..0b85869dfc8 100644 --- a/app/gui/view/graph-editor/src/builtin/visualization/native/text_grid.rs +++ b/app/gui/view/graph-editor/src/builtin/visualization/native/text_grid.rs @@ -86,7 +86,7 @@ mod entry { } fn set_position_and_size(&self, pos: &Vector2, size: &Vector2) { - self.text.set_position_xy(*pos); + self.text.set_xy(*pos); self.text.set_style_or_warn("left", format!("{}px", pos.x - size.x / 2.0)); self.text.set_style_or_warn("top", format!("{}px", -pos.y - size.y / 2.0)); @@ -205,10 +205,10 @@ impl Model { } fn set_size(&self, size: Vector2) { - self.scroll_bar_horizontal.set_position_y(-size.y / 2.0); + self.scroll_bar_horizontal.set_y(-size.y / 2.0); self.scroll_bar_horizontal.set_length(size.x); - self.scroll_bar_vertical.set_position_x(size.x / 2.0); + self.scroll_bar_vertical.set_x(size.x / 2.0); self.scroll_bar_vertical.set_length(size.y); self.clipping_div.set_size(size); diff --git a/app/gui/view/graph-editor/src/component/add_node_button.rs b/app/gui/view/graph-editor/src/component/add_node_button.rs index 54d6502c337..60dd4db032e 100644 --- a/app/gui/view/graph-editor/src/component/add_node_button.rs +++ b/app/gui/view/graph-editor/src/component/add_node_button.rs @@ -129,8 +129,8 @@ impl AddNodeButton { let screen = camera.screen(); let x = -screen.width / 2.0 + margin + size / 2.0; let y = -screen.height / 2.0 + margin + size / 2.0; - view.set_position_x(x.round()); - view.set_position_y(y.round()); + view.set_x(x.round()); + view.set_y(y.round()); } } diff --git a/app/gui/view/graph-editor/src/component/breadcrumbs.rs b/app/gui/view/graph-editor/src/component/breadcrumbs.rs index 974fa546a64..97f92273dc8 100644 --- a/app/gui/view/graph-editor/src/component/breadcrumbs.rs +++ b/app/gui/view/graph-editor/src/component/breadcrumbs.rs @@ -264,8 +264,8 @@ impl BreadcrumbsModel { let gap_width = self.gap_width.get(); let project_name_width = self.project_name.width.value().round(); - self.project_name.set_position_x(gap_width); - self.breadcrumbs_container.set_position_x(gap_width + project_name_width); + self.project_name.set_x(gap_width); + self.breadcrumbs_container.set_x(gap_width + project_name_width); let width = gap_width + project_name_width + self.breadcrumbs_container_width(); let background_width = width + 2.0 * BACKGROUND_PADDING; @@ -274,8 +274,8 @@ impl BreadcrumbsModel { let width_with_shadow = background_width + MAGIC_SHADOW_MARGIN * 2.0; let height_with_shadow = background_height + MAGIC_SHADOW_MARGIN * 2.0; self.background.size.set(Vector2(width_with_shadow, height_with_shadow)); - self.background.set_position_x(width / 2.0); - self.background.set_position_y(-HEIGHT / 2.0); + self.background.set_x(width / 2.0); + self.background.set_y(-HEIGHT / 2.0); } fn get_breadcrumb(&self, index: usize) -> Option { @@ -352,7 +352,7 @@ impl BreadcrumbsModel { } debug!("Pushing {} breadcrumb.", breadcrumb.info.method_pointer.name); - breadcrumb.set_position_x(self.breadcrumbs_container_width().round()); + breadcrumb.set_x(self.breadcrumbs_container_width().round()); self.breadcrumbs_container.add_child(&breadcrumb); self.breadcrumbs.borrow_mut().push(breadcrumb); } diff --git a/app/gui/view/graph-editor/src/component/breadcrumbs/breadcrumb.rs b/app/gui/view/graph-editor/src/component/breadcrumbs/breadcrumb.rs index 3b57d9e2ce8..82853a3770f 100644 --- a/app/gui/view/graph-editor/src/component/breadcrumbs/breadcrumb.rs +++ b/app/gui/view/graph-editor/src/component/breadcrumbs/breadcrumb.rs @@ -341,8 +341,8 @@ impl BreadcrumbModel { self.label.set_property_default(color); self.label.set_property_default(text::formatting::Size::from(TEXT_SIZE)); self.label.set_single_line_mode(true); - self.label.set_position_x(ICON_RADIUS + ICON_RIGHT_MARGIN); - self.label.set_position_y(TEXT_SIZE / 2.0); + self.label.set_x(ICON_RADIUS + ICON_RIGHT_MARGIN); + self.label.set_y(TEXT_SIZE / 2.0); self.label.set_content(&self.info.method_pointer.name); let width = self.width(); @@ -354,10 +354,10 @@ impl BreadcrumbModel { let separator_size = (SEPARATOR_SIZE + PADDING * 2.0).max(0.0); let icon_size = (ICON_SIZE + PADDING * 2.0).max(0.0); self.separator.size.set(Vector2::new(separator_size, separator_size)); - self.separator.set_position_x((offset - width / 2.0).round()); + self.separator.set_x((offset - width / 2.0).round()); self.icon.size.set(Vector2::new(icon_size, icon_size)); let x_position = offset + PADDING + ICON_SIZE / 2.0 + LEFT_MARGIN + ICON_LEFT_MARGIN; - self.icon.set_position_x(x_position.round()); + self.icon.set_x(x_position.round()); self } diff --git a/app/gui/view/graph-editor/src/component/edge.rs b/app/gui/view/graph-editor/src/component/edge.rs index 409cc6520d2..5aab6e69d3e 100644 --- a/app/gui/view/graph-editor/src/component/edge.rs +++ b/app/gui/view/graph-editor/src/component/edge.rs @@ -680,25 +680,25 @@ impl LayoutLine for front::line::View { let pos = Vector2(start.x, start.y + len / 2.0); let size = Vector2(LINE_SHAPE_WIDTH, len.abs() + LINE_SIDES_OVERLAP); self.size.set(size); - self.set_position_xy(pos); + self.set_xy(pos); } fn layout_h(&self, start: Vector2, len: f32) { let pos = Vector2(start.x + len / 2.0, start.y); let size = Vector2(LINE_SHAPE_WIDTH, len.abs() + LINE_SIDES_OVERLAP); self.size.set(size); - self.set_position_xy(pos); + self.set_xy(pos); } fn layout_v_no_overlap(&self, start: Vector2, len: f32) { let pos = Vector2(start.x, start.y + len / 2.0); let size = Vector2(LINE_SHAPE_WIDTH, len.abs()); self.size.set(size); - self.set_position_xy(pos); + self.set_xy(pos); } fn layout_h_no_overlap(&self, start: Vector2, len: f32) { let pos = Vector2(start.x + len / 2.0, start.y); let size = Vector2(LINE_SHAPE_WIDTH, len.abs()); self.size.set(size); - self.set_position_xy(pos); + self.set_xy(pos); } } @@ -707,25 +707,25 @@ impl LayoutLine for back::line::View { let pos = Vector2(start.x, start.y + len / 2.0); let size = Vector2(LINE_SHAPE_WIDTH, len.abs() + LINE_SIDES_OVERLAP); self.size.set(size); - self.set_position_xy(pos); + self.set_xy(pos); } fn layout_h(&self, start: Vector2, len: f32) { let pos = Vector2(start.x + len / 2.0, start.y); let size = Vector2(LINE_SHAPE_WIDTH, len.abs() + LINE_SIDES_OVERLAP); self.size.set(size); - self.set_position_xy(pos); + self.set_xy(pos); } fn layout_v_no_overlap(&self, start: Vector2, len: f32) { let pos = Vector2(start.x, start.y + len / 2.0); let size = Vector2(LINE_SHAPE_WIDTH, len.abs()); self.size.set(size); - self.set_position_xy(pos); + self.set_xy(pos); } fn layout_h_no_overlap(&self, start: Vector2, len: f32) { let pos = Vector2(start.x + len / 2.0, start.y); let size = Vector2(LINE_SHAPE_WIDTH, len.abs()); self.size.set(size); - self.set_position_xy(pos); + self.set_xy(pos); } } @@ -1398,7 +1398,7 @@ impl EdgeModelData { self.try_enable_focus_split(hover_position, hover_target, focus_part); if let Ok(snap_data) = focus_split_result { let joint_position = snap_data.position - self.display_object.position().xy(); - self.joint.set_position_xy(joint_position); + self.joint.set_xy(joint_position); let joint_size = LINE_WIDTH + PADDING; self.joint.size.set(Vector2(joint_size, joint_size)); } @@ -1541,7 +1541,7 @@ impl EdgeModelData { bg.corner.angle.set(corner1_angle); bg.corner.radius.set(corner1_radius); bg.corner.pos.set(corner1); - bg.corner.set_position_xy(corner1); + bg.corner.set_xy(corner1); if !fully_attached { bg.corner.dim.set(Vector2(node_half_width, source_node_half_height)); fg.corner.size.set(corner1_size); @@ -1550,7 +1550,7 @@ impl EdgeModelData { fg.corner.radius.set(corner1_radius); fg.corner.pos.set(corner1); fg.corner.dim.set(Vector2(node_half_width, source_node_half_height)); - fg.corner.set_position_xy(corner1); + fg.corner.set_xy(corner1); } else { fg.corner.size.set(zero()); bg.corner.dim.set(Vector2(INFINITE, INFINITE)); @@ -1687,7 +1687,7 @@ impl EdgeModelData { bg.corner3.radius.set(corner3_radius); bg.corner3.pos.set(corner3); bg.corner3.dim.set(Vector2(INFINITE, INFINITE)); - bg.corner3.set_position_xy(corner3); + bg.corner3.set_xy(corner3); } else { bg.corner3.size.set(zero()); fg.corner3.size.set(corner3_size); @@ -1696,7 +1696,7 @@ impl EdgeModelData { fg.corner3.radius.set(corner3_radius); fg.corner3.pos.set(corner3); fg.corner3.dim.set(zero()); - fg.corner3.set_position_xy(corner3); + fg.corner3.set_xy(corner3); } let corner2_x = corner1_target.x + corner_2_3_side * corner2_radius; @@ -1711,7 +1711,7 @@ impl EdgeModelData { bg.corner2.radius.set(corner2_radius); bg.corner2.pos.set(corner2); bg.corner2.dim.set(Vector2(INFINITE, INFINITE)); - bg.corner2.set_position_xy(corner2); + bg.corner2.set_xy(corner2); } else { bg.corner2.size.set(zero()); fg.corner2.size.set(corner1_size); @@ -1720,7 +1720,7 @@ impl EdgeModelData { fg.corner2.radius.set(corner2_radius); fg.corner2.pos.set(corner2); fg.corner2.dim.set(zero()); - fg.corner2.set_position_xy(corner2); + fg.corner2.set_xy(corner2); } @@ -1751,11 +1751,11 @@ impl EdgeModelData { if fully_attached { fg.arrow.size.set(zero()); bg.arrow.size.set(arrow_size); - bg.arrow.set_position_xy(arrow_pos); + bg.arrow.set_xy(arrow_pos); } else { bg.arrow.size.set(zero()); fg.arrow.size.set(arrow_size); - fg.arrow.set_position_xy(arrow_pos); + fg.arrow.set_xy(arrow_pos); } } else { bg.arrow.size.set(zero()); diff --git a/app/gui/view/graph-editor/src/component/node.rs b/app/gui/view/graph-editor/src/component/node.rs index e14f7f55816..715614f47ca 100644 --- a/app/gui/view/graph-editor/src/component/node.rs +++ b/app/gui/view/graph-editor/src/component/node.rs @@ -629,11 +629,11 @@ impl NodeModel { self.error_indicator.size.set(padded_size); self.vcs_indicator.set_size(padded_size); let x_offset_to_node_center = x_offset_to_node_center(width); - self.backdrop.set_position_x(x_offset_to_node_center); - self.background.set_position_x(x_offset_to_node_center); - self.drag_area.set_position_x(x_offset_to_node_center); - self.error_indicator.set_position_x(x_offset_to_node_center); - self.vcs_indicator.set_position_x(x_offset_to_node_center); + self.backdrop.set_x(x_offset_to_node_center); + self.background.set_x(x_offset_to_node_center); + self.drag_area.set_x(x_offset_to_node_center); + self.error_indicator.set_x(x_offset_to_node_center); + self.vcs_indicator.set_x(x_offset_to_node_center); let action_bar_width = ACTION_BAR_WIDTH; self.action_bar.mod_position(|t| { @@ -642,8 +642,8 @@ impl NodeModel { self.action_bar.frp.set_size(Vector2::new(action_bar_width, ACTION_BAR_HEIGHT)); let visualization_offset = visualization_offset(width); - self.error_visualization.set_position_xy(visualization_offset); - self.visualization.set_position_xy(visualization_offset); + self.error_visualization.set_xy(visualization_offset); + self.visualization.set_xy(visualization_offset); size } @@ -688,6 +688,7 @@ impl Node { let input = &frp.private.input; let model = Rc::new(NodeModel::new(app, registry)); let selection = Animation::::new(network); + let display_object = &model.display_object; // TODO[ao] The comment color should be animated, but this is currently slow. Will be fixed // in https://github.com/enso-org/ide/issues/1031 @@ -696,12 +697,13 @@ impl Node { let style = StyleWatch::new(&app.display.default_scene.style_sheet); let style_frp = &model.style; let action_bar = &model.action_bar.frp; - // Hook up the display object position updates to the node's FRP. Required to calculate the - // bounding box. - model.display_object.set_on_updated(f!((p) out.position.emit(p.position().xy()))); frp::extend! { network + // Hook up the display object position updates to the node's FRP. Required to calculate + // the bounding box. + out.position <+ display_object.on_updated.map(f_!(display_object.position().xy())); + // === Hover === // The hover discovery of a node is an interesting process. First, we discover whether // ths user hovers the drag area. The input port manager merges this information with @@ -758,9 +760,9 @@ impl Node { eval comment_color ((value) model.comment.set_property(.., color::Rgba::from(value))); eval model.comment.width ([model](width) - model.comment.set_position_x(-*width - COMMENT_MARGIN)); + model.comment.set_x(-*width - COMMENT_MARGIN)); eval model.comment.height ([model](height) - model.comment.set_position_y(*height / 2.0)); + model.comment.set_y(*height / 2.0)); model.comment.set_content <+ input.set_comment; out.comment <+ model.comment.content.map(|text| text.to_im_string()); diff --git a/app/gui/view/graph-editor/src/component/node/action_bar.rs b/app/gui/view/graph-editor/src/component/node/action_bar.rs index dbea2680e47..cd6704f0605 100644 --- a/app/gui/view/graph-editor/src/component/node/action_bar.rs +++ b/app/gui/view/graph-editor/src/component/node/action_bar.rs @@ -192,12 +192,12 @@ impl Model { self.hover_area.size.set(hover_ara_size); let center_offset = -size.x / 2.0 + hover_ara_size.x / 2.0; let padding_offset = -0.5 * hover_padding * button_width - HOVER_EXTENSION_X / 2.0; - self.hover_area.set_position_x(center_offset + padding_offset); + self.hover_area.set_x(center_offset + padding_offset); } fn set_size(&self, size: Vector2) { self.size.set(size); - self.icons.set_position_x(-size.x / 2.0); + self.icons.set_x(-size.x / 2.0); // Note: Disabled for https://github.com/enso-org/ide/issues/1397 // Should be re-enabled when https://github.com/enso-org/ide/issues/862 as been implemented. diff --git a/app/gui/view/graph-editor/src/component/node/input/area.rs b/app/gui/view/graph-editor/src/component/node/input/area.rs index f4ce7d54381..10b6f45598e 100644 --- a/app/gui/view/graph-editor/src/component/node/input/area.rs +++ b/app/gui/view/graph-editor/src/component/node/input/area.rs @@ -230,8 +230,8 @@ impl Model { self.label.remove_all_cursors(); let origin = Vector2(TEXT_OFFSET, 0.0); - self.ports.set_position_xy(origin); - self.label.set_position_xy(origin); + self.ports.set_xy(origin); + self.label.set_xy(origin); self.label.mod_position(|t| t.y += TEXT_SIZE / 2.0); self diff --git a/app/gui/view/graph-editor/src/component/node/output/area.rs b/app/gui/view/graph-editor/src/component/node/output/area.rs index 1ff0a2e416f..da140a7108a 100644 --- a/app/gui/view/graph-editor/src/component/node/output/area.rs +++ b/app/gui/view/graph-editor/src/component/node/output/area.rs @@ -239,7 +239,7 @@ impl Model { fn set_label(&self, content: impl Into) { let str = if ARGS.node_labels.unwrap_or(true) { content.into() } else { default() }; self.label.set_content(str); - self.label.set_position_x(-self.label.width.value() - input::area::TEXT_OFFSET); + self.label.set_x(-self.label.width.value() - input::area::TEXT_OFFSET); } /// Update expression type for the particular `ast::Id`. @@ -329,7 +329,7 @@ impl Model { #[profile(Debug)] fn set_size(&self, size: Vector2) { - self.ports.set_position_x(size.x / 2.0); + self.ports.set_x(size.x / 2.0); self.traverse_borrowed_expression_mut(|is_a_port, node, _| { if is_a_port { node.payload_mut().set_size(size) diff --git a/app/gui/view/graph-editor/src/component/node/output/port.rs b/app/gui/view/graph-editor/src/component/node/output/port.rs index 280155920ff..cc288e79475 100644 --- a/app/gui/view/graph-editor/src/component/node/output/port.rs +++ b/app/gui/view/graph-editor/src/component/node/output/port.rs @@ -485,7 +485,7 @@ impl Model { let type_label = app.new_view::(); let offset_y = styles.get_number(ensogl_hardcoded_theme::graph_editor::node::type_label::offset_y); - type_label.set_position_y(offset_y); + type_label.set_y(offset_y); self.type_label = Some(type_label.clone()); let display_object = display::object::Instance::new(); @@ -549,7 +549,7 @@ impl Model { let label_center_x = port_center_x; label_center_x - type_label_width / 2.0 })); - eval set_type_label_x ((&t) type_label.set_position_x(t)); + eval set_type_label_x ((&t) type_label.set_x(t)); eval frp.set_size_multiplier ((t) shape.set_size_multiplier(*t)); diff --git a/app/gui/view/graph-editor/src/component/node/profiling.rs b/app/gui/view/graph-editor/src/component/node/profiling.rs index ac6e324fdaa..6ecf856ca32 100644 --- a/app/gui/view/graph-editor/src/component/node/profiling.rs +++ b/app/gui/view/graph-editor/src/component/node/profiling.rs @@ -201,7 +201,7 @@ impl ProfilingLabel { let label = text::Text::new(app); root.add_child(&label); - label.set_position_y(crate::component::node::input::area::TEXT_SIZE / 2.0); + label.set_y(crate::component::node::input::area::TEXT_SIZE / 2.0); scene.layers.main.remove(&label); label.add_to_scene_layer(&scene.layers.label); @@ -236,7 +236,7 @@ impl ProfilingLabel { // === Position === let x_offset = crate::component::node::input::area::TEXT_OFFSET; - eval label.width((&width) label.set_position_x(-width-x_offset)); + eval label.width((&width) label.set_x(-width-x_offset)); // === Content === diff --git a/app/gui/view/graph-editor/src/component/profiling.rs b/app/gui/view/graph-editor/src/component/profiling.rs index 057e2e6c314..de708358a38 100644 --- a/app/gui/view/graph-editor/src/component/profiling.rs +++ b/app/gui/view/graph-editor/src/component/profiling.rs @@ -167,8 +167,8 @@ impl Button { eval scene.frp.camera_changed([button,scene](_) { let screen = scene.camera().screen(); - button.set_position_x(screen.width/2.0 - 16.0); - button.set_position_y(screen.height/2.0 - 16.0); + button.set_x(screen.width/2.0 - 16.0); + button.set_y(screen.height/2.0 - 16.0); }); diff --git a/app/gui/view/graph-editor/src/component/visualization/container.rs b/app/gui/view/graph-editor/src/component/visualization/container.rs index 86d31448cd8..c4a4adebbeb 100644 --- a/app/gui/view/graph-editor/src/component/visualization/container.rs +++ b/app/gui/view/graph-editor/src/component/visualization/container.rs @@ -414,7 +414,7 @@ impl ContainerModel { self.action_bar.frp.set_size.emit(action_bar_size); } - self.action_bar.set_position_y((size.y - ACTION_BAR_HEIGHT) / 2.0); + self.action_bar.set_y((size.y - ACTION_BAR_HEIGHT) / 2.0); if let Some(viz) = &*self.visualization.borrow() { viz.set_size.emit(size); @@ -649,9 +649,9 @@ impl Container { // === Action bar actions === frp::extend! { network - eval_ action_bar.on_container_reset_position(model.drag_root.set_position_xy(Vector2::zero())); + eval_ action_bar.on_container_reset_position(model.drag_root.set_xy(Vector2::zero())); drag_action <- app.cursor.frp.scene_position_delta.gate(&action_bar.container_drag_state); - eval drag_action ((mouse) model.drag_root.mod_position_xy(|pos| pos - mouse.xy())); + eval drag_action ((mouse) model.drag_root.mod_xy(|pos| pos - mouse.xy())); } // FIXME[mm]: If we set the size right here, we will see spurious shapes in some diff --git a/app/gui/view/graph-editor/src/component/visualization/container/action_bar.rs b/app/gui/view/graph-editor/src/component/visualization/container/action_bar.rs index 2135771f876..7c350d74ebb 100644 --- a/app/gui/view/graph-editor/src/component/visualization/container/action_bar.rs +++ b/app/gui/view/graph-editor/src/component/visualization/container/action_bar.rs @@ -198,7 +198,7 @@ impl Icons { fn set_size(&self, size: Vector2) { self.size.set(size); - self.icon_root.set_position_x(-size.x / 2.0); + self.icon_root.set_x(-size.x / 2.0); self.place_shape_in_slot(&self.drag_icon, 0); self.place_shape_in_slot(&self.reset_position_icon, 1); } @@ -298,7 +298,7 @@ impl Model { let right_padding = height / 2.0; self.visualization_chooser.frp.set_icon_size(Vector2::new(height, height)); self.visualization_chooser.frp.set_icon_padding(Vector2::new(height / 3.0, height / 3.0)); - self.visualization_chooser.set_position_x((width / 2.0) - right_padding); + self.visualization_chooser.set_x((width / 2.0) - right_padding); self.visualization_chooser.frp.set_menu_offset_y(MENU_GAP); } diff --git a/app/gui/view/graph-editor/src/lib.rs b/app/gui/view/graph-editor/src/lib.rs index c4b67ab411b..532329ee24a 100644 --- a/app/gui/view/graph-editor/src/lib.rs +++ b/app/gui/view/graph-editor/src/lib.rs @@ -1468,7 +1468,7 @@ impl GraphEditorModelWithNetwork { ) -> (NodeId, Option, bool) { let position = new_node_position::new_node_position(self, way, mouse_position); let node = self.new_node(ctx); - node.set_position_xy(position); + node.set_xy(position); let should_edit = !matches!(way, WayOfCreatingNode::AddNodeEvent); if should_edit { node.view.set_expression(node::Expression::default()); @@ -1741,8 +1741,8 @@ impl GraphEditorModel { self.add_child(&self.breadcrumbs); let x_offset = MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET; let y_offset = MACOS_TRAFFIC_LIGHTS_VERTICAL_CENTER + component::breadcrumbs::HEIGHT / 2.0; - self.breadcrumbs.set_position_x(x_offset); - self.breadcrumbs.set_position_y(y_offset); + self.breadcrumbs.set_x(x_offset); + self.breadcrumbs.set_y(y_offset); self.breadcrumbs.gap_width(traffic_lights_gap_width()); self.scene().add_child(&self.tooltip); self.add_child(&self.profiling_button); @@ -3877,7 +3877,7 @@ mod tests { camera_pos: Vector2, ) { let camera = &scene.camera(); - camera.set_position_xy(camera_pos); + camera.set_xy(camera_pos); camera.update(scene); click_add_node_button(editor); } @@ -3941,12 +3941,12 @@ mod tests { // Create 2nd node below the 1st one and move it slightly to the right. graph_editor.nodes().select(node_1_id); let (node_2_id, node_2) = graph_editor.add_node_by(&press_add_node_shortcut); - node_2.mod_position_x(|x| x + 16.0); + node_2.mod_x(|x| x + 16.0); // Create 3rd node below the 2nd one and move it slightly down and far to the right. graph_editor.nodes().select(node_2_id); let (_, node_3) = graph_editor.add_node_by(&press_add_node_shortcut); - node_2.mod_position_xy(|pos| pos + Vector2(800.0, -7.0)); + node_2.mod_xy(|pos| pos + Vector2(800.0, -7.0)); // Create 4th node by clicking (+) button when camera is roughly centered at the 1st node. let small_displacement = Vector2(8.0, 9.0); @@ -3987,7 +3987,7 @@ mod tests { fn add_node_by_api_at_pos(&self, position: Vector2) -> (NodeId, Node) { let (node_id, node) = self.add_node_by_api(); self.stop_editing(); - node.set_position_xy(position); + node.set_xy(position); (node_id, node) } diff --git a/app/gui/view/src/code_editor.rs b/app/gui/view/src/code_editor.rs index eb6f16867db..6eb70bcf515 100644 --- a/app/gui/view/src/code_editor.rs +++ b/app/gui/view/src/code_editor.rs @@ -74,7 +74,7 @@ impl View { let model = app.new_view::(); let height_fraction = DEPRECATED_Animation::::new(network); - model.set_position_x(PADDING_LEFT); + model.set_x(PADDING_LEFT); scene.layers.main.remove(&model); model.add_to_scene_layer(&scene.layers.panel_text); // TODO[ao]: To have code editor usable we treat it as constantly mouse-hovered, but this @@ -108,7 +108,7 @@ impl View { let y = -scene_size.height / 2.0 + height; Vector2(x,y) }); - eval position ((pos) model.set_position_xy(*pos)); + eval position ((pos) model.set_xy(*pos)); let color = styles.get_color(ensogl_hardcoded_theme::code::syntax::base); eval color ((color) model.set_property_default(color)); diff --git a/app/gui/view/src/component_browser.rs b/app/gui/view/src/component_browser.rs index af808ba08b9..1a2cd02f2fe 100644 --- a/app/gui/view/src/component_browser.rs +++ b/app/gui/view/src/component_browser.rs @@ -125,8 +125,8 @@ impl component::Frp for Frp { list_position_x <- all_with3(&size, &list_panel.size, &snap, |sz, list_sz, snap| list_sz.x / 2.0 - sz.x / 2.0 + snap.x); doc_position_x <- all_with3(&size, &doc_size, &snap, |sz, doc_sz, snap| sz.x / 2.0 - doc_sz.x / 2.0 + snap.x); - eval list_position_x ((x) model.list.set_position_x(*x)); - eval doc_position_x ((x) model.documentation.set_position_x(*x)); + eval list_position_x ((x) model.list.set_x(*x)); + eval doc_position_x ((x) model.documentation.set_x(*x)); model.list.input.show <+ input.show; model.list.input.hide <+ input.hide; diff --git a/app/gui/view/src/debug_mode_popup.rs b/app/gui/view/src/debug_mode_popup.rs index d684280a1b2..36231f290aa 100644 --- a/app/gui/view/src/debug_mode_popup.rs +++ b/app/gui/view/src/debug_mode_popup.rs @@ -8,7 +8,6 @@ use enso_frp as frp; use ensogl::animation::delayed::DelayedAnimation; use ensogl::application::Application; use ensogl::display; -use ensogl::display::scene::Scene; use ensogl::Animation; use ensogl_component::label::Label; @@ -50,7 +49,7 @@ pub struct PopupLabel { } impl display::Object for PopupLabel { - fn display_object(&self) -> &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { self.label.display_object() } } @@ -180,7 +179,7 @@ impl View { let half_height = scene_size.height / 2.0; let label_height = model.label_height(); let pos_y = half_height - LABEL_PADDING_TOP - label_height / 2.0; - model.display_object.set_position_y(pos_y); + model.display_object.set_y(pos_y); })); eval_ frp.enabled(model.show_enabled_label()); @@ -198,7 +197,7 @@ impl View { } impl display::Object for View { - fn display_object(&self) -> &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { &self.model.display_object } } diff --git a/app/gui/view/src/open_dialog.rs b/app/gui/view/src/open_dialog.rs index bc7d0fa7002..d2645ca52b5 100644 --- a/app/gui/view/src/open_dialog.rs +++ b/app/gui/view/src/open_dialog.rs @@ -67,8 +67,8 @@ impl OpenDialog { project_list_x <- all_with(&width,&project_list_width,|w,pw| - *w / 2.0 + *pw / 2.0); file_browser_x <- all_with(&width,&file_browser_width, |w,fw| w / 2.0 - *fw / 2.0); - eval project_list_x ((x) project_list.set_position_x(*x)); - eval file_browser_x ((x) file_browser.set_position_x(*x)); + eval project_list_x ((x) project_list.set_x(*x)); + eval file_browser_x ((x) file_browser.set_x(*x)); } init.emit(()); Self { logger, network, project_list, file_browser, display_object, style_watch } diff --git a/app/gui/view/src/open_dialog/project_list.rs b/app/gui/view/src/open_dialog/project_list.rs index 2ec7ce18681..bf155bb612d 100644 --- a/app/gui/view/src/open_dialog/project_list.rs +++ b/app/gui/view/src/open_dialog/project_list.rs @@ -130,8 +130,8 @@ impl ProjectList { eval size ((size) background.size.set(*size)); eval list_size ((size) list.resize(*size)); - eval list_y ((y) list.set_position_y(*y)); - eval caption_xy ((xy) caption.set_position_xy(*xy)); + eval list_y ((y) list.set_y(*y)); + eval caption_xy ((xy) caption.set_xy(*xy)); eval color ((color) caption.set_property_default(color)); eval label_size ((size) caption.set_property_default(text::Size(*size))); }; diff --git a/app/gui/view/src/project.rs b/app/gui/view/src/project.rs index 72fe60842eb..6105e9db8de 100644 --- a/app/gui/view/src/project.rs +++ b/app/gui/view/src/project.rs @@ -25,7 +25,6 @@ use ensogl::application::shortcut; use ensogl::application::Application; use ensogl::display; use ensogl::display::navigation::navigator::Navigator; -use ensogl::display::Scene; use ensogl::system::web; use ensogl::system::web::dom; use ensogl::Animation; @@ -223,7 +222,7 @@ impl SearcherVariant { SearcherVariant::ComponentBrowser(view) => { frp::extend! {network cb_position <- all_with(anchor, &view.expression_input_position, |anchor, pos| anchor - pos); - eval cb_position ((pos) view.set_position_xy(*pos)); + eval cb_position ((pos) view.set_xy(*pos)); } } SearcherVariant::OldNodeSearcher(view) => { @@ -233,7 +232,7 @@ impl SearcherVariant { let y = anchor.y - node::HEIGHT / 2.0 - size.y / 2.0; Vector2(x, y) }); - eval searcher_pos ((pos) view.set_position_xy(*pos)); + eval searcher_pos ((pos) view.set_xy(*pos)); } } } @@ -241,7 +240,7 @@ impl SearcherVariant { } impl display::Object for SearcherVariant { - fn display_object(&self) -> &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { match self { SearcherVariant::ComponentBrowser(view) => view.display_object(), SearcherVariant::OldNodeSearcher(view) => view.display_object(), @@ -391,7 +390,7 @@ impl Model { // Top buttons must always stay in top-left corner. if let Some(window_control_buttons) = &*self.window_control_buttons { let pos = Vector2(-shape.width, shape.height) / 2.0; - window_control_buttons.set_position_xy(pos); + window_control_buttons.set_xy(pos); } } @@ -552,7 +551,7 @@ impl View { let move_to_edited_node = searcher_pos * (1.0 - zoom); preserve_zoom + move_to_edited_node }); - eval searcher_cam_pos ((pos) searcher_cam.set_position_xy(*pos)); + eval searcher_cam_pos ((pos) searcher_cam.set_xy(*pos)); eval searcher.is_visible ([model](is_visible) { let is_attached = model.searcher.has_parent(); @@ -737,7 +736,7 @@ impl View { ); _eval <- all_with3(&model.prompt.width,&prompt_size,&prompt_bg_padding, f!([model](width,size,padding) { - model.prompt.set_position_x(- *width / 2.0); + model.prompt.set_x(- *width / 2.0); model.prompt_background.size.set(Vector2(*width + padding, *size + padding)); }) ); diff --git a/app/gui/view/src/searcher.rs b/app/gui/view/src/searcher.rs index 974152f4054..44968c84273 100644 --- a/app/gui/view/src/searcher.rs +++ b/app/gui/view/src/searcher.rs @@ -135,10 +135,10 @@ impl Model { let action_list_gap_path = ensogl_hardcoded_theme::application::searcher::action_list_gap; let action_list_gap = style.get_number_or(action_list_gap_path, 0.0); list.set_label_layer(&scene.layers.node_searcher_text); - list.set_position_y(-action_list_gap); - list.set_position_x(ACTION_LIST_X); - documentation.set_position_x(DOCUMENTATION_X); - documentation.set_position_y(-action_list_gap); + list.set_y(-action_list_gap); + list.set_x(ACTION_LIST_X); + documentation.set_x(DOCUMENTATION_X); + documentation.set_y(-action_list_gap); Self { app, logger, display_object, list, documentation, doc_provider } } diff --git a/app/gui/view/src/status_bar.rs b/app/gui/view/src/status_bar.rs index 593f19f4fd5..5be25ce7950 100644 --- a/app/gui/view/src/status_bar.rs +++ b/app/gui/view/src/status_bar.rs @@ -16,7 +16,6 @@ use ensogl::application::Application; use ensogl::display; use ensogl::display::camera::Camera2d; use ensogl::display::style; -use ensogl::display::Scene; use ensogl_component::shadow; use ensogl_hardcoded_theme as theme; use ensogl_text as text; @@ -209,13 +208,13 @@ impl Model { fn camera_changed(&self) { let screen = self.camera.screen(); let y = screen.height / 2.0 - MARGIN; - self.root.set_position_y(y.round()); + self.root.set_y(y.round()); } fn update_layout(&self) { let label_width = self.label.width.value(); - self.label.set_position_x(-label_width / 2.0); - self.label.set_position_y(-HEIGHT / 2.0 + TEXT_SIZE / 2.0); + self.label.set_x(-label_width / 2.0); + self.label.set_y(-HEIGHT / 2.0 + TEXT_SIZE / 2.0); let bg_width = if label_width > 0.0 { label_width + 2.0 * PADDING + 2.0 * MAGIC_SHADOW_MARGIN @@ -224,7 +223,7 @@ impl Model { }; let bg_height = HEIGHT + 2.0 * MAGIC_SHADOW_MARGIN; self.background.size.set(Vector2(bg_width, bg_height)); - self.background.set_position_y(-HEIGHT / 2.0); + self.background.set_y(-HEIGHT / 2.0); } fn add_event(&self, label: &event::Label) -> event::Id { @@ -350,7 +349,7 @@ impl View { } impl display::Object for View { - fn display_object(&self) -> &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { &self.model.display_object } } diff --git a/app/gui/view/src/window_control_buttons.rs b/app/gui/view/src/window_control_buttons.rs index 40ec24c8ce5..a23c86dcea6 100644 --- a/app/gui/view/src/window_control_buttons.rs +++ b/app/gui/view/src/window_control_buttons.rs @@ -176,16 +176,16 @@ impl Model { let padding_offset = Vector2(padding_left, -padding_top); let origin_offset = |size: Vector2| Vector2(size.x / 2.0, -size.y / 2.0); - self.close.set_position_xy(padding_offset + origin_offset(close_size)); + self.close.set_xy(padding_offset + origin_offset(close_size)); let fullscreen_x = padding_left + close_size.x + spacing; self.fullscreen - .set_position_xy(Vector2(fullscreen_x, -padding_top) + origin_offset(fullscreen_size)); + .set_xy(Vector2(fullscreen_x, -padding_top) + origin_offset(fullscreen_size)); let width = fullscreen_x + fullscreen_size.x + padding_right; let height = padding_top + max(close_size.y, fullscreen_size.y) + padding_bottom; let size = Vector2(width, height); - self.shape.set_position_xy(Vector2(size.x, -size.y) / 2.0); + self.shape.set_xy(Vector2(size.x, -size.y) / 2.0); self.shape.size.set(size); size } diff --git a/integration-test/tests/graph_editor.rs b/integration-test/tests/graph_editor.rs index 87bb76a310a..af7056b4b00 100644 --- a/integration-test/tests/graph_editor.rs +++ b/integration-test/tests/graph_editor.rs @@ -147,7 +147,7 @@ async fn adding_node_with_add_node_button() { // If there is a free space, the new node is created in the center of screen. let camera = scene.layers.main.camera(); - camera.mod_position_xy(|pos| pos + Vector2(1000.0, 1000.0)); + camera.mod_xy(|pos| pos + Vector2(1000.0, 1000.0)); wait_a_frame().await; graph_editor.nodes().deselect_all(); let (node_id, node_source, _) = add_node_with_add_node_button(&graph_editor, "1").await; diff --git a/lib/rust/ensogl/component/drop-down-menu/src/lib.rs b/lib/rust/ensogl/component/drop-down-menu/src/lib.rs index 16f9e9a769f..ceea5494324 100644 --- a/lib/rust/ensogl/component/drop-down-menu/src/lib.rs +++ b/lib/rust/ensogl/component/drop-down-menu/src/lib.rs @@ -265,24 +265,24 @@ impl DropDownMenu { resize_menu <- all(model.selection_menu.size,frp.input.set_icon_size,frp.input.set_menu_offset_y); eval resize_menu (((menu_size,icon_size,menu_offset_y)) { // Align the top of the menu to the bottom of the icon. - model.selection_menu.set_position_y(-menu_size.y/2.0-icon_size.y/2.0-menu_offset_y); + model.selection_menu.set_y(-menu_size.y/2.0-icon_size.y/2.0-menu_offset_y); // Align the right of the menu to the right of the icon. let offfset_y = -menu_size.x/2.0+icon_size.x/2.0-list_view::SHADOW_PX/2.0; - model.selection_menu.set_position_x(offfset_y); + model.selection_menu.set_x(offfset_y); }); label_position <- all(model.label.frp.width,frp.input.set_icon_size); eval label_position (((text_width,icon_size)) { - model.label.set_position_x(-text_width-icon_size.x/2.0); + model.label.set_x(-text_width-icon_size.x/2.0); // Adjust for text offset, so this appears more centered. - model.label.set_position_y(0.25 * icon_size.y); + model.label.set_y(0.25 * icon_size.y); }); overlay_size <- all(model.label.frp.width,frp.input.set_icon_size); eval overlay_size ([model]((text_width,icon_size)) { let size = Vector2::new(text_width + icon_size.x,icon_size.y); model.icon_overlay.size.set(size); - model.icon_overlay.set_position_x(-text_width/2.0); + model.icon_overlay.set_x(-text_width/2.0); }); diff --git a/lib/rust/ensogl/component/file-browser/src/lib.rs b/lib/rust/ensogl/component/file-browser/src/lib.rs index cc0e702e595..a308928b629 100644 --- a/lib/rust/ensogl/component/file-browser/src/lib.rs +++ b/lib/rust/ensogl/component/file-browser/src/lib.rs @@ -38,7 +38,6 @@ use crate::prelude::*; use crate::model::AnyFolderContent; use ensogl_core::display; -use ensogl_core::display::Scene; use std::path::PathBuf; @@ -108,7 +107,7 @@ impl Default for FileBrowser { } impl display::Object for FileBrowser { - fn display_object(&self) -> &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { &self.display_object } } diff --git a/lib/rust/ensogl/component/flame-graph/src/lib.rs b/lib/rust/ensogl/component/flame-graph/src/lib.rs index 20802369556..564689e9126 100644 --- a/lib/rust/ensogl/component/flame-graph/src/lib.rs +++ b/lib/rust/ensogl/component/flame-graph/src/lib.rs @@ -136,7 +136,7 @@ pub fn shape_from_block( component.set_content.emit(block.label); component.set_size.emit(size); - component.set_position_xy(pos); + component.set_xy(pos); component } @@ -151,7 +151,7 @@ fn shape_from_mark(mark: profiler_flame_graph::Mark, app: &Application) -> Mark let label = format!("{} ({:.1}ms)", mark.label, mark.position); component.set_content.emit(label); - component.set_position_xy(pos); + component.set_xy(pos); component } @@ -267,8 +267,8 @@ impl FlameGraph { /// position as the root display object). pub fn set_origin(&mut self, new_origin: f64) { let delta = (self.origin_x - new_origin) as f32; - self.marks.iter().for_each(|mark| mark.mod_position_x(|pos| pos - delta)); - self.blocks.iter().for_each(|block| block.mod_position_x(|pos| pos - delta)); + self.marks.iter().for_each(|mark| mark.mod_x(|pos| pos - delta)); + self.blocks.iter().for_each(|block| block.mod_x(|pos| pos - delta)); self.origin_x = new_origin } } diff --git a/lib/rust/ensogl/component/grid-view/src/entry/visible.rs b/lib/rust/ensogl/component/grid-view/src/entry/visible.rs index fcd59f7cf09..712a867e0d8 100644 --- a/lib/rust/ensogl/component/grid-view/src/entry/visible.rs +++ b/lib/rust/ensogl/component/grid-view/src/entry/visible.rs @@ -101,7 +101,7 @@ where EntryParams: frp::node::Data contour <- all(init, entry_frp.contour)._1(); eval contour ((c) overlay.set_contour(*c)); contour_offset <- all(init, entry_frp.contour_offset)._1(); - eval contour_offset ((off) overlay.set_position_xy(*off)); + eval contour_offset ((off) overlay.set_xy(*off)); let events = &overlay.events; let disabled = &entry_frp.disabled; @@ -173,7 +173,7 @@ pub fn set_position( column_widths: &ColumnWidths, ) { let pos = position(row, col, entry_size, column_widths); - entry.set_position_xy(pos); + entry.set_xy(pos); entry.frp().position_set(pos); } diff --git a/lib/rust/ensogl/component/grid-view/src/header.rs b/lib/rust/ensogl/component/grid-view/src/header.rs index fb948b61b6d..6480bbd1b70 100644 --- a/lib/rust/ensogl/component/grid-view/src/header.rs +++ b/lib/rust/ensogl/component/grid-view/src/header.rs @@ -231,7 +231,7 @@ impl Model Model &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { &self.display_object } } diff --git a/lib/rust/ensogl/component/grid-view/src/selectable/highlight/shape.rs b/lib/rust/ensogl/component/grid-view/src/selectable/highlight/shape.rs index eee4bfbc329..1681ef6d05c 100644 --- a/lib/rust/ensogl/component/grid-view/src/selectable/highlight/shape.rs +++ b/lib/rust/ensogl/component/grid-view/src/selectable/highlight/shape.rs @@ -79,7 +79,7 @@ ensogl_core::shape! { /// [module's docs](mod@self) for more info. pub fn set_viewport(shape: &View, viewport: Viewport) { shape.size.set(viewport.size()); - shape.set_position_xy(viewport.center_point()); + shape.set_xy(viewport.center_point()); } diff --git a/lib/rust/ensogl/component/grid-view/src/simple.rs b/lib/rust/ensogl/component/grid-view/src/simple.rs index 14e0182eee2..0d9f8eee724 100644 --- a/lib/rust/ensogl/component/grid-view/src/simple.rs +++ b/lib/rust/ensogl/component/grid-view/src/simple.rs @@ -114,7 +114,7 @@ impl EntryData { fn update_layout(&self, contour: entry::Contour, text_size: text::Size, text_offset: f32) { self.background.set_contour(contour); let size = contour.size; - self.label.set_position_xy(Vector2(text_offset - size.x / 2.0, text_size.value / 2.0)); + self.label.set_xy(Vector2(text_offset - size.x / 2.0, text_size.value / 2.0)); } } diff --git a/lib/rust/ensogl/component/label/src/lib.rs b/lib/rust/ensogl/component/label/src/lib.rs index 5c7d1a52846..6eff3d734ed 100644 --- a/lib/rust/ensogl/component/label/src/lib.rs +++ b/lib/rust/ensogl/component/label/src/lib.rs @@ -135,7 +135,7 @@ impl Model { let padded_size = size + padding * 2.0; self.background.size.set(padded_size); let text_origin = Vector2(text_offset - size.x / 2.0, text_size / 2.0); - self.label.set_position_xy(text_origin); + self.label.set_xy(text_origin); padded_size } diff --git a/lib/rust/ensogl/component/list-view/src/entry.rs b/lib/rust/ensogl/component/list-view/src/entry.rs index 058a87a47a8..b9fcfe2d4e1 100644 --- a/lib/rust/ensogl/component/list-view/src/entry.rs +++ b/lib/rust/ensogl/component/list-view/src/entry.rs @@ -125,7 +125,7 @@ impl Label { label.set_property_default <+ color.ref_into_some(); label.set_font <+ font; label.set_property_default <+ size.map(|v| text::Size(*v)).ref_into_some(); - eval size ((size) label.set_position_y(size/2.0)); + eval size ((size) label.set_y(size/2.0)); label.set_content <+ text; label.set_view_width <+ max_width_px.some(); diff --git a/lib/rust/ensogl/component/list-view/src/entry/list.rs b/lib/rust/ensogl/component/list-view/src/entry/list.rs index b460d18ed6c..fc9c6214de2 100644 --- a/lib/rust/ensogl/component/list-view/src/entry/list.rs +++ b/lib/rust/ensogl/component/list-view/src/entry/list.rs @@ -288,7 +288,7 @@ impl ListData { entry.entry.update(&default()); } }; - entry.entry.set_position_y(Self::position_y_of_entry(id)); + entry.entry.set_y(Self::position_y_of_entry(id)); } } diff --git a/lib/rust/ensogl/component/list-view/src/lib.rs b/lib/rust/ensogl/component/list-view/src/lib.rs index 491af56856f..82d375026a9 100644 --- a/lib/rust/ensogl/component/list-view/src/lib.rs +++ b/lib/rust/ensogl/component/list-view/src/lib.rs @@ -235,10 +235,10 @@ impl Model { let margin = Vector2(2.0 * SHAPE_MARGIN, 2.0 * SHAPE_MARGIN); let shadow = Vector2(2.0 * SHADOW_PX, 2.0 * SHADOW_PX); let entry_width = view.size.x - 2.0 * entry_padding; - self.entries.set_position_x(-view.size.x / 2.0 + entry_padding); + self.entries.set_x(-view.size.x / 2.0 + entry_padding); self.background.size.set(view.size + padding + shadow + margin); self.overlay.size.set(view.size + padding + shadow + margin); - self.scrolled_area.set_position_y(view.size.y / 2.0 - view.position_y); + self.scrolled_area.set_y(view.size.y / 2.0 - view.position_y); self.entries.update_entries(visible_entries, entry_width, style_prefix); } @@ -594,7 +594,7 @@ where E::Model: Default selection_sprite_y <- all_with3(&selection_y.value, &selection_height.value, &style.selection_height, |y, h, max_h| y + (max_h - h) / 2.0 ); - eval selection_sprite_y ((y) model.selection.set_position_y(*y)); + eval selection_sprite_y ((y) model.selection.set_y(*y)); frp.source.selection_size <+ all_with3(&frp.size, &style.padding, &selection_height.value, f!([](size, padding, height) { let width = size.x - 2.0 * padding; Vector2(width,*height) diff --git a/lib/rust/ensogl/component/scroll-area/src/lib.rs b/lib/rust/ensogl/component/scroll-area/src/lib.rs index 5a6ddbaf261..81474819a06 100644 --- a/lib/rust/ensogl/component/scroll-area/src/lib.rs +++ b/lib/rust/ensogl/component/scroll-area/src/lib.rs @@ -199,14 +199,14 @@ struct Model { impl Model { fn resize(&self, size: Vector2) { - self.h_scrollbar.set_position_y(-size.y + scrollbar::WIDTH / 2.0); + self.h_scrollbar.set_y(-size.y + scrollbar::WIDTH / 2.0); let scrollbar_y = size.x - scrollbar::WIDTH / 2.0 + scrollbar::PADDING / 2.0 + 1.0; - self.v_scrollbar.set_position_x(scrollbar_y); - self.h_scrollbar.set_position_x(size.x / 2.0); - self.v_scrollbar.set_position_y(-size.y / 2.0); + self.v_scrollbar.set_x(scrollbar_y); + self.h_scrollbar.set_x(size.x / 2.0); + self.v_scrollbar.set_y(-size.y / 2.0); self.mask.size.set(size); - self.mask.set_position_x(size.x / 2.0); - self.mask.set_position_y(-size.y / 2.0); + self.mask.set_x(size.x / 2.0); + self.mask.set_y(-size.y / 2.0); } } @@ -335,8 +335,8 @@ impl ScrollArea { frp.source.scroll_position_target_x <+ model.h_scrollbar.thumb_position_target.map(|x| -x); frp.source.scroll_position_target_y <+ model.v_scrollbar.thumb_position_target; - eval frp.scroll_position_x((&pos) model.content.set_position_x(pos)); - eval frp.scroll_position_y((&pos) model.content.set_position_y(pos)); + eval frp.scroll_position_x((&pos) model.content.set_x(pos)); + eval frp.scroll_position_y((&pos) model.content.set_y(pos)); scroll_position <- all(&frp.scroll_position_x, &frp.scroll_position_y); scroll_position <- scroll_position.map(|(x,y)| Vector2::new(*x,*y)); diff --git a/lib/rust/ensogl/component/selector/src/decimal_aligned.rs b/lib/rust/ensogl/component/selector/src/decimal_aligned.rs index 0ee8c008a39..76a2d350ae7 100644 --- a/lib/rust/ensogl/component/selector/src/decimal_aligned.rs +++ b/lib/rust/ensogl/component/selector/src/decimal_aligned.rs @@ -83,7 +83,7 @@ impl Frp { model.label_full.set_content <+ formatted; eval model.label_left.width((offset) - model.label_full.set_position_x(-offset-LABEL_OFFSET)); + model.label_full.set_x(-offset-LABEL_OFFSET)); } } } diff --git a/lib/rust/ensogl/component/selector/src/frp.rs b/lib/rust/ensogl/component/selector/src/frp.rs index 49be503eea1..c1cb1685b6c 100644 --- a/lib/rust/ensogl/component/selector/src/frp.rs +++ b/lib/rust/ensogl/component/selector/src/frp.rs @@ -91,11 +91,11 @@ impl Frp { let track_click = relative_shape_down_position(net, scene, &model.track); // Initialisation of components. Required for correct layout on startup. - model.label_right.set_position_y(text_size.value() / 2.0); - model.label_left.set_position_y(text_size.value() / 2.0); - model.label.set_position_y(text_size.value() / 2.0); - model.caption_left.set_position_y(text_size.value() / 2.0); - model.caption_center.set_position_y(text_size.value() / 2.0); + model.label_right.set_y(text_size.value() / 2.0); + model.label_left.set_y(text_size.value() / 2.0); + model.label.set_y(text_size.value() / 2.0); + model.caption_left.set_y(text_size.value() / 2.0); + model.caption_center.set_y(text_size.value() / 2.0); let bg_color = style.get_color(theme::component::slider::background); model.set_background_color(bg_color.value()); @@ -106,9 +106,9 @@ impl Frp { init_shadow_padding <- source::<()>(); shadow_padding <- all_with(&shadow.size,&init_shadow_padding,|&v,_| Vector2(v,v)); eval text_size ((size) { - model.label.set_position_y(size / 2.0); - model.label_right.set_position_y(size / 2.0); - model.label_left.set_position_y(size / 2.0); + model.label.set_y(size / 2.0); + model.label_right.set_y(size / 2.0); + model.label_left.set_y(size / 2.0); }); eval bg_color ((color) model.set_background_color(*color) ); @@ -116,7 +116,7 @@ impl Frp { update_caption_position <- all(&size,&text_size); eval update_caption_position((args) model.update_caption_position(args)); eval model.caption_center.frp.width((width) - model.caption_center.set_position_x(-width/2.0) + model.caption_center.set_x(-width/2.0) ); // Size updates diff --git a/lib/rust/ensogl/component/selector/src/model.rs b/lib/rust/ensogl/component/selector/src/model.rs index b9199994354..9f313479514 100644 --- a/lib/rust/ensogl/component/selector/src/model.rs +++ b/lib/rust/ensogl/component/selector/src/model.rs @@ -152,12 +152,12 @@ impl Model { let overflow_icon_size = size.y; let label_offset = size.x / 2.0 - overflow_icon_size + left_padding; - self.label_left.set_position_x(-label_offset); - self.label_right.set_position_x(label_offset - self.label_right.width.value()); + self.label_left.set_x(-label_offset); + self.label_right.set_x(label_offset - self.label_right.width.value()); let overflow_icon_offset = size.x / 2.0 - overflow_icon_size / 2.0; - self.left_overflow.set_position_x(-overflow_icon_offset); - self.right_overflow.set_position_x(overflow_icon_offset); + self.left_overflow.set_x(-overflow_icon_offset); + self.right_overflow.set_x(overflow_icon_offset); let track_handle_size = Vector2::new(size.y / 2.0, size.y); self.track_handle_left.size.set(track_handle_size); @@ -171,9 +171,9 @@ impl Model { let left_padding = LABEL_OFFSET; let overflow_icon_size = size.y / 2.0; let caption_offset = size.x / 2.0 - overflow_icon_size - left_padding; - self.caption_left.set_position_x(-caption_offset); - self.caption_left.set_position_y(text_size / 2.0); - self.caption_center.set_position_y(text_size / 2.0); + self.caption_left.set_x(-caption_offset); + self.caption_left.set_y(text_size / 2.0); + self.caption_center.set_y(text_size / 2.0); } /// Set whether to allow interactions with the edges of the track shape. If this is set to @@ -208,8 +208,8 @@ impl Model { self.track.left.set(value.start); self.track.right.set(value.end); - self.track_handle_left.set_position_x(value.start * size.x - size.x / 2.0); - self.track_handle_right.set_position_x(value.end * size.x - size.x / 2.0); + self.track_handle_left.set_x(value.start * size.x - size.x / 2.0); + self.track_handle_right.set_x(value.end * size.x - size.x / 2.0); } /// Set the label in the center of the background to show the given numeric value. diff --git a/lib/rust/ensogl/component/sequence-diagram/src/lib.rs b/lib/rust/ensogl/component/sequence-diagram/src/lib.rs index cb5d0d9668b..e6904811265 100644 --- a/lib/rust/ensogl/component/sequence-diagram/src/lib.rs +++ b/lib/rust/ensogl/component/sequence-diagram/src/lib.rs @@ -126,7 +126,7 @@ impl Model { self.display_object.add_child(&line); line.set_content(process.to_string()); line.set_size(Vector2::new(LINE_WIDTH, INFINITE)); - line.set_position_y(ROW_HEIGHT * ix as f32); + line.set_y(ROW_HEIGHT * ix as f32); line.set_rotation_z(90.0_f32.to_radians()); line }) @@ -156,8 +156,8 @@ impl Model { let start = message.recipient.id.min(message.sender.id) as u32; line.set_size(Vector2::new(LINE_WIDTH, height_px)); - line.set_position_x(message.time as f32); - line.set_position_y(ROW_HEIGHT * start as f32 + height_px / 2.0); + line.set_x(message.time as f32); + line.set_y(ROW_HEIGHT * start as f32 + height_px / 2.0); line }) .collect(); @@ -195,7 +195,7 @@ impl Model { .borrow() .deref() .iter() - .for_each(|line| line.mod_position_x(|x| x + delta)) + .for_each(|line| line.mod_x(|x| x + delta)) } } diff --git a/lib/rust/ensogl/component/slider/src/lib.rs b/lib/rust/ensogl/component/slider/src/lib.rs index e3a1f6673d2..8c59ec5290a 100644 --- a/lib/rust/ensogl/component/slider/src/lib.rs +++ b/lib/rust/ensogl/component/slider/src/lib.rs @@ -320,16 +320,16 @@ impl Slider { &model.value_text_dot.width, ); value_text_left_pos_x <- value_text_left_pos_x.map(|(left, dot)| -*left - *dot / 2.0); - eval value_text_left_pos_x((x) model.value_text_left.set_position_x(*x)); - eval model.value_text_left.height((h) model.value_text_left.set_position_y(*h / 2.0)); - eval model.value_text_dot.width((w) model.value_text_dot.set_position_x(-*w / 2.0)); - eval model.value_text_dot.height((h) model.value_text_dot.set_position_y(*h / 2.0)); - eval model.value_text_dot.width((w) model.value_text_right.set_position_x(*w / 2.0)); - eval model.value_text_right.height((h) model.value_text_right.set_position_y(*h / 2.0)); + eval value_text_left_pos_x((x) model.value_text_left.set_x(*x)); + eval model.value_text_left.height((h) model.value_text_left.set_y(*h / 2.0)); + eval model.value_text_dot.width((w) model.value_text_dot.set_x(-*w / 2.0)); + eval model.value_text_dot.height((h) model.value_text_dot.set_y(*h / 2.0)); + eval model.value_text_dot.width((w) model.value_text_right.set_x(*w / 2.0)); + eval model.value_text_right.height((h) model.value_text_right.set_y(*h / 2.0)); model.label.set_content <+ input.set_label; eval input.set_label_hidden((v) model.set_label_hidden(*v)); - eval model.label.height((h) model.label.set_position_y(*h / 2.0)); + eval model.label.height((h) model.label.set_y(*h / 2.0)); label_pos_x <- all4( &input.set_width, &input.set_height, @@ -341,7 +341,7 @@ impl Slider { LabelPosition::Outside => -comp_width / 2.0 - comp_height / 2.0 - lab_width, } ); - eval label_pos_x((x) model.label.set_position_x(*x)); + eval label_pos_x((x) model.label.set_x(*x)); }; } diff --git a/lib/rust/ensogl/component/text/src/component/line.rs b/lib/rust/ensogl/component/text/src/component/line.rs index 792474c3b63..9f6d086412f 100644 --- a/lib/rust/ensogl/component/text/src/component/line.rs +++ b/lib/rust/ensogl/component/text/src/component/line.rs @@ -270,7 +270,7 @@ impl View { baseline_anim.target <+ frp.set_baseline; baseline_anim.skip <+ frp.skip_baseline_animation; - eval baseline_anim.value ((y) display_object.set_position_y(*y)); + eval baseline_anim.value ((y) display_object.set_y(*y)); new_baseline <- baseline_anim.value.on_change(); frp.private.output.baseline <+ new_baseline; @@ -307,7 +307,7 @@ impl View { let truncation = TruncationData::new(size, ellipsis); let x = self.glyphs.last().map(|g| g.position().x + g.x_advance.get()).unwrap_or(0.0); let x = x + truncation.x_after_last_glyph(); - truncation.ellipsis.set_position_xy(Vector2(x, truncation.y())); + truncation.ellipsis.set_xy(Vector2(x, truncation.y())); truncation.ellipsis.scale.set(truncation.scale); truncation.ellipsis.size.set(truncation.dim()); let was_truncated = self.truncation.borrow().is_some(); diff --git a/lib/rust/ensogl/component/text/src/component/selection.rs b/lib/rust/ensogl/component/text/src/component/selection.rs index a7a549eb7eb..192f6b68075 100644 --- a/lib/rust/ensogl/component/text/src/component/selection.rs +++ b/lib/rust/ensogl/component/text/src/component/selection.rs @@ -182,7 +182,7 @@ impl Selection { _eval <- all_with(&ascender.value, &descender.value, f!([model](ascender,descender) { let height = ascender - descender; - model.view.set_position_y(height / 2.0 + descender); + model.view.set_y(height / 2.0 + descender); model.view.size.modify(|t| Vector2(t.x, CURSOR_PADDING * 2.0 + height)); }) ); @@ -217,10 +217,10 @@ impl Selection { let width = max(CURSOR_WIDTH, abs_width - CURSORS_SPACING); let view_width = CURSOR_PADDING * 2.0 + width; let view_x = (abs_width/2.0) * side; - model.display_object.set_position_xy(*p); - model.right_side.set_position_x(abs_width); + model.display_object.set_xy(*p); + model.right_side.set_x(abs_width); model.view.size.modify(|t| Vector2(view_width,t.y)); - model.view.set_position_x(view_x); + model.view.set_x(view_x); }) ); eval frp.set_color((color) model.view.color_rgb.set(color.into())); diff --git a/lib/rust/ensogl/component/text/src/component/text.rs b/lib/rust/ensogl/component/text/src/component/text.rs index 91065081848..131d125f94e 100644 --- a/lib/rust/ensogl/component/text/src/component/text.rs +++ b/lib/rust/ensogl/component/text/src/component/text.rs @@ -807,7 +807,7 @@ impl TextModel { let camera = self.layer.get().camera(); let origin_world_space = Vector4(0.0, 0.0, 0.0, 1.0); let origin_clip_space = camera.view_projection_matrix() * origin_world_space; - let inv_object_matrix = self.transform_matrix().try_inverse().unwrap(); + let inv_object_matrix = self.transformation_matrix().try_inverse().unwrap(); let shape = self.app.display.default_scene.frp.shape.value(); let clip_space_z = origin_clip_space.z; @@ -1369,8 +1369,8 @@ impl TextModel { glyph.set_properties(shaped_glyph_set.non_variable_variations); glyph.set_glyph_id(shaped_glyph.id()); glyph.x_advance.set(x_advance); - glyph.view.set_position_xy(glyph_render_offset * magic_scale); - glyph.set_position_xy(Vector2(glyph_offset_x, 0.0)); + glyph.view.set_xy(glyph_render_offset * magic_scale); + glyph.set_xy(Vector2(glyph_offset_x, 0.0)); glyph_offset_x += x_advance; divs.push(glyph_offset_x); @@ -1469,7 +1469,7 @@ impl TextModel { if let Some(cursor) = &last_cursor { cursor.right_side().add_child(glyph); glyph.attached_to_cursor.set(true); - glyph.mod_position_x(|p| p - last_cursor_target_x); + glyph.mod_x(|p| p - last_cursor_target_x); attached_glyphs.push(glyph.downgrade()); } column += Column(1); @@ -1491,7 +1491,7 @@ impl TextModel { if let Some(glyph) = glyph.upgrade() { self.lines.borrow_mut()[line].add_child(&glyph); let pos_x = selection.position_target.value().x; - glyph.mod_position_xy(|pos| Vector2(pos.x + pos_x, 0.0)); + glyph.mod_xy(|pos| Vector2(pos.x + pos_x, 0.0)); glyph.attached_to_cursor.set(false); } } diff --git a/lib/rust/ensogl/component/tooltip/src/lib.rs b/lib/rust/ensogl/component/tooltip/src/lib.rs index 6687080b9b4..3c535c3360c 100644 --- a/lib/rust/ensogl/component/tooltip/src/lib.rs +++ b/lib/rust/ensogl/component/tooltip/src/lib.rs @@ -75,7 +75,7 @@ impl Model { }; let base_positions = position.xy(); - self.tooltip.set_position_xy(base_positions + layout_offset) + self.tooltip.set_xy(base_positions + layout_offset) } fn set_style(&self, update: &Style) { diff --git a/lib/rust/ensogl/core/src/data/bounding_box.rs b/lib/rust/ensogl/core/src/data/bounding_box.rs index 51dbc98c606..414fc2549fa 100644 --- a/lib/rust/ensogl/core/src/data/bounding_box.rs +++ b/lib/rust/ensogl/core/src/data/bounding_box.rs @@ -46,7 +46,7 @@ impl BoundingBox { } /// Return a bounding box given by the position and size. The position interpreted as the - /// top-right corner and size as the extend along the positive x and y-axis. Negative sizes + /// top-right corner and size as the extension along the positive x and y-axis. Negative sizes /// are valid. pub fn from_position_and_size(position: Vector2, size: Vector2) -> Self { Self::from_corners(position, position + size) diff --git a/lib/rust/ensogl/core/src/data/dirty.rs b/lib/rust/ensogl/core/src/data/dirty.rs index 1bf2c07b9cf..69a8b0027aa 100644 --- a/lib/rust/ensogl/core/src/data/dirty.rs +++ b/lib/rust/ensogl/core/src/data/dirty.rs @@ -4,9 +4,6 @@ //! a set of changed indexes and bulk-update the GPU-buffers every animation frame. You can think //! of dirty flags like about a way to introduce laziness to the program evaluation mechanisms. -// === Non-Standard Linter Configuration === -#![allow(missing_docs)] - use crate::data::function::traits::*; use crate::prelude::*; @@ -20,75 +17,140 @@ use std::mem; // === Operations === // ================== +/// Common traits for dirty flags. pub mod traits { use super::*; // === Arg === + + /// Abstraction for dirty flags which accept an argument. + #[allow(missing_docs)] pub trait HasArg { type Arg; } + /// The argument type-level getter. pub type Arg = ::Arg; + // === Global Operations === + + /// Abstraction for dirty flags which can be checked for being dirty. + #[allow(missing_docs)] pub trait HasCheckAll { fn check_all(&self) -> bool; } + + /// Abstraction for dirty flags which can be unset (set to clean). + #[allow(missing_docs)] pub trait HasUnsetAll { fn unset_all(&mut self); } + // === Arity-0 Operations === + + /// Abstraction for dirty flags which can perform a dirty check without requiring an argument. + #[allow(missing_docs)] pub trait HasCheck0 { fn check(&self) -> bool; } + + /// Abstraction for dirty flags which can be set without requiring an argument. + #[allow(missing_docs)] pub trait HasSet0 { fn set(&mut self); } + + /// Abstraction for dirty flags which can be unset without requiring an argument. + #[allow(missing_docs)] pub trait HasUnset0 { fn unset(&mut self); } + // === Arity-1 Operations === + + /// Abstraction for dirty flags which can perform a dirty check by providing a single argument. + #[allow(missing_docs)] pub trait HasCheck1: HasArg { fn check(&self, arg: &Self::Arg) -> bool; } + + /// Abstraction for dirty flags which can be set by providing a single argument. + #[allow(missing_docs)] pub trait HasSet1: HasArg { fn set(&mut self, arg: Self::Arg); } + + /// Abstraction for dirty flags which can be unset by providing a single argument. + #[allow(missing_docs)] pub trait HasUnset1: HasArg { fn unset(&mut self, arg: &Self::Arg); } - // === Shared Operations === + + // === Shared Global Operations === + + /// Abstraction for dirty flags which can be unset (set to clean) without requiring mutable + /// access to self. + #[allow(missing_docs)] pub trait SharedHasUnsetAll { fn unset_all(&self); } + + + // === Shared Arity-0 Operations === + + /// Abstraction for dirty flags which can be set without requiring an argument and without + /// requiring mutable access to self. + #[allow(missing_docs)] pub trait SharedHasSet0 { fn set(&self); } + + /// Abstraction for dirty flags which can be unset without requiring an argument and without + /// requiring mutable access to self. + #[allow(missing_docs)] pub trait SharedHasUnset0 { fn unset(&self); } + + + // === Shared Arity-1 Operations === + + /// Abstraction for dirty flags which can be set by providing a single argument without + /// requiring mutable access to self. + #[allow(missing_docs)] pub trait SharedHasSet1: HasArg { fn set(&self, arg: Self::Arg); } + + /// Abstraction for dirty flags which can be unset by providing a single argument without + /// requiring mutable access to self. + #[allow(missing_docs)] pub trait SharedHasUnset1: HasArg { fn unset(&self, arg: &Self::Arg); } // === Type Aliases === - pub trait DirtyFlagOps = Debug + HasCheckAll + HasUnsetAll; - pub trait DirtyFlagOps0 = DirtyFlagOps + HasCheck0 + HasSet0; - pub trait DirtyFlagOps1 = DirtyFlagOps + HasCheck1 + HasSet1 where Arg: Debug; + + /// Trait alias for bounds required by all dirty flags. + pub trait FlagOps = Debug + HasCheckAll + HasUnsetAll; + + /// Trait alias for bounds required by all dirty flags which does not accept an argument. + pub trait FlagOps0 = FlagOps + HasCheck0 + HasSet0; + + /// Trait alias for bounds required by all dirty flags which accept an argument. + pub trait FlagOps1 = FlagOps + HasCheck1 + HasSet1 where Arg: Debug; } pub use traits::*; -// ================= -// === DirtyFlag === -// ================= +// ============ +// === Flag === +// ============ // === Definition === @@ -97,7 +159,8 @@ pub use traits::*; /// implements public API for working with dirty flags. #[derive(Derivative)] #[derivative(Debug(bound = "T:Debug"))] -pub struct DirtyFlag { +#[allow(missing_docs)] +pub struct Flag { pub data: T, #[derivative(Debug = "ignore")] on_set: OnMut, @@ -106,12 +169,14 @@ pub struct DirtyFlag { // === Basics === -impl DirtyFlag { +impl Flag { + /// Constructor. pub fn new(on_set: OnMut) -> Self { let data = default(); Self { data, on_set } } + /// Unsets the flag and returns its dirty value. pub fn take(&mut self) -> T { mem::take(&mut self.data) } @@ -120,20 +185,20 @@ impl DirtyFlag { // === Arguments === -impl HasArg for DirtyFlag { +impl HasArg for Flag { type Arg = Arg; } // === Global Operations === -impl HasCheckAll for DirtyFlag { +impl HasCheckAll for Flag { fn check_all(&self) -> bool { self.data.check_all() } } -impl HasUnsetAll for DirtyFlag { +impl HasUnsetAll for Flag { fn unset_all(&mut self) { self.data.unset_all() } @@ -142,13 +207,13 @@ impl HasUnsetAll for DirtyFlag { // === Check === -impl HasCheck0 for DirtyFlag { +impl HasCheck0 for Flag { fn check(&self) -> bool { self.data.check() } } -impl HasCheck1 for DirtyFlag { +impl HasCheck1 for Flag { fn check(&self, arg: &Self::Arg) -> bool { self.data.check(arg) } @@ -157,7 +222,7 @@ impl HasCheck1 for DirtyFlag { // === Set === -impl HasSet0 for DirtyFlag { +impl HasSet0 for Flag { fn set(&mut self) { let is_set = self.data.check_all(); if !is_set { @@ -169,7 +234,7 @@ impl HasSet0 for DirtyFlag { } } -impl HasSet1 for DirtyFlag { +impl HasSet1 for Flag { fn set(&mut self, arg: Self::Arg) { let first_set = !self.check_all(); let is_set = self.data.check(&arg); @@ -187,14 +252,14 @@ impl HasSet1 for DirtyFlag { // === Unset === -impl HasUnset0 for DirtyFlag { +impl HasUnset0 for Flag { fn unset(&mut self) { trace!("Unsetting."); self.data.unset() } } -impl HasUnset1 for DirtyFlag +impl HasUnset1 for Flag where Arg: Display { fn unset(&mut self, arg: &Self::Arg) { @@ -205,181 +270,307 @@ where Arg: Display -// ======================= -// === SharedDirtyFlag === -// ======================= +// ================== +// === RefCellFlag === +// ================== // === Definition === -/// A version of `DirtyFlag` which uses internal mutability pattern. It is meant to expose the same -/// API but without requiring `self` reference to be mutable. -#[derive(Derivative)] +/// A version of `Flag` which uses internal mutability pattern. It is meant to expose the same +/// API but without requiring `self` reference to be mutable. This version does not allow for +/// cloning the flag. If you want to clone it you either need to put it in something like [`Rc`] or +/// use the [`SharedFlag`] instead. +#[derive(Derivative, From)] #[derivative(Debug(bound = "T:Debug"))] -#[derivative(Clone(bound = ""))] -pub struct SharedDirtyFlag { - rc: Rc>>, +#[repr(transparent)] +pub struct RefCellFlag { + data: RefCell>, } // === API === -impl SharedDirtyFlag { +impl RefCellFlag { + /// Constructor. pub fn new(on_set: OnMut) -> Self { - Self { rc: Rc::new(RefCell::new(DirtyFlag::new(on_set))) } + Self { data: RefCell::new(Flag::new(on_set)) } } + /// Unsets the flag and returns its dirty value. pub fn take(&self) -> T { - self.rc.borrow_mut().take() + self.data.borrow_mut().take() } } -impl SharedDirtyFlag { - pub fn clone_ref(&self) -> Self { - self.clone() - } -} - -impl SharedDirtyFlag { +impl RefCellFlag { + /// Replace the callback of the flag. pub fn set_callback(&self, on_set: OnMut) { - self.rc.borrow_mut().on_set = on_set; - } -} - -impl From>>> for SharedDirtyFlag { - fn from(rc: Rc>>) -> Self { - Self { rc } + self.data.borrow_mut().on_set = on_set; } } // === Arg === -impl HasArg for SharedDirtyFlag { +impl HasArg for RefCellFlag { type Arg = Arg; } // === Global Operations === -impl SharedHasUnsetAll for SharedDirtyFlag { +impl SharedHasUnsetAll for RefCellFlag { fn unset_all(&self) { - self.rc.borrow_mut().unset_all() + self.data.borrow_mut().unset_all() } } -impl HasCheckAll for SharedDirtyFlag { +impl HasCheckAll for RefCellFlag { fn check_all(&self) -> bool { - self.rc.borrow().check_all() + self.data.borrow().check_all() } } // === Check === -impl HasCheck0 for SharedDirtyFlag { +impl HasCheck0 for RefCellFlag { fn check(&self) -> bool { - self.rc.borrow().check() + self.data.borrow().check() } } -impl HasCheck1 for SharedDirtyFlag { +impl HasCheck1 for RefCellFlag { fn check(&self, arg: &Arg) -> bool { - self.rc.borrow().check(arg) + self.data.borrow().check(arg) } } // === Set === -impl SharedHasSet0 for SharedDirtyFlag { +impl SharedHasSet0 for RefCellFlag { fn set(&self) { - self.rc.borrow_mut().set() + self.data.borrow_mut().set() } } -impl SharedHasSet1 for SharedDirtyFlag { +impl SharedHasSet1 for RefCellFlag { fn set(&self, arg: Arg) { - self.rc.borrow_mut().set(arg) + self.data.borrow_mut().set(arg) } } // === Unset === -impl SharedHasUnset0 for SharedDirtyFlag { +impl SharedHasUnset0 for RefCellFlag { fn unset(&self) { - self.rc.borrow_mut().unset() + self.data.borrow_mut().unset() } } -impl SharedHasUnset1 for SharedDirtyFlag +impl SharedHasUnset1 for RefCellFlag where Arg: Display { fn unset(&self, arg: &Self::Arg) { - self.rc.borrow_mut().unset(arg) + self.data.borrow_mut().unset(arg) } } -// === Weak References === +// ================== +// === SharedFlag === +// ================== + +// === Definition === + +/// A version of `Flag` which uses internal mutability pattern. It is meant to expose the same +/// API but without requiring `self` reference to be mutable. This version implements cloning. If +/// you don't need it, or you want to store a bunch of flags enclosed in a single [`Rc`], use the +/// [`RefCellFlag`] instead. +#[derive(Derivative, CloneRef, From, Deref)] +#[derivative(Debug(bound = "T:Debug"))] +#[derivative(Clone(bound = ""))] +#[repr(transparent)] +pub struct SharedFlag { + rc: Rc>, +} + + +// === API === + +impl SharedFlag { + /// Constructor. + pub fn new(on_set: OnMut) -> Self { + Self { rc: Rc::new(RefCellFlag::new(on_set)) } + } +} + + +// === Arg === + +impl HasArg for SharedFlag { + type Arg = Arg; +} + + +// === Global Operations === + +impl SharedHasUnsetAll for SharedFlag { + fn unset_all(&self) { + self.rc.unset_all() + } +} + +impl HasCheckAll for SharedFlag { + fn check_all(&self) -> bool { + self.rc.check_all() + } +} + +// === Check === + +impl HasCheck0 for SharedFlag { + fn check(&self) -> bool { + self.rc.check() + } +} + +impl HasCheck1 for SharedFlag { + fn check(&self, arg: &Arg) -> bool { + self.rc.check(arg) + } +} + +// === Set === + +impl SharedHasSet0 for SharedFlag { + fn set(&self) { + self.rc.set() + } +} + +impl SharedHasSet1 for SharedFlag { + fn set(&self, arg: Arg) { + self.rc.set(arg) + } +} + +// === Unset === + +impl SharedHasUnset0 for SharedFlag { + fn unset(&self) { + self.rc.unset() + } +} + +impl SharedHasUnset1 for SharedFlag +where Arg: Display +{ + fn unset(&self, arg: &Self::Arg) { + self.rc.unset(arg) + } +} + + + +// ====================== +// === WeakSharedFlag === +// ====================== + +/// A weak version of [`SharedFlag`]. #[derive(Derivative)] #[derivative(Debug(bound = "T:Debug"))] #[derivative(Clone(bound = ""))] -pub struct WeakSharedDirtyFlag { - weak: Weak>>, +#[repr(transparent)] +pub struct WeakSharedFlag { + weak: Weak>, } -impl SharedDirtyFlag { - pub fn downgrade(&self) -> WeakSharedDirtyFlag { +impl SharedFlag { + /// Downgrade the flag to its weak version. + pub fn downgrade(&self) -> WeakSharedFlag { let weak = self.rc.downgrade(); - WeakSharedDirtyFlag { weak } + WeakSharedFlag { weak } } } -impl WeakSharedDirtyFlag { - pub fn upgrade(&self) -> Option> { - self.weak.upgrade().map(|rc| SharedDirtyFlag { rc }) +impl WeakSharedFlag { + /// Upgrade the flag to its strong version. + pub fn upgrade(&self) -> Option> { + self.weak.upgrade().map(|rc| SharedFlag { rc }) } } -// ============================================================================= -// === Flags =================================================================== -// ============================================================================= +// ================================================================================================= +// === Flag Definitions ============================================================================ +// ================================================================================================= + +macro_rules! define_flag { + ($(#$meta:tt)* $name:ident $(< $($param:tt),* $(,)? >)?) => { paste! { + $(#$meta)* + pub type $name< $($($param,)*)? OnMut = ()> = + Flag<[<$name Data>] $(<$($param,)*>)?, OnMut>; + + /// A version with an internal mutability pattern. + $(#$meta)* + pub type []< $($($param,)*)? OnMut = ()> = + RefCellFlag<[<$name Data>] $(<$($param,)*>)?, OnMut>; + + /// A version with an internal mutability pattern and a reference counting mechanism. + /// Can be cloned and downgraded to a weak reference. + $(#$meta)* + pub type []< $($($param,)*)? OnMut = ()> = + SharedFlag<[<$name Data>] $(<$($param,)*>)?, OnMut>; + + /// A weak version of the shared flag. + $(#$meta)* + pub type []< $($($param,)*)? OnMut = ()> = + WeakSharedFlag<[<$name Data>] $(<$($param,)*>)?, OnMut>; + }}; +} + + // ============ // === Bool === // ============ -/// The on / off dirty flag. If you need a simple dirty / clean switch, this one -/// is the right choice. - -pub type Bool = DirtyFlag; -pub type SharedBool = SharedDirtyFlag; -pub type WeakSharedBool = WeakSharedDirtyFlag; -pub trait BoolCtx = where OnMut: FnMut0; +define_flag! { + /// The on / off dirty flag. If you need a simple dirty / clean switch, this one + /// is the right choice. + Bool +} +/// Internal representation of the [`Bool`] flag. #[derive(Clone, Copy, Debug, Display, Default)] pub struct BoolData { is_dirty: bool, } + impl HasCheckAll for BoolData { fn check_all(&self) -> bool { self.is_dirty } } + impl HasUnsetAll for BoolData { fn unset_all(&mut self) { self.is_dirty = false } } + impl HasCheck0 for BoolData { fn check(&self) -> bool { self.is_dirty } } + impl HasSet0 for BoolData { fn set(&mut self) { self.is_dirty = true } } + impl HasUnset0 for BoolData { fn unset(&mut self) { self.is_dirty = false @@ -392,15 +583,17 @@ impl HasUnset0 for BoolData { // === Range === // ============= -/// Dirty flag which keeps information about a range of dirty items. It does not track items -/// separately, nor you are allowed to keep multiple ranges in it. Just a single value range. +define_flag! { + /// Dirty flag which keeps information about a range of dirty items. It does not track items + /// separately, nor you are allowed to keep multiple ranges in it. Just a single value range. + Range +} -pub type Range = DirtyFlag, OnMut>; -pub type SharedRange = SharedDirtyFlag, OnMut>; -pub trait RangeCtx = where OnMut: FnMut0; pub trait RangeIx = PartialOrd + Copy + Debug; +/// Internal representation of the [`Range`] flag. #[derive(Debug, Default)] +#[allow(missing_docs)] pub struct RangeData { pub range: Option>, } @@ -408,11 +601,13 @@ pub struct RangeData { impl HasArg for RangeData { type Arg = Ix; } + impl HasCheckAll for RangeData { fn check_all(&self) -> bool { self.range.is_some() } } + impl HasUnsetAll for RangeData { fn unset_all(&mut self) { self.range = None @@ -464,18 +659,20 @@ impl Display for RangeData { // === Set === // =========== -/// Dirty flag which keeps a set of dirty values. The `HashSet` dirty flag -/// counterpart. Please note that it uses `FxHashSet` under the hood, so there -/// are no guarantees regarding attack-proof hashing algorithm here. +define_flag! { + /// Dirty flag which keeps a set of dirty values. The `HashSet` dirty flag counterpart. Please + /// note that it uses `FxHashSet` under the hood, so there are no guarantees regarding + /// attack-proof hashing algorithm here. + Set +} -pub type Set = DirtyFlag, OnMut>; -pub type SharedSet = SharedDirtyFlag, OnMut>; -pub trait SetCtx = where OnMut: FnMut0; pub trait SetItem = Eq + Hash + Debug; +/// Internal representation of the [`Set`] flag. #[derive(Derivative, Shrinkwrap)] #[derivative(Debug(bound = "Item:SetItem"))] #[derivative(Default(bound = "Item:SetItem"))] +#[allow(missing_docs)] pub struct SetData { pub set: FxHashSet, } @@ -534,13 +731,17 @@ impl<'t, Item: SetItem> IntoIterator for &'t SetData { // === Vector === // ============== -/// Dirty flag which keeps a vector of dirty values. -pub type Vector = DirtyFlag, OnMut>; -pub type SharedVector = SharedDirtyFlag, OnMut>; +define_flag! { + /// Dirty flag which keeps a vector of dirty values. + Vector +} + pub trait VectorItem = Debug + PartialEq; +/// Internal representation of the [`Vector`] flag. #[derive(Derivative, Debug, Shrinkwrap)] #[derivative(Default(bound = ""))] +#[allow(missing_docs)] pub struct VectorData { pub vec: Vec, } @@ -548,11 +749,13 @@ pub struct VectorData { impl HasArg for VectorData { type Arg = Item; } + impl HasCheckAll for VectorData { fn check_all(&self) -> bool { !self.vec.is_empty() } } + impl HasUnsetAll for VectorData { fn unset_all(&mut self) { self.vec.clear(); @@ -599,24 +802,27 @@ impl<'t, Item> IntoIterator for &'t VectorData { use bit_field::BitField as BF; -/// Dirty flag which keeps information about a set of enumerator values. The -/// items must be a plain enumerator implementing `Into`. The data is -/// stored as an efficient `BitField` under the hood. +define_flag! { + /// Dirty flag which keeps information about a set of enumerator values. The items must be a + /// plain enumerators implementing `Into`. The data is stored as an efficient `BitField` + /// under the hood. + Enum +} -pub type Enum = DirtyFlag, OnMut>; -pub type SharedEnum = SharedDirtyFlag, OnMut>; -pub trait EnumCtx = where OnMut: FnMut0; pub trait EnumBase = Default + PartialEq + Copy + BF; pub trait EnumElem = Copy + Into; /// Dirty flag which keeps dirty indexes in a `BitField` under the hood. - pub type BitField = Enum; + +/// Shared version of the [`BitField`] flag. pub type SharedBitField = SharedEnum; +/// Internal representation of the [`Enum`] flag. #[derive(Derivative)] #[derivative(Debug(bound = "Prim:Debug"))] #[derivative(Default(bound = "Prim:Default"))] +#[allow(missing_docs)] pub struct EnumData { pub bits: Prim, phantom: PhantomData, diff --git a/lib/rust/ensogl/core/src/display/camera/camera2d.rs b/lib/rust/ensogl/core/src/display/camera/camera2d.rs index 928a7f9c295..06f499458d5 100644 --- a/lib/rust/ensogl/core/src/display/camera/camera2d.rs +++ b/lib/rust/ensogl/core/src/display/camera/camera2d.rs @@ -197,7 +197,7 @@ type ProjectionDirty = dirty::SharedBool<()>; type TransformDirty = dirty::SharedBool<()>; impl Camera2dData { - fn new(display_object: &display::object::Instance) -> Self { + fn new() -> Self { let screen = Screen::new(); let projection = default(); let clipping = default(); @@ -205,10 +205,9 @@ impl Camera2dData { let z_zoom_1 = 1.0; let matrix = default(); let dirty = Dirty::new(); - let display_object = display_object.clone_ref(); + let display_object = display::object::Instance::new(); let zoom_update_registry = default(); let screen_update_registry = default(); - display_object.set_on_updated(f_!(dirty.transform.set())); display_object.mod_position(|p| p.z = 1.0); dirty.projection.set(); let network = frp::Network::new("Camera2d"); @@ -216,6 +215,7 @@ impl Camera2dData { frp_position <- source(); frp_zoom <- source(); frp_screen <- source(); + eval_ display_object.on_updated (dirty.transform.set()); } let frp = Frp { network, position: frp_position, zoom: frp_zoom, screen: frp_screen }; Self { @@ -248,7 +248,7 @@ impl Camera2dData { } fn recompute_view_matrix(&mut self) { - let transform = self.display_object.matrix(); + let transform = self.display_object.transformation_matrix(); self.matrix.view_inversed = transform; self.matrix.view = transform.try_inverse().unwrap() } @@ -402,8 +402,8 @@ impl Camera2d { /// Creates new [`Camera2d`] instance. Please note that the camera will be of zero-size and in /// order for it to work properly, you have to initialize it by using the `set_screen` method. pub fn new() -> Self { - let display_object = display::object::Instance::new(); - let data = Camera2dData::new(&display_object); + let data = Camera2dData::new(); + let display_object = data.display_object.clone_ref(); let data = Rc::new(RefCell::new(data)); Self { display_object, data } } diff --git a/lib/rust/ensogl/core/src/display/object.rs b/lib/rust/ensogl/core/src/display/object.rs index fef19273dd0..c6518ac0c3e 100644 --- a/lib/rust/ensogl/core/src/display/object.rs +++ b/lib/rust/ensogl/core/src/display/object.rs @@ -9,12 +9,12 @@ use crate::display::scene::layer::Layer; // === Export === // ============== -pub mod class; pub mod event; -pub mod transform; +pub mod instance; +pub mod transformation; -pub use class::Any; -pub use class::*; +pub use instance::Any; +pub use instance::*; @@ -64,14 +64,17 @@ impl + 'static> InstanceWithLayer { /// callback ensures that the `layer` will always be attached to the same layer the /// `instance` is attached to. pub fn new(instance: Instance, layer: L) -> Self { - instance.set_on_scene_layer_changed(f!([layer](_, source, destination) { - if let Some(src_layer) = source { - src_layer.remove_sublayer(layer.as_ref()); - } - if let Some(dst_layer) = destination { - dst_layer.add_sublayer(layer.as_ref()); - } - })); + let network = &instance.network; + frp::extend! { network + eval instance.on_layer_change ([layer] ((_, source, destination)) { + if let Some(src_layer) = source { + src_layer.remove_sublayer(layer.as_ref()); + } + if let Some(dst_layer) = destination { + dst_layer.add_sublayer(layer.as_ref()); + } + }); + } Self { instance, layer } } } diff --git a/lib/rust/ensogl/core/src/display/object/event.rs b/lib/rust/ensogl/core/src/display/object/event.rs index f6b3ee61097..923466e0b42 100644 --- a/lib/rust/ensogl/core/src/display/object/event.rs +++ b/lib/rust/ensogl/core/src/display/object/event.rs @@ -5,8 +5,8 @@ use crate::prelude::*; -use crate::display::object::class::Instance; -use crate::display::object::class::WeakInstance; +use crate::display::object::instance::Instance; +use crate::display::object::instance::WeakInstance; @@ -47,8 +47,8 @@ pub struct SomeEvent { impl SomeEvent { /// Constructor. - pub fn new(target: Option<&Instance>, payload: T) -> Self { - let event = Event::new(target.map(|t| t.downgrade()), payload); + pub fn new(target: Option, payload: T) -> Self { + let event = Event::new(target, payload); let state = event.state.clone_ref(); let captures = Rc::new(Cell::new(true)); let bubbles = Rc::new(Cell::new(true)); @@ -68,7 +68,7 @@ impl SomeEvent { impl Default for SomeEvent { fn default() -> Self { - Self::new::<(), ()>(None, ()) + Self::new::<()>(None, ()) } } @@ -93,23 +93,23 @@ impl Default for SomeEvent { #[derivative(Clone(bound = ""))] #[derivative(Debug(bound = "T: Debug"))] #[derivative(Default(bound = "T: Default"))] -pub struct Event { - data: Rc>, +pub struct Event { + data: Rc>, } /// Internal representation of [`Event`]. #[derive(Deref, Derivative)] #[derivative(Debug(bound = "T: Debug"))] #[derivative(Default(bound = "T: Default"))] -pub struct EventData { +pub struct EventData { #[deref] payload: T, - target: Option>, + target: Option, state: Rc>, } -impl Event { - fn new(target: Option>, payload: T) -> Self { +impl Event { + fn new(target: Option, payload: T) -> Self { let state = default(); let data = Rc::new(EventData { payload, target, state }); Self { data } @@ -130,7 +130,7 @@ impl Event { /// A reference to the object onto which the event was dispatched. /// /// See: https://developer.mozilla.org/en-US/docs/Web/API/Event/target. - pub fn target(&self) -> Option> { + pub fn target(&self) -> Option { self.data.target.as_ref().and_then(|t| t.upgrade()) } } diff --git a/lib/rust/ensogl/core/src/display/object/class.rs b/lib/rust/ensogl/core/src/display/object/instance.rs similarity index 53% rename from lib/rust/ensogl/core/src/display/object/class.rs rename to lib/rust/ensogl/core/src/display/object/instance.rs index 803eb2f9f4d..17a40d2d4df 100644 --- a/lib/rust/ensogl/core/src/display/object/class.rs +++ b/lib/rust/ensogl/core/src/display/object/instance.rs @@ -5,179 +5,36 @@ use crate::data::dirty::traits::*; use crate::prelude::*; -use crate::data::dirty; +use crate::display::object::event; +use crate::display::object::transformation; use crate::display::scene::layer::Layer; use crate::display::scene::layer::WeakLayer; use crate::display::scene::Scene; -use super::event; -use super::transform; use data::opt_vec::OptVec; use nalgebra::Matrix4; use nalgebra::Vector3; -use transform::CachedTransform; +use transformation::CachedTransformation; -// ================== -// === ParentBind === -// ================== +// ========== +// === Id === +// ========== -/// Description of parent-child relation. It contains reference to parent node and information -/// about the child index there. It is used when a child is reconnected to different parent to -/// update the old parent with the information that the child was removed. -#[derive(Derivative)] -#[derivative(Debug(bound = ""))] -#[allow(missing_docs)] -pub struct ParentBind { - pub parent: WeakInstance, - pub index: usize, -} +/// Globally unique identifier of a display object. +#[derive( + Clone, CloneRef, Copy, Debug, Default, Display, Eq, From, Hash, Into, PartialEq, Ord, + PartialOrd +)] +pub struct Id(usize); -impl ParentBind { - fn parent(&self) -> Option> { - self.parent.upgrade() - } -} - -impl Drop for ParentBind { - fn drop(&mut self) { - if let Some(parent) = self.parent() { - parent.remove_child_by_index(self.index) - } - } -} - - - -// ================= -// === Callbacks === -// ================= - -/// Callbacks manager for display objects. Callbacks can be set only once. Panics if you try set -/// another callback to field with an already assigned callback. This design was chosen because it -/// is very lightweight and is not confusing (setting a callback unregistering previous one will be -/// confusing, while allowing to set multiple callbacks will use more resources). We may -/// want to switch to a real callback registry in the future if there will be suitable use cases for -/// it. -#[derive(Derivative)] -#[derivative(Default(bound = ""))] -#[allow(clippy::type_complexity)] -pub struct Callbacks { - on_updated: RefCell)>>>, - on_show: RefCell)>>>, - on_hide: RefCell>>, - on_scene_layer_changed: - RefCell, Option<&WeakLayer>)>>>, -} - -impl Callbacks { - fn on_updated(&self, model: &Model) { - if let Some(f) = &*self.on_updated.borrow() { - f(model) - } - } - - fn on_show(&self, host: &Host, layer: Option<&WeakLayer>) { - if let Some(f) = &*self.on_show.borrow() { - f(host, layer) - } - } - - fn on_hide(&self, host: &Host) { - if let Some(f) = &*self.on_hide.borrow() { - f(host) - } - } - - fn on_scene_layer_changed( - &self, - host: &Host, - old_layer: Option<&WeakLayer>, - new_layer: Option<&WeakLayer>, - ) { - if let Some(f) = &*self.on_scene_layer_changed.borrow() { - f(host, old_layer, new_layer) - } - } -} - -impl Debug for Callbacks { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Callbacks") - } -} - - - -// ================== -// === DirtyFlags === -// ================== - -// === Types === - -type NewParentDirty = dirty::SharedBool<()>; -type ChildrenDirty = dirty::SharedSet; -type RemovedChildren = dirty::SharedVector, OnDirtyCallback>; -type TransformDirty = dirty::SharedBool; -type SceneLayerDirty = dirty::SharedBool; - - -// === Definition === - -/// Set of dirty flags indicating whether some display object properties are not up to date. -/// -/// In order to achieve high performance, display object hierarchy is not updated immediately after -/// a change. Instead, dirty flags are set and propagated in the hierarchy and the needed subset of -/// the hierarchy is updated after calling the `update` method. -#[derive(Derivative)] -#[derivative(Debug(bound = ""))] -pub struct DirtyFlags { - parent: NewParentDirty, - children: ChildrenDirty, - removed_children: RemovedChildren, - transform: TransformDirty, - scene_layer: SceneLayerDirty, - #[derivative(Debug = "ignore")] - on_dirty: Rc>>, -} - -impl Default for DirtyFlags { - fn default() -> Self { - Self::new() - } -} - - -impl DirtyFlags { - #![allow(trivial_casts)] - fn new() -> Self { - let on_dirty = Rc::new(RefCell::new(Box::new(|| {}) as Box)); - let parent = NewParentDirty::new(()); - let children = ChildrenDirty::new(on_dirty_callback(&on_dirty)); - let removed_children = RemovedChildren::new(on_dirty_callback(&on_dirty)); - let transform = TransformDirty::new(on_dirty_callback(&on_dirty)); - let scene_layer = SceneLayerDirty::new(on_dirty_callback(&on_dirty)); - Self { parent, children, removed_children, transform, scene_layer, on_dirty } - } - - fn set_on_dirty(&self, f: F) { - *self.on_dirty.borrow_mut() = Box::new(f); - } - - fn unset_on_dirty(&self) { - *self.on_dirty.borrow_mut() = Box::new(|| {}); - } -} - - -// === Callback === - -type OnDirtyCallback = impl Fn(); -fn on_dirty_callback(f: &Rc>>) -> OnDirtyCallback { - let f = f.clone(); - move || (f.borrow())() -} +/// The index of a child of a display object. +#[derive( + Clone, CloneRef, Copy, Debug, Default, Deref, Display, Eq, From, Hash, Into, PartialEq, Ord, + PartialOrd +)] +pub struct ChildIndex(usize); @@ -185,121 +42,523 @@ fn on_dirty_callback(f: &Rc>>) -> OnDirtyCallback { // === Model === // ============= -/// A hierarchical representation of object containing information about transformation in 3D space, -/// list of children, and set of utils for dirty flag propagation. +/// Display objects are essential structures used to build elements visible on the screen. They are +/// used to build objects hierarchy, computing elements transformations within this hierarchy +/// (position, rotation, and scale), passing events trough that hierarchy, and layouting the +/// elements on the screen (e.g. with horizontal or vertical layout). /// -/// See the documentation of [`Instance`] to learn more. +/// ## Lazy updates of display objects +/// Some operations on display objects are very expensive. For example, after moving the root object +/// of a hierarchy, the matrix transformations of all its children, their children, etc. need to be +/// updated. That's why these operations are performed in a lazy way. After an element is +/// transformed, or when the hierarchy is modified, the change information is propagated up to the +/// root of the hierarchy and is updated once per frame, after the [`update`] function is called +/// (usually, it is called by the [`Scene`]). Emitting events is not done in a lazy fashion, as they +/// do not require passing the event down the hierarchy. Instead, the event is passed up the +/// hierarchy, from the object the event was emitted on all way to the root of the hierarchy. +/// +/// ## Scene Layers +/// Every display object can be assigned to a [`scene::Layer`]. During object update, the assignment +/// information is passed down the hierarchy. If an object was not assigned to a layer explicitly, +/// it will inherit the assignment from its parent object, if any. This means that adding an object +/// to a layer will also move all of its children there, until they are assigned with a different +/// layer explicitly. #[derive(Derivative)] +#[derive(CloneRef, Deref, From)] +#[derivative(Clone(bound = ""))] #[derivative(Debug(bound = ""))] -pub struct Model { - network: frp::Network, - /// Source for events. See the documentation of [`event::Event`] to learn more about events. - pub event_source: frp::Source, - capturing_event_fan: frp::Fan, - bubbling_event_fan: frp::Fan, - host: PhantomData, - focused_descendant: RefCell>>, - /// Layer the object was explicitly assigned to by the user, if any. - assigned_layer: RefCell>, - /// Layer where the object is displayed. It may be set to by user or inherited from the parent. - layer: RefCell>, - dirty: DirtyFlags, - callbacks: Callbacks, - parent_bind: Rc>>>, - children: RefCell>>, - transform: RefCell, - visible: Cell, +#[derivative(Default(bound = ""))] +#[repr(transparent)] +pub struct Instance { + def: InstanceDef, } -impl Default for Model { +/// Internal representation of [`Instance`]. It exists only to make the implementation less +/// error-prone. The [`ObjectOps`] trait defines the public API of display objects, such as the +/// [`add_child`] method, and it is automatically defined for every struct that implements +/// the [`Object`] trait, including the [`Instance`]. Without this struct, the [`add_child`] method +/// would need to be implemented as [`self.display_object().add_child(child)`]. Such an +/// implementation will be very error-prone. After renaming the function in [`Instance`], the +/// [`ObjectOps`] trait would still compile, but its function will call itself infinitely (this is +/// not caught by rustc yet: https://github.com/rust-lang/rust/issues/57965). This struct allows the +/// implementation to be written as [`self.display_object().def.add_child(child)`] instead, which +/// will fail to compile after renaming the function in [`InstanceDef`]. +#[derive(Derivative)] +#[derive(CloneRef, Deref)] +#[derivative(Clone(bound = ""))] +#[repr(transparent)] +pub struct InstanceDef { + rc: Rc, +} + +/// A display object model. See the documentation of [`Instance`] to learn more. +#[derive(Debug, Deref)] +pub struct Model { + /// This is the display object's FRP network. Feel free to extend it with new FRP nodes as long + /// as they are inherently bound with this display object. For example, a sprite, which owns a + /// display object instance, can extend this network to perform computations. However, you + /// should not extend it if you don't own the display object, as nodes created in this network + /// may survive the lifetime of other objects causing memory leaks. See the docs of FRP to + /// learn more. + pub network: frp::Network, + + #[deref] + hierarchy: HierarchyModel, + event: EventModel, + bounding_box: Cell>, +} + + +// === Contructors === + +impl Instance { + /// Constructor. + pub fn new() -> Self { + default() + } +} + +impl InstanceDef { + /// Constructor. + pub fn new() -> Self { + Self { rc: Rc::new(Model::new()) }.init_events_handling() + } + + /// ID getter of this display object. + pub fn id(&self) -> Id { + Id(Rc::downgrade(&self.rc).as_ptr() as *const () as usize) + } +} + +impl Model { + /// Constructor. + pub fn new() -> Self { + let network = frp::Network::new("display_object"); + let hierarchy = HierarchyModel::new(&network); + let event = EventModel::new(&network); + let bounding_box = default(); + Self { network, hierarchy, event, bounding_box } + } +} + + +// === Impls === + +impl Default for InstanceDef { fn default() -> Self { Self::new() } } -impl Model { - /// Constructor. - pub fn new() -> Self { - let network = frp::Network::new("display_object"); - let host = default(); - let focused_descendant = default(); - let assigned_layer = default(); - let layer = default(); - let dirty = default(); - let callbacks = default(); - let parent_bind = default(); - let children = default(); - let transform = default(); - let visible = default(); - let capturing_event_fan = frp::Fan::new(&network); - let bubbling_event_fan = frp::Fan::new(&network); - frp::extend! { network - event_source <- source(); +impl Default for Model { + fn default() -> Self { + Self::new() + } +} + +impl PartialEq for InstanceDef { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.rc, &other.rc) + } +} + +impl PartialEq for Instance { + fn eq(&self, other: &Self) -> bool { + self.def.eq(&other.def) + } +} + +impl Display for Instance { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Instance") + } +} + +impl Display for InstanceDef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Instance") + } +} + +impl Debug for InstanceDef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "DisplayObject") + } +} + + + +// ================================================================================================= +// === Hierarchy =================================================================================== +// ================================================================================================= + +// ================== +// === ParentBind === +// ================== + +/// A parent-child binding. It contains reference to parent node and information about the child +/// index. When dropped, it removes the child from its parent. +#[derive(Debug)] +pub struct ParentBind { + /// The parent's child index. If this is a binding stored by [`Instance`], this will be the + /// instance index in the parent's instance vector. + child_index: ChildIndex, + parent: WeakInstance, +} + +impl ParentBind { + fn parent(&self) -> Option { + self.parent.upgrade() + } +} + +impl Drop for ParentBind { + fn drop(&mut self) { + if let Some(parent) = self.parent() { + if let Some(weak_child) = parent.children.borrow_mut().remove(*self.child_index) { + parent.dirty.modified_children.unset(&self.child_index); + if let Some(child) = weak_child.upgrade() { + child.dirty.new_parent.set(); + parent.dirty.removed_children.set(weak_child); + } + } } - Self { - network, - event_source, - capturing_event_fan, - bubbling_event_fan, - host, - focused_descendant, - assigned_layer, - layer, - dirty, - callbacks, - parent_bind, - children, - transform, - visible, + } +} + + + +// ======================== +// === SharedParentBind === +// ======================== + +/// A shared version of [`Option`]. +#[derive(Clone, CloneRef, Debug, Default)] +pub struct SharedParentBind { + data: Rc>>, +} + +impl SharedParentBind { + fn is_none(&self) -> bool { + self.data.borrow().is_none() + } + + fn is_some(&self) -> bool { + self.data.borrow().is_some() + } + + fn set_bind(&self, bind: ParentBind) { + *self.data.borrow_mut() = Some(bind) + } + + fn take_bind(&self) -> Option { + self.data.borrow_mut().take() + } + + fn parent(&self) -> Option { + self.data.borrow().as_ref().and_then(|t| t.parent()) + } + + fn parent_and_child_index(&self) -> Option<(Instance, ChildIndex)> { + self.data.borrow().as_ref().and_then(|t| t.parent().map(|s| (s, t.child_index))) + } + + fn child_index(&self) -> Option { + self.data.borrow().as_ref().map(|t| t.child_index) + } +} + + + +// =================== +// === Dirty Flags === +// =================== + +/// Dirty flags. +pub mod dirty { + pub use super::*; + + // === Types === + + type NewParent = crate::data::dirty::RefCellBool<()>; + type ModifiedChildren = crate::data::dirty::RefCellSet; + type RemovedChildren = crate::data::dirty::RefCellVector; + type Transform = crate::data::dirty::RefCellBool; + type SceneLayer = crate::data::dirty::RefCellBool; + + + // === Definition === + + /// A set of dirty flags encoding which hierarchy-related properties of a display object have + /// been changed and not yet updated. See the docs of [`Instance`] to learn more about the lazy + /// update mechanism. + /// + /// # Performance + /// Let's consider a deep tree of objects. To render an object, we need its position in the + /// world-space (global-space). Thus, when the tree root object moves, all of its children, + /// their sub-children, etc., need to be updated. As there might be hundreds or thousands of + /// such sub-children, this might be very costly. Even worse, if the user of this library moves + /// the root object, and then moves its child, all the sub-children of that child would be + /// recomputed twice if not updated lazily. + #[derive(Debug)] + #[allow(missing_docs)] + pub struct Flags { + pub new_parent: NewParent, + /// A set of children that were added, removed, transformed, moved to a different layer, or + /// whose ancestors were modified in such a way. + pub modified_children: ModifiedChildren, + pub removed_children: RemovedChildren, + pub transformation: Transform, + pub new_layer: SceneLayer, + } + + impl Flags { + /// Constructor. + pub fn new(parent_bind: &SharedParentBind) -> Self { + let new_parent = NewParent::new(()); + let modified_children = ModifiedChildren::new(on_dirty_callback(parent_bind)); + let removed_children = RemovedChildren::new(on_dirty_callback(parent_bind)); + let transformation = Transform::new(on_dirty_callback(parent_bind)); + let new_layer = SceneLayer::new(on_dirty_callback(parent_bind)); + Self { new_parent, modified_children, removed_children, transformation, new_layer } } } + type OnDirtyCallback = impl Fn(); + fn on_dirty_callback(parent_bind: &SharedParentBind) -> OnDirtyCallback { + let parent_bind = parent_bind.clone_ref(); + move || { + if let Some((parent, index)) = parent_bind.parent_and_child_index() { + parent.dirty.modified_children.set(index); + } + } + } +} + + + +// ===================== +// === Hierarchy FRP === +// ===================== + +/// FRP endpoints relate to display object hierarchy modification. +#[derive(Debug)] +pub struct HierarchyFrp { + /// Fires when the display object is shown. It will fire during the first scene refresh if this + /// object was invisible and was added as a child to a visible parent. + pub on_show: frp::Stream<(Option, Option)>, + /// Fires when the display object is hidden. This can happen for example after detaching it + /// from a visible parent. It will fire during the first scene refresh if this object was + /// removed from a visible parent or added to an invisible one. + pub on_hide: frp::Stream>, + /// Fires during the first scene refresh if this object was moved between scene layers. + pub on_layer_change: frp::Stream<(Option, Option, Option)>, + /// Fires during the first scene refresh if this object needed an update and the update was + /// performed. + pub on_updated: frp::Stream<()>, + on_show_source: frp::Source<(Option, Option)>, + on_hide_source: frp::Source>, + on_layer_change_source: frp::Source<(Option, Option, Option)>, + on_updated_source: frp::Source<()>, +} + +impl HierarchyFrp { + fn new(network: &frp::Network) -> Self { + frp::extend! { network + on_show_source <- source(); + on_hide_source <- source(); + on_layer_change_source <- source(); + on_updated_source <- source(); + } + let on_show = on_show_source.clone_ref().into(); + let on_hide = on_hide_source.clone_ref().into(); + let on_layer_change = on_layer_change_source.clone_ref().into(); + let on_updated = on_updated_source.clone_ref().into(); + Self { + on_show_source, + on_hide_source, + on_layer_change_source, + on_updated_source, + on_show, + on_hide, + on_layer_change, + on_updated, + } + } +} + + + +// ======================= +// === Hierarchy Model === +// ======================= + +/// The part of display object model related to its hierarchy. +#[derive(Debug, Deref)] +pub struct HierarchyModel { + #[deref] + frp: HierarchyFrp, + visible: Cell, + transformation: RefCell, + parent_bind: SharedParentBind, + children: RefCell>, + /// Layer the object was explicitly assigned to by the user, if any. + assigned_layer: RefCell>, + /// Layer where the object is displayed. It may be set to by user or inherited from the parent. + layer: RefCell>, + dirty: dirty::Flags, +} + +impl HierarchyModel { + fn new(network: &frp::Network) -> Self { + let frp = HierarchyFrp::new(network); + let visible = default(); + let transformation = default(); + let parent_bind = default(); + let children = default(); + let assigned_layer = default(); + let layer = default(); + let dirty = dirty::Flags::new(&parent_bind); + Self { frp, visible, transformation, parent_bind, children, assigned_layer, layer, dirty } + } +} + + + +// ======================= +// === Hierarchy Logic === +// ======================= + +// === Updates and Visibility === + +impl Model { + /// Get the layer this object is displayed in. May be equal to layer explicitly set by the user + /// or a layer inherited from the parent. + fn display_layer(&self) -> Option { + self.layer.borrow().as_ref().and_then(|t| t.upgrade()) + } + + /// Add this object to the provided scene layer. Do not use this method explicitly. Use layers' + /// methods instead. + pub(crate) fn add_to_display_layer(&self, layer: &Layer) { + let layer = layer.downgrade(); + let mut assigned_layer = self.assigned_layer.borrow_mut(); + if assigned_layer.as_ref() != Some(&layer) { + self.dirty.new_layer.set(); + *assigned_layer = Some(layer); + } + } + + /// Remove this object from the provided scene layer. Do not use this method explicitly. Use + /// layers' methods instead. + pub(crate) fn remove_from_display_layer(&self, layer: &Layer) { + let layer = layer.downgrade(); + let mut assigned_layer = self.assigned_layer.borrow_mut(); + if assigned_layer.as_ref() == Some(&layer) { + self.dirty.new_layer.set(); + *assigned_layer = None; + } + } +} + +impl Model { /// Checks whether the object is visible. pub fn is_visible(&self) -> bool { self.visible.get() } + /// Hide the object. This is a helper API. Used by tests and the [`Root`] object. + fn hide(&self) { + self.set_vis_false(None) + } + + /// Show the object. This is a helper API. Used by tests and the [`Root`] object. + fn show(&self) { + self.set_vis_true(None, None) + } + + fn set_vis_false(&self, scene: Option<&Scene>) { + if self.visible.get() { + trace!("Hiding."); + self.visible.set(false); + self.on_hide_source.emit(scene.cloned()); + self.children + .borrow() + .iter() + .filter_map(|t| t.upgrade()) + .for_each(|t| t.set_vis_false(scene)); + } + } + + fn set_vis_true(&self, scene: Option<&Scene>, parent_layer: Option<&WeakLayer>) { + if !self.visible.get() { + trace!("Showing."); + self.visible.set(true); + let assigned_layer_borrow = self.assigned_layer.borrow(); + let assigned_layer = assigned_layer_borrow.as_ref(); + let new_layer = assigned_layer.or(parent_layer); + self.on_show_source.emit((scene.cloned(), new_layer.cloned())); + self.children + .borrow() + .iter() + .filter_map(|t| t.upgrade()) + .for_each(|t| t.set_vis_true(scene, new_layer)); + } + } + /// Checks whether the object is orphan (do not have parent object attached). - pub fn is_orphan(&self) -> bool { - self.parent_bind.borrow().is_none() + pub fn has_parent(&self) -> bool { + self.parent_bind.is_some() } - /// Parent object getter. - pub fn parent(&self) -> Option> { - self.parent_bind.borrow().as_ref().and_then(|t| t.parent()) + /// Get reference to the parent object if any. + pub fn parent(&self) -> Option { + self.parent_bind.parent() } - /// Count of children objects. + /// The index of this display object in the parent's children list. + fn my_index(&self) -> Option { + self.parent_bind.child_index() + } + + fn has_visible_parent(&self) -> bool { + self.parent_bind.parent().map_or(false, |parent| parent.is_visible()) + } + + /// Number of children of this object. pub fn children_count(&self) -> usize { self.children.borrow().len() } - /// Recompute the transformation matrix of this object and update all of its dirty children. - pub fn update(&self, host: &Host) { - let origin0 = Matrix4::identity(); - self.update_with_origin(host, origin0, false, false, None) + /// Removes and returns the parent bind. Please note that the parent is not updated as long as + /// the parent bind is not dropped. + fn take_parent_bind(&self) -> Option { + let parent_bind = self.parent_bind.take_bind(); + if let Some(parent) = parent_bind.as_ref().and_then(|t| t.parent.upgrade()) { + let is_focused = self.event.focused_descendant.borrow().is_some(); + if is_focused { + parent.propagate_up_no_focus_instance(); + } + } + parent_bind } - /// The default visibility of a new [`Instance`] is false. You can use this function to override - /// it. It is mainly used for a special 'root' element if such exists. - pub fn force_set_visibility(&self, visibility: bool) { - self.visible.set(visibility); - // TODO[ao] this function should make the next update call on_show or on_hide - // https://github.com/enso-org/ide/issues/1406 - } - - /// Removes child by a given index. Does nothing if the index was incorrect. - fn remove_child_by_index(&self, index: usize) { - self.children.borrow_mut().remove(index).for_each(|child| { - child.upgrade().for_each(|child| child.unsafe_unset_parent_without_update()); - self.dirty.children.unset(&index); - self.dirty.removed_children.set(child); - }); + /// Set parent of the object. If the object already has a parent, the parent would be replaced. + fn set_parent_bind(&self, bind: ParentBind) { + trace!("Adding new parent bind."); + if let Some(parent) = bind.parent() { + self.parent_bind.set_bind(bind); + self.dirty.new_parent.set(); + if let Some(focus_instance) = &*self.event.focused_descendant.borrow() { + parent.blur_tree(); + parent.propagate_up_new_focus_instance(focus_instance); + } + } } /// Removes all children of this display object and returns them. - pub fn remove_all_children(&self) -> Vec> { - let children: Vec> = + pub fn remove_all_children(&self) -> Vec { + let children: Vec = self.children.borrow().iter().filter_map(|weak| weak.upgrade()).collect(); for child in &children { child.unset_parent(); @@ -307,52 +566,33 @@ impl Model { children } - /// Removes the binding to the parent object. Parent is not updated. - fn unsafe_unset_parent_without_update(&self) { - trace!("Removing parent bind."); - self.dirty.unset_on_dirty(); - self.dirty.parent.set(); + /// Recompute the transformation matrix of the display object tree starting with this object and + /// traversing all of its dirty children. + pub fn update(&self, scene: &Scene) { + let origin0 = Matrix4::identity(); + self.update_with_origin(scene, origin0, false, false, None) } - /// Get event stream for bubbling events. See docs of [`event::Event`] to learn more. - pub fn on_event(&self) -> frp::Stream> - where T: frp::Data { - self.bubbling_event_fan.output::>() - } - - /// Get event stream for capturing events. You should rather not need this function. Use - /// [`on_event`] instead. See docs of [`event::Event`] to learn more. - pub fn on_event_capturing(&self) -> frp::Stream> - where T: frp::Data { - self.capturing_event_fan.output::>() - } -} - - -// === Update API === - -impl Model { - /// Updates object transformations by providing a new origin location. See docs of `update` to - /// learn more. + /// Update the display object tree transformations based on the parent object origin. See docs + /// of [`update`] to learn more. fn update_with_origin( &self, - host: &Host, + scene: &Scene, parent_origin: Matrix4, parent_origin_changed: bool, parent_layers_changed: bool, parent_layer: Option<&WeakLayer>, ) { // === Scene Layers Update === - let has_new_parent = self.dirty.parent.check(); + let has_new_parent = self.dirty.new_parent.check(); let assigned_layer_ref = self.assigned_layer.borrow(); let assigned_layer = assigned_layer_ref.as_ref(); - let assigned_layers_changed = self.dirty.scene_layer.take().check(); + let assigned_layers_changed = self.dirty.new_layer.take().check(); let has_assigned_layer = assigned_layer.is_some(); let layer_changed = if assigned_layers_changed { // We might as well check here if assigned layers were not removed and accidentally the // inherited layers are not the same as previously assigned ones, but this is so rare - // situation that we are not checking it to optimize the performance of this case in - // most popular cases. + // situation that we are not checking it to optimize the performance of this case. true } else if has_assigned_layer { false @@ -373,7 +613,11 @@ impl Model { if let Some(new_layer) = new_layer_opt { debug_span!("Scene layer changed.").in_scope(|| { let old_layer = mem::replace(&mut *self.layer.borrow_mut(), new_layer.cloned()); - self.callbacks.on_scene_layer_changed(host, old_layer.as_ref(), new_layer); + self.on_layer_change_source.emit(( + Some(scene.clone_ref()), + old_layer, + new_layer.cloned(), + )); }); } @@ -383,27 +627,27 @@ impl Model { // === Origin & Visibility Update === - self.update_visibility(host, parent_layer); + self.update_visibility(scene, parent_layer); let is_origin_dirty = has_new_parent || parent_origin_changed || layer_changed; let new_parent_origin = is_origin_dirty.as_some(parent_origin); let parent_origin_label = if new_parent_origin.is_some() { "new" } else { "old" }; debug_span!("Update with {} parent origin.", parent_origin_label).in_scope(|| { - let origin_changed = self.transform.borrow_mut().update(new_parent_origin); - let new_origin = self.transform.borrow().matrix; + let origin_changed = self.transformation.borrow_mut().update(new_parent_origin); + let new_origin = self.transformation.borrow().matrix; if origin_changed || layer_changed { if origin_changed { trace!("Self origin changed."); } else { trace!("Self origin did not change, but the layers changed"); } - self.callbacks.on_updated(self); + self.on_updated_source.emit(()); if !self.children.borrow().is_empty() { debug_span!("Updating all children.").in_scope(|| { let children = self.children.borrow().clone(); children.iter().for_each(|weak_child| { weak_child.upgrade().for_each(|child| { child.update_with_origin( - host, + scene, new_origin, true, layer_changed, @@ -415,16 +659,16 @@ impl Model { } } else { trace!("Self origin and layers did not change."); - if self.dirty.children.check_all() { + if self.dirty.modified_children.check_all() { debug_span!("Updating dirty children.").in_scope(|| { - self.dirty.children.take().iter().for_each(|ix| { + self.dirty.modified_children.take().iter().for_each(|ix| { self.children .borrow() - .safe_index(*ix) + .safe_index(**ix) .and_then(|t| t.upgrade()) .for_each(|child| { child.update_with_origin( - host, + scene, new_origin, false, layer_changed, @@ -435,293 +679,229 @@ impl Model { }) } } - self.dirty.children.unset_all(); + self.dirty.modified_children.unset_all(); }); - self.dirty.transform.unset(); - self.dirty.parent.unset(); + self.dirty.transformation.unset(); + self.dirty.new_parent.unset(); } /// Hide all removed children and show this display object if it was attached to a new parent. - fn update_visibility(&self, host: &Host, parent_layer: Option<&WeakLayer>) { - self.take_removed_children_and_update_their_visibility(host); - let parent_changed = self.dirty.parent.check(); - if parent_changed && !self.is_orphan() { - self.set_vis_true(host, parent_layer) + fn update_visibility(&self, scene: &Scene, parent_layer: Option<&WeakLayer>) { + self.take_removed_children_and_update_their_visibility(scene); + let parent_changed = self.dirty.new_parent.check(); + if parent_changed && self.has_parent() { + self.set_vis_true(Some(scene), parent_layer) } } - fn take_removed_children_and_update_their_visibility(&self, host: &Host) { + fn take_removed_children_and_update_their_visibility(&self, scene: &Scene) { if self.dirty.removed_children.check_all() { debug_span!("Updating removed children.").in_scope(|| { for child in self.dirty.removed_children.take().into_iter() { if let Some(child) = child.upgrade() { if !child.has_visible_parent() { - child.set_vis_false(host); + // The child was not attached to another visible parent. + child.set_vis_false(Some(scene)); } // Even if the child is visible at this point, it does not mean that it // should be visible after the entire update. Therefore, we must ensure that // "removed children" lists in its subtree will be managed. // See also test `visibility_test3`. - child.take_removed_children_and_update_their_visibility(host); + child.take_removed_children_and_update_their_visibility(scene); } } }) } } - - fn set_vis_false(&self, host: &Host) { - if self.visible.get() { - trace!("Hiding."); - self.visible.set(false); - self.callbacks.on_hide(host); - self.children.borrow().iter().for_each(|child| { - child.upgrade().for_each(|t| t.set_vis_false(host)); - }); - } - } - - fn set_vis_true(&self, host: &Host, parent_layer: Option<&WeakLayer>) { - if !self.visible.get() { - trace!("Showing."); - let this_scene_layer = self.assigned_layer.borrow(); - let this_scene_layers_ref = this_scene_layer.as_ref(); - let layer = - if this_scene_layers_ref.is_none() { parent_layer } else { this_scene_layers_ref }; - self.visible.set(true); - self.callbacks.on_show(host, layer); - self.children.borrow().iter().for_each(|child| { - child.upgrade().for_each(|t| t.set_vis_true(host, layer)); - }); - } - } } +impl InstanceDef { + /// Checks if the provided object is child of the current one. + pub fn has_child(&self, child: &T) -> bool { + self.child_index(child).is_some() + } -// === Register / Unregister === + /// Returns the index of the provided object if it was a child of the current one. + pub fn child_index(&self, child: &T) -> Option { + let child = child.display_object(); + child.parent_bind.parent_and_child_index().and_then(|(parent, index)| { + if &parent.def == self { + Some(index) + } else { + None + } + }) + } -impl Model { - fn register_child>(&self, child: &T) -> usize { - let index = self.children.borrow_mut().insert(child.weak_display_object()); - self.dirty.children.set(index); + /// Replaces the parent binding with a new parent. + fn set_parent(&self, parent: &InstanceDef) { + parent.add_child(self); + } + + /// Removes the current parent binding. + fn unset_parent(&self) { + self.take_parent_bind(); + } + + /// Attaches the provided display object as a child to this one. + fn add_child(&self, child: &InstanceDef) { + child.unset_parent(); + let child_index = self.register_child(child); + trace!("Adding a new child at index {child_index}."); + let parent_bind = ParentBind { parent: self.downgrade(), child_index }; + child.set_parent_bind(parent_bind); + } + + fn register_child(&self, child: &InstanceDef) -> ChildIndex { + let index = ChildIndex(self.children.borrow_mut().insert(child.downgrade())); + self.dirty.modified_children.set(index); index } - /// Removes and returns the parent bind. Please note that the parent is not updated as long as - /// the parent bind is not dropped. - fn take_parent_bind(&self) -> Option> { - let parent_bind = self.parent_bind.borrow_mut().take(); - if let Some(parent) = parent_bind.as_ref().and_then(|t| t.parent.upgrade()) { - let is_focused = self.focused_descendant.borrow().is_some(); - if is_focused { - parent.propagate_up_no_focus_instance(); - } + /// Removes the provided object reference from child list of this object. Does nothing if the + /// reference was not a child of this object. + fn remove_child(&self, child: &T) { + let child = child.display_object(); + if self.has_child(child) { + child.unset_parent() } - parent_bind } - /// Set parent of the object. If the object already has a parent, the parent would be replaced. - fn set_parent_bind(&self, bind: ParentBind) { - trace!("Adding new parent bind."); - if let Some(focus_instance) = &*self.focused_descendant.borrow() { - if let Some(parent) = bind.parent.upgrade() { - parent._blur_tree(); - parent.propagate_up_new_focus_instance(focus_instance); - } - } - if let Some(parent) = bind.parent() { - let index = bind.index; - let dirty = parent.dirty.children.clone_ref(); - self.dirty.set_on_dirty(move || dirty.set(index)); - self.dirty.parent.set(); - *self.parent_bind.borrow_mut() = Some(bind); + /// Get reversed parent chain of this display object (`[root, child_of root, ..., parent, + /// self]`). The last item is this object. + fn rev_parent_chain(&self) -> Vec { + let mut vec = default(); + Self::build_rev_parent_chain(&mut vec, Some(self.clone_ref().into())); + vec + } + + fn build_rev_parent_chain(vec: &mut Vec, parent: Option) { + if let Some(parent) = parent { + Self::build_rev_parent_chain(vec, parent.parent()); + vec.push(parent); } } } -// === Getters === -impl Model { +// ======================= +// === Transformations === +// ======================= + +impl Model { /// Position of the object in the global coordinate space. - pub fn global_position(&self) -> Vector3 { - self.transform.borrow().global_position() + fn global_position(&self) -> Vector3 { + self.transformation.borrow().global_position() } /// Position of the object in the parent coordinate space. - pub fn position(&self) -> Vector3 { - self.transform.borrow().position() + fn position(&self) -> Vector3 { + self.transformation.borrow().position() } /// Scale of the object in the parent coordinate space. - pub fn scale(&self) -> Vector3 { - self.transform.borrow().scale() + fn scale(&self) -> Vector3 { + self.transformation.borrow().scale() } /// Rotation of the object in the parent coordinate space. - pub fn rotation(&self) -> Vector3 { - self.transform.borrow().rotation() + fn rotation(&self) -> Vector3 { + self.transformation.borrow().rotation() } /// Transformation matrix of the object in the parent coordinate space. - pub fn matrix(&self) -> Matrix4 { - self.transform.borrow().matrix() + fn transformation_matrix(&self) -> Matrix4 { + self.transformation.borrow().matrix() } } -// === Setters === +// === Transformation Setters === -impl Model { - fn with_mut_borrowed_transform(&self, f: F) -> T - where F: FnOnce(&mut CachedTransform) -> T { - self.dirty.transform.set(); - f(&mut self.transform.borrow_mut()) - } - - fn set_position(&self, v: Vector3) { - self.with_mut_borrowed_transform(|t| t.set_position(v)); - } - - fn set_scale(&self, v: Vector3) { - self.with_mut_borrowed_transform(|t| t.set_scale(v)); - } - - fn set_rotation(&self, v: Vector3) { - self.with_mut_borrowed_transform(|t| t.set_rotation(v)); - } - - fn mod_position)>(&self, f: F) { - self.with_mut_borrowed_transform(|t| t.mod_position(f)); - } - - fn mod_rotation)>(&self, f: F) { - self.with_mut_borrowed_transform(|t| t.mod_rotation(f)); - } - - fn mod_scale)>(&self, f: F) { - self.with_mut_borrowed_transform(|t| t.mod_scale(f)); - } - - /// Sets a callback which will be called with a reference to the display object when the object - /// will be updated. - pub fn set_on_updated(&self, f: F) - where F: Fn(&Model) + 'static { - self.callbacks.on_updated.set(Box::new(f)) - } - - /// Sets a callback which will be called with a reference to scene when the object will be - /// shown (attached to visible display object graph). - pub fn set_on_show(&self, f: F) - where F: Fn(&Host, Option<&WeakLayer>) + 'static { - self.callbacks.on_show.set(Box::new(f)) - } - - /// Sets a callback which will be called with a reference to scene when the object will be - /// hidden (detached from display object graph). - pub fn set_on_hide(&self, f: F) - where F: Fn(&Host) + 'static { - self.callbacks.on_hide.set(Box::new(f)) - } - - /// Sets a callback which will be called on every change to the layers assignment. The callback - /// will be provided with a reference to scene and two lists of layers this object was - /// previously and is currently attached to . - pub fn set_on_scene_layer_changed(&self, f: F) - where F: Fn(&Host, Option<&WeakLayer>, Option<&WeakLayer>) + 'static { - self.callbacks.on_scene_layer_changed.set_if_empty_or_warn(Box::new(f)) +impl Model { + fn with_mut_borrowed_transformation(&self, f: F) -> T + where F: FnOnce(&mut CachedTransformation) -> T { + self.dirty.transformation.set(); + f(&mut self.transformation.borrow_mut()) } } +macro_rules! generate_transformation_getters_and_setters { + ($($name:ident),*) => { paste! { + impl Model {$( + fn [](&self, v: Vector3) { + self.with_mut_borrowed_transformation(|t| t.[](v)); + } - -// ========== -// === Id === -// ========== - -/// Globally unique identifier of a display object. -#[derive( - Clone, CloneRef, Copy, Debug, Default, Display, Eq, From, Hash, Into, PartialEq, Ord, - PartialOrd -)] -pub struct Id(usize); - - - -// ================ -// === Instance === -// ================ - -/// A hierarchical representation of object containing information about transformation in 3D space, -/// list of children, and set of utils for dirty flag propagation. -/// -/// ## Host -/// The model is parametrized with a `Host`. In real life use cases, host is **ALWAYS** instantiated -/// with `Scene`. For the needs of tests, its often instantiated with empty tuple for simplicity. -/// Host has a very important role in decoupling the architecture. You need to provide the `update` -/// method with a reference to the host, which is then passed to `on_show` and `on_hide` callbacks -/// when a particular display objects gets shown or hidden respectively. -/// -/// This can be used for a dynamic management of GPU-side rendering. After adding a display object -/// to a scene, a new sprite can be created to display it visually. After removing the object and -/// adding it to a different scene (another GPU context), the sprite in the first context can be -/// trashed, and a new sprite in the new context can be created instead. This mechanism is currently -/// also used for sprites layer management, but this functionality is inherently connected to the -/// sprites creation in a given context (moving object to a different layer of the same [`Scene`] is -/// similar to moving it to a layer of a different [`Scene`]. -/// -/// Thus, abstracting over `Host` allows users of this library to define a view model (like few -/// sliders in a box) without the need to contain reference to a particular renderer, and attach the -/// renderer on-demand, when the objects will be placed on the stage. -/// -/// Please note, that moving an object between two Scenes (two WebGL contexts) is not implemented -/// yet. -/// -/// ## Possible changes to the Host parametrization design -/// Instead of parametrizing the Display Object, the [`Host`] could be implemented as dyn trait -/// object exposing a few options to registering sprites in Scene layers. This is a way less generic -/// solution than the one implemented currently, but it would allow [`Scene`] parametrization. For -/// example, if we would like to implement [`Scene`], where the [`Context`] is either a -/// WebGL or an OpenGL context (currently contexts are implemented as dyn traits instead). -/// -/// ## Scene Layers -/// Each display object instance contains an optional list of [`scene::LayerId`]. During object -/// update, the list is passed from parent display objects to their children as long as the child -/// does not override it (is assigned with [`None`]). Similar to [`Host`], the scene layers list -/// plays a very important role in decoupling the architecture. It allows objects and their children -/// to be assigned to a particular [`scene::Layer`], and thus allows for easy to use depth -/// management. -#[derive(Derivative)] -#[derive(CloneRef, Deref)] -#[derivative(Clone(bound = ""))] -pub struct Instance { - rc: Rc>, + fn [](&self, f: impl FnOnce(&mut Vector3)) { + self.with_mut_borrowed_transformation(|t| t.[](f)); + } + )*} + }}; } +generate_transformation_getters_and_setters!(position, scale, rotation); -impl Instance { - /// Create a new weak pointer to this display object instance. - pub fn downgrade(&self) -> WeakInstance { - let weak = Rc::downgrade(&self.rc); - WeakInstance { weak } + + +// ====================== +// === Events & Focus === +// ====================== +// See the documentation of [`event::Event`] to learn more about events. + +/// The part of display object model related to event handling. +#[derive(Debug)] +pub struct EventModel { + source: frp::Source, + capturing_fan: frp::Fan, + bubbling_fan: frp::Fan, + focused_descendant: RefCell>, +} + +impl EventModel { + fn new(network: &frp::Network) -> Self { + let capturing_fan = frp::Fan::new(network); + let bubbling_fan = frp::Fan::new(network); + let focused_descendant = default(); + frp::extend! { network + source <- source(); + } + Self { source, capturing_fan, bubbling_fan, focused_descendant } } } -impl Instance { - /// Constructor. - pub fn new() -> Self { - Self { rc: Rc::new(Model::new()) }.init() +impl Model { + // FIXME: this is not finished yet, should be finished in the next PR regarding auto-layouts. + pub(crate) fn set_bounding_box(&self, bounding_box: Vector2) { + self.bounding_box.set(bounding_box); } - fn init(self) -> Self { + /// Get event stream for bubbling events. See docs of [`event::Event`] to learn more. + fn on_event(&self) -> frp::Stream> + where T: frp::Data { + self.event.bubbling_fan.output::>() + } + + /// Get event stream for capturing events. You should rather not need this function. Use + /// [`on_event`] instead. See docs of [`event::Event`] to learn more. + fn on_event_capturing(&self) -> frp::Stream> + where T: frp::Data { + self.event.capturing_fan.output::>() + } +} + +impl InstanceDef { + fn init_events_handling(self) -> Self { // This implementation is a bit complex because we do not want to clone network to the FRP // closure in order to avoid a memory leak. let network = &self.network; let parent_bind = &self.parent_bind; - let capturing_event_fan = &self.capturing_event_fan; - let bubbling_event_fan = &self.bubbling_event_fan; + let capturing_event_fan = &self.event.capturing_fan; + let bubbling_event_fan = &self.event.bubbling_fan; frp::extend! { network - eval self.event_source ([parent_bind, capturing_event_fan, bubbling_event_fan] (event) { - let parent = parent_bind.borrow().as_ref().and_then(|t| t.parent()); + eval self.event.source ([parent_bind, capturing_event_fan, bubbling_event_fan] (event) { + let parent = parent_bind.parent(); Self::emit_event_impl(event, parent, &capturing_event_fan, &bubbling_event_fan); }); } @@ -730,15 +910,15 @@ impl Instance { fn emit_event_impl( event: &event::SomeEvent, - parent: Option>, + parent: Option, capturing_event_fan: &frp::Fan, bubbling_event_fan: &frp::Fan, ) { - let rev_parent_chain = Self::rev_parent_chain(parent); + let rev_parent_chain = parent.map(|p| p.rev_parent_chain()).unwrap_or_default(); if event.captures.get() { for object in &rev_parent_chain { if !event.is_cancelled() { - object.capturing_event_fan.emit(&event.data); + object.event.capturing_fan.emit(&event.data); } else { break; } @@ -753,7 +933,7 @@ impl Instance { if event.bubbles.get() { for object in rev_parent_chain.iter().rev() { if !event.is_cancelled() { - object.bubbling_event_fan.emit(&event.data); + object.event.bubbling_fan.emit(&event.data); } else { break; } @@ -761,67 +941,52 @@ impl Instance { } } - /// Get reversed parent chain of this display object (`[root, child_of root, ..., - /// parent]`). The last item is the argument passed to this function. - fn rev_parent_chain(parent: Option>) -> Vec> { - let mut vec = default(); - Self::build_rev_parent_chain(&mut vec, parent); - vec - } - - fn build_rev_parent_chain(vec: &mut Vec>, parent: Option>) { - if let Some(parent) = parent { - Self::build_rev_parent_chain(vec, parent.parent()); - vec.push(parent); - } - } - - fn _new_event(&self, payload: T) -> event::SomeEvent + fn new_event(&self, payload: T) -> event::SomeEvent where T: 'static { - event::SomeEvent::new(Some(self), payload) + event::SomeEvent::new(Some(self.downgrade()), payload) } - fn _emit_event(&self, payload: T) + fn emit_event(&self, payload: T) where T: 'static { - self.event_source.emit(event::SomeEvent::new(Some(self), payload)); + self.event.source.emit(event::SomeEvent::new(Some(self.downgrade()), payload)); } - fn focused_descendant(&self) -> Option> { - self.focused_descendant.borrow().as_ref().and_then(|t| t.upgrade()) + fn focused_descendant(&self) -> Option { + self.event.focused_descendant.borrow().as_ref().and_then(|t| t.upgrade()) } - fn _focused_instance(&self) -> Option> { + fn focused_instance(&self) -> Option { if let Some(child) = self.focused_descendant() { Some(child) } else { - self.parent().and_then(|parent| parent._focused_instance()) + self.parent().and_then(|parent| parent.focused_instance()) } } - fn _is_focused(&self) -> bool { - self.focused_descendant().as_ref() == Some(self) + fn is_focused(&self) -> bool { + self.focused_descendant().as_ref().map(|t| &t.def) == Some(self) } - fn _focus(&self) { - self._blur_tree(); + fn focus(&self) { + self.blur_tree(); self.propagate_up_new_focus_instance(&self.downgrade()); - let focus_event = self._new_event(event::Focus); - let focus_in_event = self._new_event(event::FocusIn); + let focus_event = self.new_event(event::Focus); + let focus_in_event = self.new_event(event::FocusIn); focus_event.bubbles.set(false); - self.event_source.emit(focus_event); - self.event_source.emit(focus_in_event); + self.event.source.emit(focus_event); + self.event.source.emit(focus_in_event); } - fn _blur(&self) { - if self._is_focused() { + fn blur(&self) { + if self.is_focused() { self.blur_unchecked(); } } /// Blur the display object tree this object belongs to. If any tree node (any node directly or /// indirectly connected with each other) was focused, it will be blurred. - fn _blur_tree(&self) { - if let Some(instance) = self._focused_instance() { + fn blur_tree(&self) { + if let Some(instance) = self.focused_instance() { instance.blur_unchecked(); } } @@ -831,163 +996,30 @@ impl Instance { /// objects will erase information about the currently focused object. fn blur_unchecked(&self) { self.propagate_up_no_focus_instance(); - let blur_event = self._new_event(event::Blur); - let focus_out_event = self._new_event(event::FocusOut); + let blur_event = self.new_event(event::Blur); + let focus_out_event = self.new_event(event::FocusOut); blur_event.bubbles.set(false); - self.event_source.emit(blur_event); - self.event_source.emit(focus_out_event); + self.event.source.emit(blur_event); + self.event.source.emit(focus_out_event); } /// Clears the focus info in this instance and all parent instances. In order to work properly, /// this should be called on the focused instance. Otherwise, it may clear the information /// only partially. fn propagate_up_no_focus_instance(&self) { - *self.focused_descendant.borrow_mut() = None; + *self.event.focused_descendant.borrow_mut() = None; self.parent().for_each(|parent| parent.propagate_up_no_focus_instance()); } /// Set the focus instance to the provided one here and in all instances on the path to the /// root. - fn propagate_up_new_focus_instance(&self, instance: &WeakInstance) { - debug_assert!(self.focused_descendant.borrow().is_none()); - *self.focused_descendant.borrow_mut() = Some(instance.clone()); + fn propagate_up_new_focus_instance(&self, instance: &WeakInstance) { + debug_assert!(self.event.focused_descendant.borrow().is_none()); + *self.event.focused_descendant.borrow_mut() = Some(instance.clone()); self.parent().for_each(|parent| parent.propagate_up_new_focus_instance(instance)); } } -impl Default for Instance { - fn default() -> Self { - Self::new() - } -} - - -// === Public API == - -impl Instance { - /// ID getter of this display object. - pub fn _id(&self) -> Id { - Id(Rc::downgrade(&self.rc).as_ptr() as *const () as usize) - } -} - -impl Instance { - /// Get the layers where this object is displayed. May be equal to layers it was explicitly - /// assigned, or layers inherited from the parent. - pub fn _display_layers(&self) -> Option { - self.layer.borrow().as_ref().cloned() - } - - /// Add this object to the provided scene layer. - /// Do not use this method explicitly. Use layers' methods instead. - pub(crate) fn add_to_display_layer(&self, layer: &Layer) { - let layer = layer.downgrade(); - self.dirty.scene_layer.set(); - let mut assigned_layer = self.assigned_layer.borrow_mut(); - if assigned_layer.as_ref() != Some(&layer) { - *assigned_layer = Some(layer); - } - } - - /// Remove this object from the provided scene layer. Do not use this method explicitly. Use - /// layers' methods instead. - pub(crate) fn remove_from_scene_layer(&self, layer: &Layer) { - let layer = layer.downgrade(); - let mut assigned_layer = self.assigned_layer.borrow_mut(); - if assigned_layer.as_ref() == Some(&layer) { - self.dirty.scene_layer.set(); - *assigned_layer = None; - } - } - - /// Adds a new `Object` as a child to the current one. - pub fn _add_child>(&self, child: &T) { - trace!("Adding new child."); - let child = child.display_object(); - child.unset_parent(); - let index = self.register_child(child); - trace!("Child index is {index}."); - let parent_bind = ParentBind { parent: self.downgrade(), index }; - child.set_parent_bind(parent_bind); - } - - /// Removes the provided object reference from child list of this object. Does nothing if the - /// reference was not a child of this object. - pub fn _remove_child>(&self, child: &T) { - let child = child.display_object(); - if self.has_child(child) { - child.unset_parent() - } - } - - /// Replaces the parent binding with a new parent. - pub fn set_parent>(&self, parent: &T) { - parent.display_object().add_child(self); - } - - /// Removes the current parent binding. - pub fn _unset_parent(&self) { - self.take_parent_bind(); - } - - /// Checks if the provided object is child of the current one. - pub fn has_child>(&self, child: &T) -> bool { - self.child_index(child).is_some() - } - - /// Checks if the object has a parent. - pub fn _has_parent(&self) -> bool { - self.rc.parent_bind.borrow().is_some() - } - - /// Returns the index of the provided object if it was a child of the current one. - pub fn child_index>(&self, child: &T) -> Option { - let child = child.display_object(); - child.parent_bind.borrow().as_ref().and_then(|bind| { - if bind.parent().as_ref() == Some(self) { - Some(bind.index) - } else { - None - } - }) - } -} - - -// === Private API === - -impl Instance { - fn parent_index(&self) -> Option { - self.parent_bind.borrow().as_ref().map(|t| t.index) - } - - fn has_visible_parent(&self) -> bool { - let parent = self.parent_bind.borrow().as_ref().and_then(|b| b.parent.upgrade()); - parent.map_or(false, |parent| parent.is_visible()) - } -} - - -// === Instances === - -impl PartialEq for Instance { - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.rc, &other.rc) - } -} - -impl Display for Instance { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Instance") - } -} - -impl Debug for Instance { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "DisplayObject") - } -} - // ==================== @@ -998,14 +1030,14 @@ impl Debug for Instance { #[derive(Derivative)] #[derivative(Clone(bound = ""))] #[derivative(Debug(bound = ""))] -pub struct WeakInstance { - weak: Weak>, +pub struct WeakInstance { + weak: Weak, } -impl WeakInstance { +impl WeakInstance { /// Upgrade the weak instance to strong one if it was not yet dropped. - pub fn upgrade(&self) -> Option> { - self.weak.upgrade().map(|rc| Instance { rc }) + pub fn upgrade(&self) -> Option { + self.weak.upgrade().map(|rc| InstanceDef { rc }.into()) } /// Checks whether this weak instance still exists (its strong instance was not dropped yet). @@ -1014,7 +1046,15 @@ impl WeakInstance { } } -impl PartialEq for WeakInstance { +impl InstanceDef { + /// Create a new weak pointer to this display object instance. + pub fn downgrade(&self) -> WeakInstance { + let weak = Rc::downgrade(&self.rc); + WeakInstance { weak } + } +} + +impl PartialEq for WeakInstance { fn eq(&self, other: &Self) -> bool { if self.exists() && other.exists() { self.weak.ptr_eq(&other.weak) @@ -1026,6 +1066,55 @@ impl PartialEq for WeakInstance { +// ============ +// === Root === +// ============ + +/// A root element of a display object hierarchy. Unlike [`Instance`], [`Root`] is visible by +/// default and has explicit methods to hide and show it. +#[derive(Clone, CloneRef, Debug, Deref)] +#[repr(transparent)] +pub struct Root { + def: Instance, +} + +impl Root { + /// Constructor. + pub fn new() -> Self { + let def = default(); + Self { def }.init() + } + + fn init(self) -> Self { + self.show(); + self + } + + /// Hide the display object. + pub fn hide(&self) { + self.def.hide() + } + + /// Show the display object. + pub fn show(&self) { + self.def.show() + } +} + +impl Default for Root { + fn default() -> Self { + Self::new() + } +} + +impl Object for Root { + fn display_object(&self) -> &Instance { + &self.def + } +} + + + // ============== // === Object === // ============== @@ -1035,27 +1124,27 @@ impl PartialEq for WeakInstance { /// implements it, automatically implements the `display::object::ObjectOps`, and thus gets a lot /// of methods implemented automatically. #[allow(missing_docs)] -pub trait Object { - fn display_object(&self) -> &Instance; - fn weak_display_object(&self) -> WeakInstance { +pub trait Object { + fn display_object(&self) -> &Instance; + fn weak_display_object(&self) -> WeakInstance { self.display_object().downgrade() } /// See `Any` description. - fn into_any(self) -> Any + fn into_any(self) -> Any where Self: Sized + 'static { Any { wrapped: Rc::new(self) } } } -impl Object for Instance { - fn display_object(&self) -> &Instance { +impl Object for Instance { + fn display_object(&self) -> &Instance { self } } -impl> Object for &T { - fn display_object(&self) -> &Instance { +impl Object for &T { + fn display_object(&self) -> &Instance { let t: &T = self; t.display_object() } @@ -1063,384 +1152,6 @@ impl> Object for &T { -// ================= -// === ObjectOps === -// ================= - -impl + ?Sized> ObjectOps for T {} - -/// Implementation of operations available for every struct which implements `display::Object`. -/// To learn more about the design, please refer to the documentation of [`Instance`]. -// -// HOTFIX[WD]: We are using names with underscores in order to fix this bug: -// https://github.com/rust-lang/rust/issues/70727 . To be removed as soon as the bug is fixed. -#[allow(missing_docs)] -pub trait ObjectOps: Object { - // === Information === - - /// Globally unique identifier of this display object. - fn id(&self) -> Id { - self.display_object()._id() - } - - - // === Hierarchy === - - /// Get the layers where this object is displayed. May be equal to layers it was explicitly - /// assigned, or layers inherited from the parent. - fn display_layer(&self) -> Option { - self.display_object()._display_layers() - } - - /// Add another display object as a child to this display object. Children will inherit all - /// transformations of their parents. - fn add_child + ?Sized>(&self, child: &T) { - self.display_object()._add_child(child.display_object()); - } - - /// Remove the display object from the children list of this display object. Does nothing if - /// the child was not registered. - fn remove_child>(&self, child: &T) { - self.display_object()._remove_child(child.display_object()); - } - - /// Removes this display object from its parent's children list. - fn unset_parent(&self) { - self.display_object()._unset_parent(); - } - - /// Check whether this display object is attached to a parent. - fn has_parent(&self) -> bool { - self.display_object()._has_parent() - } - - /// Checks whether the object is visible. - fn is_visible(&self) -> bool { - self.display_object().rc.is_visible() - } - - /// Checks whether the object is orphan (do not have parent object attached). - fn is_orphan(&self) -> bool { - self.display_object().rc.is_orphan() - } - - - // === Events === - - /// Emit a new event. See docs of [`event::Event`] to learn more. - fn emit_event(&self, event: T) - where T: 'static { - self.display_object()._emit_event(event) - } - - /// Get event stream for bubbling events. See docs of [`event::Event`] to learn more. - fn on_event(&self) -> frp::Stream> - where T: frp::Data { - self.display_object().rc.on_event() - } - - /// Get event stream for capturing events. You should rather not need this function. Use - /// [`on_event`] instead. See docs of [`event::Event`] to learn more. - fn on_event_capturing(&self) -> frp::Stream> - where T: frp::Data { - self.display_object().rc.on_event_capturing() - } - - /// Creates a new event with this object set to target. - fn new_event(&self, payload: T) -> event::SomeEvent { - self.display_object()._new_event(payload) - } - - - // === Focus === - - /// Check whether this object is focused. - fn is_focused(&self) -> bool { - self.display_object()._is_focused() - } - - /// Focus this object. See docs of [`Event::Focus`] to learn more. - fn focus(&self) { - self.display_object()._focus() - } - - /// Blur ("unfocus") this object. See docs of [`Event::Blur`] to learn more. - fn blur(&self) { - self.display_object()._blur() - } - - /// Blur the display object tree this object belongs to. If any tree node (any node directly or - /// indirectly connected with each other) was focused, it will be blurred. - fn blur_tree(&self) { - self.display_object()._blur_tree() - } - - /// Get the currently focused object if any. See docs of [`Event::Focus`] to learn more. - fn focused_instance(&self) -> Option> { - self.display_object()._focused_instance() - } - - - // === Transform === - - fn transform_matrix(&self) -> Matrix4 { - self.display_object().rc.matrix() - } - - fn global_position(&self) -> Vector3 { - self.display_object().rc.global_position() - } - - - // === Position === - - fn position(&self) -> Vector3 { - self.display_object().rc.position() - } - - fn x(&self) -> f32 { - self.position().x - } - - fn y(&self) -> f32 { - self.position().y - } - - fn z(&self) -> f32 { - self.position().z - } - - fn xy(&self) -> Vector2 { - let position = self.position(); - Vector2(position.x, position.y) - } - - fn xz(&self) -> Vector2 { - let position = self.position(); - Vector2(position.x, position.z) - } - - fn yz(&self) -> Vector2 { - let position = self.position(); - Vector2(position.y, position.z) - } - - fn xyz(&self) -> Vector3 { - self.position() - } - - fn mod_position)>(&self, f: F) { - self.display_object().rc.mod_position(f) - } - - fn mod_position_xy) -> Vector2>(&self, f: F) { - self.set_position_xy(f(self.position().xy())); - } - - fn mod_position_xz) -> Vector2>(&self, f: F) { - self.set_position_xz(f(self.position().xz())); - } - - fn mod_position_yz) -> Vector2>(&self, f: F) { - self.set_position_yz(f(self.position().yz())); - } - - fn mod_position_x f32>(&self, f: F) { - self.set_position_x(f(self.position().x)); - } - - fn mod_position_y f32>(&self, f: F) { - self.set_position_y(f(self.position().y)); - } - - fn mod_position_z f32>(&self, f: F) { - self.set_position_z(f(self.position().z)); - } - - fn set_position(&self, t: Vector3) { - self.display_object().rc.set_position(t); - } - - fn set_position_xy(&self, t: Vector2) { - self.mod_position(|p| { - p.x = t.x; - p.y = t.y; - }) - } - - fn set_position_xz(&self, t: Vector2) { - self.mod_position(|p| { - p.x = t.x; - p.z = t.y; - }) - } - - fn set_position_yz(&self, t: Vector2) { - self.mod_position(|p| { - p.y = t.x; - p.z = t.y; - }) - } - - fn set_position_x(&self, t: f32) { - self.mod_position(|p| p.x = t) - } - - fn set_position_y(&self, t: f32) { - self.mod_position(|p| p.y = t) - } - - fn set_position_z(&self, t: f32) { - self.mod_position(|p| p.z = t) - } - - - // === Scale === - - fn scale(&self) -> Vector3 { - self.display_object().rc.scale() - } - - fn mod_scale)>(&self, f: F) { - self.display_object().rc.mod_scale(f) - } - - fn mod_scale_xy) -> Vector2>(&self, f: F) { - self.set_scale_xy(f(self.scale().xy())); - } - - fn mod_scale_xz) -> Vector2>(&self, f: F) { - self.set_scale_xz(f(self.scale().xz())); - } - - fn mod_scale_yz) -> Vector2>(&self, f: F) { - self.set_scale_yz(f(self.scale().yz())); - } - - fn mod_scale_x f32>(&self, f: F) { - self.set_scale_x(f(self.scale().x)); - } - - fn mod_scale_y f32>(&self, f: F) { - self.set_scale_y(f(self.scale().y)); - } - - fn mod_scale_z f32>(&self, f: F) { - self.set_scale_z(f(self.scale().z)); - } - - fn set_scale(&self, t: Vector3) { - self.display_object().rc.set_scale(t); - } - - fn set_scale_xy(&self, t: Vector2) { - self.mod_scale(|p| { - p.x = t.x; - p.y = t.y; - }) - } - - fn set_scale_xz(&self, t: Vector2) { - self.mod_scale(|p| { - p.x = t.x; - p.z = t.y; - }) - } - - fn set_scale_yz(&self, t: Vector2) { - self.mod_scale(|p| { - p.y = t.x; - p.z = t.y; - }) - } - - fn set_scale_x(&self, t: f32) { - self.mod_scale(|p| p.x = t) - } - - fn set_scale_y(&self, t: f32) { - self.mod_scale(|p| p.y = t) - } - - fn set_scale_z(&self, t: f32) { - self.mod_scale(|p| p.z = t) - } - - - // === Rotation === - - fn rotation(&self) -> Vector3 { - self.display_object().rc.rotation() - } - - fn mod_rotation)>(&self, f: F) { - self.display_object().rc.mod_rotation(f) - } - - fn mod_rotation_xy) -> Vector2>(&self, f: F) { - self.set_rotation_xy(f(self.rotation().xy())); - } - - fn mod_rotation_xz) -> Vector2>(&self, f: F) { - self.set_rotation_xz(f(self.rotation().xz())); - } - - fn mod_rotation_yz) -> Vector2>(&self, f: F) { - self.set_rotation_yz(f(self.rotation().yz())); - } - - fn mod_rotation_x f32>(&self, f: F) { - self.set_rotation_x(f(self.rotation().x)); - } - - fn mod_rotation_y f32>(&self, f: F) { - self.set_rotation_y(f(self.rotation().y)); - } - - fn mod_rotation_z f32>(&self, f: F) { - self.set_rotation_z(f(self.rotation().z)); - } - - fn set_rotation(&self, t: Vector3) { - self.display_object().rc.set_rotation(t); - } - - fn set_rotation_xy(&self, t: Vector2) { - self.mod_rotation(|p| { - p.x = t.x; - p.y = t.y; - }) - } - - fn set_rotation_xz(&self, t: Vector2) { - self.mod_rotation(|p| { - p.x = t.x; - p.z = t.y; - }) - } - - fn set_rotation_yz(&self, t: Vector2) { - self.mod_rotation(|p| { - p.y = t.x; - p.z = t.y; - }) - } - - fn set_rotation_x(&self, t: f32) { - self.mod_rotation(|p| p.x = t) - } - - fn set_rotation_y(&self, t: f32) { - self.mod_rotation(|p| p.y = t) - } - - fn set_rotation_z(&self, t: f32) { - self.mod_rotation(|p| p.z = t) - } -} - - - // ================== // === Any Object === // ================== @@ -1451,24 +1162,24 @@ pub trait ObjectOps: Object { /// to make general `From` implementation, because `Any` itself would use it as well, and it clashes /// with base implementation `From for T`. #[derive(CloneRef)] -pub struct Any { - wrapped: Rc>, +pub struct Any { + wrapped: Rc, } -impl Clone for Any { +impl Clone for Any { fn clone(&self) -> Self { Self { wrapped: self.wrapped.clone() } } } -impl Debug for Any { +impl Debug for Any { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "display::object::Any") } } -impl Object for Any { - fn display_object(&self) -> &Instance { +impl Object for Any { + fn display_object(&self) -> &Instance { self.wrapped.display_object() } } @@ -1502,6 +1213,193 @@ impl Drop for UnsetParentOnDrop { +// ================= +// === ObjectOps === +// ================= + +/// Generates getters and setters for display object transformations, such as `x()`, `xy()`, +/// `set_x()`, `rotation_z()`, `set_scale_x()`, etc. +macro_rules! gen_object_trans { + ($trans:ident $(,$tx_name:ident)?) => { + paste! { + fn $trans(&self) -> Vector3 { + self.display_object().def.$trans() + } + + fn [])>(&self, f: F) { + self.display_object().def.[](f) + } + + fn [](&self, t: Vector3) { + self.display_object().def.[](t); + } + } + enso_types::with_swizzling_for_dim!(1, gen_getters, $trans $(,$tx_name)?); + enso_types::with_swizzling_for_dim!(2, gen_getters, $trans $(,$tx_name)?); + enso_types::with_swizzling_for_dim!(3, gen_getters, $trans $(,$tx_name)?); + + enso_types::with_swizzling_for_dim_unique!(1, gen_setters, $trans $(,$tx_name)?); + enso_types::with_swizzling_for_dim_unique!(2, gen_setters, $trans $(,$tx_name)?); + enso_types::with_swizzling_for_dim_unique!(3, gen_setters, $trans $(,$tx_name)?); + }; +} + +macro_rules! gen_getters { + ([$tx:tt] $_dim:tt $( $name:ident $dim:tt $_dim_ix:tt $_dim_ord:tt )*) => { + gen_getters! {@ $tx $( $name $name $dim )* } + }; + ([$tx:tt, $tx_name:tt] $_dim:tt $( $name:ident $dim:tt $_dim_ix:tt $_dim_ord:tt )*) => { + gen_getters! {@ $tx $( [<$tx_name _ $name>] $name $dim )* } + }; + (@ $tx:tt $( $fn_name:tt $name:tt $dim:tt )*) => { paste! { + $( fn $fn_name(&self) -> [] { self.$tx().$name() } )* + }}; +} + +macro_rules! gen_setters { + ([$tx:tt] $_dim:tt $( $name:ident $dim:tt $_dim_ix:tt $_dim_ord:tt )*) => { + gen_setters! {@ $tx $( [] [] $name $dim )* } + }; + ([$tx:tt, $tx_name:tt] $_dim:tt $( $name:ident $dim:tt $_dim_ix:tt $_dim_ord:tt )*) => { + gen_setters! {@ $tx $( [] [] $name $dim )* } + }; + (@ $tx:tt $( $set_name:tt $mod_name:tt $name:tt $dim:tt )*) => { paste! { + $( + fn $set_name(&self, value: []) { + self.[](|p| p.[](value)); + } + + fn $mod_name(&self, f: F) + where F: FnOnce([]) -> [] { + self.[](f(self.$name())); + } + )* + }}; +} + +impl ObjectOps for T {} + +/// Implementation of operations available for every struct which implements `display::Object`. +/// To learn more about the design, please refer to the documentation of [`Instance`]. +#[allow(missing_docs)] +pub trait ObjectOps: Object { + // === Transformations === + + gen_object_trans!(position); + gen_object_trans!(rotation, rotation); + gen_object_trans!(scale, scale); + + fn transformation_matrix(&self) -> Matrix4 { + self.display_object().def.transformation_matrix() + } + + fn global_position(&self) -> Vector3 { + self.display_object().def.global_position() + } + + + // === Information === + + /// Globally unique identifier of this display object. + fn id(&self) -> Id { + self.display_object().def.id() + } + + + // === Hierarchy === + + /// Get the layer this object is displayed in. May be equal to layer explicitly set by the user + /// or a layer inherited from the parent. + fn display_layer(&self) -> Option { + self.display_object().def.display_layer() + } + + /// Add another display object as a child to this display object. Children will inherit all + /// transformations of their parents. + fn add_child(&self, child: &T) { + self.display_object().def.add_child(child.display_object()); + } + + /// Remove the display object from the children list of this display object. Does nothing if + /// the child was not registered. + fn remove_child(&self, child: &T) { + self.display_object().def.remove_child(child.display_object()); + } + + /// Removes this display object from its parent's children list. + fn unset_parent(&self) { + self.display_object().def.unset_parent(); + } + + /// Check whether this display object is attached to a parent. + fn has_parent(&self) -> bool { + self.display_object().def.has_parent() + } + + /// Checks whether the object is visible. + fn is_visible(&self) -> bool { + self.display_object().def.is_visible() + } + + + // === EventModel === + + /// Emit a new event. See docs of [`event::Event`] to learn more. + fn emit_event(&self, event: T) + where T: 'static { + self.display_object().def.emit_event(event) + } + + /// Get event stream for bubbling events. See docs of [`event::Event`] to learn more. + fn on_event(&self) -> frp::Stream> + where T: frp::Data { + self.display_object().def.on_event() + } + + /// Get event stream for capturing events. You should rather not need this function. Use + /// [`on_event`] instead. See docs of [`event::Event`] to learn more. + fn on_event_capturing(&self) -> frp::Stream> + where T: frp::Data { + self.display_object().def.on_event_capturing() + } + + /// Creates a new event with this object set to target. + fn new_event(&self, payload: T) -> event::SomeEvent { + self.display_object().def.new_event(payload) + } + + + // === Focus === + + /// Check whether this object is focused. + fn is_focused(&self) -> bool { + self.display_object().def.is_focused() + } + + /// Focus this object. See docs of [`Event::Focus`] to learn more. + fn focus(&self) { + self.display_object().def.focus() + } + + /// Blur ("unfocus") this object. See docs of [`Event::Blur`] to learn more. + fn blur(&self) { + self.display_object().def.blur() + } + + /// Blur the display object tree this object belongs to. If any tree node (any node directly or + /// indirectly connected with each other) was focused, it will be blurred. + fn blur_tree(&self) { + self.display_object().def.blur_tree() + } + + /// Get the currently focused object if any. See docs of [`Event::Focus`] to learn more. + fn focused_instance(&self) -> Option { + InstanceDef::focused_instance(self.display_object()) + } +} + + + // ============= // === Tests === // ============= @@ -1509,31 +1407,35 @@ impl Drop for UnsetParentOnDrop { #[cfg(test)] mod tests { use super::*; + use crate::display::world::World; use std::f32::consts::PI; #[test] fn hierarchy_test() { - let node1 = Instance::<()>::new(); - let node2 = Instance::<()>::new(); - let node3 = Instance::<()>::new(); + let node1 = Instance::new(); + let node2 = Instance::new(); + let node3 = Instance::new(); node1.add_child(&node2); - assert_eq!(node2.parent_index(), Some(0)); + assert_eq!(node2.my_index(), Some(ChildIndex(0))); node1.add_child(&node2); - assert_eq!(node2.parent_index(), Some(0)); + assert_eq!(node2.my_index(), Some(ChildIndex(0))); node1.add_child(&node3); - assert_eq!(node3.parent_index(), Some(1)); + assert_eq!(node3.my_index(), Some(ChildIndex(1))); node1.remove_child(&node3); - assert_eq!(node3.parent_index(), None); + assert_eq!(node3.my_index(), None); } #[test] fn transformation_test() { - let node1 = Instance::<()>::new(); - let node2 = Instance::<()>::new(); - let node3 = Instance::<()>::new(); + let world = World::new(); + let scene = &world.default_scene; + + let node1 = Instance::new(); + let node2 = Instance::new(); + let node3 = Instance::new(); assert_eq!(node1.position(), Vector3::new(0.0, 0.0, 0.0)); assert_eq!(node2.position(), Vector3::new(0.0, 0.0, 0.0)); assert_eq!(node3.position(), Vector3::new(0.0, 0.0, 0.0)); @@ -1551,7 +1453,7 @@ mod tests { assert_eq!(node2.global_position(), Vector3::new(0.0, 0.0, 0.0)); assert_eq!(node3.global_position(), Vector3::new(0.0, 0.0, 0.0)); - node1.update(&()); + node1.update(scene); assert_eq!(node1.position(), Vector3::new(7.0, 0.0, 0.0)); assert_eq!(node2.position(), Vector3::new(0.0, 0.0, 0.0)); assert_eq!(node3.position(), Vector3::new(0.0, 0.0, 0.0)); @@ -1560,47 +1462,47 @@ mod tests { assert_eq!(node3.global_position(), Vector3::new(7.0, 0.0, 0.0)); node2.mod_position(|t| t.y += 5.0); - node1.update(&()); + node1.update(scene); assert_eq!(node1.global_position(), Vector3::new(7.0, 0.0, 0.0)); assert_eq!(node2.global_position(), Vector3::new(7.0, 5.0, 0.0)); assert_eq!(node3.global_position(), Vector3::new(7.0, 5.0, 0.0)); node3.mod_position(|t| t.x += 1.0); - node1.update(&()); + node1.update(scene); assert_eq!(node1.global_position(), Vector3::new(7.0, 0.0, 0.0)); assert_eq!(node2.global_position(), Vector3::new(7.0, 5.0, 0.0)); assert_eq!(node3.global_position(), Vector3::new(8.0, 5.0, 0.0)); node2.mod_rotation(|t| t.z += PI / 2.0); - node1.update(&()); + node1.update(scene); assert_eq!(node1.global_position(), Vector3::new(7.0, 0.0, 0.0)); assert_eq!(node2.global_position(), Vector3::new(7.0, 5.0, 0.0)); assert_eq!(node3.global_position(), Vector3::new(7.0, 6.0, 0.0)); node1.add_child(&node3); - node1.update(&()); + node1.update(scene); assert_eq!(node3.global_position(), Vector3::new(8.0, 0.0, 0.0)); node1.remove_child(&node3); - node3.update(&()); + node3.update(scene); assert_eq!(node3.global_position(), Vector3::new(1.0, 0.0, 0.0)); node2.add_child(&node3); - node1.update(&()); + node1.update(scene); assert_eq!(node3.global_position(), Vector3::new(7.0, 6.0, 0.0)); node1.remove_child(&node3); - node1.update(&()); - node2.update(&()); - node3.update(&()); + node1.update(scene); + node2.update(scene); + node3.update(scene); assert_eq!(node3.global_position(), Vector3::new(7.0, 6.0, 0.0)); } #[test] fn parent_test() { - let node1 = Instance::<()>::new(); - let node2 = Instance::<()>::new(); - let node3 = Instance::<()>::new(); + let node1 = Instance::new(); + let node2 = Instance::new(); + let node3 = Instance::new(); node1.add_child(&node2); node1.add_child(&node3); node2.unset_parent(); @@ -1609,33 +1511,30 @@ mod tests { } /// A utility to test display object instances' visibility. - #[derive(Clone, CloneRef, Debug)] + #[derive(Clone, CloneRef, Debug, Deref)] struct TestedNode { - node: Instance<()>, + #[deref] + node: Instance, show_counter: Rc>, hide_counter: Rc>, } - impl Deref for TestedNode { - type Target = Instance<()>; - fn deref(&self) -> &Self::Target { - &self.node - } - } - - impl Object<()> for TestedNode { - fn display_object(&self) -> &Instance<()> { + impl Object for TestedNode { + fn display_object(&self) -> &Instance { &self.node } } impl TestedNode { fn new() -> Self { - let node = Instance::<()>::new(); + let node = Instance::new(); let show_counter = Rc::>::default(); let hide_counter = Rc::>::default(); - node.set_on_show(f__!(show_counter.set(show_counter.get() + 1))); - node.set_on_hide(f_!(hide_counter.set(hide_counter.get() + 1))); + let network = &node.network; + frp::extend! { network + eval_ node.on_show(show_counter.set(show_counter.get() + 1)); + eval_ node.on_hide(hide_counter.set(hide_counter.get() + 1)); + } Self { node, show_counter, hide_counter } } @@ -1674,102 +1573,114 @@ mod tests { #[test] fn visibility_test() { + let world = World::new(); + let scene = &world.default_scene; + let node1 = TestedNode::new(); let node2 = TestedNode::new(); let node3 = TestedNode::new(); - node1.force_set_visibility(true); + node1.show(); node3.check_if_still_hidden(); - node3.update(&()); + node3.update(scene); node3.check_if_still_hidden(); node1.add_child(&node2); node2.add_child(&node3); - node1.update(&()); + node1.update(scene); node3.check_if_was_shown(); node3.unset_parent(); node3.check_if_still_shown(); - node1.update(&()); + node1.update(scene); node3.check_if_was_hidden(); node1.add_child(&node3); - node1.update(&()); + node1.update(scene); node3.check_if_was_shown(); node2.add_child(&node3); - node1.update(&()); + node1.update(scene); node3.check_if_still_shown(); node3.unset_parent(); - node1.update(&()); + node1.update(scene); node3.check_if_was_hidden(); node2.add_child(&node3); - node1.update(&()); + node1.update(scene); node3.check_if_was_shown(); } #[test] fn visibility_test2() { + let world = World::new(); + let scene = &world.default_scene; + let node1 = TestedNode::new(); let node2 = TestedNode::new(); node1.check_if_still_hidden(); - node1.update(&()); + node1.update(scene); node1.check_if_still_hidden(); - node1.force_set_visibility(true); - node1.update(&()); - node1.check_if_still_shown(); + node1.show(); + node1.update(scene); + node1.check_if_was_shown(); node1.add_child(&node2); - node1.update(&()); + node1.update(scene); node1.check_if_still_shown(); node2.check_if_was_shown(); } #[test] fn visibility_test3() { + let world = World::new(); + let scene = &world.default_scene; + let node1 = TestedNode::new(); let node2 = TestedNode::new(); let node3 = TestedNode::new(); - node1.force_set_visibility(true); + node1.show(); node1.add_child(&node2); node2.add_child(&node3); - node1.update(&()); + node1.update(scene); node2.check_if_was_shown(); node3.check_if_was_shown(); node3.unset_parent(); node3.add_child(&node2); - node1.update(&()); + node1.update(scene); node2.check_if_was_hidden(); node3.check_if_was_hidden(); } #[test] fn visibility_test4() { + let world = World::new(); + let scene = &world.default_scene; + let node1 = TestedNode::new(); let node2 = TestedNode::new(); let node3 = TestedNode::new(); let node4 = TestedNode::new(); - node1.force_set_visibility(true); + node1.show(); node1.add_child(&node2); node2.add_child(&node3); - node1.update(&()); + node1.update(scene); node2.check_if_was_shown(); node3.check_if_was_shown(); node4.check_if_still_hidden(); node2.unset_parent(); node1.add_child(&node2); - node1.update(&()); + node1.update(scene); node2.check_if_still_shown(); node3.check_if_still_shown(); node4.check_if_still_hidden(); node1.add_child(&node4); node4.add_child(&node3); - node1.update(&()); + node1.update(scene); node2.check_if_still_shown(); // TODO[ao]: This assertion fails, see https://github.com/enso-org/ide/issues/1405 // node3.check_if_still_shown(); @@ -1778,13 +1689,13 @@ mod tests { node4.unset_parent(); node2.unset_parent(); - node1.update(&()); + node1.update(scene); node2.check_if_was_hidden(); node3.check_if_was_hidden(); node4.check_if_was_hidden(); node2.add_child(&node3); - node1.update(&()); + node1.update(scene); node2.check_if_still_hidden(); node3.check_if_still_hidden(); node4.check_if_still_hidden(); @@ -1794,18 +1705,20 @@ mod tests { #[test] fn deep_hierarchy_test() { // === Init === + let world = World::new(); + let scene = &world.default_scene; - let world = Instance::<()>::new(); - let node1 = Instance::<()>::new(); - let node2 = Instance::<()>::new(); - let node3 = Instance::<()>::new(); - let node4 = Instance::<()>::new(); - let node5 = Instance::<()>::new(); - let node6 = Instance::<()>::new(); + let root = Instance::new(); + let node1 = Instance::new(); + let node2 = Instance::new(); + let node3 = Instance::new(); + let node4 = Instance::new(); + let node5 = Instance::new(); + let node6 = Instance::new(); - world.force_set_visibility(true); + root.show(); - world.add_child(&node1); + root.add_child(&node1); node1.add_child(&node2); node2.add_child(&node3); node3.add_child(&node4); @@ -1820,7 +1733,7 @@ mod tests { // === Init Update === - world.update(&()); + root.update(scene); assert!(node3.is_visible()); assert!(node4.is_visible()); @@ -1842,7 +1755,7 @@ mod tests { node5.mod_position(|t| t.x += 5.0); node6.mod_position(|t| t.x += 7.0); - world.update(&()); + root.update(scene); assert_eq!(node1.global_position(), Vector3::new(0.0, 0.0, 0.0)); assert_eq!(node2.global_position(), Vector3::new(0.0, 0.0, 0.0)); @@ -1856,7 +1769,7 @@ mod tests { node4.unset_parent(); node3.unset_parent(); - world.update(&()); + root.update(scene); assert!(!node3.is_visible()); assert!(!node4.is_visible()); @@ -1866,29 +1779,32 @@ mod tests { #[test] fn layers_test() { + let world = World::new(); + let scene = &world.default_scene; + let layer1 = Layer::new("0"); let layer2 = Layer::new("1"); - let node1 = Instance::<()>::new(); - let node2 = Instance::<()>::new(); - let node3 = Instance::<()>::new(); + let node1 = Instance::new(); + let node2 = Instance::new(); + let node3 = Instance::new(); node1.add_child(&node2); node1.add_child(&node3); - node1.update(&()); + node1.update(scene); assert_eq!(node1.display_layer(), None); assert_eq!(node2.display_layer(), None); assert_eq!(node3.display_layer(), None); node1.add_to_display_layer(&layer1); - node1.update(&()); - assert_eq!(node1.display_layer(), Some(layer1.downgrade())); - assert_eq!(node2.display_layer(), Some(layer1.downgrade())); - assert_eq!(node3.display_layer(), Some(layer1.downgrade())); + node1.update(scene); + assert_eq!(node1.display_layer().as_ref(), Some(&layer1)); + assert_eq!(node2.display_layer().as_ref(), Some(&layer1)); + assert_eq!(node3.display_layer().as_ref(), Some(&layer1)); node2.add_to_display_layer(&layer2); - node1.update(&()); - assert_eq!(node1.display_layer(), Some(layer1.downgrade())); - assert_eq!(node2.display_layer(), Some(layer2.downgrade())); - assert_eq!(node3.display_layer(), Some(layer1.downgrade())); + node1.update(scene); + assert_eq!(node1.display_layer().as_ref(), Some(&layer1)); + assert_eq!(node2.display_layer().as_ref(), Some(&layer2)); + assert_eq!(node3.display_layer().as_ref(), Some(&layer1)); } #[test] @@ -1898,17 +1814,17 @@ mod tests { // obj_left_1 obj_right_1 // | | // obj_left_2 obj_right_2 - let obj_root = Instance::<()>::new(); - let obj_left_1 = Instance::<()>::new(); - let obj_left_2 = Instance::<()>::new(); - let obj_right_1 = Instance::<()>::new(); - let obj_right_2 = Instance::<()>::new(); + let obj_root = Instance::new(); + let obj_left_1 = Instance::new(); + let obj_left_2 = Instance::new(); + let obj_right_1 = Instance::new(); + let obj_right_2 = Instance::new(); obj_root.add_child(&obj_left_1); obj_root.add_child(&obj_right_1); obj_left_1.add_child(&obj_left_2); obj_right_1.add_child(&obj_right_2); - let check_focus_consistency = |focused: Option<&Instance<()>>| { + let check_focus_consistency = |focused: Option<&Instance>| { // Check that at most one object is focused and if so, that it is the correct one. assert_eq!(obj_root.is_focused(), focused == Some(&obj_root)); assert_eq!(obj_left_1.is_focused(), focused == Some(&obj_left_1)); @@ -2020,9 +1936,9 @@ mod tests { #[test] fn focus_event_propagation_test() { - let obj_1 = Instance::<()>::new(); - let obj_2 = Instance::<()>::new(); - let obj_3 = Instance::<()>::new(); + let obj_1 = Instance::new(); + let obj_2 = Instance::new(); + let obj_3 = Instance::new(); obj_1.add_child(&obj_2); obj_2.add_child(&obj_3); @@ -2097,7 +2013,7 @@ mod tests { } let event = obj_3.new_event::(0.0); - obj_3.event_source.emit(&event); + obj_3.event.source.emit(&event); assert_eq!(&*out.borrow(), &[ "capturing_1", "capturing_2", diff --git a/lib/rust/ensogl/core/src/display/object/transform.rs b/lib/rust/ensogl/core/src/display/object/transformation.rs similarity index 81% rename from lib/rust/ensogl/core/src/display/object/transform.rs rename to lib/rust/ensogl/core/src/display/object/transformation.rs index d277321a1df..522af897593 100644 --- a/lib/rust/ensogl/core/src/display/object/transform.rs +++ b/lib/rust/ensogl/core/src/display/object/transformation.rs @@ -11,8 +11,9 @@ use crate::prelude::*; /// Defines the order in which particular axis coordinates are processed. Used for example to define /// the rotation order in `DisplayObject`. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub enum AxisOrder { + #[default] XYZ, XZY, YXZ, @@ -21,22 +22,17 @@ pub enum AxisOrder { ZYX, } -impl Default for AxisOrder { - fn default() -> Self { - Self::XYZ - } -} - -// ====================== -// === TransformOrder === -// ====================== +// =========================== +// === TransformationOrder === +// =========================== /// Defines the order in which transformations (scale, rotate, translate) are applied to a /// particular object. -#[derive(Clone, Copy, Debug)] -pub enum TransformOrder { +#[derive(Clone, Copy, Debug, Default)] +pub enum TransformationOrder { + #[default] ScaleRotateTranslate, ScaleTranslateRotate, RotateScaleTranslate, @@ -45,32 +41,26 @@ pub enum TransformOrder { TranslateScaleRotate, } -impl Default for TransformOrder { - fn default() -> Self { - Self::ScaleRotateTranslate - } -} - -// ================= -// === Transform === -// ================= +// ====================== +// === Transformation === +// ====================== /// Structure describing transform of an object, in particular its position, scale, and rotation. /// You can use methods like `matrix` to get a combined transformation matrix. Bear in mind that /// the matrix will always be recomputed from scratch. This structure does not contain any caching /// mechanisms. #[derive(Clone, Copy, Debug)] -pub struct Transform { +pub struct Transformation { pub position: Vector3, pub scale: Vector3, pub rotation: Vector3, - pub transform_order: TransformOrder, + pub transform_order: TransformationOrder, pub rotation_order: AxisOrder, } -impl Default for Transform { +impl Default for Transformation { fn default() -> Self { let position = Vector3::new(0.0, 0.0, 0.0); let scale = Vector3::new(1.0, 1.0, 1.0); @@ -81,7 +71,7 @@ impl Default for Transform { } } -impl Transform { +impl Transformation { /// Creates a new transformation object. pub fn new() -> Self { default() @@ -93,32 +83,32 @@ impl Transform { let mut matrix = Matrix4::identity(); let matrix_ref = &mut matrix; match self.transform_order { - TransformOrder::ScaleRotateTranslate => { + TransformationOrder::ScaleRotateTranslate => { self.append_scale(matrix_ref); self.append_rotation(matrix_ref); self.append_translation(matrix_ref); } - TransformOrder::ScaleTranslateRotate => { + TransformationOrder::ScaleTranslateRotate => { self.append_scale(matrix_ref); self.append_translation(matrix_ref); self.append_rotation(matrix_ref); } - TransformOrder::RotateScaleTranslate => { + TransformationOrder::RotateScaleTranslate => { self.append_rotation(matrix_ref); self.append_scale(matrix_ref); self.append_translation(matrix_ref); } - TransformOrder::RotateTranslateScale => { + TransformationOrder::RotateTranslateScale => { self.append_rotation(matrix_ref); self.append_translation(matrix_ref); self.append_scale(matrix_ref); } - TransformOrder::TranslateRotateScale => { + TransformationOrder::TranslateRotateScale => { self.append_translation(matrix_ref); self.append_rotation(matrix_ref); self.append_scale(matrix_ref); } - TransformOrder::TranslateScaleRotate => { + TransformationOrder::TranslateScaleRotate => { self.append_translation(matrix_ref); self.append_scale(matrix_ref); self.append_rotation(matrix_ref); @@ -158,24 +148,24 @@ impl Transform { -// ======================= -// === CachedTransform === -// ======================= +// ============================ +// === CachedTransformation === +// ============================ -/// The same as `Transform` but with caching. It contains cached transformation matrix and dirty -/// flags which are set after fields are modified. You can use the `update` function to recompute -/// the matrix. +/// The same as `Transformation` but with caching. It contains cached transformation matrix and +/// dirty flags which are set after fields are modified. You can use the `update` function to +/// recompute the matrix. #[derive(Clone, Debug)] #[allow(missing_copy_implementations)] -pub struct CachedTransform { - transform: Transform, +pub struct CachedTransformation { + transform: Transformation, transform_matrix: Matrix4, origin: Matrix4, pub matrix: Matrix4, pub dirty: bool, } -impl Default for CachedTransform { +impl Default for CachedTransformation { fn default() -> Self { let transform = default(); let transform_matrix = Matrix4::identity(); @@ -186,16 +176,16 @@ impl Default for CachedTransform { } } -impl CachedTransform { +impl CachedTransformation { /// Constructor. pub fn new() -> Self { default() } - /// Update the transformation matrix and return information if the data was really updated. + /// Update the transformation matrix if it was out of date. Returns [`true`] if the update was + /// needed. pub fn update(&mut self, new_origin: Option>) -> bool { - let origin_changed = new_origin.is_some(); - let changed = self.dirty || origin_changed; + let changed = self.dirty || new_origin.is_some(); if changed { if self.dirty { self.transform_matrix = self.transform.matrix(); @@ -211,7 +201,7 @@ impl CachedTransform { // === Getters === -impl CachedTransform { +impl CachedTransformation { pub fn position(&self) -> Vector3 { self.transform.position } @@ -236,7 +226,7 @@ impl CachedTransform { // === Setters === -impl CachedTransform { +impl CachedTransformation { pub fn position_mut(&mut self) -> &mut Vector3 { self.dirty = true; &mut self.transform.position diff --git a/lib/rust/ensogl/core/src/display/scene.rs b/lib/rust/ensogl/core/src/display/scene.rs index 2cd5a891081..b6bd05e1336 100644 --- a/lib/rust/ensogl/core/src/display/scene.rs +++ b/lib/rust/ensogl/core/src/display/scene.rs @@ -15,6 +15,7 @@ use crate::display; use crate::display::camera::Camera2d; use crate::display::render; use crate::display::scene::dom::DomScene; +use crate::display::shape::primitive::glsl; use crate::display::style; use crate::display::style::data::DataMatch; use crate::display::symbol::registry::SymbolRegistry; @@ -122,6 +123,7 @@ pub struct Mouse { pub mouse_manager: MouseManager, pub last_position: Rc>>, pub position: Uniform>, + pub click_count: Uniform, pub hover_rgba: Uniform>, pub target: Rc>, pub handles: Rc<[callback::Handle; 4]>, @@ -135,47 +137,71 @@ impl Mouse { root: &web::dom::WithKnownShape, variables: &UniformScope, current_js_event: &CurrentJsEvent, + display_mode: &Rc>, ) -> Self { let scene_frp = scene_frp.clone_ref(); let target = PointerTargetId::default(); let last_position = Rc::new(Cell::new(Vector2::new(0, 0))); let position = variables.add_or_panic("mouse_position", Vector2(0, 0)); + let click_count = variables.add_or_panic("mouse_click_count", 0); let hover_rgba = variables.add_or_panic("mouse_hover_ids", Vector4(0, 0, 0, 0)); let target = Rc::new(Cell::new(target)); let mouse_manager = MouseManager::new_separated(&root.clone_ref().into(), &web::window); let frp = frp::io::Mouse::new(); let on_move = mouse_manager.on_move.add(current_js_event.make_event_handler( - f!([frp,scene_frp,position,last_position] (event:&mouse::OnMove) { - let shape = scene_frp.shape.value(); - let pixel_ratio = shape.pixel_ratio; - let screen_x = event.client_x(); - let screen_y = event.client_y(); + f!([frp, scene_frp, position, last_position, display_mode] (event: &mouse::OnMove) { + let shape = scene_frp.shape.value(); + let pixel_ratio = shape.pixel_ratio; + let screen_x = event.client_x(); + let screen_y = event.client_y(); - let new_pos = Vector2::new(screen_x,screen_y); - let pos_changed = new_pos != last_position.get(); - if pos_changed { - last_position.set(new_pos); - let new_canvas_position = new_pos.map(|v| (v as f32 * pixel_ratio) as i32); - position.set(new_canvas_position); - let position = Vector2(new_pos.x as f32,new_pos.y as f32) - shape.center(); + let new_pos = Vector2::new(screen_x,screen_y); + let pos_changed = new_pos != last_position.get(); + if pos_changed { + last_position.set(new_pos); + let new_canvas_position = new_pos.map(|v| (v as f32 * pixel_ratio) as i32); + position.set(new_canvas_position); + let position = Vector2(new_pos.x as f32,new_pos.y as f32) - shape.center(); + if display_mode.get().allow_mouse_events() { frp.position.emit(position); } } - ), + }), + )); + let on_down = mouse_manager.on_down.add(current_js_event.make_event_handler( + f!([frp, click_count, display_mode] (event:&mouse::OnDown) { + click_count.modify(|v| *v += 1); + if display_mode.get().allow_mouse_events() { + frp.down.emit(event.button()); + } + }), + )); + let on_up = mouse_manager.on_up.add(current_js_event.make_event_handler( + f!([frp, display_mode] (event:&mouse::OnUp) { + if display_mode.get().allow_mouse_events() { + frp.up.emit(event.button()) + } + }), + )); + let on_wheel = mouse_manager.on_wheel.add(current_js_event.make_event_handler( + f_!([frp, display_mode] { + if display_mode.get().allow_mouse_events() { + frp.wheel.emit(()) + } + }), )); - let on_down = mouse_manager.on_down.add( - current_js_event - .make_event_handler(f!((event:&mouse::OnDown) frp.down.emit(event.button()))), - ); - let on_up = mouse_manager.on_up.add( - current_js_event - .make_event_handler(f!((event:&mouse::OnUp) frp.up.emit(event.button()))), - ); - let on_wheel = mouse_manager - .on_wheel - .add(current_js_event.make_event_handler(f_!(frp.wheel.emit(())))); let handles = Rc::new([on_move, on_down, on_up, on_wheel]); - Self { mouse_manager, last_position, position, hover_rgba, target, handles, frp, scene_frp } + Self { + mouse_manager, + last_position, + position, + click_count, + hover_rgba, + target, + handles, + frp, + scene_frp, + } } /// Re-emits FRP mouse changed position event with the last mouse position value. @@ -688,7 +714,7 @@ pub struct UpdateStatus { #[derive(Clone, CloneRef, Debug)] pub struct SceneData { - pub display_object: display::object::Instance, + pub display_object: display::object::Root, pub dom: Dom, pub context: Rc>>, pub context_lost_handler: Rc>>, @@ -710,17 +736,22 @@ pub struct SceneData { pub frp: Frp, pub pointer_position_changed: Rc>, pub shader_compiler: shader::compiler::Controller, + display_mode: Rc>, extensions: Extensions, disable_context_menu: Rc, } impl SceneData { /// Create new instance with the provided on-dirty callback. - pub fn new(stats: &Stats, on_mut: OnMut) -> Self { + pub fn new( + stats: &Stats, + on_mut: OnMut, + display_mode: &Rc>, + ) -> Self { debug!("Initializing."); + let display_mode = display_mode.clone_ref(); let dom = Dom::new(); - let display_object = display::object::Instance::new(); - display_object.force_set_visibility(true); + let display_object = display::object::Root::new(); let variables = UniformScope::new(); let dirty = Dirty::new(on_mut); let symbols_dirty = &dirty.symbols; @@ -734,7 +765,7 @@ impl SceneData { let style_sheet = style::Sheet::new(); let current_js_event = CurrentJsEvent::new(); let frp = Frp::new(&dom.root.shape); - let mouse = Mouse::new(&frp, &dom.root, &variables, ¤t_js_event); + let mouse = Mouse::new(&frp, &dom.root, &variables, ¤t_js_event, &display_mode); let disable_context_menu = Rc::new(web::ignore_context_menu(&dom.root)); let keyboard = Keyboard::new(¤t_js_event); let network = &frp.network; @@ -759,6 +790,7 @@ impl SceneData { let shader_compiler = default(); Self { display_object, + display_mode, dom, context, context_lost_handler, @@ -927,10 +959,10 @@ impl SceneData { screen_pos: Vector2, ) -> Vector2 { let origin_world_space = Vector4(0.0, 0.0, 0.0, 1.0); - let layer = object.display_layer().and_then(|t| t.upgrade()); + let layer = object.display_layer(); let camera = layer.map_or(self.camera(), |l| l.camera()); let origin_clip_space = camera.view_projection_matrix() * origin_world_space; - let inv_object_matrix = object.transform_matrix().try_inverse().unwrap(); + let inv_object_matrix = object.transformation_matrix().try_inverse().unwrap(); let shape = camera.screen(); let clip_space_z = origin_clip_space.z; @@ -1017,8 +1049,12 @@ pub struct Scene { } impl Scene { - pub fn new(stats: &Stats, on_mut: OnMut) -> Self { - let no_mut_access = SceneData::new(stats, on_mut); + pub fn new( + stats: &Stats, + on_mut: OnMut, + display_mode: &Rc>, + ) -> Self { + let no_mut_access = SceneData::new(stats, on_mut, display_mode); let this = Self { no_mut_access }; this } diff --git a/lib/rust/ensogl/core/src/display/scene/dom.rs b/lib/rust/ensogl/core/src/display/scene/dom.rs index 9dbcd5333e9..d9cb5033aa2 100644 --- a/lib/rust/ensogl/core/src/display/scene/dom.rs +++ b/lib/rust/ensogl/core/src/display/scene/dom.rs @@ -210,14 +210,7 @@ impl DomScene { /// Creates a new instance of DomSymbol and adds it to parent. pub fn manage(&self, object: &DomSymbol) { let dom = object.dom(); - let data = &self.data; - if object.is_visible() { - self.view_projection_dom.append_or_warn(dom); - } - object.display_object().set_on_hide(f_!(dom.remove())); - object.display_object().set_on_show(f__!([data,dom] { - data.view_projection_dom.append_or_warn(&dom) - })); + self.view_projection_dom.append_or_warn(dom); } /// Update the objects to match the new camera's point of view. This function should be called @@ -227,7 +220,7 @@ impl DomScene { return; } - let trans_cam = camera.transform_matrix().try_inverse(); + let trans_cam = camera.transformation_matrix().try_inverse(); let trans_cam = trans_cam.expect("Camera's matrix is not invertible."); let trans_cam = trans_cam.map(eps); let trans_cam = inverse_y_translation(trans_cam); diff --git a/lib/rust/ensogl/core/src/display/scene/layer.rs b/lib/rust/ensogl/core/src/display/scene/layer.rs index 2787df728ab..8e015eab227 100644 --- a/lib/rust/ensogl/core/src/display/scene/layer.rs +++ b/lib/rust/ensogl/core/src/display/scene/layer.rs @@ -154,30 +154,11 @@ use std::any::TypeId; /// Please note that the current implementation does not allow for hierarchical masks (masks applied /// to already masked area or masks applied to masks). If you try using masks in hierarchical way, /// the nested masks will be skipped and a warning will be emitted to the console. -#[derive(Clone, CloneRef)] +#[derive(Clone, CloneRef, Deref)] pub struct Layer { model: Rc, } -impl Deref for Layer { - type Target = LayerModel; - fn deref(&self) -> &Self::Target { - &self.model - } -} - -impl AsRef for Layer { - fn as_ref(&self) -> &Layer { - self - } -} - -impl Debug for Layer { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&*self.model, f) - } -} - impl Layer { /// Constructor. pub fn new(name: impl Into) -> Self { @@ -207,7 +188,7 @@ impl Layer { /// Remove the display object from a layer it was assigned to, if any. pub fn remove(&self, object: impl display::Object) { - object.display_object().remove_from_scene_layer(self); + object.display_object().remove_from_display_layer(self); } /// Instantiate the provided [`ShapeProxy`]. @@ -258,12 +239,31 @@ impl Layer { } } +impl AsRef for Layer { + fn as_ref(&self) -> &Layer { + self + } +} + +impl Debug for Layer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&*self.model, f) + } +} + impl From<&Layer> for LayerId { fn from(t: &Layer) -> Self { t.id() } } +impl Eq for Layer {} +impl PartialEq for Layer { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.model, &other.model) + } +} + // ================= @@ -315,6 +315,7 @@ impl PartialEq for WeakLayer { } + // ================== // === LayerModel === // ================== diff --git a/lib/rust/ensogl/core/src/display/scene/pointer_target.rs b/lib/rust/ensogl/core/src/display/scene/pointer_target.rs index 0a1ffc84d15..b9d13bab946 100644 --- a/lib/rust/ensogl/core/src/display/scene/pointer_target.rs +++ b/lib/rust/ensogl/core/src/display/scene/pointer_target.rs @@ -3,21 +3,13 @@ use crate::prelude::*; use crate::control::io::mouse; +use crate::display::shape::primitive::glsl; use crate::display::symbol; use enso_frp as frp; -// ================= -// === Constants === -// ================= - -const ID_ENCODING_OVERFLOW_ERR: u32 = - include!("../shape/primitive/glsl/error_codes/id_encoding_overflow.txt"); - - - // ===================== // === PointerTarget === // ===================== @@ -175,7 +167,7 @@ impl PointerTargetId { Ok(Self::Symbol { id }) } _ => { - let err = if alpha == ID_ENCODING_OVERFLOW_ERR { + let err = if alpha == glsl::codes::ID_ENCODING_OVERFLOW_ERROR { DecodeError::Overflow } else { DecodeError::WrongAlpha(alpha) diff --git a/lib/rust/ensogl/core/src/display/shape/primitive.rs b/lib/rust/ensogl/core/src/display/shape/primitive.rs index fe555986154..551cba5ce28 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive.rs +++ b/lib/rust/ensogl/core/src/display/shape/primitive.rs @@ -6,6 +6,7 @@ // ============== pub mod def; +pub mod glsl; pub mod shader; pub mod style_watch; pub mod system; diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/def/primitive.rs b/lib/rust/ensogl/core/src/display/shape/primitive/def/primitive.rs index 0440a14bdb0..fa263552f72 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/def/primitive.rs +++ b/lib/rust/ensogl/core/src/display/shape/primitive/def/primitive.rs @@ -206,7 +206,7 @@ define_sdf_shapes! { } Line (width:f32) { - return bound_sdf(abs(position.y)-width, bounding_box(0.0,width)); + return bound_sdf(abs(position.y) - width/2.0, bounding_box(0.0,width)); } diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/def/var.rs b/lib/rust/ensogl/core/src/display/shape/primitive/def/var.rs index 9830c7b5684..1e05a0ac2ae 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/def/var.rs +++ b/lib/rust/ensogl/core/src/display/shape/primitive/def/var.rs @@ -8,6 +8,7 @@ use crate::data::color; use crate::display::shape::primitive::def::unit::PixelDistance; use crate::system::gpu::shader::glsl::Glsl; +use enso_types; use nalgebra::Scalar; @@ -192,123 +193,6 @@ where T: Max + Into } } -macro_rules! dim_impl { - ($trait:ident for $tp:ty { - type $dim_ty_name:ident = $dim_ty:ty; - args = [$($single_arg:ident),* $(,)?]; - $(swizzling = $multi_ty:ident [$($multi_arg:ident),* $(,)?];)* - }) => { - impl $trait for $tp { - type $dim_ty_name = $dim_ty; - $( - fn $single_arg(&self) -> Self::Dim1Type { - match self { - Self::Static(t) => Var::Static(t.$single_arg.clone()), - Self::Dynamic(t) => { - let code = format!("{}.{}", t, stringify!($single_arg)); - Var::Dynamic(code.into()) - } - } - } - )* - $($( - fn $multi_arg(&self) -> Self::$multi_ty { - match self { - Self::Static(t) => Var::Static(t.$multi_arg()), - Self::Dynamic(t) => { - let code = format!("{}.{}", t, stringify!($multi_arg)); - Var::Dynamic(code.into()) - } - } - } - )*)* - } - }; -} - -dim_impl! ( Dim1 for Var> { - type Dim1Type = Var; - args = [x]; -}); - -dim_impl! ( Dim2 for Var> { - type Dim2Type = Var>; - args = [y]; - swizzling = Dim2Type [xx, xy, yx, yy]; -}); - -dim_impl! ( Dim1 for Var> { - type Dim1Type = Var; - args = [x]; -}); - -dim_impl! ( Dim2 for Var> { - type Dim2Type = Var>; - args = [y]; - swizzling = Dim2Type [xx, xy, yx, yy]; -}); - -dim_impl! ( Dim3 for Var> { - type Dim3Type = Var>; - args = [z]; - swizzling = Dim2Type [zz, xz, zx, yz, zy]; - swizzling = Dim3Type [ - xxx, xxy, xxz, xyx, xyy, xyz, xzx, xzy, xzz, yxx, yxy, yxz, yyx, yyy, yyz, yzx, yzy, yzz, - zxx, zxy, zxz, zyx, zyy, zyz, zzx, zzy, zzz - ]; -}); - -dim_impl! ( Dim1 for Var> { - type Dim1Type = Var; - args = [x]; -}); - -dim_impl! ( Dim2 for Var> { - type Dim2Type = Var>; - args = [y]; - swizzling = Dim2Type [xx, xy, yx, yy]; -}); - -dim_impl! ( Dim3 for Var> { - type Dim3Type = Var>; - args = [z]; - swizzling = Dim2Type [zz, xz, zx, yz, zy]; - swizzling = Dim3Type [ - xxx, xxy, xxz, xyx, xyy, xyz, xzx, xzy, xzz, yxx, yxy, yxz, yyx, yyy, yyz, yzx, yzy, yzz, - zxx, zxy, zxz, zyx, zyy, zyz, zzx, zzy, zzz - ]; -}); - -dim_impl! ( Dim4 for Var> { - type Dim4Type = Var>; - args = [w]; - swizzling = Dim2Type [ww, xw, wx, yw, wy, zw, wz]; - swizzling = Dim3Type [ - xxw, xyw, xzw, yxw, yyw, yzw, zxw, zyw, zzw, xwx, xwy, xwz, ywx, ywy, ywz, zwx, zwy, zwz, - wxx, wxy, wxz, wyx, wyy, wyz, wzx, wzy, wzz - ]; - swizzling = Dim4Type [ - xxxx, xxxy, xxxz, xxxw, xxyx, xxyy, xxyz, xxyw, xxzx, xxzy, xxzz, xxzw, xxwx, xxwy, xxwz, - xxww, xyxx, xyxy, xyxz, xyxw, xyyx, xyyy, xyyz, xyyw, xyzx, xyzy, xyzz, xyzw, xywx, xywy, - xywz, xyww, xzxx, xzxy, xzxz, xzxw, xzyx, xzyy, xzyz, xzyw, xzzx, xzzy, xzzz, xzzw, xzwx, - xzwy, xzwz, xzww, xwxx, xwxy, xwxz, xwxw, xwyx, xwyy, xwyz, xwyw, xwzx, xwzy, xwzz, xwzw, - xwwx, xwwy, xwwz, xwww, yxxx, yxxy, yxxz, yxxw, yxyx, yxyy, yxyz, yxyw, yxzx, yxzy, yxzz, - yxzw, yxwx, yxwy, yxwz, yxww, yyxx, yyxy, yyxz, yyxw, yyyx, yyyy, yyyz, yyyw, yyzx, yyzy, - yyzz, yyzw, yywx, yywy, yywz, yyww, yzxx, yzxy, yzxz, yzxw, yzyx, yzyy, yzyz, yzyw, yzzx, - yzzy, yzzz, yzzw, yzwx, yzwy, yzwz, yzww, ywxx, ywxy, ywxz, ywxw, ywyx, ywyy, ywyz, ywyw, - ywzx, ywzy, ywzz, ywzw, ywwx, ywwy, ywwz, ywww, zxxx, zxxy, zxxz, zxxw, zxyx, zxyy, zxyz, - zxyw, zxzx, zxzy, zxzz, zxzw, zxwx, zxwy, zxwz, zxww, zyxx, zyxy, zyxz, zyxw, zyyx, zyyy, - zyyz, zyyw, zyzx, zyzy, zyzz, zyzw, zywx, zywy, zywz, zyww, zzxx, zzxy, zzxz, zzxw, zzyx, - zzyy, zzyz, zzyw, zzzx, zzzy, zzzz, zzzw, zzwx, zzwy, zzwz, zzww, zwxx, zwxy, zwxz, zwxw, - zwyx, zwyy, zwyz, zwyw, zwzx, zwzy, zwzz, zwzw, zwwx, zwwy, zwwz, zwww, wxxx, wxxy, wxxz, - wxxw, wxyx, wxyy, wxyz, wxyw, wxzx, wxzy, wxzz, wxzw, wxwx, wxwy, wxwz, wxww, wyxx, wyxy, - wyxz, wyxw, wyyx, wyyy, wyyz, wyyw, wyzx, wyzy, wyzz, wyzw, wywx, wywy, wywz, wyww, wzxx, - wzxy, wzxz, wzxw, wzyx, wzyy, wzyz, wzyw, wzzx, wzzy, wzzz, wzzw, wzwx, wzwy, wzwz, wzww, - wwxx, wwxy, wwxz, wwxw, wwyx, wwyy, wwyz, wwyw, wwzx, wwzy, wwzz, wwzw, wwwx, wwwy, wwwz, - wwww - ]; -}); - impl PixelDistance for Var> { type Output = Var>; fn px(&self) -> Self::Output { @@ -571,6 +455,46 @@ define_shape_data_string_operator! { Mul mul (*) } define_shape_data_string_operator! { Div div (/) } + +// ============ +// === Dim* === +// ============ + +macro_rules! gen_dim_impl_for_vector { + ([$vec:tt] $dim:tt $( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )*) => { + paste! { + impl [] for Var<$vec> { + type [] = Var<[]>; + $( + fn $name(&self) -> Self::[] { + match self { + Self::Static(t) => Var::Static(t.$name()), + Self::Dynamic(t) => { + let code = format!("{}.{}", t, stringify!($name)); + Var::Dynamic(code.into()) + } + } + } + )* + } + } + }; +} + +enso_types::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector2); +enso_types::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector2); + +enso_types::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector3); +enso_types::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector3); +enso_types::with_swizzling_for_dim!(3, gen_dim_impl_for_vector, Vector3); + +enso_types::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector4); +enso_types::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector4); +enso_types::with_swizzling_for_dim!(3, gen_dim_impl_for_vector, Vector4); +enso_types::with_swizzling_for_dim!(4, gen_dim_impl_for_vector, Vector4); + + + // ========================= // === Utility Functions === // ========================= diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/glsl.rs b/lib/rust/ensogl/core/src/display/shape/primitive/glsl.rs new file mode 100644 index 00000000000..bcc79040673 --- /dev/null +++ b/lib/rust/ensogl/core/src/display/shape/primitive/glsl.rs @@ -0,0 +1,8 @@ +//! GLSL constants and utilities. + + +// ============== +// === Export === +// ============== + +pub mod codes; diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/codes.rs b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/codes.rs new file mode 100644 index 00000000000..5330a7c0105 --- /dev/null +++ b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/codes.rs @@ -0,0 +1,81 @@ +//! GLSL codes, numbers which are used to identify errors and display modes. These are shared +//! between Rust and GLSL code. + +use crate::prelude::*; + +use inflector::Inflector; + + + +// ============= +// === Codes === +// ============= + +/// The error code used for ID encoding errors. +pub const ID_ENCODING_OVERFLOW_ERROR: u32 = 100; + +/// Enum describing possible GLSL display modes. +#[derive(Clone, Copy, Debug, num_enum::IntoPrimitive, num_enum::TryFromPrimitive)] +#[repr(u32)] +#[allow(missing_docs)] +pub enum DisplayModes { + Normal, + DebugSpriteUv, + DebugSpriteOverview, + DebugSpriteGrid, + DebugSdf, + DebugShapeAaSpan, + DebugInstanceId, +} + +// This is not derived, as then [`num_enum::TryFromPrimitive`] will return the default value for +// not matched numbers. +impl Default for DisplayModes { + fn default() -> Self { + Self::Normal + } +} + +impl DisplayModes { + /// The numeric representation of the code. + pub const fn value(self) -> u32 { + self as u32 + } + + /// Conversion from the numeric representation of the code to the code variant. + pub fn from_value(number: u32) -> Option { + Self::try_from(number).ok() + } + + /// Name of the code. + pub fn name(self) -> String { + format!("display_mode_{:?}", self).to_snake_case() + } + + /// Check if the display mode allows mouse interactions in GUI. The display modes that do not + /// allow it use mouse for debug purposes (like changing object hue on click). + pub fn allow_mouse_events(self) -> bool { + match self { + DisplayModes::Normal => true, + DisplayModes::DebugSpriteUv => true, + DisplayModes::DebugSpriteOverview => false, + DisplayModes::DebugSpriteGrid => false, + DisplayModes::DebugSdf => true, + DisplayModes::DebugShapeAaSpan => true, + DisplayModes::DebugInstanceId => false, + } + } + + /// All registered codes. + pub fn all() -> Vec { + let mut codes = vec![]; + for i in 0.. { + if let Some(code) = Self::from_value(i) { + codes.push(code); + } else { + break; + } + } + codes + } +} diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/color.glsl b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/color.glsl index 45641a044b5..2265bf9a1fe 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/color.glsl +++ b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/color.glsl @@ -1,5 +1,5 @@ // ================================================================================================= -// === Colorspaces Definition ====================================================================== +// === Color spaces definition ===================================================================== // ================================================================================================= /// Helper for colors definition. @@ -12,100 +12,100 @@ /// All component values are in range 0.0..1.0. -#define DEF_COLOR(type_name3,type_name4,name3,name4,t1,t2,t3) \ - \ -/* ============================= */ \ -/* === Non Transparent Color === */ \ -/* ============================= */ \ - \ -/* === Definition === */ \ - \ -struct type_name3 { \ - vec3 raw; \ -}; \ - \ - \ -/* === Getters === */ \ - \ -float t1 (type_name3 color) { return color.raw.x; } \ -float t2 (type_name3 color) { return color.raw.y; } \ -float t3 (type_name3 color) { return color.raw.z; } \ - \ - \ -/* === Constructors === */ \ - \ -type_name3 name3(type_name3 identity) { \ - return identity; \ -} \ - \ -type_name3 name3(vec3 raw) { \ - return type_name3(raw); \ -} \ - \ -type_name3 name3(float t1, float t2, float t3) { \ - return name3(vec3(t1,t2,t3)); \ -} \ - \ - \ - \ -/* ========================= */ \ -/* === Transparent Color === */ \ -/* ========================= */ \ - \ -/* === Definition === */ \ - \ -struct type_name4 { \ - vec4 raw; \ -}; \ - \ - \ -/* === Getters === */ \ - \ -float t1 (type_name4 name4) { return name4.raw.x; } \ -float t2 (type_name4 name4) { return name4.raw.y; } \ -float t3 (type_name4 name4) { return name4.raw.z; } \ -float a (type_name4 name4) { return name4.raw.a; } \ - \ - \ -/* === Constructors === */ \ - \ -type_name4 name4 (type_name4 identity) { \ - return identity; \ -} \ - \ -type_name4 name4 (vec4 raw) { \ - return type_name4(raw); \ -} \ - \ -type_name4 name4 (vec3 raw) { \ - return name4(vec4(raw,1.0)); \ -} \ - \ -type_name4 name4 (vec3 raw, float a) { \ - return name4(vec4(raw,a)); \ -} \ - \ -type_name4 name4 (type_name3 name3) { \ - return name4(name3.raw); \ -} \ - \ -type_name4 name4 (type_name3 name3, float a) { \ - return name4(name3.raw,a); \ -} \ - \ -type_name4 name4 (float t1, float t2, float t3) { \ - return name4(vec3(t1,t2,t3)); \ -} \ - \ -type_name4 name4 (float t1, float t2, float t3, float a) { \ - return name4(vec4(t1,t2,t3,a)); \ -} \ - \ - \ -/* === Conversions === */ \ - \ -type_name3 name3 (type_name4 a) { \ - return name3(a.raw.xyz); \ +#define DEF_COLOR(TYPE_NAME_3, TYPE_NAME_4, NAME_3, NAME_4, T_1, T_2, T_3) \ + \ +/* ============================= */ \ +/* === Non Transparent Color === */ \ +/* ============================= */ \ + \ +/* === Definition === */ \ + \ +struct TYPE_NAME_3 { \ + vec3 raw; \ +}; \ + \ + \ +/* === Getters === */ \ + \ +float T_1 (TYPE_NAME_3 color) { return color.raw.x; } \ +float T_2 (TYPE_NAME_3 color) { return color.raw.y; } \ +float T_3 (TYPE_NAME_3 color) { return color.raw.z; } \ + \ + \ +/* === Constructors === */ \ + \ +TYPE_NAME_3 NAME_3(TYPE_NAME_3 identity) { \ + return identity; \ +} \ + \ +TYPE_NAME_3 NAME_3(vec3 raw) { \ + return TYPE_NAME_3(raw); \ +} \ + \ +TYPE_NAME_3 NAME_3(float T_1, float T_2, float T_3) { \ + return NAME_3(vec3(T_1, T_2, T_3)); \ +} \ + \ + \ + \ +/* ========================= */ \ +/* === Transparent Color === */ \ +/* ========================= */ \ + \ +/* === Definition === */ \ + \ +struct TYPE_NAME_4 { \ + vec4 raw; \ +}; \ + \ + \ +/* === Getters === */ \ + \ +float T_1 (TYPE_NAME_4 NAME_4) { return NAME_4.raw.x; } \ +float T_2 (TYPE_NAME_4 NAME_4) { return NAME_4.raw.y; } \ +float T_3 (TYPE_NAME_4 NAME_4) { return NAME_4.raw.z; } \ +float a (TYPE_NAME_4 NAME_4) { return NAME_4.raw.a; } \ + \ + \ +/* === Constructors === */ \ + \ +TYPE_NAME_4 NAME_4 (TYPE_NAME_4 identity) { \ + return identity; \ +} \ + \ +TYPE_NAME_4 NAME_4 (vec4 raw) { \ + return TYPE_NAME_4(raw); \ +} \ + \ +TYPE_NAME_4 NAME_4 (vec3 raw) { \ + return NAME_4(vec4(raw,1.0)); \ +} \ + \ +TYPE_NAME_4 NAME_4 (vec3 raw, float a) { \ + return NAME_4(vec4(raw,a)); \ +} \ + \ +TYPE_NAME_4 NAME_4 (TYPE_NAME_3 NAME_3) { \ + return NAME_4(NAME_3.raw); \ +} \ + \ +TYPE_NAME_4 NAME_4 (TYPE_NAME_3 NAME_3, float a) { \ + return NAME_4(NAME_3.raw, a); \ +} \ + \ +TYPE_NAME_4 NAME_4 (float T_1, float T_2, float T_3) { \ + return NAME_4(vec3(T_1, T_2, T_3)); \ +} \ + \ +TYPE_NAME_4 NAME_4 (float T_1, float T_2, float T_3, float a) { \ + return NAME_4(vec4(T_1, T_2, T_3, a)); \ +} \ + \ + \ +/* === Conversions === */ \ + \ +TYPE_NAME_3 NAME_3 (TYPE_NAME_4 a) { \ + return NAME_3(a.raw.xyz); \ } @@ -117,30 +117,34 @@ DEF_COLOR(Lch , Lcha , lch , lcha , l , c ,h) // ================================================================================================= -// === Colorpsace Conversion ======================================================================= +// === Color space conversion ====================================================================== // ================================================================================================= -#define DEF_TRANSITIVE_CONVERSIONS_1_WAY( \ -a_type_name3,a_type_name4,a_name3,a_name4,b_type_name3,b_type_name4,b_name3,b_name4) \ - \ -a_type_name3 a_name3(b_type_name4 b_name4) { \ - return a_name3(b_name3(b_name4)); \ -} \ - \ -a_type_name4 a_name4(b_type_name4 b_name4) { \ - return a_name4(a_name3(b_name3(b_name4)),a(b_name4)); \ -} \ - \ -a_type_name4 a_name4(b_type_name3 b_name3) { \ - return a_name4(a_name3(b_name3)); \ +#define DEF_TRANSITIVE_CONVERSIONS_1_WAY( \ +A_TYPE_NAME_3, A_TYPE_NAME_4, A_NAME_3, A_NAME_4, B_TYPE_NAME_3, B_TYPE_NAME_4, B_NAME_3, B_NAME_4)\ + \ +A_TYPE_NAME_3 A_NAME_3(B_TYPE_NAME_4 B_NAME_4) { \ + return A_NAME_3(B_NAME_3(B_NAME_4)); \ +} \ + \ +A_TYPE_NAME_4 A_NAME_4(B_TYPE_NAME_4 B_NAME_4) { \ + return A_NAME_4(A_NAME_3(B_NAME_3(B_NAME_4)), a(B_NAME_4)); \ +} \ + \ +A_TYPE_NAME_4 A_NAME_4(B_TYPE_NAME_3 B_NAME_3) { \ + return A_NAME_4(A_NAME_3(B_NAME_3)); \ +} \ + \ +A_TYPE_NAME_4 A_NAME_4(B_TYPE_NAME_3 B_NAME_3, float alpha) { \ + return A_NAME_4(A_NAME_3(B_NAME_3), alpha); \ } -#define DEF_TRANSITIVE_CONVERSIONS( \ -a_type_name3,a_type_name4,a_name3,a_name4,b_type_name3,b_type_name4,b_name3,b_name4) \ -DEF_TRANSITIVE_CONVERSIONS_1_WAY( \ -a_type_name3,a_type_name4,a_name3,a_name4,b_type_name3,b_type_name4,b_name3,b_name4) \ -DEF_TRANSITIVE_CONVERSIONS_1_WAY( \ -b_type_name3,b_type_name4,b_name3,b_name4,a_type_name3,a_type_name4,a_name3,a_name4) +#define DEF_TRANSITIVE_CONVERSIONS( \ +A_TYPE_NAME_3, A_TYPE_NAME_4, A_NAME_3, A_NAME_4, B_TYPE_NAME_3, B_TYPE_NAME_4, B_NAME_3, B_NAME_4)\ +DEF_TRANSITIVE_CONVERSIONS_1_WAY( \ +A_TYPE_NAME_3, A_TYPE_NAME_4, A_NAME_3, A_NAME_4, B_TYPE_NAME_3, B_TYPE_NAME_4, B_NAME_3, B_NAME_4)\ +DEF_TRANSITIVE_CONVERSIONS_1_WAY( \ +B_TYPE_NAME_3, B_TYPE_NAME_4, B_NAME_3, B_NAME_4, A_TYPE_NAME_3, A_TYPE_NAME_4, A_NAME_3, A_NAME_4) @@ -178,7 +182,7 @@ Rgb rgb(Srgb srgb) { return rgb(r,g,b); } -DEF_TRANSITIVE_CONVERSIONS(Srgb,Srgba,srgb,srgba,Rgb,Rgba,rgb,rgba) +DEF_TRANSITIVE_CONVERSIONS(Srgb, Srgba, srgb, srgba, Rgb, Rgba, rgb, rgba) @@ -195,17 +199,17 @@ Lch lch(Srgb rgb) { ( 0.4124, 0.3576, 0.1805 , 0.2126, 0.7152, 0.0722 , 0.0193, 0.1192, 0.9505 ); - c.x = xyzF(c.x/lch_rgb_weights.x); - c.y = xyzF(c.y/lch_rgb_weights.y); - c.z = xyzF(c.z/lch_rgb_weights.z); + c.x = xyzF(c.x / lch_rgb_weights.x); + c.y = xyzF(c.y / lch_rgb_weights.y); + c.z = xyzF(c.z / lch_rgb_weights.z); vec3 lab = vec3(max(0.,116.0*c.y - 16.0), 500.0*(c.x - c.y), 200.0*(c.y - c.z)); - return lch(lab.x, length(vec2(lab.y,lab.z)), atan(lab.z, lab.y)); + return lch(lab.x, length(vec2(lab.y, lab.z)), atan(lab.z, lab.y)); } Srgb srgb (Lch lch) { vec3 c = lch.raw; c = vec3(c.x, cos(c.z) * c.y, sin(c.z) * c.y); - float lg = 1./116.*(c.x + 16.); + float lg = 1. / 116. * (c.x + 16.); float x = lch_rgb_weights.x*xyzR(lg + 0.002*c.y); float y = lch_rgb_weights.y*xyzR(lg); float z = lch_rgb_weights.z*xyzR(lg - 0.005*c.z); @@ -217,7 +221,7 @@ Srgb srgb (Lch lch) { return srgb(raw); } -DEF_TRANSITIVE_CONVERSIONS(Srgb,Srgba,srgb,srgba,Lch,Lcha,lch,lcha) +DEF_TRANSITIVE_CONVERSIONS(Srgb, Srgba, srgb, srgba, Lch, Lcha, lch, lcha) @@ -245,7 +249,7 @@ Srgb srgb(HSV hsv) { return srgb(c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y)); } -DEF_TRANSITIVE_CONVERSIONS(Srgb,Srgba,srgb,srgba,HSV,HSVA,hsv,hsva) +DEF_TRANSITIVE_CONVERSIONS(Srgb, Srgba, srgb, srgba, HSV, HSVA, hsv, hsva) @@ -269,7 +273,8 @@ Rgba mix(Rgba color1, Rgba color2, float t) { // ================ -#define DEF_GRADIENT(COLOR,COLOR_CONS,CONTROL_POINT,GRADIENT1,GRADIENT2,GRADIENT3,GRADIENT4,GRADIENT5) \ +#define DEF_GRADIENT( \ +COLOR, COLOR_CONS, CONTROL_POINT, GRADIENT_1, GRADIENT_2, GRADIENT_3, GRADIENT_4, GRADIENT_5) \ struct CONTROL_POINT { \ float offset; \ COLOR color; \ @@ -279,29 +284,29 @@ CONTROL_POINT gradient_control_point(float offset, COLOR color) { return CONTROL_POINT(offset,color); \ } \ \ -struct GRADIENT1 { \ +struct GRADIENT_1 { \ CONTROL_POINT control_point1; \ }; \ \ -struct GRADIENT2 { \ +struct GRADIENT_2 { \ CONTROL_POINT control_point1; \ CONTROL_POINT control_point2; \ }; \ \ -struct GRADIENT3 { \ +struct GRADIENT_3 { \ CONTROL_POINT control_point1; \ CONTROL_POINT control_point2; \ CONTROL_POINT control_point3; \ }; \ \ -struct GRADIENT4 { \ +struct GRADIENT_4 { \ CONTROL_POINT control_point1; \ CONTROL_POINT control_point2; \ CONTROL_POINT control_point3; \ CONTROL_POINT control_point4; \ }; \ \ -struct GRADIENT5 { \ +struct GRADIENT_5 { \ CONTROL_POINT control_point1; \ CONTROL_POINT control_point2; \ CONTROL_POINT control_point3; \ @@ -309,93 +314,88 @@ struct GRADIENT5 { CONTROL_POINT control_point5; \ }; \ \ -GRADIENT2 gradient \ +GRADIENT_2 gradient \ ( CONTROL_POINT control_point1 \ , CONTROL_POINT control_point2 ) { \ - return GRADIENT2(control_point1,control_point2); \ + return GRADIENT_2(control_point1, control_point2); \ } \ \ -GRADIENT3 gradient \ +GRADIENT_3 gradient \ ( CONTROL_POINT control_point1 \ , CONTROL_POINT control_point2 \ , CONTROL_POINT control_point3 ) { \ - return GRADIENT3(control_point1,control_point2,control_point3); \ + return GRADIENT_3(control_point1, control_point2, control_point3); \ } \ \ -GRADIENT4 gradient \ +GRADIENT_4 gradient \ ( CONTROL_POINT control_point1 \ , CONTROL_POINT control_point2 \ , CONTROL_POINT control_point3 \ , CONTROL_POINT control_point4 ) { \ - return GRADIENT4(control_point1,control_point2,control_point3,control_point4); \ + return GRADIENT_4(control_point1, control_point2, control_point3, control_point4); \ } \ \ -GRADIENT5 gradient \ +GRADIENT_5 gradient \ ( CONTROL_POINT control_point1 \ , CONTROL_POINT control_point2 \ , CONTROL_POINT control_point3 \ , CONTROL_POINT control_point4 \ , CONTROL_POINT control_point5 ) { \ - return GRADIENT5(control_point1,control_point2,control_point3,control_point4,control_point5); \ + return GRADIENT_5 \ + (control_point1, control_point2, control_point3, control_point4, control_point5); \ } \ \ -COLOR sample(GRADIENT2 gradient, float offset) { \ +COLOR sample(GRADIENT_2 gradient, float offset) { \ float span = gradient.control_point2.offset - gradient.control_point1.offset; \ - float t = clamp((offset - gradient.control_point1.offset)/span); \ - return COLOR_CONS(mix(gradient.control_point1.color.raw,gradient.control_point2.color.raw,t)); \ + float t = clamp((offset - gradient.control_point1.offset)/span); \ + return COLOR_CONS(mix \ + (gradient.control_point1.color.raw, gradient.control_point2.color.raw, t)); \ } \ \ -COLOR sample(GRADIENT3 gradient, float offset) { \ +COLOR sample(GRADIENT_3 gradient, float offset) { \ if (offset < gradient.control_point1.offset) { \ return gradient.control_point1.color; \ } else if (offset < gradient.control_point2.offset) { \ - return sample(GRADIENT2(gradient.control_point1,gradient.control_point2),offset); \ + return sample(GRADIENT_2(gradient.control_point1, gradient.control_point2), offset); \ } else if (offset < gradient.control_point3.offset) { \ - return sample(GRADIENT2(gradient.control_point2,gradient.control_point3),offset); \ + return sample(GRADIENT_2(gradient.control_point2, gradient.control_point3), offset); \ } else { \ return gradient.control_point3.color; \ } \ } \ \ -COLOR sample(GRADIENT4 gradient, float offset) { \ +COLOR sample(GRADIENT_4 gradient, float offset) { \ if (offset < gradient.control_point1.offset) { \ return gradient.control_point1.color; \ } else if (offset < gradient.control_point2.offset) { \ - return sample(GRADIENT2(gradient.control_point1,gradient.control_point2),offset); \ + return sample(GRADIENT_2(gradient.control_point1, gradient.control_point2), offset); \ } else if (offset < gradient.control_point3.offset) { \ - return sample(GRADIENT2(gradient.control_point2,gradient.control_point3),offset); \ + return sample(GRADIENT_2(gradient.control_point2, gradient.control_point3), offset); \ } else if (offset < gradient.control_point4.offset) { \ - return sample(GRADIENT2(gradient.control_point3,gradient.control_point4),offset); \ + return sample(GRADIENT_2(gradient.control_point3, gradient.control_point4), offset); \ } else { \ return gradient.control_point4.color; \ } \ } \ \ -COLOR sample(GRADIENT5 gradient, float offset) { \ +COLOR sample(GRADIENT_5 gradient, float offset) { \ if (offset < gradient.control_point1.offset) { \ return gradient.control_point1.color; \ } else if (offset < gradient.control_point2.offset) { \ - return sample(GRADIENT2(gradient.control_point1,gradient.control_point2),offset); \ + return sample(GRADIENT_2(gradient.control_point1, gradient.control_point2), offset); \ } else if (offset < gradient.control_point3.offset) { \ - return sample(GRADIENT2(gradient.control_point2,gradient.control_point3),offset); \ + return sample(GRADIENT_2(gradient.control_point2, gradient.control_point3), offset); \ } else if (offset < gradient.control_point4.offset) { \ - return sample(GRADIENT2(gradient.control_point3,gradient.control_point4),offset); \ + return sample(GRADIENT_2(gradient.control_point3, gradient.control_point4), offset); \ } else if (offset < gradient.control_point5.offset) { \ - return sample(GRADIENT2(gradient.control_point4,gradient.control_point5),offset); \ + return sample(GRADIENT_2(gradient.control_point4, gradient.control_point5), offset); \ } else { \ return gradient.control_point5.color; \ } \ } \ -DEF_GRADIENT(Rgb,rgb,RgbGradientControlPoint,RgbGradient1,RgbGradient2,RgbGradient3,RgbGradient4,RgbGradient5) -DEF_GRADIENT(Rgba,rgba,RgbaGradientControlPoint,RgbaGradient1,RgbaGradient2,RgbaGradient3,RgbaGradient4,RgbaGradient5) - - - - -//Rgba blend(Rgba bottom, Rgba top, float t) { -// float weight = t * a(top); -// float rgb = mix(bottom.raw.rgb, top.raw.rgb, weight); -// float alpha = a(bottom) + a(top); -//} +DEF_GRADIENT(Rgb, rgb, RgbGradientControlPoint, RgbGradient1, RgbGradient2, RgbGradient3, \ + RgbGradient4, RgbGradient5) +DEF_GRADIENT(Rgba, rgba, RgbaGradientControlPoint, RgbaGradient1, RgbaGradient2, RgbaGradient3, \ + RgbaGradient4, RgbaGradient5) diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/error_codes/id_encoding_overflow.txt b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/error_codes/id_encoding_overflow.txt deleted file mode 100644 index 29d6383b52c..00000000000 --- a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/error_codes/id_encoding_overflow.txt +++ /dev/null @@ -1 +0,0 @@ -100 diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/fragment_runner.glsl b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/fragment_runner.glsl index 528451e7a4b..53d6d6f9b72 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/fragment_runner.glsl +++ b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/fragment_runner.glsl @@ -1,23 +1,21 @@ -/// This code is the body of the fragment shader main function of a GLSL shape. - -// ================= -// === Constants === -// ================= - -const int DISPLAY_MODE_NORMAL = 0; -const int DISPLAY_MODE_DEBUG_SDF = 1; -const int DISPLAY_MODE_DEBUG_ID = 2; +//! This code is the body of the fragment shader main function of a GLSL shape. -// ============ -// === Init === -// ============ +// ======================= +// === Shape Rendering === +// ======================= +// The shape is first rendered by sampling the SDF equation generated by EnsoGL shape system and +// then it is clipped by a rectangle of the canvas size. The clipping is performed because the +// sprite size is slightly bigger than the canvas size in order to display anti-aliased border +// pixels when the sprite coordinates are not integers or if the scene is zoomed. See the docs +// attached to the shape system's geometry material to learn more. -Env env = Env(1); -vec2 position = input_local.xy ; -Shape shape = run(env,position); -float alpha = shape.color.color.raw.a; +vec2 position = input_local.xy ; +Shape view_box = debug_shape(rect(position, input_size)); +Shape shape = run(position); +shape = intersection_no_blend(shape, view_box); +float alpha = shape.color.repr.raw.a; @@ -26,33 +24,69 @@ float alpha = shape.color.color.raw.a; // =========================== float alpha_no_aa = alpha > ID_ALPHA_THRESHOLD ? 1.0 : 0.0; - if (pointer_events_enabled) { output_id = encode(input_global_instance_id,alpha_no_aa); } -// ======================= -// === Color Rendering === -// ======================= +// ===================== +// === Display Modes === +// ===================== if (input_display_mode == DISPLAY_MODE_NORMAL) { - output_color = srgba(unpremultiply(shape.color)).raw; + output_color = srgba(shape.color).raw; output_color.rgb *= alpha; +} else if (input_display_mode == DISPLAY_MODE_DEBUG_SHAPE_AA_SPAN) { + output_color = srgba(shape.color).raw; + output_color.rgb *= alpha; + output_color = outside_of_uv() ? vec4(1.0,0.0,0.0,1.0) : output_color; + } else if (input_display_mode == DISPLAY_MODE_DEBUG_SDF) { - float zoom = zoom(); - float factor = 200.0/zoom * input_pixel_ratio; - Rgb col = distance_meter(shape.sdf.distance,factor,factor); - output_color = rgba(col).raw; - output_color.a = alpha_no_aa; + float zoom = zoom(); + float factor = 200.0/zoom * input_pixel_ratio; + Rgb col = distance_meter(shape.sdf.distance, factor, factor); + output_color = rgba(col).raw; + output_color.a = alpha_no_aa; output_color.rgb *= alpha_no_aa; -} else if (input_display_mode == DISPLAY_MODE_DEBUG_ID) { - float object_hue = float((input_global_instance_id * 7) % 100) / 100.0; - Srgb object_color = srgb(hsv(object_hue, 1.0, 0.5)); - output_color.rgb = object_color.raw.rgb; - output_color.a = alpha_no_aa; +} else if (input_display_mode == DISPLAY_MODE_DEBUG_INSTANCE_ID) { + float hue = float((input_global_instance_id + input_mouse_click_count % 10) * 7 % 100) / 100.0; + Srgb color = srgb(hsv(hue, 1.0, 0.5)); + output_color.rgb = color.raw.rgb; + output_color.a = alpha_no_aa; output_color.rgb *= alpha_no_aa; + +} else if (input_display_mode == DISPLAY_MODE_DEBUG_SPRITE_OVERVIEW) { + float hue_seed = float(input_global_instance_id + input_mouse_click_count % 10) * 17.0; + float hue = mod(hue_seed, 100.0) / 100.0; + output_color = srgba(hsva(hue, 1.0, 1.0, alpha_no_aa)).raw; + output_color = outside_of_uv() ? vec4(output_color.rgb, 1.0) : output_color; + output_color.a *= clamp(float(input_mouse_position.x)/1000.0, 0.1, 1.0); + output_color.rgb *= output_color.a; + +} else if (input_display_mode == DISPLAY_MODE_DEBUG_SPRITE_GRID) { + float hue = float((input_global_instance_id + input_mouse_click_count % 10) * 7 % 100) / 100.0; + Srgba color = srgba(hsv(hue, 1.0, 0.8), 1.0); + Srgba grid_color = srgba(hsv(hue, 1.0, 0.6), 1.0); + output_color = vec4(color.raw.rgb, clamp(float(input_mouse_position.x)/100.0, 0.1, 1.0)); + output_color *= alpha_no_aa; + output_color = draw_grid(position, 1, grid_color.raw, output_color); + output_color = draw_grid(position, 2, grid_color.raw, output_color); + output_color = draw_grid(position, 3, grid_color.raw, output_color); + +} else if (input_display_mode == DISPLAY_MODE_DEBUG_SPRITE_UV) { + bool overflow = input_uv.x >= 1.0 || input_uv.y >= 1.0; + float blue = overflow? .5 : .0; + output_color = vec4(input_uv, blue, 1.0); + +} else { + // Unknown code, display a debug checkerboard. + float stripe_width = input_size.x / 4.0; + float stripe_height = input_size.y / 4.0; + bool vertical = mod(position.x, stripe_width * 2.0) < stripe_width; + bool horizontal = mod(position.y, stripe_height * 2.0) < stripe_height; + bool filled = (vertical || horizontal) && !(vertical && horizontal); + output_color = filled ? vec4(1.0,0.0,0.0,1.0) : vec4(0.0,0.0,0.0,1.0); } diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/math.glsl b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/math.glsl index 25e6d30b4be..503f50bbc88 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/math.glsl +++ b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/math.glsl @@ -257,7 +257,7 @@ vec4 encode(int value, float alpha) { rgb *= alpha; #ifdef ID_ENCODING_OVERFLOW_CHECK bool is_overflow = value > MAX_ENCODE_ID; - alpha = is_overflow ? (ID_ENCODING_OVERFLOW_ERROR_CODE/255.0) : alpha; + alpha = is_overflow ? (float(ID_ENCODING_OVERFLOW_ERROR)/255.0) : alpha; #endif return vec4(as_float_u8(chunks)*alpha,alpha); } diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/prelude.glsl b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/prelude.glsl new file mode 100644 index 00000000000..10fa9562bee --- /dev/null +++ b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/prelude.glsl @@ -0,0 +1,20 @@ +/// A zoom level. Zoom of 1.0 means that all figures on the screen will be displayed with their +/// native size. Zoom of 2.0 means that all figures are scaled down twice. +float zoom() { + return input_z_zoom_1 / input_local.z; +} + +/// We are adding a side padding to all sprites when drawing shapes on the in order to make +/// anti-aliasing working properly. Consider a situation when a box moves 0.5 pixels to the right. +/// Then the pixel with the x-coordinate 0 should be half-transparent. The pixel on the left from it +/// should be half-transparent as well. However, it will not exist without the padding. +/// +/// Also, the padding depends on the zoom level. When shapes are zoomed out 2 times, the screen +/// pixel will display 2 pixels of the sprite canvas. +float aa_side_padding() { + return max(1.0, ceil(1.0 / zoom())); +} + +bool outside_of_uv() { + return input_uv.x < 0.0 || input_uv.x > 1.0 || input_uv.y < 0.0 || input_uv.y > 1.0; +} diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/shape.glsl b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/shape.glsl index 4e726cdd6f3..d74251f32d5 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/glsl/shape.glsl +++ b/lib/rust/ensogl/core/src/display/shape/primitive/glsl/shape.glsl @@ -1,3 +1,64 @@ +//! GLSL shape definition boilerplate. + + +// ============= +// === Color === +// ============= + +/// The default color used for [`Shape`]s. The LCHA representation was chosen because it gives good +/// results for color blending (better than RGB and way better than sRGB). +struct Color { + Lcha repr; +}; + +Color color (Lcha color) { + return Color(color); +} + +Color color(vec3 lch, float a) { + return Color(lcha(lch, a)); +} + +Srgba srgba(Color color) { + return srgba(color.repr); +} + + + +// ========================== +// === PremultipliedColor === +// ========================== + +/// The premultiplied version of [`Color`] (the `xyz` components are multiplied by its alpha). +struct PremultipliedColor { + Lcha repr; +}; + +PremultipliedColor premultiply(Color t) { + float alpha = a(t.repr); + vec3 rgb = t.repr.raw.rgb * alpha; + return PremultipliedColor(lcha(rgb, alpha)); +} + +Color unpremultiply(PremultipliedColor c) { + float alpha = c.repr.raw.a; + vec3 rgb = alpha > 0.0 ? c.repr.raw.rgb / alpha : c.repr.raw.rgb; + return color(rgb, alpha); +} + +/// 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(lcha(raw)); +} + +Srgba srgba(PremultipliedColor color) { + return srgba(unpremultiply(color)); +} + + + // =================== // === BoundingBox === // =================== @@ -11,43 +72,43 @@ struct BoundingBox { }; BoundingBox bounding_box (float min_x, float max_x, float min_y, float max_y) { - return BoundingBox(min_x,max_x,min_y,max_y); + return BoundingBox(min_x, max_x, min_y, max_y); } BoundingBox bounding_box (float w, float h) { - return BoundingBox(-w,w,-h,h); + return BoundingBox(-w, w, -h, h); } BoundingBox bounding_box (vec2 size) { float w2 = size.x / 2.0; float h2 = size.y / 2.0; - return BoundingBox(-w2,w2,-h2,h2); + return BoundingBox(-w2, w2, -h2, h2); +} + +BoundingBox infinite () { + return BoundingBox(0.0, 0.0, 0.0, 0.0); } /// Inverses the bounding box. Please note that the inversed bounding box is infinite and thus /// it does not have a proper representation. We represent infinite bounding boxes as 0-sized ones. BoundingBox inverse (BoundingBox a) { - return BoundingBox(0.0,0.0,0.0,0.0); -} - -BoundingBox infinite () { - return BoundingBox(0.0,0.0,0.0,0.0); + return infinite(); } BoundingBox unify (BoundingBox a, BoundingBox b) { - float min_x = min(a.min_x,b.min_x); - float max_x = max(a.max_x,b.max_x); - float min_y = min(a.min_y,b.min_y); - float max_y = max(a.max_y,b.max_y); - return BoundingBox(min_x,max_x,min_y,max_y); + float min_x = min(a.min_x, b.min_x); + float max_x = max(a.max_x, b.max_x); + float min_y = min(a.min_y, b.min_y); + float max_y = max(a.max_y, b.max_y); + return BoundingBox(min_x, max_x, min_y, max_y); } BoundingBox intersection (BoundingBox a, BoundingBox b) { - float min_x = max(a.min_x,b.min_x); - float max_x = min(a.max_x,b.max_x); - float min_y = max(a.min_y,b.min_y); - float max_y = min(a.max_y,b.max_y); - return BoundingBox(min_x,max_x,min_y,max_y); + float min_x = max(a.min_x, b.min_x); + float max_x = min(a.max_x, b.max_x); + float min_y = max(a.min_y, b.min_y); + float max_y = min(a.max_y, b.max_y); + return BoundingBox(min_x, max_x, min_y, max_y); } /// Please note that we cannot compute the exact bounding box for a difference of `a - b`. Thus, we @@ -57,20 +118,21 @@ BoundingBox difference (BoundingBox a, BoundingBox b) { } BoundingBox grow (BoundingBox a, float value) { - float min_x = a.min_x-value; - float max_x = a.max_x+value; - float min_y = a.min_y-value; - float max_y = a.max_y+value; - return BoundingBox(min_x,max_x,min_y,max_y); + float min_x = a.min_x - value; + float max_x = a.max_x + value; + float min_y = a.min_y - value; + float max_y = a.max_y + value; + return BoundingBox(min_x, max_x, min_y, max_y); } + // =========== // === Sdf === // =========== -/// Signed distance field. Describes the distance to the nearest point of a shape. -/// Follow the link to learn more: https://en.wikipedia.org/wiki/Signed_distance_function . +/// Signed distance field. Describes the distance to the nearest point of a shape. Follow the link +/// to learn more: https://en.wikipedia.org/wiki/Signed_distance_function. struct Sdf { float distance; }; @@ -84,15 +146,15 @@ Sdf inverse (Sdf a) { } Sdf unify (Sdf a, Sdf b) { - return Sdf(min(a.distance,b.distance)); + return Sdf(min(a.distance, b.distance)); } Sdf intersection (Sdf a, Sdf b) { - return Sdf(max(a.distance,b.distance)); + return Sdf(max(a.distance, b.distance)); } Sdf difference (Sdf a, Sdf b) { - return intersection(a,inverse(b)); + return intersection(a, inverse(b)); } Sdf grow (Sdf a, float size) { @@ -105,13 +167,19 @@ Sdf grow (Sdf a, float size) { // === BoundSdf === // ================ -/// Bound SDF. Signed distance field with associated bounds. See documentation of `sdf` and `bbox` -/// to learn more. +/// Bound SDF. Signed distance field with associated bounds. See documentation of [`sdf`] and +/// [`bbox`] to learn more. struct BoundSdf { float distance; BoundingBox bounds; }; +float render(BoundSdf sdf) { + float zoom = zoom(); + float growth = 0.5 / zoom; + return clamp((-sdf.distance * input_pixel_ratio + growth) * zoom); +} + // === Getters === @@ -119,10 +187,6 @@ float distance (BoundSdf a) { return a.distance; } -//BoundingBox bounds (BoundSdf a) { -// return a.bounds; -//} - Sdf sdf (BoundSdf a) { return sdf(a.distance); } @@ -131,11 +195,11 @@ Sdf sdf (BoundSdf a) { // === Smart Constructors === BoundSdf bound_sdf (float distance, BoundingBox bounds) { - return BoundSdf(distance,bounds); + return BoundSdf(distance, bounds); } BoundSdf bound_sdf (Sdf sdf, BoundingBox bounds) { - return bound_sdf(sdf.distance,bounds); + return bound_sdf(sdf.distance, bounds); } @@ -153,24 +217,24 @@ BoundSdf pixel_snap (BoundSdf a) { BoundSdf grow (BoundSdf a, float size) { a.distance = a.distance - size; - a.bounds = grow(a.bounds,size); + a.bounds = grow(a.bounds,size); return a; } BoundSdf inverse (BoundSdf a) { - return bound_sdf(inverse(sdf(a)),inverse(a.bounds)); + return bound_sdf(inverse(sdf(a)), inverse(a.bounds)); } BoundSdf unify (BoundSdf a, BoundSdf b) { - return bound_sdf(unify(sdf(a),sdf(b)),unify(a.bounds,b.bounds)); + return bound_sdf(unify(sdf(a), sdf(b)), unify(a.bounds, b.bounds)); } BoundSdf difference (BoundSdf a, BoundSdf b) { - return bound_sdf(difference(sdf(a),sdf(b)),difference(a.bounds,b.bounds)); + return bound_sdf(difference(sdf(a), sdf(b)), difference(a.bounds, b.bounds)); } BoundSdf intersection (BoundSdf a, BoundSdf b) { - return bound_sdf(intersection(sdf(a),sdf(b)),intersection(a.bounds,b.bounds)); + return bound_sdf(intersection(sdf(a), sdf(b)), intersection(a.bounds, b.bounds)); } @@ -179,6 +243,8 @@ BoundSdf intersection (BoundSdf a, BoundSdf b) { // === Id === // ========== +/// The ID of a shape. It is used to identify shapes after rendering to an non-antialiased ID +/// texture. struct Id { int value; }; @@ -192,133 +258,118 @@ Id new_id_layer (BoundSdf sdf, int i) { } -// Premultiplied -struct Color { - Srgba color; -}; - -Color premultiply(Srgba t) { - float alpha = a(t); - vec3 rgb = t.raw.rgb * alpha; - return Color(srgba(rgb,alpha)); -} - -Srgba unpremultiply(Color t) { - float alpha = t.color.raw.a; - vec3 rgb = t.color.raw.rgb / alpha; - return srgba(rgb,alpha); -} - -// Implements glBlendFuncSeparate(GL_ONE,GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA); -Color blend(Color bg, Color fg) { - vec4 raw = fg.color.raw + (1.0 - fg.color.raw.a) * bg.color.raw; - return Color(srgba(raw)); -} - - // ============= // === Shape === // ============= -float zoom() { - return input_z_zoom_1 / input_local.z; -} - -float render(BoundSdf sdf) { - return clamp((-sdf.distance * input_pixel_ratio + 0.5) * zoom()); -} - -// Note: the color is premultiplied. +/// A visual shape that can be displayed on the screen or combined with other shapes. struct Shape { - Id id; + /// The ID of the shape. It is used to identify shapes after rendering to an non-antialiased ID + /// texture. + Id id; + /// The Signed Distance Field, describing the shape boundaries. BoundSdf sdf; - Color color; - float alpha; + /// The color of the shape. Please note that we are storing the premultiplied version of the + /// color, as blending requires premultiplied values. We could store the non-premultiplied, + /// however, then we would need to unpremultiply the color after blending, which leads to + /// a serious issue. If the alpha is 0, then either unpremultiplication needs to be more costly + /// and check for this condition, or it will produce infinite/invalid values for the `xyz` + /// components. If we blend such a color with another one, then we will get artifacts, as + /// multiplying an infinite/invalid value by 0 is an undefined behavior. + PremultipliedColor color; + /// The opacity of the shape. It is the result of rendering of the [`sdf`]. + float alpha; }; -Shape shape (Id id, BoundSdf bound_sdf, Srgba rgba) { +Shape shape (Id id, BoundSdf bound_sdf, PremultipliedColor color) { float alpha = render(bound_sdf); - rgba.raw.a *= alpha; - Color color = premultiply(rgba); - return Shape(id,bound_sdf,color,alpha); + color.repr.raw *= alpha; + return Shape(id, bound_sdf, color, alpha); } Shape shape (Id id, BoundSdf bound_sdf, Color color) { - float alpha = render(bound_sdf); - return Shape(id,bound_sdf,color,alpha); + return shape(id, bound_sdf, premultiply(color)); +} + +Shape shape (Id id, BoundSdf bound_sdf, Srgba rgba) { + return shape(id, bound_sdf, Color(lcha(rgba))); +} + +Shape shape (Id id, BoundSdf bound_sdf) { + return shape(id, bound_sdf, srgba(1.0, 0.0, 0.0, 1.0)); +} + +Shape shape (Id id, BoundSdf bound_sdf, Lcha lcha) { + return shape(id, bound_sdf, Color(lcha)); +} + +/// A debug [`Shape`] constructor. Should not be used to create shapes that are rendered to the +/// screen as it's ID is always 0. It can be used to create temporary shapes. For example, it can +/// be used to create a clipping rectangle, that will be intersected with another shape. +Shape debug_shape (BoundSdf bound_sdf) { + Id id = new_id_layer(bound_sdf, 10); + return shape(id, bound_sdf); } Shape resample (Shape s, float multiplier) { - Id id = s.id; - BoundSdf sdf = resample(s.sdf,multiplier); - Srgba color = unpremultiply(s.color); - color.raw.a /= s.alpha; - return shape(id,sdf,color); + Id id = s.id; + BoundSdf sdf = resample(s.sdf, multiplier); + s.color.repr.raw.a /= s.alpha; + return shape(id, sdf, s.color); } Shape pixel_snap (Shape s) { - Id id = s.id; - BoundSdf sdf = pixel_snap(s.sdf); - Srgba color = unpremultiply(s.color); - color.raw.a /= s.alpha; - return shape(id,sdf,color); + Id id = s.id; + BoundSdf sdf = pixel_snap(s.sdf); + s.color.repr.raw.a /= s.alpha; + return shape(id, sdf, s.color); } Shape grow (Shape s, float value) { - Id id = s.id; - BoundSdf sdf = grow(s.sdf,value); - Srgba color = unpremultiply(s.color); - color.raw.a /= s.alpha; - return shape(id,sdf,color); + Id id = s.id; + BoundSdf sdf = grow(s.sdf,value); + s.color.repr.raw.a /= s.alpha; + return shape(id, sdf, s.color); } Shape inverse (Shape s1) { - return shape(s1.id,inverse(s1.sdf),s1.color); + return shape(s1.id, inverse(s1.sdf), s1.color); } Shape unify (Shape s1, Shape s2) { - return shape(s1.id,unify(s1.sdf,s2.sdf),blend(s1.color,s2.color)); + return shape(s1.id, unify(s1.sdf, s2.sdf), blend(s1.color, s2.color)); } Shape difference (Shape s1, Shape s2) { - return shape(s1.id,difference(s1.sdf,s2.sdf),s1.color); + return shape(s1.id, difference(s1.sdf, s2.sdf), s1.color); } Shape intersection (Shape s1, Shape s2) { - return shape(s1.id,intersection(s1.sdf,s2.sdf),blend(s1.color,s2.color)); + return shape(s1.id, intersection(s1.sdf, s2.sdf), blend(s1.color, s2.color)); +} + +Shape intersection_no_blend (Shape s1, Shape s2) { + return shape(s1.id, intersection(s1.sdf, s2.sdf), s1.color); } Shape set_color(Shape shape, Srgba t) { t.raw.a *= shape.alpha; - Color color = premultiply(t); - shape.color = color; + shape.color = premultiply(Color(lcha(t))); return shape; } -Shape withInfiniteBounds (Shape s) { - Id id = s.id; - Color color = s.color; - BoundSdf sdf = s.sdf; - sdf.bounds = infinite(); - return shape(id, sdf, color); +Shape with_infinite_bounds (Shape s) { + BoundSdf sdf = s.sdf; + sdf.bounds = infinite(); + return shape(s.id, sdf, s.color); } -// =========== -// === Env === -// =========== - -struct Env { - int test; -}; - - - -/////////////////////// -////// Transform ////// -/////////////////////// +// ================= +// === Transform === +// ================= vec2 translate (vec2 position, vec2 t) { return position - t; @@ -326,7 +377,7 @@ vec2 translate (vec2 position, vec2 t) { vec2 rotate (vec2 position, Radians angle) { float v_angle = value(angle); - return position*cos(-v_angle) + vec2(position.y,-position.x)*sin(-v_angle); + return position * cos(-v_angle) + vec2(position.y, -position.x) * sin(-v_angle); } vec2 scale (vec2 position, float value) { @@ -340,3 +391,23 @@ vec2 cartesian2polar (vec2 position) { vec2 repeat (vec2 position, vec2 tile_size) { return mod(position+tile_size/2.0, tile_size) - tile_size/2.0; } + + + +// ============= +// === Debug === +// ============= + +vec4 draw_grid(vec2 position, int level, vec4 color, vec4 output_color) { + float sampling = pow(2.0, float(level - 1)); + float width = min(sampling, zoom()) / input_pixel_ratio + 0.1; + float sampling2 = sampling / 2.0; + bool v = abs(mod(position.x + sampling2, sampling) - sampling2) <= width/2.0/zoom(); + bool h = abs(mod(position.y + sampling2, sampling) - sampling2) <= width/2.0/zoom(); + if ((v || h) && !outside_of_uv()) { + float alpha = clamp((zoom() - (4.0 - sampling))/(5.0 - sampling), 0.0, 1.0); + color *= alpha; + output_color = color + (1.0 - color.a) * output_color; + } + return output_color; +} diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/shader/builder.rs b/lib/rust/ensogl/core/src/display/shape/primitive/shader/builder.rs index 690e3fa73d6..679cb4f1059 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/shader/builder.rs +++ b/lib/rust/ensogl/core/src/display/shape/primitive/shader/builder.rs @@ -4,6 +4,7 @@ use crate::prelude::*; use crate::display::shape::primitive::def::primitive; +use crate::display::shape::primitive::glsl::codes; use crate::display::shape::primitive::shader::overload; use crate::display::symbol::shader::builder::CodeTemplate; @@ -18,15 +19,13 @@ use super::canvas::Canvas; // === GLSL Sources === +/// Common GLSL functions for all sprite types. +pub const GLSL_PRELUDE: &str = include_str!("../glsl/prelude.glsl"); const MATH: &str = include_str!("../glsl/math.glsl"); const COLOR: &str = include_str!("../glsl/color.glsl"); const DEBUG: &str = include_str!("../glsl/debug.glsl"); const SHAPE: &str = include_str!("../glsl/shape.glsl"); const FRAGMENT_RUNNER: &str = include_str!("../glsl/fragment_runner.glsl"); -const ERROR_CODES: &[(&str, &str)] = &[( - "ID_ENCODING_OVERFLOW_ERROR_CODE", - include_str!("../glsl/error_codes/id_encoding_overflow.txt"), -)]; // === Definition === @@ -47,7 +46,7 @@ impl Builder { canvas.add_current_function_code_line(iformat!("return {shape_ref.getter()};")); canvas.submit_shape_constructor("run"); let shape_def = overload::allow_overloading(&canvas.to_glsl()); - let code = [GLSL_PRELUDE.as_str(), "", &shape_header, &shape_def].join("\n\n"); + let code = [GLSL_BOILERPLATE.as_str(), "", &shape_header, &shape_def].join("\n\n"); let main = format!( "bool pointer_events_enabled = {};\n{}", pointer_events_enabled, FRAGMENT_RUNNER @@ -68,26 +67,49 @@ fn header(label: &str) -> String { } -// == GLSL_PRELUDE == +// == GLSL Boilerplate == lazy_static! { /// A common preamble used to start every shader program. - static ref GLSL_PRELUDE: String = make_glsl_prelude(); + static ref GLSL_BOILERPLATE: String = gen_glsl_boilerplate(); } -fn make_error_codes() -> String { - let codes = ERROR_CODES.iter(); - codes.map(|(name, code)| format!("const float {} = {}.0;", name, code.trim())).join("\n") +fn glsl_codes() -> String { + let codes = codes::DisplayModes::all(); + let header = header("Codes"); + let display_modes = codes + .iter() + .map(|code| format!("const int {} = {};", code.name().to_uppercase(), code.value())) + .join("\n"); + let error_codes = + format!("const int ID_ENCODING_OVERFLOW_ERROR = {};", codes::ID_ENCODING_OVERFLOW_ERROR); + format!("{}\n\n{}\n{}", header, display_modes, error_codes) } -fn make_glsl_prelude() -> String { +/// The GLSL common code and debug codes. +pub fn glsl_prelude_and_codes() -> String { + let codes = glsl_codes(); + format!("{}\n\n{}", GLSL_PRELUDE, codes) +} + +fn gen_glsl_boilerplate() -> String { let redirections = overload::builtin_redirections(); let math = overload::allow_overloading(MATH); let color = overload::allow_overloading(COLOR); let debug = overload::allow_overloading(DEBUG); let shape = overload::allow_overloading(SHAPE); - let err_codes = make_error_codes(); + let codes_and_prelude = glsl_prelude_and_codes(); let defs_header = header("SDF Primitives"); let sdf_defs = overload::allow_overloading(&primitive::all_shapes_glsl_definitions()); - [redirections, err_codes, math, color, debug, shape, defs_header, sdf_defs].join("\n\n") + [ + redirections.as_str(), + codes_and_prelude.as_str(), + math.as_str(), + color.as_str(), + debug.as_str(), + shape.as_str(), + defs_header.as_str(), + sdf_defs.as_str(), + ] + .join("\n\n") } diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/shader/canvas.rs b/lib/rust/ensogl/core/src/display/shape/primitive/shader/canvas.rs index 6386aec304d..abd88a952fd 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/shader/canvas.rs +++ b/lib/rust/ensogl/core/src/display/shape/primitive/shader/canvas.rs @@ -62,7 +62,7 @@ impl ShapeData { /// Getter of the shape as GLSL expression. pub fn getter(&self) -> String { - iformat!("{self.name}(env,position)") + iformat!("{self.name}(position)") } } @@ -76,8 +76,8 @@ impl ShapeData { /// Canvas for drawing vector graphics. /// -/// The API is stateful, similar to the API of HTML5 canvas element. -/// It uses GLSL and signed distance fields under the hood. +/// The API is stateful, similar to the API of HTML5 canvas element. It uses GLSL and signed +/// distance fields under the hood. #[derive(Debug, Default)] pub struct Canvas { @@ -123,17 +123,13 @@ impl Canvas { /// Defines a new variable in the GLSL code. pub fn define(&mut self, ty: &str, name: &str, expr: E) { - let max_type_length = 8; - let max_name_length = 6; - let ty = format!("{:1$}", ty, max_type_length); - let name = format!("{:1$}", name, max_name_length); self.add_current_function_code_line(iformat!("{ty} {name} = {expr.as_ref()};")); } /// Submits the `current_function_lines` as a new shape construction function in the GLSL code. pub fn submit_shape_constructor(&mut self, name: &str) { let body = self.current_function_lines.join("\n "); - let func = iformat!("Shape {name} (Env env, vec2 position) {{\n {body}\n}}"); + let func = iformat!("Shape {name} (vec2 position) {{\n {body}\n}}"); self.current_function_lines = default(); self.functions.push(func); } @@ -155,13 +151,11 @@ impl Canvas { /// Defines a new shape with a new id and associated parameters, like color. pub fn define_shape(&mut self, num: usize, sdf: &str) -> Shape { self.if_not_defined(num, |this| { - let color = "srgba(1.0,0.0,0.0)"; let mut shape = ShapeData::new(num); let id = this.get_new_id(); - this.define("Srgba", "color", iformat!("{color}")); this.define("BoundSdf", "sdf", iformat!("{sdf}")); this.define("Id", "id", iformat!("new_id_layer(sdf,{id})")); - this.add_current_function_code_line("return shape(id,sdf,color);"); + this.add_current_function_code_line("return shape(id, sdf);"); this.submit_shape_constructor(&shape.name); shape.add_id(id); shape diff --git a/lib/rust/ensogl/core/src/display/shape/primitive/system.rs b/lib/rust/ensogl/core/src/display/shape/primitive/system.rs index dee0018f87a..2ab8c916fff 100644 --- a/lib/rust/ensogl/core/src/display/shape/primitive/system.rs +++ b/lib/rust/ensogl/core/src/display/shape/primitive/system.rs @@ -349,6 +349,7 @@ pub struct ShapeSystemModel { pub sprite_system: SpriteSystem, pub shape: Rc>, pub material: Rc>, + pub geometry_material: Rc>, /// 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 /// through all mouse events to shapes behind them). @@ -366,10 +367,18 @@ impl ShapeSystemModel { pub fn new(shape: def::AnyShape, pointer_events: bool) -> Self { let sprite_system = SpriteSystem::new(); let material = Rc::new(RefCell::new(Self::default_material())); + let geometry_material = Rc::new(RefCell::new(Self::default_geometry_material())); let pointer_events = Immutable(pointer_events); let shape = Rc::new(RefCell::new(shape)); let do_not_use_shape_definition = default(); - Self { sprite_system, shape, material, pointer_events, do_not_use_shape_definition } + Self { + sprite_system, + shape, + material, + geometry_material, + pointer_events, + do_not_use_shape_definition, + } } fn init(&self) { @@ -384,11 +393,63 @@ impl ShapeSystemModel { material.add_input("pixel_ratio", 1.0); material.add_input("z_zoom_1", 1.0); material.add_input("time", 0.0); + material.add_input_def::>("mouse_position"); + material.add_input_def::("mouse_click_count"); material.add_input("display_mode", 0); material.add_output("id", Vector4::::zero()); material } + fn default_geometry_material() -> Material { + let mut material = SpriteSystem::default_geometry_material(); + material.set_before_main(shader::builder::glsl_prelude_and_codes()); + // The GLSL vertex shader implementing automatic shape padding for anti-aliasing. See the + // docs of [`aa_side_padding`] to learn more about the concept of shape padding. + // + // First, we are computing the vertex position without shape padding. This is required to + // make the function [`aa_side_padding`] work, as it uses [`zoom`], which uses the + // [`input_local.z`] value. The depth of the vertex can be computed only after the + // [`model_view_projection`] matrix is applied. + // + // Please note that this method is not guaranteed to always provide correct results. If + // there is a big angle between the camera and the shape normal axes (e.g. when the shape is + // significantly rotated around its Y-axis), the padding might be too small. To correct it, + // we might take normal axes into account, but it will require more computations, and we do + // not need it currently. + // + // Also, please note that we are first using the [`input_uv`] variable, and then we are + // changing it. It's because the unchanged value is the incoming UV in range 0..1, and then + // we are scaling it to a bigger range, so the padded area UV is not contained within 0..1. + material.set_main( + " + mat4 model_view_projection = input_view_projection * input_transform; + + // Computing the vertex position without shape padding. + vec3 input_local_no_padding = vec3((input_uv - input_alignment) * input_size, 0.0); + vec4 position_no_padding = model_view_projection * vec4(input_local_no_padding, 1.0); + input_local.z = position_no_padding.z; + + // We are now able to compute the padding and grow the canvas by its value. + vec2 padding = vec2(aa_side_padding()); + if (input_display_mode == DISPLAY_MODE_DEBUG_SPRITE_OVERVIEW) { + padding = vec2(float(input_mouse_position.y) / 10.0); + } + + vec2 padding2 = 2.0 * padding; + vec2 padded_size = input_size + padding2; + vec2 uv_scale = padded_size / input_size; + vec2 uv_offset = padding / input_size; + input_uv = vertex_uv * uv_scale - uv_offset; + + // We need to recompute the vertex position with the padding. + input_local = vec3((input_uv - input_alignment) * input_size, 0.0); + gl_Position = model_view_projection * vec4(input_local,1.0); + input_local.z = gl_Position.z; + ", + ); + material + } + /// Replaces the shape definition. #[profile(Detail)] pub fn set_shape(&self, shape: def::AnyShape) { @@ -419,6 +480,7 @@ impl ShapeSystemModel { #[profile(Detail)] fn reload_material(&self) { self.sprite_system.set_material(&*self.material.borrow()); + self.sprite_system.set_geometry_material(&*self.geometry_material.borrow()); } } diff --git a/lib/rust/ensogl/core/src/display/symbol/dom.rs b/lib/rust/ensogl/core/src/display/symbol/dom.rs index d7fad937b0b..606e9b75531 100644 --- a/lib/rust/ensogl/core/src/display/symbol/dom.rs +++ b/lib/rust/ensogl/core/src/display/symbol/dom.rs @@ -116,15 +116,23 @@ impl DomSymbol { dom.set_style_or_warn("position", "absolute"); dom.set_style_or_warn("width", "0px"); dom.set_style_or_warn("height", "0px"); + dom.set_style_or_warn("display", "none"); dom.append_or_warn(content); let display_object = display::object::Instance::new(); + let weak_display_object = display_object.downgrade(); + let network = &display_object.network; + frp::extend! { network + eval_ display_object.on_show (dom.set_style_or_warn("display", "")); + eval_ display_object.on_hide (dom.set_style_or_warn("display", "none")); + eval_ display_object.on_updated ([dom] { + if let Some(display_object) = weak_display_object.upgrade() { + let mut transform = inverse_y_translation(display_object.transformation_matrix()); + transform.iter_mut().for_each(|a| *a = eps(*a)); + set_object_transform(&dom, &transform); + } + }); + } let guard = Rc::new(Guard::new(&display_object, &dom)); - display_object.set_on_updated(enclose!((dom) move |t| { - let mut transform = inverse_y_translation(t.matrix()); - transform.iter_mut().for_each(|a| *a = eps(*a)); - set_object_transform(&dom,&transform); - })); - Self { dom, display_object, size, guard } } diff --git a/lib/rust/ensogl/core/src/display/symbol/gpu.rs b/lib/rust/ensogl/core/src/display/symbol/gpu.rs index 8555e0cf6ad..5b70141e06f 100644 --- a/lib/rust/ensogl/core/src/display/symbol/gpu.rs +++ b/lib/rust/ensogl/core/src/display/symbol/gpu.rs @@ -591,16 +591,19 @@ impl SymbolData { fn init(self) -> Self { let is_hidden = &self.is_hidden; let id = self.id; - self.display_object.set_on_hide(f_!(is_hidden.set(true))); - self.display_object.set_on_show(f__!(is_hidden.set(false))); - self.display_object.set_on_scene_layer_changed(move |_, old_layers, new_layers| { - for layer in old_layers.iter().filter_map(|t| t.upgrade()) { - layer.remove_symbol(id) - } - for layer in new_layers.iter().filter_map(|t| t.upgrade()) { - layer.add_symbol(id) - } - }); + let network = &self.display_object.network; + frp::extend! { network + eval_ self.display_object.on_hide(is_hidden.set(true)); + eval_ self.display_object.on_show(is_hidden.set(false)); + eval self.display_object.on_layer_change([] ((_, old_layers, new_layers)) { + for layer in old_layers.iter().filter_map(|t| t.upgrade()) { + layer.remove_symbol(id) + } + for layer in new_layers.iter().filter_map(|t| t.upgrade()) { + layer.add_symbol(id) + } + }); + } self } diff --git a/lib/rust/ensogl/core/src/display/symbol/gpu/geometry/compound/sprite.rs b/lib/rust/ensogl/core/src/display/symbol/gpu/geometry/compound/sprite.rs index 4de68211288..4dca4a05925 100644 --- a/lib/rust/ensogl/core/src/display/symbol/gpu/geometry/compound/sprite.rs +++ b/lib/rust/ensogl/core/src/display/symbol/gpu/geometry/compound/sprite.rs @@ -111,6 +111,71 @@ impl Size { +// =================== +// === SizedObject === +// =================== + +/// A display object bound with [`Size`]. +#[derive(Debug)] +pub struct SizedObject { + size: Size, + display_object: display::object::Instance, +} + +impl SizedObject { + fn new(attr: Attribute>, transform: &Attribute>) -> Self { + let size = Size::new(attr); + let display_object = display::object::Instance::new(); + let weak_display_object = display_object.downgrade(); + let network = &display_object.network; + frp::extend! { network + eval_ display_object.on_updated ([transform] { + if let Some(display_object) = weak_display_object.upgrade() { + transform.set(display_object.transformation_matrix()) + } + }); + } + Self { size, display_object }.init() + } + + /// Init display object bindings. In particular defines the behavior of the show and hide + /// callbacks. + fn init(self) -> Self { + let size = &self.size; + let display_object = &self.display_object; + let network = &display_object.network; + frp::extend! { network + eval_ display_object.on_show(size.show()); + eval_ display_object.on_hide(size.hide()); + } + self + } + + /// Clone ref the underlying [`Size`]. + pub fn clone_ref(&self) -> Size { + self.size.clone_ref() + } +} + +impl HasItem for SizedObject { + type Item = Vector2; +} + +impl CellGetter for SizedObject { + fn get(&self) -> Vector2 { + self.size.get() + } +} + +impl CellSetter for SizedObject { + fn set(&self, v: Vector2) { + self.size.set(v); + self.display_object.set_bounding_box(v); + } +} + + + // ============== // === Sprite === // ============== @@ -119,17 +184,44 @@ impl Size { /// freely rotated only by their local z-axis. This implementation, however, implements sprites as /// full 3D objects. We may want to fork this implementation in the future to create a specialized /// 2d representation as well. -#[derive(Debug, Clone, CloneRef)] +#[derive(Debug, Clone, CloneRef, Deref)] #[allow(missing_docs)] pub struct Sprite { - pub symbol: Symbol, + model: Rc, +} + +/// Internal representation of [`Sprite`]. +#[derive(Debug, Deref)] +#[allow(missing_docs)] +pub struct SpriteModel { + #[deref] pub instance: SymbolInstance, - pub size: Size, - display_object: display::object::Instance, + pub symbol: Symbol, + pub size: SizedObject, transform: Attribute>, - stats: Rc, - erase_on_drop: Rc>>>, - unset_parent_on_drop: Rc, + stats: SpriteStats, + erase_on_drop: EraseOnDrop>>, + unset_parent_on_drop: display::object::UnsetParentOnDrop, +} + +impl SpriteModel { + /// Constructor. + pub fn new( + symbol: &Symbol, + instance: SymbolInstance, + transform: Attribute>, + size: Attribute>, + stats: &Stats, + ) -> Self { + let symbol = symbol.clone_ref(); + let stats = SpriteStats::new(stats); + let erase_on_drop = EraseOnDrop::new(size.clone_ref()); + let size = SizedObject::new(size, &transform); + let unset_parent_on_drop = display::object::UnsetParentOnDrop::new(&size.display_object); + let default_size = Vector2(DEFAULT_SPRITE_SIZE.0, DEFAULT_SPRITE_SIZE.1); + size.set(default_size); + Self { symbol, instance, size, transform, stats, erase_on_drop, unset_parent_on_drop } + } } impl Sprite { @@ -141,37 +233,8 @@ impl Sprite { size: Attribute>, stats: &Stats, ) -> Self { - let symbol = symbol.clone_ref(); - let display_object = display::object::Instance::new(); - let stats = Rc::new(SpriteStats::new(stats)); - let erase_on_drop = Rc::new(EraseOnDrop::new(size.clone_ref())); - let size = Size::new(size); - let unset_parent_on_drop = - Rc::new(display::object::UnsetParentOnDrop::new(&display_object)); - let default_size = Vector2(DEFAULT_SPRITE_SIZE.0, DEFAULT_SPRITE_SIZE.1); - size.set(default_size); - Self { - symbol, - instance, - size, - display_object, - transform, - stats, - erase_on_drop, - unset_parent_on_drop, - } - .init() - } - - /// Init display object bindings. In particular defines the behavior of the show and hide - /// callbacks. - fn init(self) -> Self { - let size = &self.size; - let transform = &self.transform; - self.display_object.set_on_updated(f!((t) transform.set(t.matrix()))); - self.display_object.set_on_hide(f_!(size.hide())); - self.display_object.set_on_show(f__!(size.show())); - self + let model = SpriteModel::new(symbol, instance, transform, size, stats); + Self { model: Rc::new(model) } } /// Get the symbol id. @@ -188,16 +251,15 @@ impl Sprite { } } -impl display::Object for Sprite { +impl display::Object for SpriteModel { fn display_object(&self) -> &display::object::Instance { - &self.display_object + &self.size.display_object } } -impl Deref for Sprite { - type Target = SymbolInstance; - fn deref(&self) -> &Self::Target { - &self.instance +impl display::Object for Sprite { + fn display_object(&self) -> &display::object::Instance { + self.model.display_object() } } @@ -310,13 +372,14 @@ impl SpriteSystem { fn init_shader(&self) { let shader = self.symbol.shader(); - let surface_material = Self::surface_material(); - let geometry_material = Self::geometry_material(); + let surface_material = Self::default_surface_material(); + let geometry_material = Self::default_geometry_material(); shader.set_geometry_material(&geometry_material); shader.set_material(&surface_material); } - fn geometry_material() -> Material { + /// The default geometry material for all sprites. + pub fn default_geometry_material() -> Material { let mut material = Material::new(); material.add_input_def::>("size"); material.add_input_def::>("uv"); @@ -328,10 +391,10 @@ impl SpriteSystem { material.set_main( " mat4 model_view_projection = input_view_projection * input_transform; - input_local = vec3((input_uv - input_alignment) * input_size, 0.0); - gl_Position = model_view_projection * vec4(input_local,1.0); - input_local.z = gl_Position.z; - ", + input_local = vec3((input_uv - input_alignment) * input_size, 0.0); + gl_Position = model_view_projection * vec4(input_local,1.0); + input_local.z = gl_Position.z; + ", // This is left here in case it will be needed. The `instance_id` is the same as the // built-in `gl_InstanceID` and can be implemented very efficiently: // input_instance_id = gl_InstanceID; @@ -339,7 +402,8 @@ impl SpriteSystem { material } - fn surface_material() -> Material { + /// The default surface material for all sprites. + pub fn default_surface_material() -> Material { let mut material = Material::new(); // FIXME We need to use this output, as we need to declare the same amount of shader // FIXME outputs as the number of attachments to framebuffer. We should manage this more diff --git a/lib/rust/ensogl/core/src/display/symbol/gpu/shader.rs b/lib/rust/ensogl/core/src/display/symbol/gpu/shader.rs index e26f2206766..1880252295a 100644 --- a/lib/rust/ensogl/core/src/display/symbol/gpu/shader.rs +++ b/lib/rust/ensogl/core/src/display/symbol/gpu/shader.rs @@ -159,7 +159,7 @@ impl { let vertex_code = self.geometry_material.code().clone(); let fragment_code = self.surface_material.code().clone(); - shader_builder.compute(&shader_cfg,vertex_code,fragment_code); + shader_builder.compute(&shader_cfg, vertex_code, fragment_code); let code = shader_builder.build(); *self.program.borrow_mut() = None; diff --git a/lib/rust/ensogl/core/src/display/world.rs b/lib/rust/ensogl/core/src/display/world.rs index a24705cc165..f7a34945cb0 100644 --- a/lib/rust/ensogl/core/src/display/world.rs +++ b/lib/rust/ensogl/core/src/display/world.rs @@ -20,6 +20,7 @@ use crate::display::render; use crate::display::render::passes::SymbolsRenderPass; use crate::display::scene::DomPath; use crate::display::scene::Scene; +use crate::display::shape::primitive::glsl; use crate::system::web; use enso_types::unit2::Duration; @@ -229,6 +230,7 @@ pub struct WorldData { pub default_scene: Scene, scene_dirty: dirty::SharedBool, uniforms: Uniforms, + display_mode: Rc>, stats: Stats, stats_monitor: debug::monitor::Monitor, stats_draw_handle: callback::Handle, @@ -246,7 +248,8 @@ impl WorldData { let on = Callbacks::default(); let scene_dirty = dirty::SharedBool::new(()); let on_change = enclose!((scene_dirty) move || scene_dirty.set()); - let default_scene = Scene::new(&stats, on_change); + let display_mode = Rc::>::default(); + let default_scene = Scene::new(&stats, on_change, &display_mode); let uniforms = Uniforms::new(&default_scene.variables); let debug_hotkeys_handle = default(); let garbage_collector = default(); @@ -262,6 +265,7 @@ impl WorldData { default_scene, scene_dirty, uniforms, + display_mode, stats, on, debug_hotkeys_handle, @@ -285,24 +289,29 @@ impl WorldData { fn init_debug_hotkeys(&self) { let stats_monitor = self.stats_monitor.clone_ref(); - let display_mode = self.uniforms.display_mode.clone_ref(); + let display_mode = self.display_mode.clone_ref(); + let display_mode_uniform = self.uniforms.display_mode.clone_ref(); let closure: Closure = Closure::new(move |val: JsValue| { let event = val.unchecked_into::(); + let digit_prefix = "Digit"; if event.alt_key() && event.ctrl_key() { let key = event.code(); if key == "Backquote" { stats_monitor.toggle() - } else if key == "Digit0" { - display_mode.set(0) - } else if key == "Digit1" { - display_mode.set(1) - } else if key == "Digit2" { - display_mode.set(2) } else if key == "KeyP" { enso_debug_api::save_profile(&profiler::internal::take_log()); } else if key == "KeyQ" { enso_debug_api::save_profile(&profiler::internal::take_log()); enso_debug_api::LifecycleController::new().map(|api| api.quit()); + } else if key.starts_with(digit_prefix) { + let code_value = key.trim_start_matches(digit_prefix).parse().unwrap_or(0); + if let Some(mode) = glsl::codes::DisplayModes::from_value(code_value) { + warn!("Setting display mode to {:?}.", mode.name()); + display_mode.set(mode); + } else { + warn!("Invalid display mode code: {code_value}."); + } + display_mode_uniform.set(code_value as i32); } } }); diff --git a/lib/rust/ensogl/core/src/gui/component.rs b/lib/rust/ensogl/core/src/gui/component.rs index b0f830b04a4..a0d9c8ac769 100644 --- a/lib/rust/ensogl/core/src/gui/component.rs +++ b/lib/rust/ensogl/core/src/gui/component.rs @@ -59,11 +59,16 @@ impl ShapeView { fn init_on_scene_layer_changed(&self) { let weak_model = Rc::downgrade(&self.model); - self.display_object().set_on_scene_layer_changed(move |scene, old_layer, new_layer| { - if let Some(model) = weak_model.upgrade() { - model.on_scene_layer_changed(scene, old_layer, new_layer) - } - }); + let display_object = self.display_object(); + let network = &display_object.network; + frp::extend! { network + eval display_object.on_layer_change([] ((scene, old_layer, new_layer)) { + let scene = scene.as_ref().unwrap(); + if let Some(model) = weak_model.upgrade() { + model.on_scene_layer_changed(scene, old_layer.as_ref(), new_layer.as_ref()); + } + }); + } } } @@ -298,7 +303,7 @@ impl Widget { } impl display::Object for Widget { - fn display_object(&self) -> &display::object::Instance { + fn display_object(&self) -> &display::object::Instance { &self.data.display_object } } diff --git a/lib/rust/ensogl/core/src/system/gpu/data/uniform.rs b/lib/rust/ensogl/core/src/system/gpu/data/uniform.rs index cf111943328..aab01bf178e 100644 --- a/lib/rust/ensogl/core/src/system/gpu/data/uniform.rs +++ b/lib/rust/ensogl/core/src/system/gpu/data/uniform.rs @@ -191,6 +191,11 @@ impl { self.value = value; } + /// Modifies the value of this uniform. + pub fn modify(&mut self, f: impl FnOnce(&mut Value)) { + f(&mut self.value); + } + // /// Checks whether the uniform was changed and not yet updated. // pub fn check_dirty(&self) -> bool { // self.dirty diff --git a/lib/rust/ensogl/example/complex-shape-system/src/lib.rs b/lib/rust/ensogl/example/complex-shape-system/src/lib.rs index 0a5adfb4ad5..a0d616b4ded 100644 --- a/lib/rust/ensogl/example/complex-shape-system/src/lib.rs +++ b/lib/rust/ensogl/example/complex-shape-system/src/lib.rs @@ -121,7 +121,7 @@ pub fn main() { .on .before_frame .add(move |_time| { - mask.set_position_x(((frame as f32) / 30.0).sin() * 100.0); + mask.set_x(((frame as f32) / 30.0).sin() * 100.0); let _keep_alive = &navigator; let _keep_alive = &style_watch; let _keep_alive = &theme_manager; diff --git a/lib/rust/ensogl/example/dom-symbols/src/lib.rs b/lib/rust/ensogl/example/dom-symbols/src/lib.rs index 6a0d65a09ce..69e671a0330 100644 --- a/lib/rust/ensogl/example/dom-symbols/src/lib.rs +++ b/lib/rust/ensogl/example/dom-symbols/src/lib.rs @@ -30,9 +30,49 @@ use ensogl_core::display::symbol::geometry::SpriteSystem; use ensogl_core::display::symbol::DomSymbol; use ensogl_core::system::web; use nalgebra::Vector2; -use nalgebra::Vector3; +// ============== +// === Export === +// ============== + +pub use ensogl_core::system::web::dom::Shape; + + + +const ELEM_COUNT: i32 = 10; +const HTML_PADDING: f32 = 10.0; +const VERTICAL_MARGIN: f32 = 10.0; +const HEIGHT_FRACTION: f32 = 0.8; + +fn update_shape(screen: Shape, sprites: &[Sprite], dom_symbols: &[DomSymbol]) { + let side_offset = 10.0; + let display_objects = sprites + .iter() + .map(|s| s.display_object()) + .interleave(dom_symbols.iter().map(|s| s.display_object())); + let width = (screen.width - 3.0 * side_offset) / ELEM_COUNT as f32 + 2.0 * side_offset; + let height = screen.height; + for (i, object) in display_objects.enumerate() { + let fi = i as f32; + let x = -screen.width / 2.0 + width / 2.0 + (width - 2.0 * side_offset) * fi; + object.set_position(Vector3(x, 0.0, 0.0)); + } + for symbol in sprites { + let size = Vector2::new(width, height * HEIGHT_FRACTION); + symbol.size.set(size); + symbol.mod_y(|y| y - screen.height / 2.0 + size.y / 2.0 + VERTICAL_MARGIN); + } + for symbol in dom_symbols { + let size = Vector2::new(width, height * HEIGHT_FRACTION - HTML_PADDING * 2.0); + symbol.set_size(size); + symbol.mod_x(|y| y - HTML_PADDING); + symbol.mod_y(|y| y + HTML_PADDING); + symbol.mod_y(|y| { + y + screen.height / 2.0 - (size.y + HTML_PADDING * 2.0) / 2.0 - VERTICAL_MARGIN + }); + } +} #[entry_point] #[allow(dead_code)] @@ -41,7 +81,6 @@ pub fn main() { let world = World::new().displayed_in("root"); let scene = &world.default_scene; let camera = scene.camera(); - let screen = camera.screen(); let navigator = Navigator::new(scene, &camera); let sprite_system = SpriteSystem::new(); world.add_child(&sprite_system); @@ -50,44 +89,49 @@ pub fn main() { let dom_back_layer = &scene.dom.layers.back; let mut sprites: Vec = default(); - let mut css3d_objects: Vec = default(); - let count = 10; - for i in 0..count { - let x = i as f32; - let width = screen.width * 1.5 / count as f32; - let height = screen.height; - let y = height / 2.0; + let mut dom_symbols: Vec = default(); + for i in 0..ELEM_COUNT { + let fi = i as f32; if i % 2 == 0 { - let height = height * 0.75; - let size = Vector2::new(width, height); - let position = Vector3::new(width / 1.5 * x + width / 2.0, y, 0.0); let sprite = sprite_system.new_instance(); - sprite.size.set(size); - sprite.mod_position(|t| *t = position); sprites.push(sprite); } else { let div = web::document.create_div_or_panic(); div.set_style_or_warn("width", "100%"); div.set_style_or_warn("height", "100%"); - div.set_inner_html("top-left"); + div.set_style_or_warn("padding", format!("{HTML_PADDING}px")); + div.set_style_or_warn( + "font-family", + "SF Pro Display,SF Pro Icons,Helvetica Neue,Helvetica,Arial,sans-serif", + ); + div.set_inner_html( + "This is a dom element.
\ + Black boxes are WebGL sprites.

\ + Try zooming and moving the scene!", + ); - let size = Vector2::new(width, height); - let position = Vector3::new(width / 1.5 * x + width / 2.0, y, 0.0); let object = DomSymbol::new(&div); dom_front_layer.manage(&object); world.add_child(&object); - let r = ((x + 0.0) * 16.0) as u8; - let g = ((x + 2.0) * 32.0) as u8; - let b = ((x + 4.0) * 64.0) as u8; + let r = ((fi + 2.0) * 64.0 / (ELEM_COUNT as f32)) as u8; + let g = ((fi + 4.0) * 128.0 / (ELEM_COUNT as f32)) as u8; + let b = ((fi + 8.0) * 255.0 / (ELEM_COUNT as f32)) as u8; let color = iformat!("rgb({r},{g},{b})"); div.set_style_or_warn("background-color", color); - object.dom().append_or_warn(&div); - object.set_size(size); - object.mod_position(|t| *t = position); - css3d_objects.push(object); + dom_symbols.push(object); } } + + let network = ensogl_core::frp::Network::new("network"); + + let sprites2 = sprites.clone(); + let dom_symbols2 = dom_symbols.clone(); + ensogl_core::frp::extend! { network + eval scene.frp.shape ([] (screen) update_shape(*screen, &sprites2, &dom_symbols2)); + } + + let layers = vec![dom_front_layer.clone_ref(), dom_back_layer.clone_ref()]; let mut iter_to_change = 0; @@ -97,14 +141,14 @@ pub fn main() { .on .before_frame .add(move |_| { + let _keep_alive = &network; let _keep_alive = &navigator; - let _keep_alive = &sprites; let _keep_alive = &sprite_system; if iter_to_change == 0 { iter_to_change = 50; i = (i + 1) % 2; - for (j, object) in css3d_objects.iter_mut().enumerate() { + for (j, object) in dom_symbols.iter_mut().enumerate() { layers[(i + j) % 2].manage(object); } } diff --git a/lib/rust/ensogl/example/focus-management/src/lib.rs b/lib/rust/ensogl/example/focus-management/src/lib.rs index bfeb5997f80..808fb4a92bd 100644 --- a/lib/rust/ensogl/example/focus-management/src/lib.rs +++ b/lib/rust/ensogl/example/focus-management/src/lib.rs @@ -37,7 +37,22 @@ mod rectangle { let rect = Rect((&width, &height)).corners_radius(10.0.px()); let inside = rect.shrink(BORDER_SIZE.px()); let border = &inside.grow((border_size - 1.0).px()) - &inside; - let shape = inside.fill(color) + border.fill(border_color); + let shape = border.fill(border_color) + inside.fill(color::Rgba(0.0,0.0,0.0,0.2)); + // let line = Line(4.0.px()).fill(color::Rgba(1.0,0.0,0.0,1.0)); + + // let shape = inside.fill(color::Rgba(0.0,0.0,0.0,0.2)); + // let shape = shape + line; + shape.into() + } + } +} + +mod rectangle2 { + use super::*; + ensogl_core::shape! { + (style: Style) { + let rect = Rect((10.px(), 10.px())); + let shape = rect.fill(color::Rgba::new(0.0, 1.0, 0.0, 1.0)); shape.into() } } @@ -108,8 +123,13 @@ pub fn main() { let container = define_rect(container_size * 2.0, container_size, network); let left_stack = define_stack(network); let right_stack = define_stack(network); - left_stack.mod_position_x(|x| x - (container_size) / 2.0); - right_stack.mod_position_x(|x| x + (container_size) / 2.0); + left_stack.mod_x(|x| x - (container_size) / 2.0); + right_stack.mod_x(|x| x + (container_size) / 2.0); + + let rect = rectangle2::View::new(); + rect.size.set(Vector2::new(2.0, 2.0)); + world.add_child(&rect); + mem::forget(rect); world.add_child(&container); container.add_child(&left_stack); diff --git a/lib/rust/ensogl/example/grid-view/src/lib.rs b/lib/rust/ensogl/example/grid-view/src/lib.rs index 8542f94657c..5e4e4e1a0f3 100644 --- a/lib/rust/ensogl/example/grid-view/src/lib.rs +++ b/lib/rust/ensogl/example/grid-view/src/lib.rs @@ -189,10 +189,10 @@ fn init(app: &Application) { let mut positions = itertools::iproduct!([-450.0, 50.0], [350.0, -50.0]).map(pair_to_vec2); grids_layer.add(&plain_grid_view); - plain_grid_view.set_position_xy(positions.next().unwrap()); + plain_grid_view.set_xy(positions.next().unwrap()); for (view, position) in grid_views_with_headers.iter().zip(positions) { grids_layer.add(view); - view.set_position_xy(position); + view.set_xy(position); } let view = &grid_views_with_headers[0]; diff --git a/lib/rust/ensogl/example/profiling-run-graph/src/lib.rs b/lib/rust/ensogl/example/profiling-run-graph/src/lib.rs index f125bc3147e..a34f5a401da 100644 --- a/lib/rust/ensogl/example/profiling-run-graph/src/lib.rs +++ b/lib/rust/ensogl/example/profiling-run-graph/src/lib.rs @@ -88,7 +88,7 @@ pub async fn main() { let graph_height: f32 = flame_graph.height(); let sequence_diagram_offset = graph_height + sequence_diagram.height.value(); - sequence_diagram.set_position_y(-sequence_diagram_offset); + sequence_diagram.set_y(-sequence_diagram_offset); scene.add_child(&sequence_diagram); scene.layers.main.add(&sequence_diagram); diff --git a/lib/rust/ensogl/example/scroll-area/src/lib.rs b/lib/rust/ensogl/example/scroll-area/src/lib.rs index 930fdb0fde6..1dd02763e91 100644 --- a/lib/rust/ensogl/example/scroll-area/src/lib.rs +++ b/lib/rust/ensogl/example/scroll-area/src/lib.rs @@ -101,7 +101,7 @@ fn init(app: &Application) { theme::builtin::light::enable(app); let scene = &app.display.default_scene; - scene.camera().set_position_xy(Vector2(100.0, -100.0)); + scene.camera().set_xy(Vector2(100.0, -100.0)); let navigator = Navigator::new(scene, &scene.camera()); navigator.disable_wheel_panning(); @@ -125,8 +125,8 @@ fn init(app: &Application) { scroll_area.add_child(&background); scene.layers.below_main.add(&background); background.size.set(Vector2::new(200.0, 200.0)); - background.set_position_x(100.0); - background.set_position_y(-100.0); + background.set_x(100.0); + background.set_y(-100.0); std::mem::forget(background); @@ -135,8 +135,8 @@ fn init(app: &Application) { let content = content::View::new(); scroll_area.content().add_child(&content); content.size.set(Vector2::new(300.0, 1000.0)); - content.set_position_x(150.0); - content.set_position_y(-500.0); + content.set_x(150.0); + content.set_y(-500.0); std::mem::forget(content); diff --git a/lib/rust/ensogl/example/slider/src/lib.rs b/lib/rust/ensogl/example/slider/src/lib.rs index 0933fd326d7..e9d848d643d 100644 --- a/lib/rust/ensogl/example/slider/src/lib.rs +++ b/lib/rust/ensogl/example/slider/src/lib.rs @@ -80,7 +80,7 @@ fn init(app: &Application) { let slider2 = make_slider(app); slider2.inner().frp.set_width(400.0); slider2.inner().frp.set_height(50.0); - slider2.inner().set_position_y(60.0); + slider2.inner().set_y(60.0); slider2.inner().frp.set_slider_track_color(color::Lcha(0.4, 0.7, 0.2, 1.0)); slider2.inner().frp.set_value_text_color(color::Lcha(0.2, 0.7, 0.7, 1.0)); slider2.inner().frp.set_slider_disabled(true); @@ -89,7 +89,7 @@ fn init(app: &Application) { let slider3 = make_slider(app); slider3.inner().frp.set_width(400.0); slider3.inner().frp.set_height(50.0); - slider3.inner().set_position_y(120.0); + slider3.inner().set_y(120.0); slider3.inner().frp.set_slider_track_color(color::Lcha(0.4, 0.7, 0.7, 1.0)); slider3.inner().frp.set_value_text_color(color::Lcha(0.2, 0.7, 0.2, 1.0)); slider3.inner().frp.set_label("Inner label"); @@ -98,7 +98,7 @@ fn init(app: &Application) { let slider4 = make_slider(app); slider4.inner().frp.set_width(400.0); slider4.inner().frp.set_height(50.0); - slider4.inner().set_position_y(180.0); + slider4.inner().set_y(180.0); slider4.inner().frp.set_slider_track_color(color::Lcha(0.4, 0.7, 0.2, 1.0)); slider4.inner().frp.set_value_text_color(color::Lcha(0.2, 0.7, 0.7, 1.0)); slider4.inner().frp.set_label("Disabled label"); diff --git a/lib/rust/ensogl/example/text-area/src/lib.rs b/lib/rust/ensogl/example/text-area/src/lib.rs index 4c216f81114..28d8deb9363 100644 --- a/lib/rust/ensogl/example/text-area/src/lib.rs +++ b/lib/rust/ensogl/example/text-area/src/lib.rs @@ -128,22 +128,22 @@ impl Borders { eval area.height ([borders](h) { borders.right.size.set(Vector2(BORDER_WIDTH + BORDER_PADDING * 2.0, *h)); borders.left.size.set(Vector2(BORDER_WIDTH + BORDER_PADDING * 2.0, *h)); - borders.right.set_position_y(-h/2.0); - borders.left.set_position_y(-h/2.0); + borders.right.set_y(-h/2.0); + borders.left.set_y(-h/2.0); borders.bottom_changed_frame_hold.set(DEBUG_FRAME_HOLD); borders.bottom.color_rgba.set(RED); - borders.bottom.set_position_y(-*h); + borders.bottom.set_y(-*h); }); eval area.width ([borders](w) { borders.top.size.set(Vector2(*w, BORDER_WIDTH + BORDER_PADDING * 2.0)); borders.bottom.size.set(Vector2(*w, BORDER_WIDTH + BORDER_PADDING * 2.0)); - borders.top.set_position_x(w/2.0); - borders.bottom.set_position_x(w/2.0); + borders.top.set_x(w/2.0); + borders.bottom.set_x(w/2.0); borders.right_changed_frame_hold.set(DEBUG_FRAME_HOLD); borders.right.color_rgba.set(RED); - borders.right.set_position_x(*w); + borders.right.set_x(*w); }); } mem::forget(frp); diff --git a/lib/rust/types/Cargo.toml b/lib/rust/types/Cargo.toml index fc7173c75c7..1c4ea450833 100644 --- a/lib/rust/types/Cargo.toml +++ b/lib/rust/types/Cargo.toml @@ -12,3 +12,7 @@ nalgebra = { version = "0.26.1" } num-traits = { version = "0.2" } paste = "1.0.7" serde = { version = "1.0", features = ["derive"], optional = true } +enso-prelude = { path = "../prelude" } + +[build-dependencies] +enso-prelude = { path = "../prelude" } diff --git a/lib/rust/types/build.rs b/lib/rust/types/build.rs new file mode 100644 index 00000000000..90899e957fa --- /dev/null +++ b/lib/rust/types/build.rs @@ -0,0 +1,177 @@ +//! Generation of Dim* macros, macros allowing generation of swizzling getters and setters. + +// === Non-Standard Linter Configuration === +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::let_and_return)] +#![allow(clippy::option_map_unit_fn)] +#![allow(clippy::precedence)] +#![allow(dead_code)] +#![deny(non_ascii_idents)] +#![deny(unconditional_recursion)] +#![warn(unsafe_code)] +#![warn(missing_copy_implementations)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![warn(trivial_casts)] +#![warn(trivial_numeric_casts)] +#![warn(unused_import_braces)] +#![warn(unused_qualifications)] + +use enso_prelude::*; + +use std::fmt::Write; +use std::fs::File; +use std::io::Write as IoWrite; + + + +// ================= +// === Constants === +// ================= + +const FILE: &str = "src/dim_macros.rs"; +const AXES: &[&str] = &["x", "y", "z", "w"]; +const INDENT_SIZE: usize = 4; + + + +// ======================== +// === Formatting Utils === +// ======================== + +fn indent(level: usize) -> String { + " ".repeat(level * INDENT_SIZE) +} + + + +// ====================== +// === Implementation === +// ====================== + +/// Generates swizzling data. The [`base_dim`] describes what dimension the data should be generated +/// in. For example, if it is set to 3, all of "x", "y", and "z" axes will be combined to generate +/// the result. The [`dim`] describes the dimension of the swizzling. For example, if it is set to +/// 2, the result will contain 2-dimensional coordinates, like "xy", or "yz". If the [`unique`] flag +/// is set, the generated swizzling will not have repeated axes (e.g. `xx` is not allowed). +/// +/// The output is a vector of four elements: +/// - The swizzling name, like "xy", "xyz", "xz", etc. +/// - The swizzling dimension. +/// - The swizzling component indexes. For example [0, 2] for "xz". +/// - The enumeration of components. For example [0, 1] for "xz". +/// +/// For example, for the base dimension of 3 and the dimension of 2, the following swizzles will be +/// generated: +/// +/// ```text +/// xz 2 [0, 2] [0, 1] +/// yz 2 [1, 2] [0, 1] +/// zx 2 [2, 0] [0, 1] +/// zy 2 [2, 1] [0, 1] +/// zz 2 [2, 2] [0, 1] +/// ``` +/// +/// See the generated [`FILE`] to see the result of this script. +fn gen_swizzling( + base_dim: usize, + dim: usize, + unique: bool, +) -> Vec<(Vec, usize, Vec, Vec)> { + let mut vec: Vec<(Vec, Vec, Vec)> = vec![(vec![], vec![], vec![])]; + for _ in 0..dim { + vec = vec + .clone() + .into_iter() + .cartesian_product(AXES[0..base_dim].iter().enumerate()) + .filter_map(|((mut prod, mut ixs, mut ord), (ix, axis))| { + if unique && ixs.contains(&ix) { + return None; + } + prod.push(axis.to_string()); + ixs.push(ix); + ord.push(ord.len()); + Some((prod, ixs, ord)) + }) + .collect_vec(); + } + vec.into_iter().map(|(prod, ixs, ord)| (prod, dim, ixs, ord)).collect_vec() +} + +/// Just like [`gen_swizzling`], but the output always contains the dimension component. For +/// example, if the dimension was set to 2, the output will contain all swizzling combinations that +/// contain the "z" component. +fn gen_swizzling_force_dim_component( + input_dim: usize, + dim: usize, + unique: bool, +) -> Vec<(Vec, usize, Vec, Vec)> { + let axe = AXES[input_dim - 1]; + gen_swizzling(input_dim, dim, unique) + .into_iter() + .filter(|(axes, _, _, _)| axes.contains(&axe.to_string())) + .collect() +} + +fn gen_swizzling_macro_branch(input_dim: usize, unique: bool) -> String { + let mut out = String::new(); + out.write_str(&format!( + "{}({}, $f: ident $(,$($args:tt)*)?) => {{ $f! {{ $([$($args)*])? {}\n", + indent(1), + input_dim, + input_dim, + )) + .unwrap(); + + for dim in 1..input_dim { + for (axes, dim, ixs, ord) in gen_swizzling_force_dim_component(input_dim, dim, unique) { + out.write_str(&format!("{}{} {} {:?} {:?}\n", indent(2), axes.join(""), dim, ixs, ord)) + .unwrap(); + } + } + for (axes, dim, ixs, ord) in gen_swizzling(input_dim, input_dim, unique) { + out.write_str(&format!("{}{} {} {:?} {:?}\n", indent(2), axes.join(""), dim, ixs, ord)) + .unwrap(); + } + out.write_str(&format!("{}}}}};\n", indent(1))).unwrap(); + out +} + +/// The generated macro accepts two arguments, the dimension of the swizzling and another macro name +/// that should be called with the swizzling data. The provided macro will be called with the chosen +/// dimension and the data generated by the [`gen_swizzling_macro_branch`] function. +/// +/// See the generated [`FILE`] to see the result of this script. +fn gen_swizzling_macro(unique: bool) -> String { + let mut out = String::new(); + let sfx = if unique { "_unique" } else { "" }; + out.write_str("/// Swizzling data for the given dimension.\n").unwrap(); + out.write_str("/// See the [`build.rs`] file to learn more.\n").unwrap(); + out.write_str("#[macro_export]\n").unwrap(); + out.write_str(&format!("macro_rules! with_swizzling_for_dim{} {{\n", sfx)).unwrap(); + out.write_str(&gen_swizzling_macro_branch(1, unique)).unwrap(); + out.write_str(&gen_swizzling_macro_branch(2, unique)).unwrap(); + out.write_str(&gen_swizzling_macro_branch(3, unique)).unwrap(); + out.write_str(&gen_swizzling_macro_branch(4, unique)).unwrap(); + out.write_str("}").unwrap(); + out +} + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let mut file = File::create(FILE).unwrap(); + let warning = "THIS IS AN AUTO-GENERATED FILE. DO NOT EDIT IT DIRECTLY!"; + let border = "!".repeat(warning.len()); + + let mut out = String::new(); + out.write_str("//! Macros allowing generation of swizzling getters and setters.\n").unwrap(); + out.write_str("//! See the docs of [`build.rs`] and usage places to learn more.\n").unwrap(); + out.write_str(&format!("\n// {}\n", border)).unwrap(); + out.write_str("// THIS IS AN AUTO-GENERATED FILE. DO NOT EDIT IT DIRECTLY!\n").unwrap(); + out.write_str(&format!("// {}\n\n\n", border)).unwrap(); + out.write_str(&gen_swizzling_macro(false)).unwrap(); + out.write_str("\n\n").unwrap(); + out.write_str(&gen_swizzling_macro(true)).unwrap(); + out.write_str("\n").unwrap(); + file.write_all(out.as_bytes()).unwrap(); +} diff --git a/lib/rust/types/src/algebra.rs b/lib/rust/types/src/algebra.rs index 5c8f0ed11cf..8875dad4bf5 100644 --- a/lib/rust/types/src/algebra.rs +++ b/lib/rust/types/src/algebra.rs @@ -15,6 +15,7 @@ use nalgebra::Scalar; // === Export === // ============== +pub use crate::dim::*; pub use nalgebra::Matrix2; pub use nalgebra::Matrix2x3; pub use nalgebra::Matrix2x4; @@ -551,1383 +552,3 @@ macro_rules! impl_saturating_integer { } impl_saturating_integer!(u8, u16, u32, u64, u128, usize); - - - -// ================== -// === Dimensions === -// ================== - -/// Component accessors and swizzling for 1-dimensional types. -#[allow(missing_docs)] -pub trait Dim1 { - /// The type of 1-dimensional projection of this type. For example, for `Vector4` this is - /// `f32`. - type Dim1Type; - fn x(&self) -> Self::Dim1Type; -} - -/// Component accessors and swizzling for 2-dimensional types. -#[allow(missing_docs)] -pub trait Dim2: Dim1 { - /// The type of 2-dimensional projection of this type. For example, for `Vector4` this is - /// `Vector2`. - type Dim2Type; - fn y(&self) -> Self::Dim1Type; - fn xx(&self) -> Self::Dim2Type; - fn xy(&self) -> Self::Dim2Type; - fn yy(&self) -> Self::Dim2Type; - fn yx(&self) -> Self::Dim2Type; -} - -/// Component accessors and swizzling for 3-dimensional types. -#[allow(missing_docs)] -pub trait Dim3: Dim2 { - /// The type of 3-dimensional projection of this type. For example, for `Vector4` this is - /// `Vector3`. - type Dim3Type; - fn z(&self) -> Self::Dim1Type; - fn zz(&self) -> Self::Dim2Type; - fn xz(&self) -> Self::Dim2Type; - fn zx(&self) -> Self::Dim2Type; - fn yz(&self) -> Self::Dim2Type; - fn zy(&self) -> Self::Dim2Type; - - fn xxx(&self) -> Self::Dim3Type; - fn xxy(&self) -> Self::Dim3Type; - fn xxz(&self) -> Self::Dim3Type; - fn xyx(&self) -> Self::Dim3Type; - fn xyy(&self) -> Self::Dim3Type; - fn xyz(&self) -> Self::Dim3Type; - fn xzx(&self) -> Self::Dim3Type; - fn xzy(&self) -> Self::Dim3Type; - fn xzz(&self) -> Self::Dim3Type; - fn yxx(&self) -> Self::Dim3Type; - fn yxy(&self) -> Self::Dim3Type; - fn yxz(&self) -> Self::Dim3Type; - fn yyx(&self) -> Self::Dim3Type; - fn yyy(&self) -> Self::Dim3Type; - fn yyz(&self) -> Self::Dim3Type; - fn yzx(&self) -> Self::Dim3Type; - fn yzy(&self) -> Self::Dim3Type; - fn yzz(&self) -> Self::Dim3Type; - fn zxx(&self) -> Self::Dim3Type; - fn zxy(&self) -> Self::Dim3Type; - fn zxz(&self) -> Self::Dim3Type; - fn zyx(&self) -> Self::Dim3Type; - fn zyy(&self) -> Self::Dim3Type; - fn zyz(&self) -> Self::Dim3Type; - fn zzx(&self) -> Self::Dim3Type; - fn zzy(&self) -> Self::Dim3Type; - fn zzz(&self) -> Self::Dim3Type; -} - -/// Component accessors and swizzling for 4-dimensional types. -#[allow(missing_docs)] -pub trait Dim4: Dim3 { - /// The type of 4-dimensional projection of this type. For example, for `Vector4` this is - /// `Vector4`. - type Dim4Type; - fn w(&self) -> Self::Dim1Type; - fn ww(&self) -> Self::Dim2Type; - fn xw(&self) -> Self::Dim2Type; - fn wx(&self) -> Self::Dim2Type; - fn yw(&self) -> Self::Dim2Type; - fn wy(&self) -> Self::Dim2Type; - fn zw(&self) -> Self::Dim2Type; - fn wz(&self) -> Self::Dim2Type; - - fn xxw(&self) -> Self::Dim3Type; - fn xyw(&self) -> Self::Dim3Type; - fn xzw(&self) -> Self::Dim3Type; - fn yxw(&self) -> Self::Dim3Type; - fn yyw(&self) -> Self::Dim3Type; - fn yzw(&self) -> Self::Dim3Type; - fn zxw(&self) -> Self::Dim3Type; - fn zyw(&self) -> Self::Dim3Type; - fn zzw(&self) -> Self::Dim3Type; - fn xwx(&self) -> Self::Dim3Type; - fn xwy(&self) -> Self::Dim3Type; - fn xwz(&self) -> Self::Dim3Type; - fn ywx(&self) -> Self::Dim3Type; - fn ywy(&self) -> Self::Dim3Type; - fn ywz(&self) -> Self::Dim3Type; - fn zwx(&self) -> Self::Dim3Type; - fn zwy(&self) -> Self::Dim3Type; - fn zwz(&self) -> Self::Dim3Type; - fn wxx(&self) -> Self::Dim3Type; - fn wxy(&self) -> Self::Dim3Type; - fn wxz(&self) -> Self::Dim3Type; - fn wyx(&self) -> Self::Dim3Type; - fn wyy(&self) -> Self::Dim3Type; - fn wyz(&self) -> Self::Dim3Type; - fn wzx(&self) -> Self::Dim3Type; - fn wzy(&self) -> Self::Dim3Type; - fn wzz(&self) -> Self::Dim3Type; - - fn xxxx(&self) -> Self::Dim4Type; - fn xxxy(&self) -> Self::Dim4Type; - fn xxxz(&self) -> Self::Dim4Type; - fn xxxw(&self) -> Self::Dim4Type; - fn xxyx(&self) -> Self::Dim4Type; - fn xxyy(&self) -> Self::Dim4Type; - fn xxyz(&self) -> Self::Dim4Type; - fn xxyw(&self) -> Self::Dim4Type; - fn xxzx(&self) -> Self::Dim4Type; - fn xxzy(&self) -> Self::Dim4Type; - fn xxzz(&self) -> Self::Dim4Type; - fn xxzw(&self) -> Self::Dim4Type; - fn xxwx(&self) -> Self::Dim4Type; - fn xxwy(&self) -> Self::Dim4Type; - fn xxwz(&self) -> Self::Dim4Type; - fn xxww(&self) -> Self::Dim4Type; - fn xyxx(&self) -> Self::Dim4Type; - fn xyxy(&self) -> Self::Dim4Type; - fn xyxz(&self) -> Self::Dim4Type; - fn xyxw(&self) -> Self::Dim4Type; - fn xyyx(&self) -> Self::Dim4Type; - fn xyyy(&self) -> Self::Dim4Type; - fn xyyz(&self) -> Self::Dim4Type; - fn xyyw(&self) -> Self::Dim4Type; - fn xyzx(&self) -> Self::Dim4Type; - fn xyzy(&self) -> Self::Dim4Type; - fn xyzz(&self) -> Self::Dim4Type; - fn xyzw(&self) -> Self::Dim4Type; - fn xywx(&self) -> Self::Dim4Type; - fn xywy(&self) -> Self::Dim4Type; - fn xywz(&self) -> Self::Dim4Type; - fn xyww(&self) -> Self::Dim4Type; - fn xzxx(&self) -> Self::Dim4Type; - fn xzxy(&self) -> Self::Dim4Type; - fn xzxz(&self) -> Self::Dim4Type; - fn xzxw(&self) -> Self::Dim4Type; - fn xzyx(&self) -> Self::Dim4Type; - fn xzyy(&self) -> Self::Dim4Type; - fn xzyz(&self) -> Self::Dim4Type; - fn xzyw(&self) -> Self::Dim4Type; - fn xzzx(&self) -> Self::Dim4Type; - fn xzzy(&self) -> Self::Dim4Type; - fn xzzz(&self) -> Self::Dim4Type; - fn xzzw(&self) -> Self::Dim4Type; - fn xzwx(&self) -> Self::Dim4Type; - fn xzwy(&self) -> Self::Dim4Type; - fn xzwz(&self) -> Self::Dim4Type; - fn xzww(&self) -> Self::Dim4Type; - fn xwxx(&self) -> Self::Dim4Type; - fn xwxy(&self) -> Self::Dim4Type; - fn xwxz(&self) -> Self::Dim4Type; - fn xwxw(&self) -> Self::Dim4Type; - fn xwyx(&self) -> Self::Dim4Type; - fn xwyy(&self) -> Self::Dim4Type; - fn xwyz(&self) -> Self::Dim4Type; - fn xwyw(&self) -> Self::Dim4Type; - fn xwzx(&self) -> Self::Dim4Type; - fn xwzy(&self) -> Self::Dim4Type; - fn xwzz(&self) -> Self::Dim4Type; - fn xwzw(&self) -> Self::Dim4Type; - fn xwwx(&self) -> Self::Dim4Type; - fn xwwy(&self) -> Self::Dim4Type; - fn xwwz(&self) -> Self::Dim4Type; - fn xwww(&self) -> Self::Dim4Type; - fn yxxx(&self) -> Self::Dim4Type; - fn yxxy(&self) -> Self::Dim4Type; - fn yxxz(&self) -> Self::Dim4Type; - fn yxxw(&self) -> Self::Dim4Type; - fn yxyx(&self) -> Self::Dim4Type; - fn yxyy(&self) -> Self::Dim4Type; - fn yxyz(&self) -> Self::Dim4Type; - fn yxyw(&self) -> Self::Dim4Type; - fn yxzx(&self) -> Self::Dim4Type; - fn yxzy(&self) -> Self::Dim4Type; - fn yxzz(&self) -> Self::Dim4Type; - fn yxzw(&self) -> Self::Dim4Type; - fn yxwx(&self) -> Self::Dim4Type; - fn yxwy(&self) -> Self::Dim4Type; - fn yxwz(&self) -> Self::Dim4Type; - fn yxww(&self) -> Self::Dim4Type; - fn yyxx(&self) -> Self::Dim4Type; - fn yyxy(&self) -> Self::Dim4Type; - fn yyxz(&self) -> Self::Dim4Type; - fn yyxw(&self) -> Self::Dim4Type; - fn yyyx(&self) -> Self::Dim4Type; - fn yyyy(&self) -> Self::Dim4Type; - fn yyyz(&self) -> Self::Dim4Type; - fn yyyw(&self) -> Self::Dim4Type; - fn yyzx(&self) -> Self::Dim4Type; - fn yyzy(&self) -> Self::Dim4Type; - fn yyzz(&self) -> Self::Dim4Type; - fn yyzw(&self) -> Self::Dim4Type; - fn yywx(&self) -> Self::Dim4Type; - fn yywy(&self) -> Self::Dim4Type; - fn yywz(&self) -> Self::Dim4Type; - fn yyww(&self) -> Self::Dim4Type; - fn yzxx(&self) -> Self::Dim4Type; - fn yzxy(&self) -> Self::Dim4Type; - fn yzxz(&self) -> Self::Dim4Type; - fn yzxw(&self) -> Self::Dim4Type; - fn yzyx(&self) -> Self::Dim4Type; - fn yzyy(&self) -> Self::Dim4Type; - fn yzyz(&self) -> Self::Dim4Type; - fn yzyw(&self) -> Self::Dim4Type; - fn yzzx(&self) -> Self::Dim4Type; - fn yzzy(&self) -> Self::Dim4Type; - fn yzzz(&self) -> Self::Dim4Type; - fn yzzw(&self) -> Self::Dim4Type; - fn yzwx(&self) -> Self::Dim4Type; - fn yzwy(&self) -> Self::Dim4Type; - fn yzwz(&self) -> Self::Dim4Type; - fn yzww(&self) -> Self::Dim4Type; - fn ywxx(&self) -> Self::Dim4Type; - fn ywxy(&self) -> Self::Dim4Type; - fn ywxz(&self) -> Self::Dim4Type; - fn ywxw(&self) -> Self::Dim4Type; - fn ywyx(&self) -> Self::Dim4Type; - fn ywyy(&self) -> Self::Dim4Type; - fn ywyz(&self) -> Self::Dim4Type; - fn ywyw(&self) -> Self::Dim4Type; - fn ywzx(&self) -> Self::Dim4Type; - fn ywzy(&self) -> Self::Dim4Type; - fn ywzz(&self) -> Self::Dim4Type; - fn ywzw(&self) -> Self::Dim4Type; - fn ywwx(&self) -> Self::Dim4Type; - fn ywwy(&self) -> Self::Dim4Type; - fn ywwz(&self) -> Self::Dim4Type; - fn ywww(&self) -> Self::Dim4Type; - fn zxxx(&self) -> Self::Dim4Type; - fn zxxy(&self) -> Self::Dim4Type; - fn zxxz(&self) -> Self::Dim4Type; - fn zxxw(&self) -> Self::Dim4Type; - fn zxyx(&self) -> Self::Dim4Type; - fn zxyy(&self) -> Self::Dim4Type; - fn zxyz(&self) -> Self::Dim4Type; - fn zxyw(&self) -> Self::Dim4Type; - fn zxzx(&self) -> Self::Dim4Type; - fn zxzy(&self) -> Self::Dim4Type; - fn zxzz(&self) -> Self::Dim4Type; - fn zxzw(&self) -> Self::Dim4Type; - fn zxwx(&self) -> Self::Dim4Type; - fn zxwy(&self) -> Self::Dim4Type; - fn zxwz(&self) -> Self::Dim4Type; - fn zxww(&self) -> Self::Dim4Type; - fn zyxx(&self) -> Self::Dim4Type; - fn zyxy(&self) -> Self::Dim4Type; - fn zyxz(&self) -> Self::Dim4Type; - fn zyxw(&self) -> Self::Dim4Type; - fn zyyx(&self) -> Self::Dim4Type; - fn zyyy(&self) -> Self::Dim4Type; - fn zyyz(&self) -> Self::Dim4Type; - fn zyyw(&self) -> Self::Dim4Type; - fn zyzx(&self) -> Self::Dim4Type; - fn zyzy(&self) -> Self::Dim4Type; - fn zyzz(&self) -> Self::Dim4Type; - fn zyzw(&self) -> Self::Dim4Type; - fn zywx(&self) -> Self::Dim4Type; - fn zywy(&self) -> Self::Dim4Type; - fn zywz(&self) -> Self::Dim4Type; - fn zyww(&self) -> Self::Dim4Type; - fn zzxx(&self) -> Self::Dim4Type; - fn zzxy(&self) -> Self::Dim4Type; - fn zzxz(&self) -> Self::Dim4Type; - fn zzxw(&self) -> Self::Dim4Type; - fn zzyx(&self) -> Self::Dim4Type; - fn zzyy(&self) -> Self::Dim4Type; - fn zzyz(&self) -> Self::Dim4Type; - fn zzyw(&self) -> Self::Dim4Type; - fn zzzx(&self) -> Self::Dim4Type; - fn zzzy(&self) -> Self::Dim4Type; - fn zzzz(&self) -> Self::Dim4Type; - fn zzzw(&self) -> Self::Dim4Type; - fn zzwx(&self) -> Self::Dim4Type; - fn zzwy(&self) -> Self::Dim4Type; - fn zzwz(&self) -> Self::Dim4Type; - fn zzww(&self) -> Self::Dim4Type; - fn zwxx(&self) -> Self::Dim4Type; - fn zwxy(&self) -> Self::Dim4Type; - fn zwxz(&self) -> Self::Dim4Type; - fn zwxw(&self) -> Self::Dim4Type; - fn zwyx(&self) -> Self::Dim4Type; - fn zwyy(&self) -> Self::Dim4Type; - fn zwyz(&self) -> Self::Dim4Type; - fn zwyw(&self) -> Self::Dim4Type; - fn zwzx(&self) -> Self::Dim4Type; - fn zwzy(&self) -> Self::Dim4Type; - fn zwzz(&self) -> Self::Dim4Type; - fn zwzw(&self) -> Self::Dim4Type; - fn zwwx(&self) -> Self::Dim4Type; - fn zwwy(&self) -> Self::Dim4Type; - fn zwwz(&self) -> Self::Dim4Type; - fn zwww(&self) -> Self::Dim4Type; - fn wxxx(&self) -> Self::Dim4Type; - fn wxxy(&self) -> Self::Dim4Type; - fn wxxz(&self) -> Self::Dim4Type; - fn wxxw(&self) -> Self::Dim4Type; - fn wxyx(&self) -> Self::Dim4Type; - fn wxyy(&self) -> Self::Dim4Type; - fn wxyz(&self) -> Self::Dim4Type; - fn wxyw(&self) -> Self::Dim4Type; - fn wxzx(&self) -> Self::Dim4Type; - fn wxzy(&self) -> Self::Dim4Type; - fn wxzz(&self) -> Self::Dim4Type; - fn wxzw(&self) -> Self::Dim4Type; - fn wxwx(&self) -> Self::Dim4Type; - fn wxwy(&self) -> Self::Dim4Type; - fn wxwz(&self) -> Self::Dim4Type; - fn wxww(&self) -> Self::Dim4Type; - fn wyxx(&self) -> Self::Dim4Type; - fn wyxy(&self) -> Self::Dim4Type; - fn wyxz(&self) -> Self::Dim4Type; - fn wyxw(&self) -> Self::Dim4Type; - fn wyyx(&self) -> Self::Dim4Type; - fn wyyy(&self) -> Self::Dim4Type; - fn wyyz(&self) -> Self::Dim4Type; - fn wyyw(&self) -> Self::Dim4Type; - fn wyzx(&self) -> Self::Dim4Type; - fn wyzy(&self) -> Self::Dim4Type; - fn wyzz(&self) -> Self::Dim4Type; - fn wyzw(&self) -> Self::Dim4Type; - fn wywx(&self) -> Self::Dim4Type; - fn wywy(&self) -> Self::Dim4Type; - fn wywz(&self) -> Self::Dim4Type; - fn wyww(&self) -> Self::Dim4Type; - fn wzxx(&self) -> Self::Dim4Type; - fn wzxy(&self) -> Self::Dim4Type; - fn wzxz(&self) -> Self::Dim4Type; - fn wzxw(&self) -> Self::Dim4Type; - fn wzyx(&self) -> Self::Dim4Type; - fn wzyy(&self) -> Self::Dim4Type; - fn wzyz(&self) -> Self::Dim4Type; - fn wzyw(&self) -> Self::Dim4Type; - fn wzzx(&self) -> Self::Dim4Type; - fn wzzy(&self) -> Self::Dim4Type; - fn wzzz(&self) -> Self::Dim4Type; - fn wzzw(&self) -> Self::Dim4Type; - fn wzwx(&self) -> Self::Dim4Type; - fn wzwy(&self) -> Self::Dim4Type; - fn wzwz(&self) -> Self::Dim4Type; - fn wzww(&self) -> Self::Dim4Type; - fn wwxx(&self) -> Self::Dim4Type; - fn wwxy(&self) -> Self::Dim4Type; - fn wwxz(&self) -> Self::Dim4Type; - fn wwxw(&self) -> Self::Dim4Type; - fn wwyx(&self) -> Self::Dim4Type; - fn wwyy(&self) -> Self::Dim4Type; - fn wwyz(&self) -> Self::Dim4Type; - fn wwyw(&self) -> Self::Dim4Type; - fn wwzx(&self) -> Self::Dim4Type; - fn wwzy(&self) -> Self::Dim4Type; - fn wwzz(&self) -> Self::Dim4Type; - fn wwzw(&self) -> Self::Dim4Type; - fn wwwx(&self) -> Self::Dim4Type; - fn wwwy(&self) -> Self::Dim4Type; - fn wwwz(&self) -> Self::Dim4Type; - fn wwww(&self) -> Self::Dim4Type; -} - -impl Dim1 for Vector4 { - type Dim1Type = T; - fn x(&self) -> Self::Dim1Type { - self.x - } -} - -impl Dim2 for Vector4 { - type Dim2Type = Vector2; - fn y(&self) -> Self::Dim1Type { - self.y - } - fn xx(&self) -> Self::Dim2Type { - Vector2::new(self.x, self.x) - } - fn xy(&self) -> Self::Dim2Type { - Vector2::new(self.x, self.y) - } - fn yy(&self) -> Self::Dim2Type { - Vector2::new(self.y, self.y) - } - fn yx(&self) -> Self::Dim2Type { - Vector2::new(self.y, self.x) - } -} - -impl Dim3 for Vector4 { - type Dim3Type = Vector3; - fn z(&self) -> Self::Dim1Type { - self.z - } - fn zz(&self) -> Self::Dim2Type { - Vector2::new(self.z, self.z) - } - fn xz(&self) -> Self::Dim2Type { - Vector2::new(self.x, self.z) - } - fn zx(&self) -> Self::Dim2Type { - Vector2::new(self.z, self.x) - } - fn yz(&self) -> Self::Dim2Type { - Vector2::new(self.y, self.z) - } - fn zy(&self) -> Self::Dim2Type { - Vector2::new(self.z, self.y) - } - - fn xxx(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.x, self.x) - } - fn xxy(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.x, self.y) - } - fn xxz(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.x, self.z) - } - fn xyx(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.y, self.x) - } - fn xyy(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.y, self.y) - } - fn xyz(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.y, self.z) - } - fn xzx(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.z, self.x) - } - fn xzy(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.z, self.y) - } - fn xzz(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.z, self.z) - } - fn yxx(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.x, self.x) - } - fn yxy(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.x, self.y) - } - fn yxz(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.x, self.z) - } - fn yyx(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.y, self.x) - } - fn yyy(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.y, self.y) - } - fn yyz(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.y, self.z) - } - fn yzx(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.z, self.x) - } - fn yzy(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.z, self.y) - } - fn yzz(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.z, self.z) - } - fn zxx(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.x, self.x) - } - fn zxy(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.x, self.y) - } - fn zxz(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.x, self.z) - } - fn zyx(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.y, self.x) - } - fn zyy(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.y, self.y) - } - fn zyz(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.y, self.z) - } - fn zzx(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.z, self.x) - } - fn zzy(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.z, self.y) - } - fn zzz(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.z, self.z) - } -} - -impl Dim4 for Vector4 { - type Dim4Type = Vector4; - fn w(&self) -> Self::Dim1Type { - self.w - } - fn ww(&self) -> Self::Dim2Type { - Vector2::new(self.w, self.w) - } - fn xw(&self) -> Self::Dim2Type { - Vector2::new(self.x, self.w) - } - fn wx(&self) -> Self::Dim2Type { - Vector2::new(self.w, self.x) - } - fn yw(&self) -> Self::Dim2Type { - Vector2::new(self.y, self.w) - } - fn wy(&self) -> Self::Dim2Type { - Vector2::new(self.w, self.y) - } - fn zw(&self) -> Self::Dim2Type { - Vector2::new(self.z, self.w) - } - fn wz(&self) -> Self::Dim2Type { - Vector2::new(self.w, self.z) - } - - fn xxw(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.x, self.w) - } - fn xyw(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.y, self.w) - } - fn xzw(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.z, self.w) - } - fn yxw(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.x, self.w) - } - fn yyw(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.y, self.w) - } - fn yzw(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.z, self.w) - } - fn zxw(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.x, self.w) - } - fn zyw(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.y, self.w) - } - fn zzw(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.z, self.w) - } - fn xwx(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.w, self.x) - } - fn xwy(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.w, self.y) - } - fn xwz(&self) -> Self::Dim3Type { - Vector3::new(self.x, self.w, self.z) - } - fn ywx(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.w, self.x) - } - fn ywy(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.w, self.y) - } - fn ywz(&self) -> Self::Dim3Type { - Vector3::new(self.y, self.w, self.z) - } - fn zwx(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.w, self.x) - } - fn zwy(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.w, self.y) - } - fn zwz(&self) -> Self::Dim3Type { - Vector3::new(self.z, self.w, self.z) - } - fn wxx(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.x, self.x) - } - fn wxy(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.x, self.y) - } - fn wxz(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.x, self.z) - } - fn wyx(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.y, self.x) - } - fn wyy(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.y, self.y) - } - fn wyz(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.y, self.z) - } - fn wzx(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.z, self.x) - } - fn wzy(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.z, self.y) - } - fn wzz(&self) -> Self::Dim3Type { - Vector3::new(self.w, self.z, self.z) - } - - fn xxxx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.x, self.x) - } - fn xxxy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.x, self.y) - } - fn xxxz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.x, self.z) - } - fn xxxw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.x, self.w) - } - fn xxyx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.y, self.x) - } - fn xxyy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.y, self.y) - } - fn xxyz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.y, self.z) - } - fn xxyw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.y, self.w) - } - fn xxzx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.z, self.x) - } - fn xxzy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.z, self.y) - } - fn xxzz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.z, self.z) - } - fn xxzw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.z, self.w) - } - fn xxwx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.w, self.x) - } - fn xxwy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.w, self.y) - } - fn xxwz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.w, self.z) - } - fn xxww(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.x, self.w, self.w) - } - fn xyxx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.x, self.x) - } - fn xyxy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.x, self.y) - } - fn xyxz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.x, self.z) - } - fn xyxw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.x, self.w) - } - fn xyyx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.y, self.x) - } - fn xyyy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.y, self.y) - } - fn xyyz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.y, self.z) - } - fn xyyw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.y, self.w) - } - fn xyzx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.z, self.x) - } - fn xyzy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.z, self.y) - } - fn xyzz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.z, self.z) - } - fn xyzw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.z, self.w) - } - fn xywx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.w, self.x) - } - fn xywy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.w, self.y) - } - fn xywz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.w, self.z) - } - fn xyww(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.y, self.w, self.w) - } - fn xzxx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.x, self.x) - } - fn xzxy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.x, self.y) - } - fn xzxz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.x, self.z) - } - fn xzxw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.x, self.w) - } - fn xzyx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.y, self.x) - } - fn xzyy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.y, self.y) - } - fn xzyz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.y, self.z) - } - fn xzyw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.y, self.w) - } - fn xzzx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.z, self.x) - } - fn xzzy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.z, self.y) - } - fn xzzz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.z, self.z) - } - fn xzzw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.z, self.w) - } - fn xzwx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.w, self.x) - } - fn xzwy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.w, self.y) - } - fn xzwz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.w, self.z) - } - fn xzww(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.z, self.w, self.w) - } - fn xwxx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.x, self.x) - } - fn xwxy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.x, self.y) - } - fn xwxz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.x, self.z) - } - fn xwxw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.x, self.w) - } - fn xwyx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.y, self.x) - } - fn xwyy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.y, self.y) - } - fn xwyz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.y, self.z) - } - fn xwyw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.y, self.w) - } - fn xwzx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.z, self.x) - } - fn xwzy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.z, self.y) - } - fn xwzz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.z, self.z) - } - fn xwzw(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.z, self.w) - } - fn xwwx(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.w, self.x) - } - fn xwwy(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.w, self.y) - } - fn xwwz(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.w, self.z) - } - fn xwww(&self) -> Self::Dim4Type { - Vector4::new(self.x, self.w, self.w, self.w) - } - fn yxxx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.x, self.x) - } - fn yxxy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.x, self.y) - } - fn yxxz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.x, self.z) - } - fn yxxw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.x, self.w) - } - fn yxyx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.y, self.x) - } - fn yxyy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.y, self.y) - } - fn yxyz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.y, self.z) - } - fn yxyw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.y, self.w) - } - fn yxzx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.z, self.x) - } - fn yxzy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.z, self.y) - } - fn yxzz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.z, self.z) - } - fn yxzw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.z, self.w) - } - fn yxwx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.w, self.x) - } - fn yxwy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.w, self.y) - } - fn yxwz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.w, self.z) - } - fn yxww(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.x, self.w, self.w) - } - fn yyxx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.x, self.x) - } - fn yyxy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.x, self.y) - } - fn yyxz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.x, self.z) - } - fn yyxw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.x, self.w) - } - fn yyyx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.y, self.x) - } - fn yyyy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.y, self.y) - } - fn yyyz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.y, self.z) - } - fn yyyw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.y, self.w) - } - fn yyzx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.z, self.x) - } - fn yyzy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.z, self.y) - } - fn yyzz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.z, self.z) - } - fn yyzw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.z, self.w) - } - fn yywx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.w, self.x) - } - fn yywy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.w, self.y) - } - fn yywz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.w, self.z) - } - fn yyww(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.y, self.w, self.w) - } - fn yzxx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.x, self.x) - } - fn yzxy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.x, self.y) - } - fn yzxz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.x, self.z) - } - fn yzxw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.x, self.w) - } - fn yzyx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.y, self.x) - } - fn yzyy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.y, self.y) - } - fn yzyz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.y, self.z) - } - fn yzyw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.y, self.w) - } - fn yzzx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.z, self.x) - } - fn yzzy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.z, self.y) - } - fn yzzz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.z, self.z) - } - fn yzzw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.z, self.w) - } - fn yzwx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.w, self.x) - } - fn yzwy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.w, self.y) - } - fn yzwz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.w, self.z) - } - fn yzww(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.z, self.w, self.w) - } - fn ywxx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.x, self.x) - } - fn ywxy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.x, self.y) - } - fn ywxz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.x, self.z) - } - fn ywxw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.x, self.w) - } - fn ywyx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.y, self.x) - } - fn ywyy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.y, self.y) - } - fn ywyz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.y, self.z) - } - fn ywyw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.y, self.w) - } - fn ywzx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.z, self.x) - } - fn ywzy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.z, self.y) - } - fn ywzz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.z, self.z) - } - fn ywzw(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.z, self.w) - } - fn ywwx(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.w, self.x) - } - fn ywwy(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.w, self.y) - } - fn ywwz(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.w, self.z) - } - fn ywww(&self) -> Self::Dim4Type { - Vector4::new(self.y, self.w, self.w, self.w) - } - fn zxxx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.x, self.x) - } - fn zxxy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.x, self.y) - } - fn zxxz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.x, self.z) - } - fn zxxw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.x, self.w) - } - fn zxyx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.y, self.x) - } - fn zxyy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.y, self.y) - } - fn zxyz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.y, self.z) - } - fn zxyw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.y, self.w) - } - fn zxzx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.z, self.x) - } - fn zxzy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.z, self.y) - } - fn zxzz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.z, self.z) - } - fn zxzw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.z, self.w) - } - fn zxwx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.w, self.x) - } - fn zxwy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.w, self.y) - } - fn zxwz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.w, self.z) - } - fn zxww(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.x, self.w, self.w) - } - fn zyxx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.x, self.x) - } - fn zyxy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.x, self.y) - } - fn zyxz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.x, self.z) - } - fn zyxw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.x, self.w) - } - fn zyyx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.y, self.x) - } - fn zyyy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.y, self.y) - } - fn zyyz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.y, self.z) - } - fn zyyw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.y, self.w) - } - fn zyzx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.z, self.x) - } - fn zyzy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.z, self.y) - } - fn zyzz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.z, self.z) - } - fn zyzw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.z, self.w) - } - fn zywx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.w, self.x) - } - fn zywy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.w, self.y) - } - fn zywz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.w, self.z) - } - fn zyww(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.y, self.w, self.w) - } - fn zzxx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.x, self.x) - } - fn zzxy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.x, self.y) - } - fn zzxz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.x, self.z) - } - fn zzxw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.x, self.w) - } - fn zzyx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.y, self.x) - } - fn zzyy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.y, self.y) - } - fn zzyz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.y, self.z) - } - fn zzyw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.y, self.w) - } - fn zzzx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.z, self.x) - } - fn zzzy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.z, self.y) - } - fn zzzz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.z, self.z) - } - fn zzzw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.z, self.w) - } - fn zzwx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.w, self.x) - } - fn zzwy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.w, self.y) - } - fn zzwz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.w, self.z) - } - fn zzww(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.z, self.w, self.w) - } - fn zwxx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.x, self.x) - } - fn zwxy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.x, self.y) - } - fn zwxz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.x, self.z) - } - fn zwxw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.x, self.w) - } - fn zwyx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.y, self.x) - } - fn zwyy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.y, self.y) - } - fn zwyz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.y, self.z) - } - fn zwyw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.y, self.w) - } - fn zwzx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.z, self.x) - } - fn zwzy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.z, self.y) - } - fn zwzz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.z, self.z) - } - fn zwzw(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.z, self.w) - } - fn zwwx(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.w, self.x) - } - fn zwwy(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.w, self.y) - } - fn zwwz(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.w, self.z) - } - fn zwww(&self) -> Self::Dim4Type { - Vector4::new(self.z, self.w, self.w, self.w) - } - fn wxxx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.x, self.x) - } - fn wxxy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.x, self.y) - } - fn wxxz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.x, self.z) - } - fn wxxw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.x, self.w) - } - fn wxyx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.y, self.x) - } - fn wxyy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.y, self.y) - } - fn wxyz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.y, self.z) - } - fn wxyw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.y, self.w) - } - fn wxzx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.z, self.x) - } - fn wxzy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.z, self.y) - } - fn wxzz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.z, self.z) - } - fn wxzw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.z, self.w) - } - fn wxwx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.w, self.x) - } - fn wxwy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.w, self.y) - } - fn wxwz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.w, self.z) - } - fn wxww(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.x, self.w, self.w) - } - fn wyxx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.x, self.x) - } - fn wyxy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.x, self.y) - } - fn wyxz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.x, self.z) - } - fn wyxw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.x, self.w) - } - fn wyyx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.y, self.x) - } - fn wyyy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.y, self.y) - } - fn wyyz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.y, self.z) - } - fn wyyw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.y, self.w) - } - fn wyzx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.z, self.x) - } - fn wyzy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.z, self.y) - } - fn wyzz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.z, self.z) - } - fn wyzw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.z, self.w) - } - fn wywx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.w, self.x) - } - fn wywy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.w, self.y) - } - fn wywz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.w, self.z) - } - fn wyww(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.y, self.w, self.w) - } - fn wzxx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.x, self.x) - } - fn wzxy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.x, self.y) - } - fn wzxz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.x, self.z) - } - fn wzxw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.x, self.w) - } - fn wzyx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.y, self.x) - } - fn wzyy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.y, self.y) - } - fn wzyz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.y, self.z) - } - fn wzyw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.y, self.w) - } - fn wzzx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.z, self.x) - } - fn wzzy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.z, self.y) - } - fn wzzz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.z, self.z) - } - fn wzzw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.z, self.w) - } - fn wzwx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.w, self.x) - } - fn wzwy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.w, self.y) - } - fn wzwz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.w, self.z) - } - fn wzww(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.z, self.w, self.w) - } - fn wwxx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.x, self.x) - } - fn wwxy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.x, self.y) - } - fn wwxz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.x, self.z) - } - fn wwxw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.x, self.w) - } - fn wwyx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.y, self.x) - } - fn wwyy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.y, self.y) - } - fn wwyz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.y, self.z) - } - fn wwyw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.y, self.w) - } - fn wwzx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.z, self.x) - } - fn wwzy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.z, self.y) - } - fn wwzz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.z, self.z) - } - fn wwzw(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.z, self.w) - } - fn wwwx(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.w, self.x) - } - fn wwwy(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.w, self.y) - } - fn wwwz(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.w, self.z) - } - fn wwww(&self) -> Self::Dim4Type { - Vector4::new(self.w, self.w, self.w, self.w) - } -} diff --git a/lib/rust/types/src/dim.rs b/lib/rust/types/src/dim.rs new file mode 100644 index 00000000000..4cd73607b30 --- /dev/null +++ b/lib/rust/types/src/dim.rs @@ -0,0 +1,157 @@ +//! Definition of Dim* traits. These traits define common operations on types that represent +//! dimensional transformations. For example, they define getters, such as `xy()`, or setters, such +//! as `set_xy(...)` on 2-dimensional types. Moreover, this module implements these traits for +//! suitable nalgebra's Vector types. + +use enso_prelude::*; + +use nalgebra; +use nalgebra::Scalar; +use nalgebra::Vector2; +use nalgebra::Vector3; +use nalgebra::Vector4; + + + +// =================== +// === Dim* Traits === +// =================== + +macro_rules! gen_dim_trait { + ([$prev_dim:tt] $dim:tt + $( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )* + ) => { paste! { + #[doc = "Component swizzling getters for "] + #[doc = stringify!($dim)] + #[doc = "`-dimensional types."] + #[allow(missing_docs)] + pub trait [] : [] { + type []; + $( + fn $name(&self) -> Self::[]; + )* + } + }}; +} + +/// An abstract, 0-dimensional type. It is defined to simplify macro definition. +pub trait Dim0 {} +impl Dim0 for T {} + +crate::with_swizzling_for_dim!(1, gen_dim_trait, 0); +crate::with_swizzling_for_dim!(2, gen_dim_trait, 1); +crate::with_swizzling_for_dim!(3, gen_dim_trait, 2); +crate::with_swizzling_for_dim!(4, gen_dim_trait, 3); + + + +// ========================= +// === DimSetter* Traits === +// ========================= + +macro_rules! gen_dim_setter_trait { + ($dim:tt + $( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )* + ) => { paste! { + #[doc = "Component swizzling setters for "] + #[doc = stringify!($dim)] + #[doc = "`-dimensional types."] + #[allow(missing_docs)] + pub trait [] : [] { + $( + fn [](&mut self, value: Self::[]); + )* + } + }}; +} + +crate::with_swizzling_for_dim_unique!(1, gen_dim_setter_trait); +crate::with_swizzling_for_dim_unique!(2, gen_dim_setter_trait); +crate::with_swizzling_for_dim_unique!(3, gen_dim_setter_trait); +crate::with_swizzling_for_dim_unique!(4, gen_dim_setter_trait); + + + +// ===================================== +// === Getters for nalgebra::Vector* === +// ===================================== + +macro_rules! gen_dim_impl_for_vector { + ([$vec:tt] $dim:tt $( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )*) => { + paste! { + impl [] for $vec { + type [] = []; + $( + fn $name(&self) -> Self::[] { + gen_dim_impl_for_vector_body!{self, $swizzling_dim, [$($dim_ix)*]} + } + )* + } + } + }; +} + +macro_rules! gen_dim_impl_for_vector_body { + ($this:tt, $swizzling_dim:tt, [$dim_ix:tt]) => { + $this[$dim_ix] + }; + ($this:tt, $swizzling_dim:tt, [$($dim_ix:tt),*]) => { paste! { + Self::[]::new( $( $this[$dim_ix] ),* ) + }}; +} + +/// A one dimensional vector, being just a value. It is used mostly to simplify macro definitions. +pub type Vector1 = T; + +crate::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector2); +crate::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector2); + +crate::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector3); +crate::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector3); +crate::with_swizzling_for_dim!(3, gen_dim_impl_for_vector, Vector3); + +crate::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector4); +crate::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector4); +crate::with_swizzling_for_dim!(3, gen_dim_impl_for_vector, Vector4); +crate::with_swizzling_for_dim!(4, gen_dim_impl_for_vector, Vector4); + + + +// ===================================== +// === Setters for nalgebra::Vector* === +// ===================================== + +macro_rules! gen_dim_setter_impl_for_vector { + ([$vec:tt] $dim:tt $( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )*) => { + paste! { + impl [] for $vec { + $( + fn [](&mut self, value: Self::[]) { + gen_dim_setter_impl_for_vector_body!{self, value, $swizzling_dim, [$($dim_ix)*], [$($dim_ord)*]} + } + )* + } + } + }; +} + +macro_rules! gen_dim_setter_impl_for_vector_body { + ($this:tt, $value:tt, $swizzling_dim:tt, [$dim_ix:tt], [$($dim_ord:tt),*]) => { + $this[$dim_ix] = $value; + }; + ($this:tt, $value:tt, $swizzling_dim:tt, [$($dim_ix:tt),*], [$($dim_ord:tt),*]) => { paste! { + $( $this[$dim_ix] = $value[$dim_ord]; )* + }}; +} + +crate::with_swizzling_for_dim_unique!(1, gen_dim_setter_impl_for_vector, Vector2); +crate::with_swizzling_for_dim_unique!(2, gen_dim_setter_impl_for_vector, Vector2); + +crate::with_swizzling_for_dim_unique!(1, gen_dim_setter_impl_for_vector, Vector3); +crate::with_swizzling_for_dim_unique!(2, gen_dim_setter_impl_for_vector, Vector3); +crate::with_swizzling_for_dim_unique!(3, gen_dim_setter_impl_for_vector, Vector3); + +crate::with_swizzling_for_dim_unique!(1, gen_dim_setter_impl_for_vector, Vector4); +crate::with_swizzling_for_dim_unique!(2, gen_dim_setter_impl_for_vector, Vector4); +crate::with_swizzling_for_dim_unique!(3, gen_dim_setter_impl_for_vector, Vector4); +crate::with_swizzling_for_dim_unique!(4, gen_dim_setter_impl_for_vector, Vector4); diff --git a/lib/rust/types/src/dim_macros.rs b/lib/rust/types/src/dim_macros.rs new file mode 100644 index 00000000000..4d65982a991 --- /dev/null +++ b/lib/rust/types/src/dim_macros.rs @@ -0,0 +1,441 @@ +//! Macros allowing generation of swizzling getters and setters. +//! See the docs of [`build.rs`] and usage places to learn more. + + + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// THIS IS AN AUTO-GENERATED FILE. DO NOT EDIT IT DIRECTLY! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +/// Swizzling data for the given dimension. +/// See the [`build.rs`] file to learn more. +#[macro_export] +macro_rules! with_swizzling_for_dim { + (1, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 1 + x 1 [0] [0] + }}; + (2, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 2 + y 1 [1] [0] + xx 2 [0, 0] [0, 1] + xy 2 [0, 1] [0, 1] + yx 2 [1, 0] [0, 1] + yy 2 [1, 1] [0, 1] + }}; + (3, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 3 + z 1 [2] [0] + xz 2 [0, 2] [0, 1] + yz 2 [1, 2] [0, 1] + zx 2 [2, 0] [0, 1] + zy 2 [2, 1] [0, 1] + zz 2 [2, 2] [0, 1] + xxx 3 [0, 0, 0] [0, 1, 2] + xxy 3 [0, 0, 1] [0, 1, 2] + xxz 3 [0, 0, 2] [0, 1, 2] + xyx 3 [0, 1, 0] [0, 1, 2] + xyy 3 [0, 1, 1] [0, 1, 2] + xyz 3 [0, 1, 2] [0, 1, 2] + xzx 3 [0, 2, 0] [0, 1, 2] + xzy 3 [0, 2, 1] [0, 1, 2] + xzz 3 [0, 2, 2] [0, 1, 2] + yxx 3 [1, 0, 0] [0, 1, 2] + yxy 3 [1, 0, 1] [0, 1, 2] + yxz 3 [1, 0, 2] [0, 1, 2] + yyx 3 [1, 1, 0] [0, 1, 2] + yyy 3 [1, 1, 1] [0, 1, 2] + yyz 3 [1, 1, 2] [0, 1, 2] + yzx 3 [1, 2, 0] [0, 1, 2] + yzy 3 [1, 2, 1] [0, 1, 2] + yzz 3 [1, 2, 2] [0, 1, 2] + zxx 3 [2, 0, 0] [0, 1, 2] + zxy 3 [2, 0, 1] [0, 1, 2] + zxz 3 [2, 0, 2] [0, 1, 2] + zyx 3 [2, 1, 0] [0, 1, 2] + zyy 3 [2, 1, 1] [0, 1, 2] + zyz 3 [2, 1, 2] [0, 1, 2] + zzx 3 [2, 2, 0] [0, 1, 2] + zzy 3 [2, 2, 1] [0, 1, 2] + zzz 3 [2, 2, 2] [0, 1, 2] + }}; + (4, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 4 + w 1 [3] [0] + xw 2 [0, 3] [0, 1] + yw 2 [1, 3] [0, 1] + zw 2 [2, 3] [0, 1] + wx 2 [3, 0] [0, 1] + wy 2 [3, 1] [0, 1] + wz 2 [3, 2] [0, 1] + ww 2 [3, 3] [0, 1] + xxw 3 [0, 0, 3] [0, 1, 2] + xyw 3 [0, 1, 3] [0, 1, 2] + xzw 3 [0, 2, 3] [0, 1, 2] + xwx 3 [0, 3, 0] [0, 1, 2] + xwy 3 [0, 3, 1] [0, 1, 2] + xwz 3 [0, 3, 2] [0, 1, 2] + xww 3 [0, 3, 3] [0, 1, 2] + yxw 3 [1, 0, 3] [0, 1, 2] + yyw 3 [1, 1, 3] [0, 1, 2] + yzw 3 [1, 2, 3] [0, 1, 2] + ywx 3 [1, 3, 0] [0, 1, 2] + ywy 3 [1, 3, 1] [0, 1, 2] + ywz 3 [1, 3, 2] [0, 1, 2] + yww 3 [1, 3, 3] [0, 1, 2] + zxw 3 [2, 0, 3] [0, 1, 2] + zyw 3 [2, 1, 3] [0, 1, 2] + zzw 3 [2, 2, 3] [0, 1, 2] + zwx 3 [2, 3, 0] [0, 1, 2] + zwy 3 [2, 3, 1] [0, 1, 2] + zwz 3 [2, 3, 2] [0, 1, 2] + zww 3 [2, 3, 3] [0, 1, 2] + wxx 3 [3, 0, 0] [0, 1, 2] + wxy 3 [3, 0, 1] [0, 1, 2] + wxz 3 [3, 0, 2] [0, 1, 2] + wxw 3 [3, 0, 3] [0, 1, 2] + wyx 3 [3, 1, 0] [0, 1, 2] + wyy 3 [3, 1, 1] [0, 1, 2] + wyz 3 [3, 1, 2] [0, 1, 2] + wyw 3 [3, 1, 3] [0, 1, 2] + wzx 3 [3, 2, 0] [0, 1, 2] + wzy 3 [3, 2, 1] [0, 1, 2] + wzz 3 [3, 2, 2] [0, 1, 2] + wzw 3 [3, 2, 3] [0, 1, 2] + wwx 3 [3, 3, 0] [0, 1, 2] + wwy 3 [3, 3, 1] [0, 1, 2] + wwz 3 [3, 3, 2] [0, 1, 2] + www 3 [3, 3, 3] [0, 1, 2] + xxxx 4 [0, 0, 0, 0] [0, 1, 2, 3] + xxxy 4 [0, 0, 0, 1] [0, 1, 2, 3] + xxxz 4 [0, 0, 0, 2] [0, 1, 2, 3] + xxxw 4 [0, 0, 0, 3] [0, 1, 2, 3] + xxyx 4 [0, 0, 1, 0] [0, 1, 2, 3] + xxyy 4 [0, 0, 1, 1] [0, 1, 2, 3] + xxyz 4 [0, 0, 1, 2] [0, 1, 2, 3] + xxyw 4 [0, 0, 1, 3] [0, 1, 2, 3] + xxzx 4 [0, 0, 2, 0] [0, 1, 2, 3] + xxzy 4 [0, 0, 2, 1] [0, 1, 2, 3] + xxzz 4 [0, 0, 2, 2] [0, 1, 2, 3] + xxzw 4 [0, 0, 2, 3] [0, 1, 2, 3] + xxwx 4 [0, 0, 3, 0] [0, 1, 2, 3] + xxwy 4 [0, 0, 3, 1] [0, 1, 2, 3] + xxwz 4 [0, 0, 3, 2] [0, 1, 2, 3] + xxww 4 [0, 0, 3, 3] [0, 1, 2, 3] + xyxx 4 [0, 1, 0, 0] [0, 1, 2, 3] + xyxy 4 [0, 1, 0, 1] [0, 1, 2, 3] + xyxz 4 [0, 1, 0, 2] [0, 1, 2, 3] + xyxw 4 [0, 1, 0, 3] [0, 1, 2, 3] + xyyx 4 [0, 1, 1, 0] [0, 1, 2, 3] + xyyy 4 [0, 1, 1, 1] [0, 1, 2, 3] + xyyz 4 [0, 1, 1, 2] [0, 1, 2, 3] + xyyw 4 [0, 1, 1, 3] [0, 1, 2, 3] + xyzx 4 [0, 1, 2, 0] [0, 1, 2, 3] + xyzy 4 [0, 1, 2, 1] [0, 1, 2, 3] + xyzz 4 [0, 1, 2, 2] [0, 1, 2, 3] + xyzw 4 [0, 1, 2, 3] [0, 1, 2, 3] + xywx 4 [0, 1, 3, 0] [0, 1, 2, 3] + xywy 4 [0, 1, 3, 1] [0, 1, 2, 3] + xywz 4 [0, 1, 3, 2] [0, 1, 2, 3] + xyww 4 [0, 1, 3, 3] [0, 1, 2, 3] + xzxx 4 [0, 2, 0, 0] [0, 1, 2, 3] + xzxy 4 [0, 2, 0, 1] [0, 1, 2, 3] + xzxz 4 [0, 2, 0, 2] [0, 1, 2, 3] + xzxw 4 [0, 2, 0, 3] [0, 1, 2, 3] + xzyx 4 [0, 2, 1, 0] [0, 1, 2, 3] + xzyy 4 [0, 2, 1, 1] [0, 1, 2, 3] + xzyz 4 [0, 2, 1, 2] [0, 1, 2, 3] + xzyw 4 [0, 2, 1, 3] [0, 1, 2, 3] + xzzx 4 [0, 2, 2, 0] [0, 1, 2, 3] + xzzy 4 [0, 2, 2, 1] [0, 1, 2, 3] + xzzz 4 [0, 2, 2, 2] [0, 1, 2, 3] + xzzw 4 [0, 2, 2, 3] [0, 1, 2, 3] + xzwx 4 [0, 2, 3, 0] [0, 1, 2, 3] + xzwy 4 [0, 2, 3, 1] [0, 1, 2, 3] + xzwz 4 [0, 2, 3, 2] [0, 1, 2, 3] + xzww 4 [0, 2, 3, 3] [0, 1, 2, 3] + xwxx 4 [0, 3, 0, 0] [0, 1, 2, 3] + xwxy 4 [0, 3, 0, 1] [0, 1, 2, 3] + xwxz 4 [0, 3, 0, 2] [0, 1, 2, 3] + xwxw 4 [0, 3, 0, 3] [0, 1, 2, 3] + xwyx 4 [0, 3, 1, 0] [0, 1, 2, 3] + xwyy 4 [0, 3, 1, 1] [0, 1, 2, 3] + xwyz 4 [0, 3, 1, 2] [0, 1, 2, 3] + xwyw 4 [0, 3, 1, 3] [0, 1, 2, 3] + xwzx 4 [0, 3, 2, 0] [0, 1, 2, 3] + xwzy 4 [0, 3, 2, 1] [0, 1, 2, 3] + xwzz 4 [0, 3, 2, 2] [0, 1, 2, 3] + xwzw 4 [0, 3, 2, 3] [0, 1, 2, 3] + xwwx 4 [0, 3, 3, 0] [0, 1, 2, 3] + xwwy 4 [0, 3, 3, 1] [0, 1, 2, 3] + xwwz 4 [0, 3, 3, 2] [0, 1, 2, 3] + xwww 4 [0, 3, 3, 3] [0, 1, 2, 3] + yxxx 4 [1, 0, 0, 0] [0, 1, 2, 3] + yxxy 4 [1, 0, 0, 1] [0, 1, 2, 3] + yxxz 4 [1, 0, 0, 2] [0, 1, 2, 3] + yxxw 4 [1, 0, 0, 3] [0, 1, 2, 3] + yxyx 4 [1, 0, 1, 0] [0, 1, 2, 3] + yxyy 4 [1, 0, 1, 1] [0, 1, 2, 3] + yxyz 4 [1, 0, 1, 2] [0, 1, 2, 3] + yxyw 4 [1, 0, 1, 3] [0, 1, 2, 3] + yxzx 4 [1, 0, 2, 0] [0, 1, 2, 3] + yxzy 4 [1, 0, 2, 1] [0, 1, 2, 3] + yxzz 4 [1, 0, 2, 2] [0, 1, 2, 3] + yxzw 4 [1, 0, 2, 3] [0, 1, 2, 3] + yxwx 4 [1, 0, 3, 0] [0, 1, 2, 3] + yxwy 4 [1, 0, 3, 1] [0, 1, 2, 3] + yxwz 4 [1, 0, 3, 2] [0, 1, 2, 3] + yxww 4 [1, 0, 3, 3] [0, 1, 2, 3] + yyxx 4 [1, 1, 0, 0] [0, 1, 2, 3] + yyxy 4 [1, 1, 0, 1] [0, 1, 2, 3] + yyxz 4 [1, 1, 0, 2] [0, 1, 2, 3] + yyxw 4 [1, 1, 0, 3] [0, 1, 2, 3] + yyyx 4 [1, 1, 1, 0] [0, 1, 2, 3] + yyyy 4 [1, 1, 1, 1] [0, 1, 2, 3] + yyyz 4 [1, 1, 1, 2] [0, 1, 2, 3] + yyyw 4 [1, 1, 1, 3] [0, 1, 2, 3] + yyzx 4 [1, 1, 2, 0] [0, 1, 2, 3] + yyzy 4 [1, 1, 2, 1] [0, 1, 2, 3] + yyzz 4 [1, 1, 2, 2] [0, 1, 2, 3] + yyzw 4 [1, 1, 2, 3] [0, 1, 2, 3] + yywx 4 [1, 1, 3, 0] [0, 1, 2, 3] + yywy 4 [1, 1, 3, 1] [0, 1, 2, 3] + yywz 4 [1, 1, 3, 2] [0, 1, 2, 3] + yyww 4 [1, 1, 3, 3] [0, 1, 2, 3] + yzxx 4 [1, 2, 0, 0] [0, 1, 2, 3] + yzxy 4 [1, 2, 0, 1] [0, 1, 2, 3] + yzxz 4 [1, 2, 0, 2] [0, 1, 2, 3] + yzxw 4 [1, 2, 0, 3] [0, 1, 2, 3] + yzyx 4 [1, 2, 1, 0] [0, 1, 2, 3] + yzyy 4 [1, 2, 1, 1] [0, 1, 2, 3] + yzyz 4 [1, 2, 1, 2] [0, 1, 2, 3] + yzyw 4 [1, 2, 1, 3] [0, 1, 2, 3] + yzzx 4 [1, 2, 2, 0] [0, 1, 2, 3] + yzzy 4 [1, 2, 2, 1] [0, 1, 2, 3] + yzzz 4 [1, 2, 2, 2] [0, 1, 2, 3] + yzzw 4 [1, 2, 2, 3] [0, 1, 2, 3] + yzwx 4 [1, 2, 3, 0] [0, 1, 2, 3] + yzwy 4 [1, 2, 3, 1] [0, 1, 2, 3] + yzwz 4 [1, 2, 3, 2] [0, 1, 2, 3] + yzww 4 [1, 2, 3, 3] [0, 1, 2, 3] + ywxx 4 [1, 3, 0, 0] [0, 1, 2, 3] + ywxy 4 [1, 3, 0, 1] [0, 1, 2, 3] + ywxz 4 [1, 3, 0, 2] [0, 1, 2, 3] + ywxw 4 [1, 3, 0, 3] [0, 1, 2, 3] + ywyx 4 [1, 3, 1, 0] [0, 1, 2, 3] + ywyy 4 [1, 3, 1, 1] [0, 1, 2, 3] + ywyz 4 [1, 3, 1, 2] [0, 1, 2, 3] + ywyw 4 [1, 3, 1, 3] [0, 1, 2, 3] + ywzx 4 [1, 3, 2, 0] [0, 1, 2, 3] + ywzy 4 [1, 3, 2, 1] [0, 1, 2, 3] + ywzz 4 [1, 3, 2, 2] [0, 1, 2, 3] + ywzw 4 [1, 3, 2, 3] [0, 1, 2, 3] + ywwx 4 [1, 3, 3, 0] [0, 1, 2, 3] + ywwy 4 [1, 3, 3, 1] [0, 1, 2, 3] + ywwz 4 [1, 3, 3, 2] [0, 1, 2, 3] + ywww 4 [1, 3, 3, 3] [0, 1, 2, 3] + zxxx 4 [2, 0, 0, 0] [0, 1, 2, 3] + zxxy 4 [2, 0, 0, 1] [0, 1, 2, 3] + zxxz 4 [2, 0, 0, 2] [0, 1, 2, 3] + zxxw 4 [2, 0, 0, 3] [0, 1, 2, 3] + zxyx 4 [2, 0, 1, 0] [0, 1, 2, 3] + zxyy 4 [2, 0, 1, 1] [0, 1, 2, 3] + zxyz 4 [2, 0, 1, 2] [0, 1, 2, 3] + zxyw 4 [2, 0, 1, 3] [0, 1, 2, 3] + zxzx 4 [2, 0, 2, 0] [0, 1, 2, 3] + zxzy 4 [2, 0, 2, 1] [0, 1, 2, 3] + zxzz 4 [2, 0, 2, 2] [0, 1, 2, 3] + zxzw 4 [2, 0, 2, 3] [0, 1, 2, 3] + zxwx 4 [2, 0, 3, 0] [0, 1, 2, 3] + zxwy 4 [2, 0, 3, 1] [0, 1, 2, 3] + zxwz 4 [2, 0, 3, 2] [0, 1, 2, 3] + zxww 4 [2, 0, 3, 3] [0, 1, 2, 3] + zyxx 4 [2, 1, 0, 0] [0, 1, 2, 3] + zyxy 4 [2, 1, 0, 1] [0, 1, 2, 3] + zyxz 4 [2, 1, 0, 2] [0, 1, 2, 3] + zyxw 4 [2, 1, 0, 3] [0, 1, 2, 3] + zyyx 4 [2, 1, 1, 0] [0, 1, 2, 3] + zyyy 4 [2, 1, 1, 1] [0, 1, 2, 3] + zyyz 4 [2, 1, 1, 2] [0, 1, 2, 3] + zyyw 4 [2, 1, 1, 3] [0, 1, 2, 3] + zyzx 4 [2, 1, 2, 0] [0, 1, 2, 3] + zyzy 4 [2, 1, 2, 1] [0, 1, 2, 3] + zyzz 4 [2, 1, 2, 2] [0, 1, 2, 3] + zyzw 4 [2, 1, 2, 3] [0, 1, 2, 3] + zywx 4 [2, 1, 3, 0] [0, 1, 2, 3] + zywy 4 [2, 1, 3, 1] [0, 1, 2, 3] + zywz 4 [2, 1, 3, 2] [0, 1, 2, 3] + zyww 4 [2, 1, 3, 3] [0, 1, 2, 3] + zzxx 4 [2, 2, 0, 0] [0, 1, 2, 3] + zzxy 4 [2, 2, 0, 1] [0, 1, 2, 3] + zzxz 4 [2, 2, 0, 2] [0, 1, 2, 3] + zzxw 4 [2, 2, 0, 3] [0, 1, 2, 3] + zzyx 4 [2, 2, 1, 0] [0, 1, 2, 3] + zzyy 4 [2, 2, 1, 1] [0, 1, 2, 3] + zzyz 4 [2, 2, 1, 2] [0, 1, 2, 3] + zzyw 4 [2, 2, 1, 3] [0, 1, 2, 3] + zzzx 4 [2, 2, 2, 0] [0, 1, 2, 3] + zzzy 4 [2, 2, 2, 1] [0, 1, 2, 3] + zzzz 4 [2, 2, 2, 2] [0, 1, 2, 3] + zzzw 4 [2, 2, 2, 3] [0, 1, 2, 3] + zzwx 4 [2, 2, 3, 0] [0, 1, 2, 3] + zzwy 4 [2, 2, 3, 1] [0, 1, 2, 3] + zzwz 4 [2, 2, 3, 2] [0, 1, 2, 3] + zzww 4 [2, 2, 3, 3] [0, 1, 2, 3] + zwxx 4 [2, 3, 0, 0] [0, 1, 2, 3] + zwxy 4 [2, 3, 0, 1] [0, 1, 2, 3] + zwxz 4 [2, 3, 0, 2] [0, 1, 2, 3] + zwxw 4 [2, 3, 0, 3] [0, 1, 2, 3] + zwyx 4 [2, 3, 1, 0] [0, 1, 2, 3] + zwyy 4 [2, 3, 1, 1] [0, 1, 2, 3] + zwyz 4 [2, 3, 1, 2] [0, 1, 2, 3] + zwyw 4 [2, 3, 1, 3] [0, 1, 2, 3] + zwzx 4 [2, 3, 2, 0] [0, 1, 2, 3] + zwzy 4 [2, 3, 2, 1] [0, 1, 2, 3] + zwzz 4 [2, 3, 2, 2] [0, 1, 2, 3] + zwzw 4 [2, 3, 2, 3] [0, 1, 2, 3] + zwwx 4 [2, 3, 3, 0] [0, 1, 2, 3] + zwwy 4 [2, 3, 3, 1] [0, 1, 2, 3] + zwwz 4 [2, 3, 3, 2] [0, 1, 2, 3] + zwww 4 [2, 3, 3, 3] [0, 1, 2, 3] + wxxx 4 [3, 0, 0, 0] [0, 1, 2, 3] + wxxy 4 [3, 0, 0, 1] [0, 1, 2, 3] + wxxz 4 [3, 0, 0, 2] [0, 1, 2, 3] + wxxw 4 [3, 0, 0, 3] [0, 1, 2, 3] + wxyx 4 [3, 0, 1, 0] [0, 1, 2, 3] + wxyy 4 [3, 0, 1, 1] [0, 1, 2, 3] + wxyz 4 [3, 0, 1, 2] [0, 1, 2, 3] + wxyw 4 [3, 0, 1, 3] [0, 1, 2, 3] + wxzx 4 [3, 0, 2, 0] [0, 1, 2, 3] + wxzy 4 [3, 0, 2, 1] [0, 1, 2, 3] + wxzz 4 [3, 0, 2, 2] [0, 1, 2, 3] + wxzw 4 [3, 0, 2, 3] [0, 1, 2, 3] + wxwx 4 [3, 0, 3, 0] [0, 1, 2, 3] + wxwy 4 [3, 0, 3, 1] [0, 1, 2, 3] + wxwz 4 [3, 0, 3, 2] [0, 1, 2, 3] + wxww 4 [3, 0, 3, 3] [0, 1, 2, 3] + wyxx 4 [3, 1, 0, 0] [0, 1, 2, 3] + wyxy 4 [3, 1, 0, 1] [0, 1, 2, 3] + wyxz 4 [3, 1, 0, 2] [0, 1, 2, 3] + wyxw 4 [3, 1, 0, 3] [0, 1, 2, 3] + wyyx 4 [3, 1, 1, 0] [0, 1, 2, 3] + wyyy 4 [3, 1, 1, 1] [0, 1, 2, 3] + wyyz 4 [3, 1, 1, 2] [0, 1, 2, 3] + wyyw 4 [3, 1, 1, 3] [0, 1, 2, 3] + wyzx 4 [3, 1, 2, 0] [0, 1, 2, 3] + wyzy 4 [3, 1, 2, 1] [0, 1, 2, 3] + wyzz 4 [3, 1, 2, 2] [0, 1, 2, 3] + wyzw 4 [3, 1, 2, 3] [0, 1, 2, 3] + wywx 4 [3, 1, 3, 0] [0, 1, 2, 3] + wywy 4 [3, 1, 3, 1] [0, 1, 2, 3] + wywz 4 [3, 1, 3, 2] [0, 1, 2, 3] + wyww 4 [3, 1, 3, 3] [0, 1, 2, 3] + wzxx 4 [3, 2, 0, 0] [0, 1, 2, 3] + wzxy 4 [3, 2, 0, 1] [0, 1, 2, 3] + wzxz 4 [3, 2, 0, 2] [0, 1, 2, 3] + wzxw 4 [3, 2, 0, 3] [0, 1, 2, 3] + wzyx 4 [3, 2, 1, 0] [0, 1, 2, 3] + wzyy 4 [3, 2, 1, 1] [0, 1, 2, 3] + wzyz 4 [3, 2, 1, 2] [0, 1, 2, 3] + wzyw 4 [3, 2, 1, 3] [0, 1, 2, 3] + wzzx 4 [3, 2, 2, 0] [0, 1, 2, 3] + wzzy 4 [3, 2, 2, 1] [0, 1, 2, 3] + wzzz 4 [3, 2, 2, 2] [0, 1, 2, 3] + wzzw 4 [3, 2, 2, 3] [0, 1, 2, 3] + wzwx 4 [3, 2, 3, 0] [0, 1, 2, 3] + wzwy 4 [3, 2, 3, 1] [0, 1, 2, 3] + wzwz 4 [3, 2, 3, 2] [0, 1, 2, 3] + wzww 4 [3, 2, 3, 3] [0, 1, 2, 3] + wwxx 4 [3, 3, 0, 0] [0, 1, 2, 3] + wwxy 4 [3, 3, 0, 1] [0, 1, 2, 3] + wwxz 4 [3, 3, 0, 2] [0, 1, 2, 3] + wwxw 4 [3, 3, 0, 3] [0, 1, 2, 3] + wwyx 4 [3, 3, 1, 0] [0, 1, 2, 3] + wwyy 4 [3, 3, 1, 1] [0, 1, 2, 3] + wwyz 4 [3, 3, 1, 2] [0, 1, 2, 3] + wwyw 4 [3, 3, 1, 3] [0, 1, 2, 3] + wwzx 4 [3, 3, 2, 0] [0, 1, 2, 3] + wwzy 4 [3, 3, 2, 1] [0, 1, 2, 3] + wwzz 4 [3, 3, 2, 2] [0, 1, 2, 3] + wwzw 4 [3, 3, 2, 3] [0, 1, 2, 3] + wwwx 4 [3, 3, 3, 0] [0, 1, 2, 3] + wwwy 4 [3, 3, 3, 1] [0, 1, 2, 3] + wwwz 4 [3, 3, 3, 2] [0, 1, 2, 3] + wwww 4 [3, 3, 3, 3] [0, 1, 2, 3] + }}; +} + +/// Swizzling data for the given dimension. +/// See the [`build.rs`] file to learn more. +#[macro_export] +macro_rules! with_swizzling_for_dim_unique { + (1, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 1 + x 1 [0] [0] + }}; + (2, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 2 + y 1 [1] [0] + xy 2 [0, 1] [0, 1] + yx 2 [1, 0] [0, 1] + }}; + (3, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 3 + z 1 [2] [0] + xz 2 [0, 2] [0, 1] + yz 2 [1, 2] [0, 1] + zx 2 [2, 0] [0, 1] + zy 2 [2, 1] [0, 1] + xyz 3 [0, 1, 2] [0, 1, 2] + xzy 3 [0, 2, 1] [0, 1, 2] + yxz 3 [1, 0, 2] [0, 1, 2] + yzx 3 [1, 2, 0] [0, 1, 2] + zxy 3 [2, 0, 1] [0, 1, 2] + zyx 3 [2, 1, 0] [0, 1, 2] + }}; + (4, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 4 + w 1 [3] [0] + xw 2 [0, 3] [0, 1] + yw 2 [1, 3] [0, 1] + zw 2 [2, 3] [0, 1] + wx 2 [3, 0] [0, 1] + wy 2 [3, 1] [0, 1] + wz 2 [3, 2] [0, 1] + xyw 3 [0, 1, 3] [0, 1, 2] + xzw 3 [0, 2, 3] [0, 1, 2] + xwy 3 [0, 3, 1] [0, 1, 2] + xwz 3 [0, 3, 2] [0, 1, 2] + yxw 3 [1, 0, 3] [0, 1, 2] + yzw 3 [1, 2, 3] [0, 1, 2] + ywx 3 [1, 3, 0] [0, 1, 2] + ywz 3 [1, 3, 2] [0, 1, 2] + zxw 3 [2, 0, 3] [0, 1, 2] + zyw 3 [2, 1, 3] [0, 1, 2] + zwx 3 [2, 3, 0] [0, 1, 2] + zwy 3 [2, 3, 1] [0, 1, 2] + wxy 3 [3, 0, 1] [0, 1, 2] + wxz 3 [3, 0, 2] [0, 1, 2] + wyx 3 [3, 1, 0] [0, 1, 2] + wyz 3 [3, 1, 2] [0, 1, 2] + wzx 3 [3, 2, 0] [0, 1, 2] + wzy 3 [3, 2, 1] [0, 1, 2] + xyzw 4 [0, 1, 2, 3] [0, 1, 2, 3] + xywz 4 [0, 1, 3, 2] [0, 1, 2, 3] + xzyw 4 [0, 2, 1, 3] [0, 1, 2, 3] + xzwy 4 [0, 2, 3, 1] [0, 1, 2, 3] + xwyz 4 [0, 3, 1, 2] [0, 1, 2, 3] + xwzy 4 [0, 3, 2, 1] [0, 1, 2, 3] + yxzw 4 [1, 0, 2, 3] [0, 1, 2, 3] + yxwz 4 [1, 0, 3, 2] [0, 1, 2, 3] + yzxw 4 [1, 2, 0, 3] [0, 1, 2, 3] + yzwx 4 [1, 2, 3, 0] [0, 1, 2, 3] + ywxz 4 [1, 3, 0, 2] [0, 1, 2, 3] + ywzx 4 [1, 3, 2, 0] [0, 1, 2, 3] + zxyw 4 [2, 0, 1, 3] [0, 1, 2, 3] + zxwy 4 [2, 0, 3, 1] [0, 1, 2, 3] + zyxw 4 [2, 1, 0, 3] [0, 1, 2, 3] + zywx 4 [2, 1, 3, 0] [0, 1, 2, 3] + zwxy 4 [2, 3, 0, 1] [0, 1, 2, 3] + zwyx 4 [2, 3, 1, 0] [0, 1, 2, 3] + wxyz 4 [3, 0, 1, 2] [0, 1, 2, 3] + wxzy 4 [3, 0, 2, 1] [0, 1, 2, 3] + wyxz 4 [3, 1, 0, 2] [0, 1, 2, 3] + wyzx 4 [3, 1, 2, 0] [0, 1, 2, 3] + wzxy 4 [3, 2, 0, 1] [0, 1, 2, 3] + wzyx 4 [3, 2, 1, 0] [0, 1, 2, 3] + }}; +} diff --git a/lib/rust/types/src/lib.rs b/lib/rust/types/src/lib.rs index 2f8a713832b..f8b7fbaa204 100644 --- a/lib/rust/types/src/lib.rs +++ b/lib/rust/types/src/lib.rs @@ -29,6 +29,8 @@ // ============== pub mod algebra; +pub mod dim; +pub mod dim_macros; pub mod num; pub mod topology; pub mod unit;