mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Change UI coordinate system to have origin at top left corner (#6000)
# Objective Fixes #5572 ## Solution Approach is to invert the Y-axis of the UI Camera by changing the UI projection matrix to render the UI upside down. After that I'm trying to fix all issues, that pop up: - interaction expected the "old" position - images and text were displayed upside-down - baseline of text was based on the top of the glyph instead of bottom ... probably a lot more. --- Result when running examples: <details> <summary>Button example</summary> main branch: ![button main](https://user-images.githubusercontent.com/4232644/190856087-61dd1d98-42b5-4238-bd97-149744ddfeba.png) this pr: ![button pr](https://user-images.githubusercontent.com/4232644/190856097-3f4bc97a-ed15-4e97-b7f1-2b2dd6bb8b14.png) </details> <details> <summary>Text example</summary> m ![text main](https://user-images.githubusercontent.com/4232644/192142831-4cf19aa1-f49a-485e-af7b-374d6f5c396c.png) ain branch: this pr: ![text pr fixed](https://user-images.githubusercontent.com/4232644/192142829-c433db3b-32e1-4ee8-b493-0b4a4d9c8e70.png) </details> <details> <summary>Text debug example</summary> main branch: ![text_debug main](https://user-images.githubusercontent.com/4232644/192142822-940aefa6-e502-410b-8da4-5570f77b5df2.png) this pr: ![text_debug pr fixed](https://user-images.githubusercontent.com/4232644/194547010-8c968f5c-5a71-4ffc-871d-790c06d48016.png) </details> <details> <summary>Transparency UI example</summary> main branch: ![transparency_ui main](https://user-images.githubusercontent.com/4232644/190856172-328c60fe-3622-4598-97d5-2f1595db13b3.png) this pr: ![transperency_ui pr](https://user-images.githubusercontent.com/4232644/190856179-a2dafb99-41ea-45a9-9dd6-400fa3ef24b9.png) </details> <details> <summary>UI example</summary> **ui example** main branch: ![ui main](https://user-images.githubusercontent.com/4232644/192142812-e20ba31a-6841-46d9-a785-4198cf22dc99.png) this pr: ![ui pr fixed](https://user-images.githubusercontent.com/4232644/192142788-cc0b74e0-7710-4faa-b5a2-60270a5da77c.png) </details> ## Changelog UI coordinate system and cursor position was changed from bottom left origin, y+ up to top left origin, y+ down. ## Migration Guide All flex layout should be inverted (ColumnReverse => Column, FlexStart => FlexEnd, WrapReverse => Wrap) System where dealing with cursor position should be changed to account for cursor position being based on the top left instead of bottom left
This commit is contained in:
parent
13dcdba05f
commit
6ce7ce208e
11 changed files with 62 additions and 70 deletions
|
@ -73,16 +73,17 @@ impl GlyphBrush {
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let mut max_y = std::f32::MIN;
|
|
||||||
let mut min_x = std::f32::MAX;
|
let mut min_x = std::f32::MAX;
|
||||||
|
let mut min_y = std::f32::MAX;
|
||||||
for sg in &glyphs {
|
for sg in &glyphs {
|
||||||
let glyph = &sg.glyph;
|
let glyph = &sg.glyph;
|
||||||
|
|
||||||
let scaled_font = sections_data[sg.section_index].3;
|
let scaled_font = sections_data[sg.section_index].3;
|
||||||
max_y = max_y.max(glyph.position.y - scaled_font.descent());
|
|
||||||
min_x = min_x.min(glyph.position.x);
|
min_x = min_x.min(glyph.position.x);
|
||||||
|
min_y = min_y.min(glyph.position.y - scaled_font.ascent());
|
||||||
}
|
}
|
||||||
max_y = max_y.floor();
|
|
||||||
min_x = min_x.floor();
|
min_x = min_x.floor();
|
||||||
|
min_y = min_y.floor();
|
||||||
|
|
||||||
let mut positioned_glyphs = Vec::new();
|
let mut positioned_glyphs = Vec::new();
|
||||||
for sg in glyphs {
|
for sg in glyphs {
|
||||||
|
@ -119,7 +120,7 @@ impl GlyphBrush {
|
||||||
let size = Vec2::new(glyph_rect.width(), glyph_rect.height());
|
let size = Vec2::new(glyph_rect.width(), glyph_rect.height());
|
||||||
|
|
||||||
let x = bounds.min.x + size.x / 2.0 - min_x;
|
let x = bounds.min.x + size.x / 2.0 - min_x;
|
||||||
let y = max_y - bounds.max.y + size.y / 2.0;
|
let y = bounds.min.y + size.y / 2.0 - min_y;
|
||||||
let position = adjust.position(Vec2::new(x, y));
|
let position = adjust.position(Vec2::new(x, y));
|
||||||
|
|
||||||
positioned_glyphs.push(PositionedGlyph {
|
positioned_glyphs.push(PositionedGlyph {
|
||||||
|
|
|
@ -10,9 +10,8 @@ pub fn from_rect(
|
||||||
taffy::geometry::Rect {
|
taffy::geometry::Rect {
|
||||||
start: from_val(scale_factor, rect.left),
|
start: from_val(scale_factor, rect.left),
|
||||||
end: from_val(scale_factor, rect.right),
|
end: from_val(scale_factor, rect.right),
|
||||||
// NOTE: top and bottom are intentionally flipped. stretch has a flipped y-axis
|
top: from_val(scale_factor, rect.top),
|
||||||
top: from_val(scale_factor, rect.bottom),
|
bottom: from_val(scale_factor, rect.bottom),
|
||||||
bottom: from_val(scale_factor, rect.top),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! This crate contains Bevy's UI system, which can be used to create UI for both 2D and 3D games
|
//! This crate contains Bevy's UI system, which can be used to create UI for both 2D and 3D games
|
||||||
//! # Basic usage
|
//! # Basic usage
|
||||||
//! Spawn UI elements with [`entity::ButtonBundle`], [`entity::ImageBundle`], [`entity::TextBundle`] and [`entity::NodeBundle`]
|
//! Spawn UI elements with [`entity::ButtonBundle`], [`entity::ImageBundle`], [`entity::TextBundle`] and [`entity::NodeBundle`]
|
||||||
//! This UI is laid out with the Flexbox paradigm (see <https://cssreference.io/flexbox/> ) except the vertical axis is inverted
|
//! This UI is laid out with the Flexbox paradigm (see <https://cssreference.io/flexbox/>)
|
||||||
mod flex;
|
mod flex;
|
||||||
mod focus;
|
mod focus;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
|
|
|
@ -12,7 +12,7 @@ use bevy_ecs::prelude::*;
|
||||||
use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4Swizzles};
|
use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4Swizzles};
|
||||||
use bevy_reflect::TypeUuid;
|
use bevy_reflect::TypeUuid;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{Camera, CameraProjection, OrthographicProjection, WindowOrigin},
|
camera::Camera,
|
||||||
color::Color,
|
color::Color,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_graph::{RenderGraph, RunGraphOnViewNode, SlotInfo, SlotType},
|
render_graph::{RenderGraph, RunGraphOnViewNode, SlotInfo, SlotType},
|
||||||
|
@ -243,15 +243,12 @@ pub fn extract_default_ui_camera_view<T: Component>(
|
||||||
camera.physical_viewport_rect(),
|
camera.physical_viewport_rect(),
|
||||||
camera.physical_viewport_size(),
|
camera.physical_viewport_size(),
|
||||||
) {
|
) {
|
||||||
let mut projection = OrthographicProjection {
|
// use a projection matrix with the origin in the top left instead of the bottom left that comes with OrthographicProjection
|
||||||
far: UI_CAMERA_FAR,
|
let projection_matrix =
|
||||||
window_origin: WindowOrigin::BottomLeft,
|
Mat4::orthographic_rh(0.0, logical_size.x, logical_size.y, 0.0, 0.0, UI_CAMERA_FAR);
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
projection.update(logical_size.x, logical_size.y);
|
|
||||||
let default_camera_view = commands
|
let default_camera_view = commands
|
||||||
.spawn(ExtractedView {
|
.spawn(ExtractedView {
|
||||||
projection: projection.get_projection_matrix(),
|
projection: projection_matrix,
|
||||||
transform: GlobalTransform::from_xyz(
|
transform: GlobalTransform::from_xyz(
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -464,24 +461,23 @@ pub fn prepare_uinodes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clip UVs (Note: y is reversed in UV space)
|
|
||||||
let atlas_extent = extracted_uinode.atlas_size.unwrap_or(uinode_rect.max);
|
let atlas_extent = extracted_uinode.atlas_size.unwrap_or(uinode_rect.max);
|
||||||
let uvs = [
|
let uvs = [
|
||||||
Vec2::new(
|
Vec2::new(
|
||||||
uinode_rect.min.x + positions_diff[0].x,
|
uinode_rect.min.x + positions_diff[3].x,
|
||||||
uinode_rect.max.y - positions_diff[0].y,
|
uinode_rect.min.y - positions_diff[3].y,
|
||||||
),
|
|
||||||
Vec2::new(
|
|
||||||
uinode_rect.max.x + positions_diff[1].x,
|
|
||||||
uinode_rect.max.y - positions_diff[1].y,
|
|
||||||
),
|
),
|
||||||
Vec2::new(
|
Vec2::new(
|
||||||
uinode_rect.max.x + positions_diff[2].x,
|
uinode_rect.max.x + positions_diff[2].x,
|
||||||
uinode_rect.min.y - positions_diff[2].y,
|
uinode_rect.min.y - positions_diff[2].y,
|
||||||
),
|
),
|
||||||
Vec2::new(
|
Vec2::new(
|
||||||
uinode_rect.min.x + positions_diff[3].x,
|
uinode_rect.max.x + positions_diff[1].x,
|
||||||
uinode_rect.min.y - positions_diff[3].y,
|
uinode_rect.max.y - positions_diff[1].y,
|
||||||
|
),
|
||||||
|
Vec2::new(
|
||||||
|
uinode_rect.min.x + positions_diff[0].x,
|
||||||
|
uinode_rect.max.y - positions_diff[0].y,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
.map(|pos| pos / atlas_extent);
|
.map(|pos| pos / atlas_extent);
|
||||||
|
|
|
@ -303,11 +303,11 @@ pub enum FlexDirection {
|
||||||
/// Same way as text direction along the main axis
|
/// Same way as text direction along the main axis
|
||||||
#[default]
|
#[default]
|
||||||
Row,
|
Row,
|
||||||
/// Flex from bottom to top
|
/// Flex from top to bottom
|
||||||
Column,
|
Column,
|
||||||
/// Opposite way as text direction along the main axis
|
/// Opposite way as text direction along the main axis
|
||||||
RowReverse,
|
RowReverse,
|
||||||
/// Flex from top to bottom
|
/// Flex from bottom to top
|
||||||
ColumnReverse,
|
ColumnReverse,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,12 +149,9 @@ fn change_window(
|
||||||
}
|
}
|
||||||
bevy_window::WindowCommand::SetCursorPosition { position } => {
|
bevy_window::WindowCommand::SetCursorPosition { position } => {
|
||||||
let window = winit_windows.get_window(id).unwrap();
|
let window = winit_windows.get_window(id).unwrap();
|
||||||
let inner_size = window.inner_size().to_logical::<f32>(window.scale_factor());
|
|
||||||
window
|
window
|
||||||
.set_cursor_position(LogicalPosition::new(
|
.set_cursor_position(LogicalPosition::new(position.x, position.y))
|
||||||
position.x,
|
|
||||||
inner_size.height - position.y,
|
|
||||||
))
|
|
||||||
.unwrap_or_else(|e| error!("Unable to set cursor position: {}", e));
|
.unwrap_or_else(|e| error!("Unable to set cursor position: {}", e));
|
||||||
}
|
}
|
||||||
bevy_window::WindowCommand::SetMaximized { maximized } => {
|
bevy_window::WindowCommand::SetMaximized { maximized } => {
|
||||||
|
@ -431,13 +428,8 @@ pub fn winit_runner_with(mut app: App) {
|
||||||
}
|
}
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
let mut cursor_moved_events = world.resource_mut::<Events<CursorMoved>>();
|
let mut cursor_moved_events = world.resource_mut::<Events<CursorMoved>>();
|
||||||
let winit_window = winit_windows.get_window(window_id).unwrap();
|
|
||||||
let inner_size = winit_window.inner_size();
|
|
||||||
|
|
||||||
// move origin to bottom left
|
let physical_position = DVec2::new(position.x, position.y);
|
||||||
let y_position = inner_size.height as f64 - position.y;
|
|
||||||
|
|
||||||
let physical_position = DVec2::new(position.x, y_position);
|
|
||||||
window
|
window
|
||||||
.update_cursor_physical_position_from_backend(Some(physical_position));
|
.update_cursor_physical_position_from_backend(Some(physical_position));
|
||||||
|
|
||||||
|
|
|
@ -152,9 +152,8 @@ mod game {
|
||||||
style: Style {
|
style: Style {
|
||||||
// This will center the current node
|
// This will center the current node
|
||||||
margin: UiRect::all(Val::Auto),
|
margin: UiRect::all(Val::Auto),
|
||||||
// This will display its children in a column, from top to bottom. Unlike
|
// This will display its children in a column, from top to bottom
|
||||||
// in Flexbox, Bevy origin is on bottom left, so the vertical axis is reversed
|
flex_direction: FlexDirection::Column,
|
||||||
flex_direction: FlexDirection::ColumnReverse,
|
|
||||||
// `align_items` will align children on the cross axis. Here the main axis is
|
// `align_items` will align children on the cross axis. Here the main axis is
|
||||||
// vertical (column), so the cross axis is horizontal. This will center the
|
// vertical (column), so the cross axis is horizontal. This will center the
|
||||||
// children
|
// children
|
||||||
|
@ -420,7 +419,7 @@ mod menu {
|
||||||
NodeBundle {
|
NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
margin: UiRect::all(Val::Auto),
|
margin: UiRect::all(Val::Auto),
|
||||||
flex_direction: FlexDirection::ColumnReverse,
|
flex_direction: FlexDirection::Column,
|
||||||
align_items: AlignItems::Center,
|
align_items: AlignItems::Center,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
|
@ -533,7 +532,7 @@ mod menu {
|
||||||
NodeBundle {
|
NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
margin: UiRect::all(Val::Auto),
|
margin: UiRect::all(Val::Auto),
|
||||||
flex_direction: FlexDirection::ColumnReverse,
|
flex_direction: FlexDirection::Column,
|
||||||
align_items: AlignItems::Center,
|
align_items: AlignItems::Center,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
|
@ -587,7 +586,7 @@ mod menu {
|
||||||
NodeBundle {
|
NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
margin: UiRect::all(Val::Auto),
|
margin: UiRect::all(Val::Auto),
|
||||||
flex_direction: FlexDirection::ColumnReverse,
|
flex_direction: FlexDirection::Column,
|
||||||
align_items: AlignItems::Center,
|
align_items: AlignItems::Center,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
|
@ -678,7 +677,7 @@ mod menu {
|
||||||
NodeBundle {
|
NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
margin: UiRect::all(Val::Auto),
|
margin: UiRect::all(Val::Auto),
|
||||||
flex_direction: FlexDirection::ColumnReverse,
|
flex_direction: FlexDirection::Column,
|
||||||
align_items: AlignItems::Center,
|
align_items: AlignItems::Center,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -82,7 +82,21 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResM
|
||||||
let font_handle = asset_server.load("fonts/FiraSans-Bold.ttf");
|
let font_handle = asset_server.load("fonts/FiraSans-Bold.ttf");
|
||||||
state.handle = font_handle.clone();
|
state.handle = font_handle.clone();
|
||||||
commands.spawn(Camera2dBundle::default());
|
commands.spawn(Camera2dBundle::default());
|
||||||
commands.spawn(TextBundle::from_section(
|
commands
|
||||||
|
.spawn(NodeBundle {
|
||||||
|
background_color: Color::NONE.into(),
|
||||||
|
style: Style {
|
||||||
|
position_type: PositionType::Absolute,
|
||||||
|
position: UiRect {
|
||||||
|
bottom: Val::Px(0.0),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
})
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn(TextBundle::from_section(
|
||||||
"a",
|
"a",
|
||||||
TextStyle {
|
TextStyle {
|
||||||
font: font_handle,
|
font: font_handle,
|
||||||
|
@ -90,4 +104,5 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResM
|
||||||
color: Color::YELLOW,
|
color: Color::YELLOW,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
.with_text_alignment(TextAlignment::TOP_CENTER)
|
.with_text_alignment(TextAlignment::TOP_CENTER)
|
||||||
// Set the style of the TextBundle itself.
|
// Set the style of the TextBundle itself.
|
||||||
.with_style(Style {
|
.with_style(Style {
|
||||||
align_self: AlignSelf::FlexEnd,
|
|
||||||
position_type: PositionType::Absolute,
|
position_type: PositionType::Absolute,
|
||||||
position: UiRect {
|
position: UiRect {
|
||||||
bottom: Val::Px(5.0),
|
bottom: Val::Px(5.0),
|
||||||
|
@ -72,11 +71,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
font_size: 60.0,
|
font_size: 60.0,
|
||||||
color: Color::GOLD,
|
color: Color::GOLD,
|
||||||
}),
|
}),
|
||||||
])
|
]),
|
||||||
.with_style(Style {
|
|
||||||
align_self: AlignSelf::FlexEnd,
|
|
||||||
..default()
|
|
||||||
}),
|
|
||||||
FpsText,
|
FpsText,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.with_style(Style {
|
.with_style(Style {
|
||||||
align_self: AlignSelf::FlexEnd,
|
|
||||||
position_type: PositionType::Absolute,
|
position_type: PositionType::Absolute,
|
||||||
position: UiRect {
|
position: UiRect {
|
||||||
top: Val::Px(5.0),
|
top: Val::Px(5.0),
|
||||||
|
@ -55,7 +54,6 @@ fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
)
|
)
|
||||||
.with_text_alignment(TextAlignment::CENTER)
|
.with_text_alignment(TextAlignment::CENTER)
|
||||||
.with_style(Style {
|
.with_style(Style {
|
||||||
align_self: AlignSelf::FlexEnd,
|
|
||||||
position_type: PositionType::Absolute,
|
position_type: PositionType::Absolute,
|
||||||
position: UiRect {
|
position: UiRect {
|
||||||
top: Val::Px(5.0),
|
top: Val::Px(5.0),
|
||||||
|
@ -115,7 +113,6 @@ fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.with_style(Style {
|
.with_style(Style {
|
||||||
align_self: AlignSelf::FlexEnd,
|
|
||||||
position_type: PositionType::Absolute,
|
position_type: PositionType::Absolute,
|
||||||
position: UiRect {
|
position: UiRect {
|
||||||
bottom: Val::Px(5.0),
|
bottom: Val::Px(5.0),
|
||||||
|
|
|
@ -48,7 +48,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
.spawn(NodeBundle {
|
.spawn(NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
||||||
align_items: AlignItems::FlexEnd,
|
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
background_color: Color::rgb(0.15, 0.15, 0.15).into(),
|
background_color: Color::rgb(0.15, 0.15, 0.15).into(),
|
||||||
|
@ -76,7 +75,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
parent
|
parent
|
||||||
.spawn(NodeBundle {
|
.spawn(NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
flex_direction: FlexDirection::ColumnReverse,
|
flex_direction: FlexDirection::Column,
|
||||||
justify_content: JustifyContent::Center,
|
justify_content: JustifyContent::Center,
|
||||||
size: Size::new(Val::Px(200.0), Val::Percent(100.0)),
|
size: Size::new(Val::Px(200.0), Val::Percent(100.0)),
|
||||||
..default()
|
..default()
|
||||||
|
@ -109,7 +108,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
parent
|
parent
|
||||||
.spawn(NodeBundle {
|
.spawn(NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
flex_direction: FlexDirection::ColumnReverse,
|
flex_direction: FlexDirection::Column,
|
||||||
align_self: AlignSelf::Center,
|
align_self: AlignSelf::Center,
|
||||||
size: Size::new(Val::Percent(100.0), Val::Percent(50.0)),
|
size: Size::new(Val::Percent(100.0), Val::Percent(50.0)),
|
||||||
overflow: Overflow::Hidden,
|
overflow: Overflow::Hidden,
|
||||||
|
@ -124,7 +123,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
.spawn((
|
.spawn((
|
||||||
NodeBundle {
|
NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
flex_direction: FlexDirection::ColumnReverse,
|
flex_direction: FlexDirection::Column,
|
||||||
flex_grow: 1.0,
|
flex_grow: 1.0,
|
||||||
max_size: Size::UNDEFINED,
|
max_size: Size::UNDEFINED,
|
||||||
..default()
|
..default()
|
||||||
|
@ -161,7 +160,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// absolute positioning
|
|
||||||
parent
|
parent
|
||||||
.spawn(NodeBundle {
|
.spawn(NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
|
@ -277,7 +275,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
||||||
position_type: PositionType::Absolute,
|
position_type: PositionType::Absolute,
|
||||||
justify_content: JustifyContent::Center,
|
justify_content: JustifyContent::Center,
|
||||||
align_items: AlignItems::FlexEnd,
|
align_items: AlignItems::FlexStart,
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
|
@ -318,8 +316,8 @@ fn mouse_scroll(
|
||||||
MouseScrollUnit::Line => mouse_wheel_event.y * 20.,
|
MouseScrollUnit::Line => mouse_wheel_event.y * 20.,
|
||||||
MouseScrollUnit::Pixel => mouse_wheel_event.y,
|
MouseScrollUnit::Pixel => mouse_wheel_event.y,
|
||||||
};
|
};
|
||||||
scrolling_list.position += dy;
|
scrolling_list.position -= dy;
|
||||||
scrolling_list.position = scrolling_list.position.clamp(-max_scroll, 0.);
|
scrolling_list.position = scrolling_list.position.clamp(0., max_scroll);
|
||||||
style.position.top = Val::Px(scrolling_list.position);
|
style.position.top = Val::Px(scrolling_list.position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue