mirror of
https://github.com/enso-org/enso.git
synced 2024-11-22 22:10:15 +03:00
remove content_origin property from layout (#6155)
Simplified layout algorithm by removing `content_origin`, and instead treating `(0.0, 0.0)` as origin point in every layout object. This change allows overflowing containers that are within auto-layout. The parent element will no longer be moved within the grid cell when its children overflow it. ![image](https://user-images.githubusercontent.com/919491/228926310-b0117570-9f83-4687-8f8c-3fc778ff7d3c.png) # Important Notes When implementing this change, I have found that when object's size was modified without ever touching its position, that change was not being picked up in the "modified children" list, and `on_updated` was never triggered. Because some sprites now are bottom-left aligned, that is now a common case and was reproducible on the auto-layout example scene. I ended up fixing it by introducing another dirty flag for `computed_size` changes. Right now that flag is applied very broadly (on each layout update), but in the future we might make it more precise by actually checking if the size was changed in the process. I believe that this might also be a fix for #5095, as I cannot reproduce it anymore with those changes.
This commit is contained in:
parent
6ddcb553e5
commit
08f28998ab
@ -33,6 +33,7 @@ pub mod separator {
|
||||
ensogl_core::shape! {
|
||||
above = [ensogl_grid_view::entry::shape];
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let color = style.get_color(theme::separator::color);
|
||||
let width = style.get_number(theme::separator::width);
|
||||
@ -58,6 +59,7 @@ pub mod ellipsis {
|
||||
ensogl_core::shape! {
|
||||
above = [ensogl_grid_view::entry::shape];
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let radius = style.get_number(theme::ellipsis::circles_radius).px();
|
||||
let gap = style.get_number(theme::ellipsis::circles_gap).px();
|
||||
|
@ -103,6 +103,7 @@ mod mask {
|
||||
use ensogl_core::display::shape::*;
|
||||
ensogl_core::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style, corners_radius: f32) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
|
@ -65,6 +65,7 @@ pub mod background {
|
||||
ensogl_core::shape! {
|
||||
below = [grid_view::entry::overlay, grid_view::selectable::highlight::shape, icon::any];
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style:Style, color:Vector4, height: f32, shadow_height_multiplier: f32) {
|
||||
let color = Var::<color::Rgba>::from(color);
|
||||
let width: Var<Pixels> = "input_size.x".into();
|
||||
@ -231,6 +232,7 @@ impl Data {
|
||||
display_object.add_child(&background);
|
||||
display_object.add_child(&icon);
|
||||
display_object.add_child(&label);
|
||||
background.set_size((0.0, 0.0));
|
||||
icon.set_size((icon::SIZE, icon::SIZE));
|
||||
label.set_long_text_truncation_mode(true);
|
||||
if let Some(layer) = text_layer {
|
||||
@ -265,8 +267,9 @@ impl Data {
|
||||
_ => grid_style.column_width(),
|
||||
};
|
||||
let bg_height = entry_size.y + overlap;
|
||||
// See comment in [`Self::update_shadow`] method.
|
||||
let shadow_addition = self.background.computed_size().y - self.background.height.get();
|
||||
// See comment in [`Self::update_shadow`] method
|
||||
let background_y = self.background.size().y().as_pixels().expect("size set in pixels");
|
||||
let shadow_addition = background_y - self.background.height.get();
|
||||
let bg_sprite_height = bg_height + shadow_addition;
|
||||
let bg_y = -gap_over_header + overlap / 2.0 + local_scope_offset;
|
||||
self.background.set_y(bg_y);
|
||||
@ -327,7 +330,7 @@ impl Data {
|
||||
entry_size: Vector2,
|
||||
) {
|
||||
if header_position.position != Vector2::default() {
|
||||
let bg_width = self.background.computed_size().x;
|
||||
let bg_width = self.background.size().x().as_pixels().expect("size set in pixels");
|
||||
let bg_height = self.background.height.get();
|
||||
let distance_to_section_top =
|
||||
header_position.y_range.end() - header_position.position.y;
|
||||
|
@ -35,6 +35,7 @@ define_icons! {
|
||||
pub mod star(Star) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let shape = FiveStar(8.0.px(),0.447);
|
||||
let shape = shape.fill(VIVID_COLOR.glsl());
|
||||
@ -47,6 +48,7 @@ define_icons! {
|
||||
pub mod local_scope(LocalScope) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dot = Circle(3.0.px());
|
||||
let outer = Circle(8.0.px()) - Circle(7.0.px());
|
||||
@ -62,6 +64,7 @@ define_icons! {
|
||||
pub mod sub_modules(SubModules) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let corners_radius = 1.5;
|
||||
let top = Rect((8.0.px(), 1.5.px()));
|
||||
@ -82,6 +85,7 @@ define_icons! {
|
||||
pub mod libraries(Libraries) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
use special_icons::libraries as theme;
|
||||
let dull_alpha: Var<f32> = style.get_number(theme::dull_alpha).into();
|
||||
@ -120,6 +124,7 @@ define_icons! {
|
||||
pub mod marketplace(Marketplace) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
use special_icons::marketplace as theme;
|
||||
let dull_alpha: Var<f32> = style.get_number(theme::dull_alpha).into();
|
||||
@ -158,6 +163,7 @@ define_icons! {
|
||||
pub mod data_input(DataInput) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -188,6 +194,7 @@ define_icons! {
|
||||
pub mod data_output(DataOutput) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -218,6 +225,7 @@ define_icons! {
|
||||
pub mod text_input(TextInput) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -257,6 +265,7 @@ define_icons! {
|
||||
pub mod number_input(NumberInput) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -312,6 +321,7 @@ define_icons! {
|
||||
pub mod table_edit(TableEdit) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -334,6 +344,7 @@ define_icons! {
|
||||
pub mod convert(Convert) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let upper_arrow = arrow(11.0,2.0,4.0,6.0).rotate((-PI/2.0).radians());
|
||||
let upper_arrow = upper_arrow.translate(((-8.0).px(),2.0.px()));
|
||||
@ -351,6 +362,7 @@ define_icons! {
|
||||
pub mod dataframe_clean(DataframeClean) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -384,6 +396,7 @@ define_icons! {
|
||||
pub mod add_column(AddColumn) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -407,6 +420,7 @@ define_icons! {
|
||||
pub mod add_row(AddRow) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -429,6 +443,7 @@ define_icons! {
|
||||
pub mod select_column(SelectColumn) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -448,6 +463,7 @@ define_icons! {
|
||||
pub mod select_row(SelectRow) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -467,6 +483,7 @@ define_icons! {
|
||||
pub mod dataframe_map_column(DataframeMapColumn) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -489,6 +506,7 @@ define_icons! {
|
||||
pub mod dataframe_map_row(DataframeMapRow) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -511,6 +529,7 @@ define_icons! {
|
||||
pub mod dataframes_join(DataframesJoin) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -534,6 +553,7 @@ define_icons! {
|
||||
pub mod dataframes_union(DataframesUnion) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -557,6 +577,7 @@ define_icons! {
|
||||
pub mod sigma(Sigma) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let shape = path(2.0,&[
|
||||
( 4.0 , 4.0),
|
||||
@ -579,6 +600,7 @@ define_icons! {
|
||||
pub mod split_text(SplitText) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -629,6 +651,7 @@ define_icons! {
|
||||
pub mod data_science(DataScience) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -653,6 +676,7 @@ define_icons! {
|
||||
pub mod network(Network) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -676,6 +700,7 @@ define_icons! {
|
||||
pub mod system(System) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
use special_icons::system as theme;
|
||||
let background = Rect((14.0.px(),14.0.px())).corners_radius(2.0.px());
|
||||
@ -702,6 +727,7 @@ define_icons! {
|
||||
pub mod io(IO) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -726,6 +752,7 @@ define_icons! {
|
||||
pub mod preparation(Preparation) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
let dull_color = &VIVID_COLOR * &dull_alpha;
|
||||
@ -770,6 +797,7 @@ define_icons! {
|
||||
pub mod join(Join) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
use special_icons::join as theme;
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
@ -801,6 +829,7 @@ define_icons! {
|
||||
pub mod text(Text) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let page = Rect((10.0.px(),14.0.px())).corners_radius(2.0.px());
|
||||
let page = page.translate_x((-2.0).px());
|
||||
@ -825,6 +854,7 @@ define_icons! {
|
||||
pub mod date_and_time(DateAndTime) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let circle = Circle(7.75.px());
|
||||
let circle = &circle - circle.shrink(1.0.px());
|
||||
@ -846,6 +876,7 @@ define_icons! {
|
||||
pub mod spatial(Spatial) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let circle = Circle(4.5.px()).translate_y(3.5.px());
|
||||
let circle = &circle - circle.shrink(2.0.px());
|
||||
@ -871,6 +902,7 @@ define_icons! {
|
||||
pub mod predictive(Predictive) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let circle = Circle(5.5.px());
|
||||
let sphere = &circle - circle.shrink(1.0.px());
|
||||
@ -896,6 +928,7 @@ define_icons! {
|
||||
pub mod machine_learning(MachineLearning) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let body = Rect((10.0.px(),15.0.px()))
|
||||
.corners_radiuses(5.0.px(),5.0.px(),2.0.px(),2.0.px())
|
||||
@ -923,6 +956,7 @@ define_icons! {
|
||||
pub mod computer_vision(ComputerVision) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
use special_icons::computer_vision as theme;
|
||||
let dull_alpha: Var<f32> = style.get_number(dull_color_alpha).into();
|
||||
@ -952,7 +986,8 @@ define_icons! {
|
||||
pub mod r#type(Type) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
(style: Style) {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let circle = Circle(5.5.px()) - Circle(4.0.px());
|
||||
let shape = circle.fill(VIVID_COLOR.glsl());
|
||||
let shape = shape.shrink(SHRINK_AMOUNT.px());
|
||||
@ -967,7 +1002,8 @@ define_icons! {
|
||||
pub mod constructor(Constructor) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
(style: Style) {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let circle = Circle(5.5.px()) - Circle(4.0.px());
|
||||
let shape = circle.fill(VIVID_COLOR.glsl());
|
||||
let shape = shape.shrink(SHRINK_AMOUNT.px());
|
||||
@ -982,7 +1018,8 @@ define_icons! {
|
||||
pub mod function(Function) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
(style: Style) {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let triangle = Triangle(12.0, 12.0).rotate((PI/2.0).radians());
|
||||
let shape = triangle.fill(VIVID_COLOR.glsl());
|
||||
let shape = shape.shrink(SHRINK_AMOUNT.px());
|
||||
@ -997,7 +1034,8 @@ define_icons! {
|
||||
pub mod local(Local) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
(style: Style) {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let dot = Circle(4.0.px());
|
||||
let shape = dot.fill(VIVID_COLOR.glsl());
|
||||
let shape = shape.shrink(SHRINK_AMOUNT.px());
|
||||
@ -1012,7 +1050,8 @@ define_icons! {
|
||||
pub mod method(Method) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
(style: Style) {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let rhomb = path(1.5, &[
|
||||
(6.0, 0.0),
|
||||
(0.0, -6.0),
|
||||
@ -1033,7 +1072,8 @@ define_icons! {
|
||||
pub mod module(Module) {
|
||||
ensogl_core::cached_shape! {
|
||||
size = (SIZE, SIZE);
|
||||
(style: Style) {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let rect = Rect((14.0.px(), 14.0.px())).corners_radius(3.0.px());
|
||||
let rect = &rect - rect.shrink(1.5.px());
|
||||
let shape = rect.fill(VIVID_COLOR.glsl());
|
||||
|
@ -182,6 +182,7 @@ pub mod background {
|
||||
grid_view::entry::overlay,
|
||||
grid_view::selectable::highlight::shape
|
||||
];
|
||||
alignment = center;
|
||||
(style:Style,bg_color:Vector4) {
|
||||
let alpha = Var::<f32>::from(format!("({bg_color}.w)"));
|
||||
let bg_color = &Var::<color::Rgba>::from(bg_color.clone());
|
||||
|
@ -166,6 +166,7 @@ const BUTTON_BACKGROUND_COLOR: color::Rgba = color::Rgba(0.87, 0.87, 0.87, 1.0);
|
||||
mod button {
|
||||
use super::*;
|
||||
shape! {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let background = Rect((BUTTON_SIZE.px(), BUTTON_SIZE.px()));
|
||||
let background = background.corners_radius(10.0.px());
|
||||
@ -182,6 +183,7 @@ mod button {
|
||||
mod button_toggle_caption {
|
||||
use super::*;
|
||||
shape! {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let background = Rect((BUTTON_SIZE.px(), BUTTON_SIZE.px()));
|
||||
let background = background.corners_radius(10.0.px());
|
||||
|
@ -32,6 +32,7 @@ mod frame {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let inner = Rect((SIZE.px(), SIZE.px()));
|
||||
let outer = inner.grow(0.2.px());
|
||||
|
@ -23,6 +23,7 @@ pub mod shape {
|
||||
use ensogl::display::shape::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, position: Vector2<f32>, radius: f32) {
|
||||
let node = Circle(radius);
|
||||
let node = node.fill(Rgba::new(0.17,0.46,0.15,1.0));
|
||||
|
@ -19,6 +19,7 @@ mod shape {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, background_color:Vector4<f32>, icon_color:Vector4<f32>) {
|
||||
let size = Var::canvas_size();
|
||||
let shadow_size = style.get_number(ensogl_hardcoded_theme::shadow::size);
|
||||
|
@ -76,6 +76,7 @@ pub mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let theme = ensogl_hardcoded_theme::graph_editor::breadcrumbs::background;
|
||||
let theme = style::Path::from(&theme);
|
||||
|
@ -56,6 +56,7 @@ pub mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let bg_color = color::Rgba::new(0.0,0.0,0.0,0.000_001);
|
||||
Plane().fill(bg_color).into()
|
||||
@ -74,6 +75,7 @@ mod icon {
|
||||
|
||||
ensogl::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style, red: f32, green: f32, blue: f32, alpha: f32) {
|
||||
let outer_circle = Circle((ICON_RADIUS).px());
|
||||
let inner_circle = Circle((ICON_RADIUS - ICON_RING_WIDTH).px());
|
||||
@ -100,6 +102,7 @@ mod separator {
|
||||
|
||||
ensogl::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style, red: f32, green: f32, blue: f32, alpha: f32) {
|
||||
let size = SEPARATOR_SIZE;
|
||||
let angle = PI/2.0;
|
||||
|
@ -44,6 +44,7 @@ pub mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let bg_color = color::Rgba::new(0.0,0.0,0.0,0.000_001);
|
||||
Plane().fill(bg_color).into()
|
||||
|
@ -288,6 +288,7 @@ pub mod joint {
|
||||
|
||||
ensogl::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let radius = Var::<Pixels>::from("input_size.y");
|
||||
let joint = Circle((radius-PADDING.px())/2.0);
|
||||
@ -326,6 +327,7 @@ macro_rules! define_corner_start {
|
||||
|
||||
ensogl::shape! {
|
||||
below = [joint];
|
||||
alignment = center;
|
||||
( style: Style
|
||||
, radius : f32
|
||||
, angle : f32
|
||||
@ -425,6 +427,7 @@ macro_rules! define_corner_end {
|
||||
use super::*;
|
||||
ensogl::shape! {
|
||||
below = [joint];
|
||||
alignment = center;
|
||||
(
|
||||
style: Style,
|
||||
radius: f32,
|
||||
@ -529,6 +532,7 @@ macro_rules! define_line {
|
||||
use super::*;
|
||||
ensogl::shape! {
|
||||
below = [joint];
|
||||
alignment = center;
|
||||
(
|
||||
style: Style,
|
||||
focus_split_center: Vector2<f32>,
|
||||
@ -597,6 +601,7 @@ macro_rules! define_arrow { () => {
|
||||
use super::*;
|
||||
ensogl::shape! {
|
||||
above = [joint];
|
||||
alignment = center;
|
||||
(
|
||||
style: Style,
|
||||
focus_split_center: Vector2<f32>,
|
||||
|
@ -108,6 +108,7 @@ pub mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style, bg_color:Vector4) {
|
||||
let bg_color = Var::<color::Rgba>::from(bg_color);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
@ -129,6 +130,7 @@ pub mod backdrop {
|
||||
ensogl::shape! {
|
||||
// Disabled to allow interaction with the output port.
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style:Style, selection:f32) {
|
||||
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
@ -188,6 +190,7 @@ pub mod drag_area {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let width : Var<Pixels> = "input_size.x".into();
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
@ -214,6 +217,7 @@ pub mod error_shape {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style,color_rgba:Vector4<f32>) {
|
||||
use ensogl_hardcoded_theme::graph_editor::node as node_theme;
|
||||
|
||||
|
@ -45,6 +45,7 @@ mod hover_area {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, corner_radius: f32) {
|
||||
let width : Var<Pixels> = "input_size.x".into();
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
|
@ -15,6 +15,7 @@ pub mod visibility {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
|
||||
@ -52,6 +53,7 @@ pub mod visibility2 {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
@ -95,6 +97,7 @@ pub mod freeze {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
@ -132,6 +135,7 @@ pub mod skip {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
@ -168,6 +172,7 @@ pub mod disable_reevaluation {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
@ -198,6 +203,7 @@ pub mod enable_reevaluation {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
|
@ -32,6 +32,7 @@ pub const PADDING_X: f32 = 4.0;
|
||||
pub mod hover {
|
||||
use super::*;
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let width : Var<Pixels> = "input_size.x".into();
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
@ -60,6 +61,7 @@ pub mod viz {
|
||||
ensogl::shape! {
|
||||
above = [hover];
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style:Style, color:Vector4) {
|
||||
let width : Var<Pixels> = "input_size.x".into();
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
|
@ -328,6 +328,7 @@ pub mod triangle {
|
||||
crate::component::node::background,
|
||||
crate::component::node::input::port::hover
|
||||
];
|
||||
alignment = center;
|
||||
(style:Style, color:Vector4) {
|
||||
let size = Var::canvas_size();
|
||||
let radius = 1.0.px();
|
||||
|
@ -173,6 +173,7 @@ pub mod single_port {
|
||||
use ensogl::display::shape::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style, size_multiplier:f32, opacity:f32, color_rgb:Vector3<f32>) {
|
||||
let overall_width = Var::<Pixels>::from("input_size.x");
|
||||
let overall_height = Var::<Pixels>::from("input_size.y");
|
||||
@ -299,6 +300,7 @@ pub mod multi_port {
|
||||
}
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
( style : Style
|
||||
, size_multiplier : f32
|
||||
, index : f32
|
||||
|
@ -58,6 +58,7 @@ mod status_indicator_shape {
|
||||
const INDICATOR_WIDTH_INNER: f32 = 10.0;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style,color_rgba:Vector4<f32>) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
|
@ -30,6 +30,7 @@ mod icon {
|
||||
use ensogl_component::toggle_button::ColorableShape;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
|
@ -61,6 +61,7 @@ pub mod overlay {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, radius: f32, roundness: f32, selection: f32) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
@ -83,6 +84,7 @@ pub mod background {
|
||||
use ensogl_hardcoded_theme::graph_editor::visualization as theme;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style, radius:f32, roundness:f32, selection:f32) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
|
@ -41,6 +41,7 @@ mod hover_area {
|
||||
|
||||
ensogl::shape! {
|
||||
below = [drop_down_menu::arrow];
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let width : Var<Pixels> = "input_size.x".into();
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
@ -58,6 +59,7 @@ mod background {
|
||||
|
||||
ensogl::shape! {
|
||||
below = [hover_area];
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
@ -87,6 +89,7 @@ mod four_arrow_icon {
|
||||
const ARROW_LINE_WIDTH: f32 = 1.0;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
@ -127,6 +130,7 @@ mod pin_icon {
|
||||
const PIN_THORN_WIDTH: f32 = 1.0;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
|
@ -28,6 +28,7 @@ pub mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style,selected:f32,radius:f32,roundness:f32) {
|
||||
let width : Var<Pixels> = "input_size.x".into();
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
|
@ -169,6 +169,7 @@ mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let sprite_width: Var<Pixels> = "input_size.x".into();
|
||||
let sprite_height: Var<Pixels> = "input_size.y".into();
|
||||
|
@ -93,6 +93,7 @@ mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let theme = ensogl_hardcoded_theme::application::status_bar::background;
|
||||
let theme = style::Path::from(theme);
|
||||
|
@ -20,6 +20,7 @@ pub use ensogl_hardcoded_theme::application::window_control_buttons::fullscreen
|
||||
pub mod shape {
|
||||
use super::*;
|
||||
ensogl::shape! {
|
||||
alignment = center;
|
||||
(style: Style, background_color: Vector4<f32>, icon_color: Vector4<f32>) {
|
||||
let size = Var::canvas_size();
|
||||
let radius = Min::min(size.x(),size.y()) / 2.0;
|
||||
|
@ -55,6 +55,7 @@ pub mod arrow {
|
||||
|
||||
ensogl_core::shape! {
|
||||
below = [chooser_hover_area];
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
@ -74,6 +75,7 @@ pub mod chooser_hover_area {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let width : Var<Pixels> = "input_size.x".into();
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
|
@ -44,6 +44,7 @@ const OPEN_ANIMATION_OFFSET: f32 = OPEN_ANIMATION_SCALE - 1.001;
|
||||
mod rounded_rect {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style, color_rgba: Vector4<f32>, corner_radius: f32) {
|
||||
let color = Var::<color::Rgba>::from(color_rgba);
|
||||
let rect = Rect(Var::canvas_size()).corners_radius(corner_radius.px());
|
||||
|
@ -23,6 +23,7 @@ use ensogl_text as text;
|
||||
mod background {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style,color_rgba:Vector4<f32>) {
|
||||
let width : Var<Pixels> = "input_size.x".into();
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
|
@ -37,6 +37,7 @@ const INFINITE: f32 = 99999.0;
|
||||
mod background {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let width : Var<Pixels> = MARK_WIDTH.px();
|
||||
let height : Var<Pixels> = INFINITE.px();
|
||||
|
@ -187,6 +187,7 @@ pub mod overlay {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style, corner_radius: f32) {
|
||||
let size = Var::canvas_size();
|
||||
Rect(size).corners_radius(corner_radius.px()).fill(INVISIBLE_HOVER_COLOR).into()
|
||||
@ -206,6 +207,7 @@ pub mod shape {
|
||||
|
||||
ensogl_core::shape! {
|
||||
below = [overlay, highlight::shape];
|
||||
alignment = center;
|
||||
(style:Style, corner_radius: f32, color: Vector4) {
|
||||
let size = Var::canvas_size();
|
||||
Rect(size).corners_radius(corner_radius.px()).fill(color).into()
|
||||
|
@ -32,6 +32,7 @@ use ensogl_scroll_area::Viewport;
|
||||
|
||||
ensogl_core::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(
|
||||
style: Style,
|
||||
// Corners radii of viewport (x), hover highlight (y) and selection highlight (z).
|
||||
|
@ -39,6 +39,7 @@ mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style,bg_color:Vector4) {
|
||||
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
|
@ -98,6 +98,7 @@ pub mod selection {
|
||||
|
||||
ensogl_core::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style, color: Vector4, corner_radius: f32) {
|
||||
let sprite_width : Var<Pixels> = "input_size.x".into();
|
||||
let sprite_height : Var<Pixels> = "input_size.y".into();
|
||||
@ -123,6 +124,7 @@ pub mod background {
|
||||
|
||||
ensogl_core::shape! {
|
||||
below = [selection];
|
||||
alignment = center;
|
||||
(style: Style, shadow_alpha: f32, corners_radius_px: f32, color: Vector4) {
|
||||
let sprite_width : Var<Pixels> = "input_size.x".into();
|
||||
let sprite_height : Var<Pixels> = "input_size.y".into();
|
||||
@ -148,6 +150,7 @@ pub mod overlay {
|
||||
ensogl_core::shape! {
|
||||
above = [background];
|
||||
below = [selection];
|
||||
alignment = center;
|
||||
(style: Style, corners_radius_px: f32) {
|
||||
let sprite_width : Var<Pixels> = "input_size.x".into();
|
||||
let sprite_height : Var<Pixels> = "input_size.y".into();
|
||||
|
@ -167,6 +167,7 @@ impl Viewport {
|
||||
mod mask {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style, corner_radius_top_right: f32, corner_radius_top_left: f32,
|
||||
corner_radius_bottom_right: f32, corner_radius_bottom_left: f32) {
|
||||
let width: Var<Pixels> = "input_size.x".into();
|
||||
|
@ -56,6 +56,7 @@ pub mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style,corner_left:f32,corner_right:f32,color:Vector4,show_shadow:f32) {
|
||||
let background = Background::new(&corner_left,&corner_right,style);
|
||||
let shadow = shadow::from_shape_with_alpha(background.shape.clone(),
|
||||
@ -77,6 +78,7 @@ pub mod io_rect {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let sprite_width : Var<Pixels> = "input_size.x".into();
|
||||
let sprite_height : Var<Pixels> = "input_size.y".into();
|
||||
@ -105,6 +107,7 @@ pub mod track {
|
||||
ensogl_core::shape! {
|
||||
above = [background];
|
||||
below = [left_overflow, right_overflow, io_rect];
|
||||
alignment = center;
|
||||
(style:Style,left:f32,right:f32,corner_left:f32,corner_right:f32,corner_inner:f32,
|
||||
track_color:Vector4) {
|
||||
let background = Background::new(&corner_left,&corner_right,style);
|
||||
@ -169,6 +172,7 @@ pub mod left_overflow {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let overflow_shape = OverflowShape::new(style);
|
||||
let shape = overflow_shape.shape.rotate((-90.0_f32).to_radians().radians());
|
||||
@ -183,6 +187,7 @@ pub mod right_overflow {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let overflow_shape = OverflowShape::new(style);
|
||||
let shape = overflow_shape.shape.rotate(90.0_f32.to_radians().radians());
|
||||
|
@ -26,6 +26,7 @@ pub const HOVER_PADDING: f32 = 5.0;
|
||||
pub mod arrow {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style,color_rgba:Vector4<f32>) {
|
||||
let height : Var<Pixels> = "input_size.y".into();
|
||||
let zoom = Var::<f32>::from("1.0/zoom()");
|
||||
|
@ -61,6 +61,7 @@ mod background {
|
||||
use super::*;
|
||||
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style, color:Vector4) {
|
||||
let shape = Background::new().shape;
|
||||
let shape = shape.fill(color);
|
||||
@ -76,6 +77,7 @@ mod track {
|
||||
ensogl_core::shape! {
|
||||
above = [background];
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style:Style, slider_fraction_horizontal:f32, slider_fraction_vertical:f32, color:Vector4) {
|
||||
let Background{width,height,shape: background} = Background::new();
|
||||
let track = Rect((
|
||||
@ -97,6 +99,7 @@ mod thumb {
|
||||
ensogl_core::shape! {
|
||||
above = [background];
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style:Style, slider_fraction:f32, thumb_width:f32, thumb_height:f32, color:Vector4) {
|
||||
let Background{width,height,shape: background} = Background::new();
|
||||
let thumb_width = &width * &thumb_width;
|
||||
@ -120,6 +123,7 @@ mod overflow {
|
||||
ensogl_core::shape! {
|
||||
above = [background, track, thumb];
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style:Style, color:Vector4) {
|
||||
let width: Var<Pixels> = "input_size.x".into();
|
||||
let height: Var<Pixels> = "input_size.y".into();
|
||||
|
@ -30,6 +30,7 @@ const ELLIPSIS_ANIMATION_OFFSET_MS: f32 = 100.0;
|
||||
mod ellipsis {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style: Style, start_time:f32, scale: f32, rgba: Vector4<f32>) {
|
||||
let time = Var::<f32>::from("input_time");
|
||||
let time = time - start_time;
|
||||
|
@ -66,6 +66,7 @@ pub mod shape {
|
||||
|
||||
ensogl_core::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style:Style, selection:f32, start_time:f32, not_blinking:f32, color_rgb:Vector3<f32>) {
|
||||
let width_abs = Var::<f32>::from("abs(input_size.x)");
|
||||
let height = Var::<f32>::from("input_size.y");
|
||||
|
@ -939,23 +939,23 @@
|
||||
//! node2.allow_grow();
|
||||
//! ```
|
||||
//!
|
||||
//! ## The content origin
|
||||
//! ## Children at negative coordinates.
|
||||
//! In the parent container size is set to hug, the container size will be automatically increased
|
||||
//! to fit the children, however, the children will not be moved, so they can still overflow the
|
||||
//! parent container. In such a case, the content origin point is set to the minimum X-axis and
|
||||
//! Y-axis of the content. For example, the following code creates a manual layout with three that
|
||||
//! overflow the parent container:
|
||||
//! to fit the children in the top or right direction. However, the children will not be moved, so
|
||||
//! they can still overflow the parent container. Elements that overflow into negative coordinates
|
||||
//! will never influence their container's size. For example, the following code creates a manual
|
||||
//! layout with three children, where two of those overflow the parent container into negative
|
||||
//! coordinates:
|
||||
//! ```
|
||||
//! // ╭──────── ▶ ◀ ──────────────────╮
|
||||
//! // │ root │
|
||||
//! // │ ╭────────╮ │
|
||||
//! // ╭───┼────╮ │ node3 │ │
|
||||
//! // │ node1 │ │ │ ▼
|
||||
//! // │ │ │ ╭────────╮ ╰────────╯ ▲
|
||||
//! // ╰───┼────╯ │ node2 │ │
|
||||
//! // ╰──────┼────────┼───────────────╯
|
||||
//! // ╱ │ │
|
||||
//! // ◎ ╰────────╯
|
||||
//! // ╭──────── ▶ ◀ ───────────────╮
|
||||
//! // │ root ╭────────╮ │
|
||||
//! // ╭───┼────╮ │ node3 │ │
|
||||
//! // │ node1 │ │ │ ▼
|
||||
//! // │ │ │ ╭────────╮ ╰────────╯ ▲
|
||||
//! // ╰───┼────╯ │ node2 │ │
|
||||
//! // ╰──────┼────────┼────────────╯
|
||||
//! // │ │
|
||||
//! // ╰────────╯
|
||||
//!
|
||||
//! # use ensogl_core::prelude::*;
|
||||
//! # use ensogl_core::display;
|
||||
@ -971,25 +971,22 @@
|
||||
//! node3.set_xy((3.0, 1.0));
|
||||
//! ```
|
||||
//!
|
||||
//! The content origin tells the layout manager where the real bottom-left corner is. For example,
|
||||
//! we can place several manual layouts with children that overflow their parents in an auto-layout
|
||||
//! and get the correct result:
|
||||
//! The automatic layout manager will only take the elements own size and position into account. If
|
||||
//! those elements have any overflowing children, that overflow will be ignored by the auto-layout.
|
||||
//! For example, we can place several manual layouts with children that overflow their parents in an
|
||||
//! auto-layout. Those children will effectively overflow the auto-layout as well:
|
||||
//! ```
|
||||
//! // ╭────── ▶ ◀ ──────────────╮ ╭────── ▶ ◀ ─────────────╮
|
||||
//! // │ node1 │ │ node2 │
|
||||
//! // ╔════════╪═══════════════════ ▶ ◀ ═╪════╪════════════════════════╪╗
|
||||
//! // ║ ╭──────┼───────────────────────┬─┼────┼──────────────────────╮ │║
|
||||
//! // ║ │ root │ ┆ │ │ │ │║
|
||||
//! // ║ │ ╭───┼──────╮ ┆ ▼╭───┼──────╮ │ ▼║
|
||||
//! // ║ │ │ node1_1 │ ┆ ▲│ node2_1 │ │ ▲║
|
||||
//! // ║ │ │ │ │ ╭──────────╮ ┆ ││ │ │ ╭─────────╮ │ │▼
|
||||
//! // ║ │ ╰───┼──────╯ │ node1_2 │ ┆ │╰───┼──────╯ │ node2_2 │ │ │▲
|
||||
//! // ║ │ ╰─────────┼──────────┼──┼─╯ ╰─────────┼─────────┼──┼─╯║
|
||||
//! // ║ │ ╱ │ │ ┆ ╱ │ │ │ ║
|
||||
//! // ║ │ ◎ ╰──────────╯ ┆ ◎ ╰─────────╯ │ ║
|
||||
//! // ║ ╰──────────────────────────────┴─────────────────────────────╯ ║
|
||||
//! // ╚═════════════════════════════════════════════════════════════════╝
|
||||
//!
|
||||
//! // ╔═════════════════════ ▶ ◀ ═════════════════════╗
|
||||
//! // ║ ╭ root ───────────────┬─────────────────────╮ ║
|
||||
//! // ║ │╭ node1 ─ ▶ ◀ ──────╮┆╭ node2 ─ ▶ ◀ ──────╮│ ║
|
||||
//! // ╭╫─┼┼─────╮ ╭─┼┼┼─────╮ ││ ║
|
||||
//! // │║node1_1 │ │ node2_1 │ ││ ▼
|
||||
//! // │║ ││ │ │ │┆│ │ ││ ▲
|
||||
//! // │║ ││ │ ╭────────┼╮│┆│ │ ╭─────────╮││ ║
|
||||
//! // ╰╫─┼┼─────╯ │ node1_2╰┼┼┼┼─────╯ │ node2_2 │││ ║
|
||||
//! // ║ │╰────────┼─────────┼╯┆╰────────┼─────────┼╯│ ║
|
||||
//! // ║ ╰─────────┼─────────┼─┴─────────┼─────────┼─╯ ║
|
||||
//! // ╚═══════════╰─────────╯═══════════╰─────────╯═══╝
|
||||
//!
|
||||
//! # use ensogl_core::prelude::*;
|
||||
//! # use ensogl_core::display;
|
||||
@ -1013,6 +1010,83 @@
|
||||
//! node2_2.set_xy((1.0, -1.0));
|
||||
//! ```
|
||||
//!
|
||||
//! # Shape view alignment inside layout objects.
|
||||
//!
|
||||
//! The shape views defined using `shape!` can have their own set alignment, which defines how the
|
||||
//! shape sprite is positioned relative to its display object's position. For example, when the
|
||||
//! alignment is set to `center`, the shape sprite will be positioned such that it's center aligns
|
||||
//! with the display objects (0.0, 0.0) origin point. When that shape is a child of an auto-layout,
|
||||
//! it will visually overflow the parent container.
|
||||
//!
|
||||
//! ```text
|
||||
//! alignment = center alignment = bottom_right
|
||||
//! ╭╌view╌╌╌╌╌╌╌╌╮
|
||||
//! ┊ ┊ ╭ sprite ─────╮╌view╌╌╌╌╌╌╌╌╮
|
||||
//! ┊ ┊ │ │ ┊
|
||||
//! ╭ sprite ─────╮ ┊ │ │ ┊
|
||||
//! │ ┊ │ ┊ │ │ ┊
|
||||
//! │ ┊ │ ┊ │ │ ┊
|
||||
//! │ ◎╌╌╌╌╌╌┼╌╌╌╌╌╌╯ │ │ ┊
|
||||
//! │ │ ╰─────────────◎╌╌╌╌╌╌╌╌╌╌╌╌╌╯
|
||||
//! │ │
|
||||
//! ╰─────────────╯
|
||||
//! ```
|
||||
//!
|
||||
//! To avoid this effect and make sprites compatible with layout's understanding of display objects,
|
||||
//! you have to use shapes with `alignment` property set to `bottom_left` corner. It is the default
|
||||
//! shape alignment value when not specified. That way, the sprites will be exactly overlapping the
|
||||
//! display object's position and size, as set by the layout.
|
||||
//!
|
||||
//! ```text
|
||||
//! alignment = bottom_left
|
||||
//! ╭ view/sprite ╮
|
||||
//! │ │
|
||||
//! │ │
|
||||
//! │ │
|
||||
//! │ │
|
||||
//! │ │
|
||||
//! ◎─────────────╯
|
||||
//! ```
|
||||
//!
|
||||
//! Shape views that are aligned to the bottom left corner can be used as children within the
|
||||
//! auto-layout and will be positioned as expected.
|
||||
//!
|
||||
//! ```
|
||||
//! // ╔═════════════════════════ ▶ ◀ ═╗
|
||||
//! // ║ ╭ root ───────┬─────────────╮ ║
|
||||
//! // ║ │ ╭ shape1 ─╮ ┆ ╭ shape2 ─╮ │ ║
|
||||
//! // ║ │ │ │ ┆ │ │ │ ║
|
||||
//! // ║ │ │ │ ┆ │ │ │ ▼
|
||||
//! // ║ │ │ │ ┆ │ │ │ ▲
|
||||
//! // ║ │ ◎─────────╯ ┆ ◎─────────╯ │ ║
|
||||
//! // ║ ╰─────────────┴─────────────╯ ║
|
||||
//! // ╚═══════════════════════════════╝
|
||||
//!
|
||||
//! # use ensogl_core::prelude::*;
|
||||
//! # use ensogl_core::display;
|
||||
//!
|
||||
//! mod rectangle {
|
||||
//! use super::*;
|
||||
//! ensogl_core::shape! {
|
||||
//! alignment = left_bottom; // This is also the default value.
|
||||
//! (style: Style) {
|
||||
//! let rect = Rect(Var::canvas_size()).corners_radius(5.0.px());
|
||||
//! let shape = rect.fill(color::Rgba::new(0.7, 0.5, 0.3, 0.5));
|
||||
//! shape.into()
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn build_layout(root: &display::object::Instance) {
|
||||
//! root.use_auto_layout();
|
||||
//! let shape1 = rectangle::View::new();
|
||||
//! let shape2 = rectangle::View::new();
|
||||
//! root.add_child(&shape1);
|
||||
//! root.add_child(&shape2);
|
||||
//! shape1.set_size((100.0, 100.0));
|
||||
//! shape2.set_size((100.0, 100.0));
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Size and computed size.
|
||||
//! Display objects expose two functions to get their size: `size` and `computed_size`. The first
|
||||
@ -1404,6 +1478,7 @@ pub mod dirty {
|
||||
type ModifiedChildren = crate::data::dirty::RefCellSet<ChildIndex, OnDirtyCallback>;
|
||||
type RemovedChildren = crate::data::dirty::RefCellSet<WeakInstance, OnDirtyCallback>;
|
||||
type Transformation = crate::data::dirty::RefCellBool<OnDirtyCallback>;
|
||||
type ComputedSize = crate::data::dirty::RefCellBool<OnDirtyCallback>;
|
||||
type SceneLayer = crate::data::dirty::RefCellBool<OnDirtyCallback>;
|
||||
|
||||
|
||||
@ -1430,6 +1505,7 @@ pub mod dirty {
|
||||
pub modified_children: ModifiedChildren,
|
||||
pub removed_children: RemovedChildren,
|
||||
pub transformation: Transformation,
|
||||
pub computed_size: ComputedSize,
|
||||
pub new_layer: SceneLayer,
|
||||
}
|
||||
|
||||
@ -1440,8 +1516,16 @@ pub mod dirty {
|
||||
let modified_children = ModifiedChildren::new(on_dirty_callback(parent_bind));
|
||||
let removed_children = RemovedChildren::new(on_dirty_callback(parent_bind));
|
||||
let transformation = Transformation::new(on_dirty_callback(parent_bind));
|
||||
let computed_size = ComputedSize::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 }
|
||||
Self {
|
||||
new_parent,
|
||||
modified_children,
|
||||
removed_children,
|
||||
transformation,
|
||||
computed_size,
|
||||
new_layer,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether any of the dirty flags is set.
|
||||
@ -1814,6 +1898,12 @@ impl Model {
|
||||
}
|
||||
} else {
|
||||
trace!("Self origin and layers did not change.");
|
||||
|
||||
if self.dirty.computed_size.check() {
|
||||
trace!("Computed size changed.");
|
||||
self.on_updated_source.emit(());
|
||||
}
|
||||
|
||||
if self.dirty.modified_children.check_all() {
|
||||
debug_span!("Updating dirty children.").in_scope(|| {
|
||||
self.dirty.modified_children.take().iter().for_each(|ix| {
|
||||
@ -1836,6 +1926,7 @@ impl Model {
|
||||
}
|
||||
});
|
||||
self.dirty.transformation.unset();
|
||||
self.dirty.computed_size.unset();
|
||||
self.dirty.new_parent.unset();
|
||||
}
|
||||
|
||||
@ -1988,6 +2079,16 @@ impl Model {
|
||||
self.dirty.transformation.set();
|
||||
f(&mut self.transformation.borrow_mut())
|
||||
}
|
||||
|
||||
/// Access the transformation of the object as mutable, but only mark it as dirty if the
|
||||
/// provided function returns true.
|
||||
fn with_mut_borrowed_transformation_manually_flagged<F>(&self, f: F)
|
||||
where F: FnOnce(&mut CachedTransformation) -> bool {
|
||||
let modified = f(&mut self.transformation.borrow_mut());
|
||||
if modified {
|
||||
self.dirty.transformation.set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_transformation_getters_and_setters {
|
||||
@ -2007,8 +2108,8 @@ macro_rules! generate_transformation_getters_and_setters {
|
||||
|
||||
fn [<set_ $name _dim>]<D>(&self, dim: D, value: f32)
|
||||
where Vector3<f32>: DimSetter<D> {
|
||||
self.with_mut_borrowed_transformation(|t|
|
||||
t.[<modify_ $name>](|v| v.set_dim(dim, value))
|
||||
self.with_mut_borrowed_transformation_manually_flagged(|t|
|
||||
t.[<set_ $name _dim_checked>](dim, value)
|
||||
);
|
||||
}
|
||||
|
||||
@ -2250,23 +2351,19 @@ pub struct LayoutModel {
|
||||
/// used often. This field can contain [`AutoLayout`] instance even if auto layout is not used.
|
||||
/// For example, if someone sets auto layout options (e.g. the `gap`), but the auto-layout
|
||||
/// was not enabled, it will be instantiated with the `enabled` field set to `false`.
|
||||
auto_layout: RefCell<Option<AutoLayout>>,
|
||||
alignment: Cell<alignment::OptDim2>,
|
||||
margin: Cell<Vector2<SideSpacing>>,
|
||||
padding: Cell<Vector2<SideSpacing>>,
|
||||
auto_layout: RefCell<Option<AutoLayout>>,
|
||||
alignment: Cell<alignment::OptDim2>,
|
||||
margin: Cell<Vector2<SideSpacing>>,
|
||||
padding: Cell<Vector2<SideSpacing>>,
|
||||
#[derivative(Default(
|
||||
value = "Cell::new((f32::INFINITY, f32::INFINITY).into_vector_trans())"
|
||||
))]
|
||||
max_size: Cell<Vector2<Unit>>,
|
||||
min_size: Cell<Vector2<Unit>>,
|
||||
size: Cell<Vector2<Size>>,
|
||||
grow_factor: Cell<Vector2<f32>>,
|
||||
shrink_factor: Cell<Vector2<f32>>,
|
||||
computed_size: Cell<Vector2<f32>>,
|
||||
content_origin: Cell<Vector2<f32>>,
|
||||
/// Force the alignment of origin. This will assume the origin to be placed differently than
|
||||
/// computed. It is used by sprite system, as sprites handle their alignment by themselves.
|
||||
forced_origin_alignment: Cell<alignment::Dim2>,
|
||||
max_size: Cell<Vector2<Unit>>,
|
||||
min_size: Cell<Vector2<Unit>>,
|
||||
size: Cell<Vector2<Size>>,
|
||||
grow_factor: Cell<Vector2<f32>>,
|
||||
shrink_factor: Cell<Vector2<f32>>,
|
||||
computed_size: Cell<Vector2<f32>>,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
@ -2293,12 +2390,6 @@ impl Model {
|
||||
});
|
||||
}
|
||||
|
||||
fn modify_forced_origin_alignment(&self, f: impl FnOnce(&mut alignment::Dim2)) {
|
||||
self.modify_layout(|layout| {
|
||||
layout.forced_origin_alignment.modify(f);
|
||||
});
|
||||
}
|
||||
|
||||
fn set_layout(&self, layout: impl Into<Option<AutoLayout>>) {
|
||||
self.modify_layout(|l| {
|
||||
l.auto_layout.replace(layout.into());
|
||||
@ -2409,18 +2500,17 @@ pub trait LayoutOps: Object {
|
||||
/// the size either to a fixed pixel value, a percentage parent container size, or to a fraction
|
||||
/// of the free space left after placing siblings with fixed sizes.
|
||||
///
|
||||
/// In case the size was modified to a fixed pixels value, the [`computed_size`] will be updated
|
||||
/// immediately for convenience. See the docs of this module to learn more.
|
||||
/// Please note that the [`computed_size`] will not be updated immediately. It will be updated
|
||||
/// during the next display object refresh cycle, which happens once per frame. When the size is
|
||||
/// set to a fixed pixel value, the final `computed_size` can still differ from the requested
|
||||
/// size, because the layout might apply growing or shrinking to the object if it is configured
|
||||
/// to do so.
|
||||
///
|
||||
/// If you need to know the final computed size of the object, use the [`on_changed`] stream
|
||||
#[enso_shapely::gen(update, set(trait = "IntoVectorTrans2<Size>", fn = "into_vector_trans()"))]
|
||||
fn modify_size(&self, f: impl FnOnce(&mut Vector2<Size>)) -> &Self {
|
||||
self.display_object().modify_layout(|layout| {
|
||||
let new_size = layout.size.modify(f);
|
||||
if let Some(x) = new_size.x.as_pixels() {
|
||||
layout.computed_size.set_x(x);
|
||||
}
|
||||
if let Some(y) = new_size.y.as_pixels() {
|
||||
layout.computed_size.set_y(y);
|
||||
}
|
||||
layout.size.modify(f);
|
||||
});
|
||||
self
|
||||
}
|
||||
@ -2455,13 +2545,6 @@ pub trait LayoutOps: Object {
|
||||
self
|
||||
}
|
||||
|
||||
/// The left bottom corner of the content. In case the children overflow the parent, this is set
|
||||
/// to the min x and y values of the children. Otherwise, it is set to (0.0, 0.0). This value
|
||||
/// will be updated during display object refresh cycle, which happens once per frame.
|
||||
fn content_origin(&self) -> Vector2<f32> {
|
||||
self.display_object().def.layout.content_origin.get()
|
||||
}
|
||||
|
||||
/// The maximum size of the object. During auto layout, if the object [`grow_factor`] is
|
||||
/// non-zero, the object will grow to maximum this size.
|
||||
fn max_size(&self) -> Vector2<Unit> {
|
||||
@ -2610,16 +2693,6 @@ pub trait LayoutOps: Object {
|
||||
let vertical = SideSpacing::new(bottom.into(), top.into());
|
||||
self.display_object().layout.padding.set(Vector2(horizontal, vertical));
|
||||
}
|
||||
|
||||
/// Set the forced origin alignment of this object. You should not use this function. It
|
||||
/// tells the object to assume where is the alignment origin and ignore the real value. It
|
||||
/// is used by sprite system, as sprites handle their alignment by themselves.
|
||||
fn unsafe_set_forced_origin_alignment(&self, alignment: alignment::Dim2) -> &Self {
|
||||
self.display_object().modify_layout(|l| {
|
||||
l.forced_origin_alignment.set(alignment);
|
||||
});
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2967,8 +3040,8 @@ impl Model {
|
||||
/// ║ │╱╱╱╱╱ ╭── ▶ ◀ ──┬▷ ┆ ╭ R ▶ ◀ ───┤ │ ║
|
||||
/// ║ │╱╱╱╱╱ │ L │ ┆ │ △ │ │ ║
|
||||
/// ║ │╱╱╱╱╱ │ ╭ L1 ┬▷ │ ┆ │ ╭ R2 ┤ │ │ ║
|
||||
/// ║ │╱╱╱╱╱ │ │ │ │ ┆ │ │ 30 │ │ │ ║
|
||||
/// ║ │╱╱╱╱╱ │ │ │ ▼ ┆ │ ╰────╯ │ ▼ ║
|
||||
/// ║ │╱╱╱╱╱ │ │ │ │ ┆ │ │ 30 │ │ │ ║
|
||||
/// ║ │╱╱╱╱╱ │ │ │ ▼ ┆ │ ╰────╯ │ ▼ ║
|
||||
/// ║ │╱╱╱╱╱ │ │ │ ▲ ┆ │ △ │ ▲ ║
|
||||
/// ║ │╱╱╱╱╱ │ │ │ │ ┆ │ ╭ R1 ┤ │ │ ║
|
||||
/// ║ │╱╱╱╱╱ │ │ 10 │ │ ┆ │ │ 20 │ │ │ ║
|
||||
@ -3034,10 +3107,14 @@ impl Model {
|
||||
/// set to either [`X`] or [`Y`] to update horizontal and vertical axis, respectively.
|
||||
fn refresh_layout(&self) {
|
||||
if self.should_refresh_layout() {
|
||||
let old_size = self.layout.computed_size.get();
|
||||
self.reset_size_to_static_values(X, 0.0);
|
||||
self.refresh_layout_internal(X, PassConfig::Default);
|
||||
self.reset_size_to_static_values(Y, 0.0);
|
||||
self.refresh_layout_internal(X, PassConfig::Default);
|
||||
self.refresh_layout_internal(Y, PassConfig::Default);
|
||||
if old_size != self.layout.computed_size.get() {
|
||||
self.dirty.computed_size.set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3085,11 +3162,16 @@ impl Model {
|
||||
/// the size does not change.
|
||||
fn reset_size_to_static_values<Dim>(&self, x: Dim, parent_size: f32)
|
||||
where Dim: ResolutionDim {
|
||||
let size = match self.layout.size.get_dim(x) {
|
||||
let size = self.resolve_size_static_values(x, parent_size);
|
||||
self.layout.computed_size.set_dim(x, size);
|
||||
}
|
||||
|
||||
fn resolve_size_static_values<Dim>(&self, x: Dim, parent_size: f32) -> f32
|
||||
where Dim: ResolutionDim {
|
||||
match self.layout.size.get_dim(x) {
|
||||
Size::Fixed(unit) => unit.resolve_const_and_percent(parent_size).unwrap_or(0.0),
|
||||
Size::Hug => 0.0,
|
||||
};
|
||||
self.layout.computed_size.set_dim(x, size);
|
||||
}
|
||||
}
|
||||
|
||||
fn should_propagate_parent_layout_refresh<Dim>(&self, x: Dim) -> bool
|
||||
@ -3122,10 +3204,10 @@ impl Model {
|
||||
let hug_children = pass_cfg != PassConfig::DoNotHugDirectChildren;
|
||||
let hug_children = hug_children && self.layout.size.get_dim(x).is_hug();
|
||||
let children = self.children();
|
||||
let old_child_computed_sizes: Vec<f32> =
|
||||
children.iter().map(|child| child.layout.computed_size.get_dim(x)).collect();
|
||||
|
||||
let mut min_x = f32::MAX;
|
||||
let mut max_x = f32::MIN;
|
||||
let mut x_bounds_set = false;
|
||||
let mut max_x = 0.0f32;
|
||||
let mut has_aligned_non_grow_children = false;
|
||||
let mut has_grow_children = false;
|
||||
for child in &children {
|
||||
@ -3146,25 +3228,15 @@ impl Model {
|
||||
} else {
|
||||
let child_pos = child.position().get_dim(x);
|
||||
let child_size = child.computed_size().get_dim(x);
|
||||
let child_content_origin = child.content_origin().get_dim(x);
|
||||
let child_min_x = child_pos + child_content_origin;
|
||||
let child_max_x = child_min_x + child_size;
|
||||
min_x = min_x.min(child_min_x);
|
||||
max_x = max_x.max(child_max_x);
|
||||
x_bounds_set = true;
|
||||
max_x = max_x.max(child_pos + child_size);
|
||||
}
|
||||
} else {
|
||||
has_grow_children = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !x_bounds_set {
|
||||
min_x = 0.0;
|
||||
max_x = 0.0;
|
||||
}
|
||||
|
||||
if hug_children {
|
||||
self.layout.computed_size.set_dim(x, max_x - min_x);
|
||||
self.layout.computed_size.set_dim(x, max_x);
|
||||
}
|
||||
|
||||
// Resolve aligned children and hug them again.
|
||||
@ -3177,15 +3249,11 @@ impl Model {
|
||||
let remaining_size = base_size - child_size;
|
||||
let aligned_position = remaining_size * alignment.normalized();
|
||||
child.set_position_dim(x, aligned_position);
|
||||
let child_content_origin = child.content_origin().get_dim(x);
|
||||
let child_min_x = aligned_position + child_content_origin;
|
||||
let child_max_x = child_min_x + child_size;
|
||||
min_x = min_x.min(child_min_x);
|
||||
max_x = max_x.max(child_max_x);
|
||||
max_x = max_x.max(aligned_position + child_size);
|
||||
}
|
||||
}
|
||||
if hug_children {
|
||||
self.layout.computed_size.set_dim(x, max_x - min_x);
|
||||
self.layout.computed_size.set_dim(x, max_x);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3204,21 +3272,18 @@ impl Model {
|
||||
|
||||
if child.layout.alignment.get().get_dim(x).is_some() {
|
||||
// If child is set to grow, there will never be any leftover space to align
|
||||
// it. It should always be positioned at 0.0
|
||||
// relative to its parent.
|
||||
// it. It should always be positioned at 0.0 relative to its parent.
|
||||
child.set_position_dim(x, 0.0);
|
||||
}
|
||||
|
||||
let child_pos = child.position().get_dim(x);
|
||||
let child_content_origin = child.content_origin().get_dim(x);
|
||||
min_x = min_x.min(child_pos + child_content_origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let forced_origin_alignment = self.layout.forced_origin_alignment.get().get_dim(x);
|
||||
let origin_shift = forced_origin_alignment.normalized() * self_size;
|
||||
self.layout.content_origin.set_dim(x, min_x - origin_shift);
|
||||
for (child, old_size) in children.iter().zip(old_child_computed_sizes) {
|
||||
if child.layout.computed_size.get_dim(x) != old_size {
|
||||
child.dirty.computed_size.set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3308,6 +3373,7 @@ impl Model {
|
||||
where
|
||||
Dim: ResolutionDim,
|
||||
{
|
||||
let self_const_size = self.layout.size.get_dim(x).resolve_pixels_or_default();
|
||||
let columns = unresolved_columns
|
||||
.into_iter()
|
||||
.map(|column| {
|
||||
@ -3321,24 +3387,24 @@ impl Model {
|
||||
for child in &children {
|
||||
let child_grow_factor = child.layout.grow_factor.get_dim(x);
|
||||
let child_shrink_factor = child.layout.shrink_factor.get_dim(x);
|
||||
let child_can_grow_or_shrink =
|
||||
child_grow_factor > 0.0 || child_shrink_factor > 0.0;
|
||||
let refresh_child =
|
||||
child_can_grow_or_shrink || child.should_propagate_parent_layout_refresh(x);
|
||||
|
||||
let self_const_size = self.layout.size.get_dim(x).resolve_pixels_or_default();
|
||||
if refresh_child {
|
||||
child.reset_size_to_static_values(x, self_const_size);
|
||||
}
|
||||
match child.layout.size.get_dim(x) {
|
||||
Size::Hug =>
|
||||
Size::Hug => {
|
||||
let child_can_grow_or_shrink =
|
||||
child_grow_factor > 0.0 || child_shrink_factor > 0.0;
|
||||
let refresh_child = child_can_grow_or_shrink
|
||||
|| child.should_propagate_parent_layout_refresh(x);
|
||||
if refresh_child {
|
||||
child.reset_size_to_static_values(x, self_const_size);
|
||||
child.refresh_layout_internal(x, PassConfig::Default);
|
||||
},
|
||||
}
|
||||
}
|
||||
Size::Fixed(unit) => {
|
||||
max_child_fr = max(max_child_fr, unit.as_fraction_or_default());
|
||||
child.reset_size_to_static_values(x, self_const_size);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let child_margin = child.layout.margin.get_dim(x).resolve_pixels_or_default();
|
||||
let child_size = child.layout.computed_size.get_dim(x) + child_margin.total();
|
||||
let child_min_size =
|
||||
@ -3413,6 +3479,8 @@ impl Model {
|
||||
if children.is_empty() {
|
||||
return;
|
||||
}
|
||||
let old_child_computed_sizes: Vec<f32> =
|
||||
children.iter().map(|child| child.layout.computed_size.get_dim(x)).collect();
|
||||
|
||||
let unresolved_columns = self.divide_children_to_columns(x, opts, &children);
|
||||
let mut columns = self.resolve_columns(x, opts, unresolved_columns);
|
||||
@ -3482,9 +3550,9 @@ impl Model {
|
||||
let column_size = column.computed_size + fr_diff;
|
||||
let column_size = f32::max(column.min_size, column_size);
|
||||
let column_size = f32::min(column.max_size, column_size);
|
||||
for child in &column.children {
|
||||
let child_size = child.layout.computed_size.get_dim(x);
|
||||
let child_unused_space = f32::max(0.0, column_size - child_size);
|
||||
for (child, previous_size) in column.children.iter().zip(&old_child_computed_sizes) {
|
||||
let child_base_size = child.layout.computed_size.get_dim(x);
|
||||
let child_unused_space = f32::max(0.0, column_size - child_base_size);
|
||||
let unresolved_margin = child.layout.margin.get_dim(x);
|
||||
let margin_fr = unresolved_margin.as_fraction_or_default().total();
|
||||
let margin = unresolved_margin.resolve(self_size, child_unused_space, margin_fr);
|
||||
@ -3492,7 +3560,7 @@ impl Model {
|
||||
|
||||
let child_can_grow = child.layout.grow_factor.get_dim(x) > 0.0;
|
||||
let child_can_shrink = child.layout.shrink_factor.get_dim(x) > 0.0;
|
||||
if child_can_grow && child_size < column_size_minus_margin {
|
||||
if child_can_grow && child_base_size < column_size_minus_margin {
|
||||
let size = f32::min(
|
||||
column_size_minus_margin,
|
||||
child.layout.max_size.get_dim(x).resolve_pixels_or_default(),
|
||||
@ -3508,7 +3576,7 @@ impl Model {
|
||||
child.layout.computed_size.set_dim(x, size);
|
||||
}
|
||||
}
|
||||
if child_can_shrink && child_size > column_size_minus_margin {
|
||||
if child_can_shrink && child_base_size > column_size_minus_margin {
|
||||
let size = f32::max(
|
||||
column_size_minus_margin,
|
||||
child.layout.min_size.get_dim(x).resolve_pixels_or_default(),
|
||||
@ -3516,7 +3584,7 @@ impl Model {
|
||||
child.layout.computed_size.set_dim(x, size);
|
||||
}
|
||||
|
||||
let child_size_changed = child_size != child.layout.computed_size.get_dim(x);
|
||||
let child_size_changed = child_base_size != child.layout.computed_size.get_dim(x);
|
||||
let child_not_computed =
|
||||
child.layout.size.get_dim(x).is_fixed() && child.should_refresh_layout();
|
||||
if child_size_changed || child_not_computed {
|
||||
@ -3526,14 +3594,17 @@ impl Model {
|
||||
// child size, we need to refresh the child layout again.
|
||||
child.refresh_layout_internal(x, PassConfig::DoNotHugDirectChildren);
|
||||
}
|
||||
|
||||
let child_width = child.layout.computed_size.get_dim(x);
|
||||
let child_unused_space = f32::max(0.0, column_size_minus_margin - child_width);
|
||||
let def_alignment = opts.children_alignment.get_dim(x);
|
||||
let alignment = child.layout.alignment.get().get_dim(x).unwrap_or(def_alignment);
|
||||
let child_offset = child_unused_space * alignment.normalized();
|
||||
let content_origin = child.content_origin();
|
||||
let child_left = pos_x - content_origin.get_dim(x) + child_offset + margin.start;
|
||||
let child_left = pos_x + child_offset + margin.start;
|
||||
child.set_position_dim(x, child_left);
|
||||
if *previous_size != child_width {
|
||||
child.dirty.computed_size.set();
|
||||
}
|
||||
}
|
||||
pos_x += column_size + gap;
|
||||
}
|
||||
@ -4627,12 +4698,6 @@ mod layout_tests {
|
||||
self
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_root_content_origin(&self, x:f32, y:f32) -> &Self {
|
||||
assert_eq!(self.root.content_origin(), Vector2(x,y));
|
||||
self
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_root_position(&self, x:f32, y:f32) -> &Self {
|
||||
assert_eq!(self.root.position().xy(), Vector2(x,y));
|
||||
@ -4646,12 +4711,6 @@ mod layout_tests {
|
||||
}
|
||||
|
||||
$(
|
||||
#[track_caller]
|
||||
fn [<assert_node $num _content_origin>](&self, x:f32, y:f32) -> &Self {
|
||||
assert_eq!(self.[<node $num>].content_origin(), Vector2(x,y));
|
||||
self
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn [<assert_node $num _position>](&self, x:f32, y:f32) -> &Self {
|
||||
assert_eq!(self.[<node $num>].position().xy(), Vector2(x,y));
|
||||
@ -5569,8 +5628,8 @@ mod layout_tests {
|
||||
/// │ │ │ ╭────────╮ ╰───┼────╯
|
||||
/// ╰───┼────╯ │ node2 │ │
|
||||
/// ╰──────┼────────┼─────╯
|
||||
/// ╱ │ │
|
||||
/// ◎ ╰────────╯
|
||||
/// │ │
|
||||
/// ╰────────╯
|
||||
/// ```
|
||||
#[test]
|
||||
fn test_layout_manual_fixed() {
|
||||
@ -5587,7 +5646,6 @@ mod layout_tests {
|
||||
.assert_node1_computed_size(2.0, 2.0)
|
||||
.assert_node2_computed_size(2.0, 2.0)
|
||||
.assert_node3_computed_size(2.0, 2.0)
|
||||
.assert_root_content_origin(-1.0, -1.0)
|
||||
.assert_root_position(0.0, 0.0)
|
||||
.assert_node1_position(-1.0, 0.0)
|
||||
.assert_node2_position(1.0, -1.0)
|
||||
@ -5596,16 +5654,15 @@ mod layout_tests {
|
||||
}
|
||||
|
||||
/// ```text
|
||||
/// ╭──────── ▶ ◀ ──────────────────╮
|
||||
/// │ root │
|
||||
/// │ ╭────────╮ │
|
||||
/// ╭───┼────╮ │ node3 │ │
|
||||
/// │ node1 │ │ │ ▼
|
||||
/// │ │ │ ╭────────╮ ╰────────╯ ▲
|
||||
/// ╰───┼────╯ │ node2 │ │
|
||||
/// ╰──────┼────────┼───────────────╯
|
||||
/// ╱ │ │
|
||||
/// ◎ ╰────────╯
|
||||
/// ╭──────── ▶ ◀ ──────────────╮
|
||||
/// │ root ╭────────╮│
|
||||
/// ╭───┼────╮ │ node3 ││
|
||||
/// │ node1 │ │ │▼
|
||||
/// │ │ │ ╭────────╮ ╰────────╯▲
|
||||
/// ╰───┼────╯ │ node2 │ │
|
||||
/// ╰──────┼────────┼───────────╯
|
||||
/// │ │
|
||||
/// ╰────────╯
|
||||
/// ```
|
||||
#[test]
|
||||
fn test_layout_manual_hug() {
|
||||
@ -5617,11 +5674,10 @@ mod layout_tests {
|
||||
test.node2.set_xy((1.0, -1.0));
|
||||
test.node3.set_xy((3.0, 1.0));
|
||||
test.run(|| {
|
||||
test.assert_root_computed_size(6.0, 4.0)
|
||||
test.assert_root_computed_size(5.0, 3.0)
|
||||
.assert_node1_computed_size(2.0, 2.0)
|
||||
.assert_node2_computed_size(2.0, 2.0)
|
||||
.assert_node3_computed_size(2.0, 2.0)
|
||||
.assert_root_content_origin(-1.0, -1.0)
|
||||
.assert_root_position(0.0, 0.0)
|
||||
.assert_node1_position(-1.0, 0.0)
|
||||
.assert_node2_position(1.0, -1.0)
|
||||
@ -5630,23 +5686,19 @@ mod layout_tests {
|
||||
}
|
||||
|
||||
/// ```text
|
||||
/// ╭────── ▶ ◀ ──────────────╮ ╭────── ▶ ◀ ─────────────╮
|
||||
/// │ node1 │ │ node2 │
|
||||
/// ╔════════╪═══════════════════ ▶ ◀ ═╪════╪════════════════════════╪╗
|
||||
/// ║ ╭──────┼───────────────────────┬─┼────┼──────────────────────╮ │║
|
||||
/// ║ │ root │ ┆ │ │ │ │║
|
||||
/// ║ │ ╭───┼──────╮ ┆ ▼╭───┼──────╮ │ ▼║
|
||||
/// ║ │ │ node1_1 │ ┆ ▲│ node2_1 │ │ ▲║
|
||||
/// ║ │ │ │ │ ╭──────────╮ ┆ ││ │ │ ╭─────────╮ │ │▼
|
||||
/// ║ │ ╰───┼──────╯ │ node1_2 │ ┆ │╰───┼──────╯ │ node2_2 │ │ │▲
|
||||
/// ║ │ ╰─────────┼──────────┼──┼─╯ ╰─────────┼─────────┼──┼─╯║
|
||||
/// ║ │ ╱ │ │ ┆ ╱ │ │ │ ║
|
||||
/// ║ │ ◎ ╰──────────╯ ┆ ◎ ╰─────────╯ │ ║
|
||||
/// ║ ╰──────────────────────────────┴─────────────────────────────╯ ║
|
||||
/// ╚═════════════════════════════════════════════════════════════════╝
|
||||
/// ╔══════════════════════ ▶ ◀ ══════════════════════╗
|
||||
/// ║ ╭ root ────────────────┬──────────────────────╮ ║
|
||||
/// ║ │╭ node1 ─ ▶ ◀ ───────╮┆╭ node2 ─ ▶ ◀ ───────╮│ ║
|
||||
/// ╭╫─┼┼──────╮ ╭─┼┼┼──────╮ ││ ║
|
||||
/// │║node1_1 │ │ node2_1 │ ││ ▼
|
||||
/// │║ ││ │ ╭────────┼╮│┆│ │ ╭─────────╮││ ▲
|
||||
/// ╰╫─┼┼──────╯ │ node1_2╰┼┼┼┼──────╯ │ node2_2 │││ ║
|
||||
/// ║ │╰─────────┼─────────┼╯┆╰─────────┼─────────┼╯│ ║
|
||||
/// ║ ╰──────────┼─────────┼─┴──────────┼─────────┼─╯ ║
|
||||
/// ╚════════════╰─────────╯════════════╰─────────╯═══╝
|
||||
/// ```
|
||||
#[test]
|
||||
fn test_layout_with_children_with_shifted_content_origins() {
|
||||
fn test_layout_with_children_with_overflow() {
|
||||
let test = TestFlatChildren2::new();
|
||||
|
||||
test.root.use_auto_layout();
|
||||
@ -5670,65 +5722,23 @@ mod layout_tests {
|
||||
assert_eq!(node1_2.position().xy(), Vector2(1.0, -1.0));
|
||||
assert_eq!(node1_1.computed_size(), Vector2(2.0, 2.0));
|
||||
assert_eq!(node1_2.computed_size(), Vector2(2.0, 2.0));
|
||||
assert_eq!(test.node1.content_origin(), Vector2(-1.0, -1.0));
|
||||
assert_eq!(test.node1.computed_size(), Vector2(4.0, 3.0));
|
||||
assert_eq!(test.node1.computed_size(), Vector2(3.0, 2.0));
|
||||
|
||||
assert_eq!(node2_1.position().xy(), Vector2(-1.0, 0.0));
|
||||
assert_eq!(node2_2.position().xy(), Vector2(1.0, -1.0));
|
||||
assert_eq!(node2_1.computed_size(), Vector2(2.0, 2.0));
|
||||
assert_eq!(node2_2.computed_size(), Vector2(2.0, 2.0));
|
||||
assert_eq!(test.node2.content_origin(), Vector2(-1.0, -1.0));
|
||||
assert_eq!(test.node2.computed_size(), Vector2(4.0, 3.0));
|
||||
assert_eq!(test.node2.computed_size(), Vector2(3.0, 2.0));
|
||||
|
||||
test.assert_node1_position(1.0, 1.0)
|
||||
.assert_node2_position(5.0, 1.0)
|
||||
.assert_root_computed_size(8.0, 3.0)
|
||||
.assert_root_content_origin(0.0, 0.0)
|
||||
test.assert_node1_position(0.0, 0.0)
|
||||
.assert_node2_position(3.0, 0.0)
|
||||
.assert_node1_computed_size(3.0, 2.0)
|
||||
.assert_node2_computed_size(3.0, 2.0)
|
||||
.assert_root_computed_size(6.0, 2.0)
|
||||
.assert_root_position(0.0, 0.0);
|
||||
});
|
||||
}
|
||||
|
||||
/// ```text
|
||||
/// ◎╌╌╌╌╌╌╌┬───────────────╮
|
||||
/// │ root │
|
||||
/// │ △ │
|
||||
/// ╭ node1 ┼───────┼▷ │
|
||||
/// │ │ │ │
|
||||
/// │ │ │ │
|
||||
/// │ ╰───────┼───────┤
|
||||
/// │ │ ┆
|
||||
/// │ │ ┆
|
||||
/// ╰───────────────╯ ◎
|
||||
/// ```
|
||||
|
||||
/// ```text
|
||||
/// ╭───────────────────╮
|
||||
/// │ root │
|
||||
/// │ ╭─────────╮ ▼
|
||||
/// │ │ node1 │ ▲
|
||||
/// │ │ ◎ │ │
|
||||
/// │ │ │ │
|
||||
/// │ ╰─────────╯ │
|
||||
/// │ │
|
||||
/// ╰───────────────────╯
|
||||
/// ```
|
||||
#[test]
|
||||
fn test_layout_horizontal_origin_alignment_center() {
|
||||
let test = TestFlatChildren1::new();
|
||||
test.root.use_auto_layout().set_size((10.0, 10.0)).set_padding_all(1.fr());
|
||||
test.node1
|
||||
.set_size((2.0, 2.0))
|
||||
.unsafe_set_forced_origin_alignment(alignment::Dim2::center());
|
||||
test.run(|| {
|
||||
test.assert_root_computed_size(10.0, 10.0)
|
||||
.assert_node1_computed_size(2.0, 2.0)
|
||||
.assert_root_position(0.0, 0.0)
|
||||
.assert_node1_position(5.0, 5.0)
|
||||
.assert_root_content_origin(0.0, 0.0)
|
||||
.assert_node1_content_origin(-1.0, -1.0);
|
||||
});
|
||||
}
|
||||
|
||||
/// ```text
|
||||
/// ╭───────────────────╮
|
||||
/// │ root │
|
||||
@ -5736,9 +5746,33 @@ mod layout_tests {
|
||||
/// │ │ node1 │ │
|
||||
/// │ │ │ │
|
||||
/// │ │ │ │
|
||||
/// │ ◎─────────╯ │
|
||||
/// │ ╰─────────╯ │
|
||||
/// │ │
|
||||
/// ◎───────────────────╯
|
||||
/// ╰───────────────────╯
|
||||
/// ```
|
||||
#[test]
|
||||
fn test_layout_fraction_padding_all() {
|
||||
let test = TestFlatChildren1::new();
|
||||
test.root.use_auto_layout().set_size((10.0, 10.0)).set_padding_all(1.fr());
|
||||
test.node1.set_size((2.0, 2.0));
|
||||
test.run(|| {
|
||||
test.assert_root_computed_size(10.0, 10.0)
|
||||
.assert_node1_computed_size(2.0, 2.0)
|
||||
.assert_root_position(0.0, 0.0)
|
||||
.assert_node1_position(4.0, 4.0);
|
||||
});
|
||||
}
|
||||
|
||||
/// ```text
|
||||
/// ╭───────────────────╮
|
||||
/// │ root │
|
||||
/// │ ╭─────────╮ │
|
||||
/// │ │ node1 │ │
|
||||
/// │ │ │ │
|
||||
/// │ │ │ │
|
||||
/// │ ╰─────────╯ │
|
||||
/// │ │
|
||||
/// ╰───────────────────╯
|
||||
/// ```
|
||||
#[test]
|
||||
fn test_manual_layout_alignment_center() {
|
||||
@ -5750,25 +5784,23 @@ mod layout_tests {
|
||||
test.assert_root_computed_size(10.0, 10.0)
|
||||
.assert_node1_computed_size(5.0, 5.0)
|
||||
.assert_root_position(0.0, 0.0)
|
||||
.assert_node1_position(2.5, 2.5)
|
||||
.assert_node1_content_origin(0.0, 0.0)
|
||||
.assert_root_content_origin(0.0, 0.0);
|
||||
.assert_node1_position(2.5, 2.5);
|
||||
});
|
||||
}
|
||||
|
||||
/// ```text
|
||||
/// ╭─root─────────────────────╮
|
||||
/// │╭─node1──╮ │
|
||||
/// ││ │ │
|
||||
/// ││ │ │
|
||||
/// ╭─node2┼┼────────┼───────╮ │
|
||||
/// │ ││ │ │ │
|
||||
/// │ ││ │ │ │
|
||||
/// ╰──────┼┼────────┼───────╯ │
|
||||
/// ││ │ │
|
||||
/// ││ │ │
|
||||
/// │╰────────╯ │
|
||||
/// ◎╌╌╌╌╌╌╰──────────────────────────╯
|
||||
/// ╭─root─────────────╮
|
||||
/// │╭─node1──╮ │
|
||||
/// ││ │ │
|
||||
/// ││ │ │
|
||||
/// ╭─node2┼┼────────┼───────╮│
|
||||
/// │ ││ │ ││
|
||||
/// │ ││ │ ││
|
||||
/// ╰──────┼┼────────┼───────╯│
|
||||
/// ││ │ │
|
||||
/// ││ │ │
|
||||
/// │╰────────╯ │
|
||||
/// ╰──────────────────╯
|
||||
/// ```
|
||||
#[test]
|
||||
fn test_manual_layout_alignment_center_hug() {
|
||||
@ -5777,88 +5809,34 @@ mod layout_tests {
|
||||
test.node2.set_size((10.0, 5.0));
|
||||
test.node2.set_alignment_center();
|
||||
test.run(|| {
|
||||
test.assert_root_computed_size(10.0, 10.0)
|
||||
test.assert_root_computed_size(7.5, 10.0)
|
||||
.assert_node1_computed_size(5.0, 10.0)
|
||||
.assert_node2_computed_size(10.0, 5.0)
|
||||
.assert_root_position(0.0, 0.0)
|
||||
.assert_node1_position(0.0, 0.0)
|
||||
.assert_node2_position(-2.5, 2.5)
|
||||
.assert_node1_content_origin(0.0, 0.0)
|
||||
.assert_node2_content_origin(0.0, 0.0)
|
||||
.assert_root_content_origin(-2.5, 0.0);
|
||||
.assert_node2_position(-2.5, 2.5);
|
||||
});
|
||||
}
|
||||
|
||||
/// ```text
|
||||
/// ◎╌╌╌╌╌╌╌┬───────────────╮
|
||||
/// │ root │
|
||||
/// │ △ │
|
||||
/// ╭ node1 ┼───────┼▷ │
|
||||
/// │ │ │ │
|
||||
/// │ │ │ │
|
||||
/// │ ╰───────┼───────┤
|
||||
/// │ │ ┆
|
||||
/// │ │ ┆
|
||||
/// ╰───────────────╯ ◎
|
||||
/// ╭ root ───────────╮
|
||||
/// │╭ node1 ───◀ ▶──╮│
|
||||
/// ││ ▲│
|
||||
/// ││ ▼│
|
||||
/// ││ ││
|
||||
/// │╰───────────────╯│
|
||||
/// ╰─────────────────╯
|
||||
/// ```
|
||||
#[test]
|
||||
fn test_manual_layout_with_child_with_origin_alignment_center() {
|
||||
fn test_manual_layout_with_child_with_grow() {
|
||||
let test = TestFlatChildren1::new();
|
||||
test.root.set_size((10.0, 10.0));
|
||||
test.node1.allow_grow().unsafe_set_forced_origin_alignment(alignment::Dim2::center());
|
||||
test.node1.allow_grow();
|
||||
test.run(|| {
|
||||
test.assert_root_computed_size(10.0, 10.0)
|
||||
.assert_node1_computed_size(10.0, 10.0)
|
||||
.assert_root_position(0.0, 0.0)
|
||||
.assert_node1_position(0.0, 0.0)
|
||||
.assert_node1_content_origin(-5.0, -5.0)
|
||||
.assert_root_content_origin(-5.0, -5.0);
|
||||
});
|
||||
}
|
||||
|
||||
/// ```text
|
||||
/// ╭────── ▶ ◀ ──────────────╮ ╭────── ▶ ◀ ─────────────╮
|
||||
/// │ node1 │ │ node2 │
|
||||
/// ╔════════╪═══════════════════ ▶ ◀ ═╪════╪════════════════════════╪╗
|
||||
/// ║ ╭──────┼───────────────────────┬─┼────┼──────────────────────╮ │║
|
||||
/// ║ │ root │ ┆ │ │ │ │║
|
||||
/// ║ │ ╭───┼──────╮ ┆ ▼╭───┼──────╮ │ ▼║
|
||||
/// ║ │ │ node1_1 │ ┆ ▲│ node2_1 │ │ ▲║
|
||||
/// ║ │ │ │ │ ╭──────────╮ ┆ ││ │ │ ╭─────────╮ │ │▼
|
||||
/// ║ │ ╰───┼──────╯ │ node1_2 │ ┆ │╰───┼──────╯ │ node2_2 │ │ │▲
|
||||
/// ║ │ ╰─────────┼──────────┼──┼─╯ ╰─────────┼─────────┼──┼─╯║
|
||||
/// ║ │ ╱ │ │ ┆ ╱ │ │ │ ║
|
||||
/// ║ │ ◎ ╰──────────╯ ┆ ◎ ╰─────────╯ │ ║
|
||||
/// ║ ╰──────────────────────────────┴─────────────────────────────╯ ║
|
||||
/// ╚═════════════════════════════════════════════════════════════════╝
|
||||
#[test]
|
||||
fn test_horizontal_layout_with_children_with_forced_origins() {
|
||||
let test = TestFlatChildren2::new();
|
||||
|
||||
test.root.use_auto_layout();
|
||||
test.node1.set_size((2.0, 2.0));
|
||||
test.node2.set_size((2.0, 2.0));
|
||||
|
||||
let node1_1 = test.node1.new_child_named("node1_1");
|
||||
let node2_1 = test.node2.new_child_named("node2_1");
|
||||
node1_1.allow_grow().unsafe_set_forced_origin_alignment(alignment::Dim2::center());
|
||||
node2_1.allow_grow().unsafe_set_forced_origin_alignment(alignment::Dim2::center());
|
||||
|
||||
test.run(|| {
|
||||
assert_eq!(node1_1.position().xy(), Vector2(0.0, 0.0));
|
||||
assert_eq!(node2_1.position().xy(), Vector2(0.0, 0.0));
|
||||
assert_eq!(node1_1.computed_size(), Vector2(2.0, 2.0));
|
||||
assert_eq!(node2_1.computed_size(), Vector2(2.0, 2.0));
|
||||
assert_eq!(node1_1.content_origin(), Vector2(-1.0, -1.0));
|
||||
assert_eq!(node2_1.content_origin(), Vector2(-1.0, -1.0));
|
||||
assert_eq!(test.node1.content_origin(), Vector2(-1.0, -1.0));
|
||||
assert_eq!(test.node2.content_origin(), Vector2(-1.0, -1.0));
|
||||
assert_eq!(test.node1.computed_size(), Vector2(2.0, 2.0));
|
||||
assert_eq!(test.node2.computed_size(), Vector2(2.0, 2.0));
|
||||
assert_eq!(test.node1.position().xy(), Vector2(1.0, 1.0));
|
||||
assert_eq!(test.node2.position().xy(), Vector2(3.0, 1.0));
|
||||
|
||||
test.assert_root_position(0.0, 0.0);
|
||||
.assert_node1_position(0.0, 0.0);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -228,6 +228,15 @@ macro_rules! gen_transform {
|
||||
*self.[<$name _mut>]() = t;
|
||||
}
|
||||
|
||||
pub fn [<set_ $name _dim_checked>]<D>(&mut self, dim: D, t: f32) -> bool
|
||||
where
|
||||
Vector3<f32>: DimSetter<D>,
|
||||
{
|
||||
let changed = self.transform.$name.set_dim_checked(dim, t);
|
||||
self.dirty |= changed;
|
||||
changed
|
||||
}
|
||||
|
||||
pub fn [<update_ $name>]<F: FnOnce(Vector3<f32>) -> Vector3<f32>>(&mut self, f: F) {
|
||||
*self.[<$name _mut>]() = f(self.$name());
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use crate::display::shape::AnyCachedShape;
|
||||
|
||||
crate::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style, icon: AnyCachedShape) {
|
||||
icon.into()
|
||||
}
|
||||
@ -30,6 +31,7 @@ crate::shape! {
|
||||
pub mod recolorized {
|
||||
crate::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
(style: Style, icon: AnyCachedShape, r_component: Vector4, g_component: Vector4, b_component: Vector4) {
|
||||
let r: Var<color::Rgba> = r_component.into();
|
||||
let g: Var<color::Rgba> = g_component.into();
|
||||
|
@ -17,7 +17,6 @@ use crate::display;
|
||||
mod shape {
|
||||
use super::*;
|
||||
crate::shape! {
|
||||
alignment = left_bottom;
|
||||
(
|
||||
style: Style,
|
||||
color: Vector4,
|
||||
|
@ -124,10 +124,10 @@ pub trait Shape: 'static + Sized + AsRef<Self::InstanceParams> {
|
||||
type ShapeData: Debug;
|
||||
fn definition_path() -> &'static str;
|
||||
fn pointer_events() -> bool;
|
||||
/// The alignment of the drawn shape's origin position. When set to `left_bottom`, the shape's
|
||||
/// origin will be at the bottom left corner of its bounding box. The default value is `center`.
|
||||
/// The alignment of the drawn shape's origin position. When set to `center`, the shape's
|
||||
/// origin will be at the center of its bounding box. The default value is `left_bottom`.
|
||||
fn default_alignment() -> alignment::Dim2 {
|
||||
alignment::Dim2::center()
|
||||
alignment::Dim2::left_bottom()
|
||||
}
|
||||
fn always_above() -> Vec<ShapeSystemId>;
|
||||
fn always_below() -> Vec<ShapeSystemId>;
|
||||
@ -659,14 +659,12 @@ macro_rules! shape_old {
|
||||
$(above = [$($always_above_1:tt $(::$always_above_2:tt)*),*];)?
|
||||
$(below = [$($always_below_1:tt $(::$always_below_2:tt)*),*];)?
|
||||
$(pointer_events = $pointer_events:tt;)?
|
||||
$(alignment = $alignment:tt;)?
|
||||
($style:ident : Style $(,$gpu_param : ident : $gpu_param_type : ty)* $(,)?) {$($body:tt)*}
|
||||
) => {
|
||||
$crate::_shape_old! {
|
||||
$(SystemData($system_data))?
|
||||
$(ShapeData($shape_data))?
|
||||
$(flavor = [$flavor];)?
|
||||
$(alignment = $alignment;)?
|
||||
$(above = [$($always_above_1 $(::$always_above_2)*),*];)?
|
||||
$(below = [$($always_below_1 $(::$always_below_2)*),*];)?
|
||||
$(pointer_events = $pointer_events;)?
|
||||
@ -685,7 +683,6 @@ macro_rules! _shape_old {
|
||||
$(above = [$($always_above_1:tt $(::$always_above_2:tt)*),*];)?
|
||||
$(below = [$($always_below_1:tt $(::$always_below_2:tt)*),*];)?
|
||||
$(pointer_events = $pointer_events:tt;)?
|
||||
$(alignment = $alignment:tt;)?
|
||||
[$style:ident]
|
||||
($($gpu_param : ident : $gpu_param_type : ty),* $(,)?)
|
||||
{$($body:tt)*}
|
||||
@ -742,9 +739,9 @@ macro_rules! _shape_old {
|
||||
_out
|
||||
}
|
||||
|
||||
$(fn default_alignment() -> $crate::display::layout::alignment::Dim2 {
|
||||
$crate::display::layout::alignment::Dim2::$alignment()
|
||||
})?
|
||||
fn default_alignment() -> $crate::display::layout::alignment::Dim2 {
|
||||
$crate::display::layout::alignment::Dim2::center()
|
||||
}
|
||||
|
||||
fn always_above() -> Vec<ShapeSystemId> {
|
||||
vec![$($( ShapeSystem::<$always_above_1 $(::$always_above_2)*::Shape>::id() ),*)?]
|
||||
|
@ -355,6 +355,7 @@ macro_rules! cached_shape {
|
||||
$(above = [$($always_above_1:tt $(::$always_above_2:tt)*),*];)?
|
||||
$(below = [$($always_below_1:tt $(::$always_below_2:tt)*),*];)?
|
||||
$(pointer_events = $pointer_events:tt;)?
|
||||
$(alignment = $alignment:tt;)?
|
||||
($style:ident : Style) {$($body:tt)*}
|
||||
) => {
|
||||
$crate::_shape! {
|
||||
@ -364,6 +365,7 @@ macro_rules! cached_shape {
|
||||
$(above = [$($always_above_1 $(::$always_above_2)*),*];)?
|
||||
$(below = [$($always_below_1 $(::$always_below_2)*),*];)?
|
||||
$(pointer_events = $pointer_events;)?
|
||||
$(alignment = $alignment;)?
|
||||
[$style] (){$($body)*}
|
||||
}
|
||||
|
||||
@ -429,6 +431,7 @@ mod tests {
|
||||
mod shape1 {
|
||||
cached_shape! {
|
||||
size = (240, 240);
|
||||
alignment = center;
|
||||
(_style: Style) {
|
||||
Plane().into()
|
||||
}
|
||||
@ -438,6 +441,7 @@ mod tests {
|
||||
mod shape2 {
|
||||
cached_shape! {
|
||||
size = (240, 112);
|
||||
alignment = center;
|
||||
(_style: Style) {
|
||||
Plane().into()
|
||||
}
|
||||
@ -447,6 +451,7 @@ mod tests {
|
||||
mod shape3 {
|
||||
cached_shape! {
|
||||
size = (112, 114);
|
||||
alignment = center;
|
||||
(_style: Style) {
|
||||
Plane().into()
|
||||
}
|
||||
|
@ -314,7 +314,6 @@ impl SpriteSystem {
|
||||
let transform = self.transform.at(instance.instance_id);
|
||||
let size = self.size.at(instance.instance_id);
|
||||
let sprite = Sprite::new(&self.symbol, instance, transform, size, &self.stats);
|
||||
sprite.unsafe_set_forced_origin_alignment(self.alignment_value.get());
|
||||
self.add_child(&sprite);
|
||||
sprite
|
||||
}
|
||||
|
@ -138,6 +138,7 @@ pub mod shape {
|
||||
use super::*;
|
||||
crate::shape! {
|
||||
pointer_events = false;
|
||||
alignment = center;
|
||||
( style : Style
|
||||
, press : f32
|
||||
, radius : f32
|
||||
|
@ -24,12 +24,9 @@ use ensogl_core::display::object::ObjectOps;
|
||||
mod rectangle {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = left_bottom;
|
||||
(style: Style, color: Vector4<f32>) {
|
||||
let color = Var::<color::Rgba>::from(color);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
let rect = Rect((&width, &height)).corners_radius(5.0.px());
|
||||
let rect = Rect(Var::canvas_size()).corners_radius(5.0.px());
|
||||
let shape = rect.fill(color);
|
||||
shape.into()
|
||||
}
|
||||
@ -52,10 +49,10 @@ pub fn main() {
|
||||
let camera = scene.camera().clone_ref();
|
||||
let _navigator = Navigator::new(scene, &camera).leak();
|
||||
|
||||
let root = scene.new_child_named("root").leak();
|
||||
root.use_auto_layout().reverse_columns().set_gap((5.0, 5.0));
|
||||
let root1 = scene.new_child_named("root").leak();
|
||||
root1.use_auto_layout().reverse_columns().set_gap((5.0, 5.0));
|
||||
|
||||
let rect1 = root.new_child_named("rect1").leak();
|
||||
let rect1 = root1.new_child_named("rect1").leak();
|
||||
let rect1_bg = rectangle::View::new().leak();
|
||||
rect1.add_child(&rect1_bg);
|
||||
rect1_bg.color.set(Rgba::new(0.0, 0.0, 0.0, 0.3).into());
|
||||
@ -81,7 +78,7 @@ pub fn main() {
|
||||
|
||||
|
||||
let rect2 = rectangle::View::new().leak();
|
||||
root.add_child(&rect2);
|
||||
root1.add_child(&rect2);
|
||||
rect2.set_size(Vector2::new(100.0, 100.0));
|
||||
rect2.color.set(Rgba::new(0.5, 0.0, 0.0, 0.3).into());
|
||||
|
||||
@ -96,7 +93,34 @@ pub fn main() {
|
||||
rect2_inner2.color.set(Rgba::new(0.0, 0.0, 0.0, 0.4).into());
|
||||
|
||||
|
||||
let mut logged = false;
|
||||
let root2 = scene.new_child_named("root2").leak();
|
||||
|
||||
let rect_outer = rectangle::View::new().leak();
|
||||
rect_outer.allow_grow();
|
||||
rect_outer.color.set(Rgba::new(0.5, 0.5, 0.0, 0.2).into());
|
||||
root2.add_child(&rect_outer);
|
||||
|
||||
let overflow_auto_layout = root2.new_child().leak();
|
||||
overflow_auto_layout.use_auto_layout().set_padding_all(10.0);
|
||||
|
||||
let rect_inner = rectangle::View::new().leak();
|
||||
rect_inner.color.set(Rgba::new(0.0, 0.0, 0.0, 0.3).into());
|
||||
overflow_auto_layout.add_child(&rect_inner);
|
||||
|
||||
let rect_inner_1 = rectangle::View::new().leak();
|
||||
rect_inner_1.color.set(Rgba::new(0.0, 0.5, 0.5, 0.8).into());
|
||||
rect_inner_1.set_size((100, 100)).set_xy((50.0, -50.0));
|
||||
rect_inner.add_child(&rect_inner_1);
|
||||
|
||||
let rect_inner_2 = rectangle::View::new().leak();
|
||||
rect_inner_2.set_size((100, 100)).set_xy((-50.0, 50.0));
|
||||
rect_inner_2.color.set(Rgba::new(0.5, 0.0, 0.5, 0.8).into());
|
||||
rect_inner.add_child(&rect_inner_2);
|
||||
|
||||
root1.set_y(-100.0);
|
||||
root2.set_y(100.0);
|
||||
|
||||
let mut i = 0;
|
||||
world
|
||||
.on
|
||||
.before_frame
|
||||
@ -109,11 +133,12 @@ pub fn main() {
|
||||
rect2_inner1.set_alignment(anim_align_at_time(s));
|
||||
rect2_inner2.set_alignment(anim_align_at_time(s + 3.0));
|
||||
|
||||
if !logged {
|
||||
logged = true;
|
||||
if i == 1 {
|
||||
warn!("rect1: {:?}", rect1.display_object());
|
||||
warn!("rect2: {:?}", rect2.display_object());
|
||||
}
|
||||
|
||||
i += 1;
|
||||
})
|
||||
.forget();
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ mod icon1 {
|
||||
use super::*;
|
||||
ensogl_core::cached_shape! {
|
||||
size = (32, 32);
|
||||
alignment = center;
|
||||
(_style: Style) {
|
||||
let shape = Circle(16.px()).fill(color::Rgba::red());
|
||||
shape.recolorize(color::Rgba::green(), color::Rgba::red(), color::Rgba::blue()).into()
|
||||
@ -36,6 +37,7 @@ mod icon2 {
|
||||
use super::*;
|
||||
ensogl_core::cached_shape! {
|
||||
size = (200, 310);
|
||||
alignment = center;
|
||||
(_style: Style) {
|
||||
let shape = Rect((200.px(), 310.px())).fill(color::Rgba::red());
|
||||
shape.into()
|
||||
@ -63,6 +65,7 @@ pub mod data_input {
|
||||
|
||||
ensogl_core::cached_shape! {
|
||||
size = (16, 16);
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let vivid_color: Var<color::Rgba> = "srgba(1.0, 0.0, 0.0, 1.0)".into();
|
||||
let dull_color: Var<color::Rgba> = "srgba(0.0, 1.0, 0.0, 1.0)".into();
|
||||
@ -91,6 +94,7 @@ pub mod data_input {
|
||||
mod shape {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(_style: Style, shape: cached::AnyCachedShape, color: Vector4) {
|
||||
let bg = Rect((100.px(), 100.px())).fill(color::Rgba::white());
|
||||
let vivid_color: Var<color::Rgba> = color.into();
|
||||
@ -139,6 +143,7 @@ mod background {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
below = [texture, icon1, icon2];
|
||||
alignment = center;
|
||||
(style: Style,) {
|
||||
Rect((296.0.px(), 326.0.px())).fill(color::Rgba::black()).into()
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ use ensogl_core::display::object::ObjectOps;
|
||||
mod shape {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let circle1 = Circle(50.px());
|
||||
let circle_bg = circle1.translate_x(-(50.0.px()));
|
||||
|
@ -30,6 +30,7 @@ const RECT_DIFF: f32 = 40.0;
|
||||
mod rectangle {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color: Vector4<f32>, border_size: f32, border_color: Vector4<f32>) {
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
@ -45,6 +46,7 @@ mod rectangle {
|
||||
mod rectangle2 {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
let rect = Rect((10.px(), 10.px()));
|
||||
let shape = rect.fill(color::Rgba::new(0.0, 1.0, 0.0, 1.0));
|
||||
|
@ -44,6 +44,7 @@ mod shape {
|
||||
use super::*;
|
||||
|
||||
shape! {
|
||||
alignment = center;
|
||||
(style: Style) {
|
||||
Circle(100.px()).fill(color::Rgb(1.0,0.0,0.0)).into()
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ pub fn main() {
|
||||
mod content {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let circle = Circle(50.px())
|
||||
.translate(((-50.0).px(), 350.0.px()))
|
||||
@ -79,6 +80,7 @@ mod content {
|
||||
mod background {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style:Style) {
|
||||
let size = (200.px(), 200.px());
|
||||
let color = color::Rgb::new(0.9, 0.9, 0.9);
|
||||
|
@ -63,6 +63,7 @@ const GREEN: Vector4 = Vector4::new(0.2, 0.85, 0.2, 1.0);
|
||||
mod h_line {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
let height = Var::<Pixels>::from("input_size.y");
|
||||
@ -76,6 +77,7 @@ mod h_line {
|
||||
mod v_line {
|
||||
use super::*;
|
||||
ensogl_core::shape! {
|
||||
alignment = center;
|
||||
(style: Style, color_rgba: Vector4<f32>) {
|
||||
let fill_color = Var::<color::Rgba>::from(color_rgba);
|
||||
let width = Var::<Pixels>::from("input_size.x");
|
||||
|
@ -365,6 +365,8 @@ pub trait DimMut<D>: DimRef<D> {
|
||||
#[allow(missing_docs)]
|
||||
pub trait DimSetter<D>: Dim<D> {
|
||||
fn set_dim(&mut self, dim: D, value: Self::Dim1Type);
|
||||
/// Set dimension value, returning `true` only if the value was changed.
|
||||
fn set_dim_checked(&mut self, dim: D, value: Self::Dim1Type) -> bool;
|
||||
fn update_dim(&mut self, dim: D, f: impl FnOnce(Self::Dim1Type) -> Self::Dim1Type)
|
||||
where D: Copy {
|
||||
self.set_dim(dim, f(self.get_dim(dim)));
|
||||
@ -410,7 +412,16 @@ macro_rules! gen_dim_impl_for_vector {
|
||||
|
||||
impl<T: Scalar + Copy> DimSetter<[<$dim:upper>]> for $vec<T> {
|
||||
fn set_dim(&mut self, _dim: [<$dim:upper>], value: Self::Dim1Type) {
|
||||
self.[<set_ $dim>](value)
|
||||
self.[<set_ $dim>](value);
|
||||
}
|
||||
|
||||
fn set_dim_checked(&mut self, _dim: [<$dim:upper>], value: Self::Dim1Type) -> bool {
|
||||
if self.$dim() == value {
|
||||
false
|
||||
} else {
|
||||
self.[<set_ $dim>](value);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
)*}
|
||||
|
Loading…
Reference in New Issue
Block a user