mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
b6a647cc01
Adds a `default()` shorthand for `Default::default()` ... because life is too short to constantly type `Default::default()`. ```rust use bevy::prelude::*; #[derive(Default)] struct Foo { bar: usize, baz: usize, } // Normally you would do this: let foo = Foo { bar: 10, ..Default::default() }; // But now you can do this: let foo = Foo { bar: 10, ..default() }; ``` The examples have been adapted to use `..default()`. I've left internal crates as-is for now because they don't pull in the bevy prelude, and the ergonomics of each case should be considered individually.
330 lines
15 KiB
Rust
330 lines
15 KiB
Rust
use bevy::{
|
|
input::mouse::{MouseScrollUnit, MouseWheel},
|
|
prelude::*,
|
|
};
|
|
|
|
/// This example illustrates the various features of Bevy UI.
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_startup_system(setup)
|
|
.add_system(mouse_scroll)
|
|
.run();
|
|
}
|
|
|
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
// ui camera
|
|
commands.spawn_bundle(UiCameraBundle::default());
|
|
|
|
// root node
|
|
commands
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
|
justify_content: JustifyContent::SpaceBetween,
|
|
..default()
|
|
},
|
|
color: Color::NONE.into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
// left vertical fill (border)
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Px(200.0), Val::Percent(100.0)),
|
|
border: Rect::all(Val::Px(2.0)),
|
|
..default()
|
|
},
|
|
color: Color::rgb(0.65, 0.65, 0.65).into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
// left vertical fill (content)
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
|
align_items: AlignItems::FlexEnd,
|
|
..default()
|
|
},
|
|
color: Color::rgb(0.15, 0.15, 0.15).into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
// text
|
|
parent.spawn_bundle(TextBundle {
|
|
style: Style {
|
|
margin: Rect::all(Val::Px(5.0)),
|
|
..default()
|
|
},
|
|
text: Text::with_section(
|
|
"Text Example",
|
|
TextStyle {
|
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
|
font_size: 30.0,
|
|
color: Color::WHITE,
|
|
},
|
|
Default::default(),
|
|
),
|
|
..default()
|
|
});
|
|
});
|
|
});
|
|
// right vertical fill
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
flex_direction: FlexDirection::ColumnReverse,
|
|
justify_content: JustifyContent::Center,
|
|
size: Size::new(Val::Px(200.0), Val::Percent(100.0)),
|
|
..default()
|
|
},
|
|
color: Color::rgb(0.15, 0.15, 0.15).into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
// Title
|
|
parent.spawn_bundle(TextBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Undefined, Val::Px(25.)),
|
|
margin: Rect {
|
|
left: Val::Auto,
|
|
right: Val::Auto,
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
text: Text::with_section(
|
|
"Scrolling list",
|
|
TextStyle {
|
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
|
font_size: 25.,
|
|
color: Color::WHITE,
|
|
},
|
|
Default::default(),
|
|
),
|
|
..default()
|
|
});
|
|
// List with hidden overflow
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
flex_direction: FlexDirection::ColumnReverse,
|
|
align_self: AlignSelf::Center,
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(50.0)),
|
|
overflow: Overflow::Hidden,
|
|
..default()
|
|
},
|
|
color: Color::rgb(0.10, 0.10, 0.10).into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
// Moving panel
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
flex_direction: FlexDirection::ColumnReverse,
|
|
flex_grow: 1.0,
|
|
max_size: Size::new(Val::Undefined, Val::Undefined),
|
|
..default()
|
|
},
|
|
color: Color::NONE.into(),
|
|
..default()
|
|
})
|
|
.insert(ScrollingList::default())
|
|
.with_children(|parent| {
|
|
// List items
|
|
for i in 0..30 {
|
|
parent.spawn_bundle(TextBundle {
|
|
style: Style {
|
|
flex_shrink: 0.,
|
|
size: Size::new(Val::Undefined, Val::Px(20.)),
|
|
margin: Rect {
|
|
left: Val::Auto,
|
|
right: Val::Auto,
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
text: Text::with_section(
|
|
format!("Item {}", i),
|
|
TextStyle {
|
|
font: asset_server
|
|
.load("fonts/FiraSans-Bold.ttf"),
|
|
font_size: 20.,
|
|
color: Color::WHITE,
|
|
},
|
|
Default::default(),
|
|
),
|
|
..default()
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
// absolute positioning
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Px(200.0), Val::Px(200.0)),
|
|
position_type: PositionType::Absolute,
|
|
position: Rect {
|
|
left: Val::Px(210.0),
|
|
bottom: Val::Px(10.0),
|
|
..default()
|
|
},
|
|
border: Rect::all(Val::Px(20.0)),
|
|
..default()
|
|
},
|
|
color: Color::rgb(0.4, 0.4, 1.0).into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
parent.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
|
..default()
|
|
},
|
|
color: Color::rgb(0.8, 0.8, 1.0).into(),
|
|
..default()
|
|
});
|
|
});
|
|
// render order test: reddest in the back, whitest in the front (flex center)
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
|
position_type: PositionType::Absolute,
|
|
align_items: AlignItems::Center,
|
|
justify_content: JustifyContent::Center,
|
|
..default()
|
|
},
|
|
color: Color::NONE.into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Px(100.0), Val::Px(100.0)),
|
|
..default()
|
|
},
|
|
color: Color::rgb(1.0, 0.0, 0.0).into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
parent.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Px(100.0), Val::Px(100.0)),
|
|
position_type: PositionType::Absolute,
|
|
position: Rect {
|
|
left: Val::Px(20.0),
|
|
bottom: Val::Px(20.0),
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
color: Color::rgb(1.0, 0.3, 0.3).into(),
|
|
..default()
|
|
});
|
|
parent.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Px(100.0), Val::Px(100.0)),
|
|
position_type: PositionType::Absolute,
|
|
position: Rect {
|
|
left: Val::Px(40.0),
|
|
bottom: Val::Px(40.0),
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
color: Color::rgb(1.0, 0.5, 0.5).into(),
|
|
..default()
|
|
});
|
|
parent.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Px(100.0), Val::Px(100.0)),
|
|
position_type: PositionType::Absolute,
|
|
position: Rect {
|
|
left: Val::Px(60.0),
|
|
bottom: Val::Px(60.0),
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
color: Color::rgb(1.0, 0.7, 0.7).into(),
|
|
..default()
|
|
});
|
|
// alpha test
|
|
parent.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Px(100.0), Val::Px(100.0)),
|
|
position_type: PositionType::Absolute,
|
|
position: Rect {
|
|
left: Val::Px(80.0),
|
|
bottom: Val::Px(80.0),
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
color: Color::rgba(1.0, 0.9, 0.9, 0.4).into(),
|
|
..default()
|
|
});
|
|
});
|
|
});
|
|
// bevy logo (flex center)
|
|
parent
|
|
.spawn_bundle(NodeBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
|
position_type: PositionType::Absolute,
|
|
justify_content: JustifyContent::Center,
|
|
align_items: AlignItems::FlexEnd,
|
|
..default()
|
|
},
|
|
color: Color::NONE.into(),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
// bevy logo (image)
|
|
parent.spawn_bundle(ImageBundle {
|
|
style: Style {
|
|
size: Size::new(Val::Px(500.0), Val::Auto),
|
|
..default()
|
|
},
|
|
image: asset_server.load("branding/bevy_logo_dark_big.png").into(),
|
|
..default()
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
#[derive(Component, Default)]
|
|
struct ScrollingList {
|
|
position: f32,
|
|
}
|
|
|
|
fn mouse_scroll(
|
|
mut mouse_wheel_events: EventReader<MouseWheel>,
|
|
mut query_list: Query<(&mut ScrollingList, &mut Style, &Children, &Node)>,
|
|
query_item: Query<&Node>,
|
|
) {
|
|
for mouse_wheel_event in mouse_wheel_events.iter() {
|
|
for (mut scrolling_list, mut style, children, uinode) in query_list.iter_mut() {
|
|
let items_height: f32 = children
|
|
.iter()
|
|
.map(|entity| query_item.get(*entity).unwrap().size.y)
|
|
.sum();
|
|
let panel_height = uinode.size.y;
|
|
let max_scroll = (items_height - panel_height).max(0.);
|
|
let dy = match mouse_wheel_event.unit {
|
|
MouseScrollUnit::Line => mouse_wheel_event.y * 20.,
|
|
MouseScrollUnit::Pixel => mouse_wheel_event.y,
|
|
};
|
|
scrolling_list.position += dy;
|
|
scrolling_list.position = scrolling_list.position.clamp(-max_scroll, 0.);
|
|
style.position.top = Val::Px(scrolling_list.position);
|
|
}
|
|
}
|
|
}
|