mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
ui: feed computed image size into bevy_ui flex
This commit is contained in:
parent
cf9501a50e
commit
4a8c6c335a
6 changed files with 124 additions and 39 deletions
|
@ -1,7 +1,7 @@
|
|||
use super::Node;
|
||||
use crate::{
|
||||
render::UI_PIPELINE_HANDLE,
|
||||
widget::{Button, Text},
|
||||
widget::{Button, Text, Image},
|
||||
Click, FocusPolicy, Hover, Style, CalculatedSize,
|
||||
};
|
||||
use bevy_asset::Handle;
|
||||
|
@ -62,6 +62,55 @@ impl Default for NodeComponents {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Bundle)]
|
||||
pub struct ImageComponents {
|
||||
pub node: Node,
|
||||
pub style: Style,
|
||||
pub image: Image,
|
||||
pub calculated_size: CalculatedSize,
|
||||
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
|
||||
pub material: Handle<ColorMaterial>,
|
||||
pub draw: Draw,
|
||||
pub render_pipelines: RenderPipelines,
|
||||
pub transform: Transform,
|
||||
pub local_transform: LocalTransform,
|
||||
}
|
||||
|
||||
impl Default for ImageComponents {
|
||||
fn default() -> Self {
|
||||
ImageComponents {
|
||||
mesh: QUAD_HANDLE,
|
||||
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized(
|
||||
UI_PIPELINE_HANDLE,
|
||||
PipelineSpecialization {
|
||||
dynamic_bindings: vec![
|
||||
// Transform
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 0,
|
||||
},
|
||||
// Node_size
|
||||
DynamicBinding {
|
||||
bind_group: 1,
|
||||
binding: 1,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
)]),
|
||||
node: Default::default(),
|
||||
image: Default::default(),
|
||||
calculated_size: Default::default(),
|
||||
style: Default::default(),
|
||||
material: Default::default(),
|
||||
draw: Default::default(),
|
||||
transform: Default::default(),
|
||||
local_transform: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Bundle)]
|
||||
pub struct TextComponents {
|
||||
pub node: Node,
|
||||
|
|
|
@ -6,7 +6,7 @@ use bevy_math::Vec2;
|
|||
use bevy_transform::prelude::{Children, LocalTransform, Parent};
|
||||
use bevy_window::{Window, WindowId, Windows};
|
||||
use std::collections::HashMap;
|
||||
use stretch::Stretch;
|
||||
use stretch::{number::Number, Stretch};
|
||||
|
||||
pub struct FlexSurface {
|
||||
entity_to_stretch: HashMap<Entity, stretch::node::Node>,
|
||||
|
@ -43,40 +43,41 @@ impl FlexSurface {
|
|||
}
|
||||
|
||||
pub fn upsert_leaf(&mut self, entity: Entity, style: &Style, calculated_size: CalculatedSize) {
|
||||
let mut added = false;
|
||||
let stretch = &mut self.stretch;
|
||||
let stretch_style = style.into();
|
||||
let stretch_node = self.entity_to_stretch.entry(entity).or_insert_with(|| {
|
||||
added = true;
|
||||
let stretch_node = stretch
|
||||
.new_leaf(
|
||||
stretch_style,
|
||||
Box::new(move |_| {
|
||||
Ok(stretch::geometry::Size {
|
||||
width: calculated_size.size.width,
|
||||
height: calculated_size.size.height,
|
||||
})
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
stretch_node
|
||||
let measure = Box::new(move |constraints: stretch::geometry::Size<Number>| {
|
||||
let mut size = stretch::geometry::Size {
|
||||
width: calculated_size.size.width,
|
||||
height: calculated_size.size.height,
|
||||
};
|
||||
match (constraints.width, constraints.height) {
|
||||
(Number::Undefined, Number::Undefined) => {}
|
||||
(Number::Defined(width), Number::Undefined) => {
|
||||
size.height = width * size.height / size.width;
|
||||
size.width = width;
|
||||
}
|
||||
(Number::Undefined, Number::Defined(height)) => {
|
||||
size.width = height * size.width / size.height;
|
||||
size.height = height;
|
||||
}
|
||||
(Number::Defined(width), Number::Defined(height)) => {
|
||||
size.width = width;
|
||||
size.height = height;
|
||||
}
|
||||
}
|
||||
Ok(size)
|
||||
});
|
||||
|
||||
if !added {
|
||||
if let Some(stretch_node) = self.entity_to_stretch.get(&entity) {
|
||||
self.stretch
|
||||
.set_style(*stretch_node, stretch_style)
|
||||
.unwrap();
|
||||
self.stretch
|
||||
.set_measure(
|
||||
*stretch_node,
|
||||
Some(Box::new(move |_| {
|
||||
Ok(stretch::geometry::Size {
|
||||
width: calculated_size.size.width,
|
||||
height: calculated_size.size.height,
|
||||
})
|
||||
})),
|
||||
)
|
||||
.set_measure(*stretch_node, Some(measure))
|
||||
.unwrap();
|
||||
} else {
|
||||
let stretch_node = stretch.new_leaf(stretch_style, measure).unwrap();
|
||||
self.entity_to_stretch.insert(entity, stretch_node);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ impl AppPlugin for UiPlugin {
|
|||
.add_system_to_stage_front(stage::POST_UPDATE, flex_node_system.system())
|
||||
.add_system_to_stage_front(stage::POST_UPDATE, ui_z_system.system())
|
||||
.add_system_to_stage_front(stage::POST_UPDATE, widget::text_system.system())
|
||||
.add_system_to_stage_front(stage::POST_UPDATE, widget::image_node_system.system())
|
||||
.add_system_to_stage(bevy_render::stage::DRAW, widget::draw_text_system.system());
|
||||
|
||||
let resources = app.resources();
|
||||
|
|
35
crates/bevy_ui/src/widget/image.rs
Normal file
35
crates/bevy_ui/src/widget/image.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use crate::CalculatedSize;
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_ecs::{Query, Res};
|
||||
use bevy_math::Size;
|
||||
use bevy_render::texture::Texture;
|
||||
use bevy_sprite::ColorMaterial;
|
||||
|
||||
pub enum Image {
|
||||
KeepAspect,
|
||||
}
|
||||
|
||||
impl Default for Image {
|
||||
fn default() -> Self {
|
||||
Image::KeepAspect
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_node_system(
|
||||
materials: Res<Assets<ColorMaterial>>,
|
||||
textures: Res<Assets<Texture>>,
|
||||
mut query: Query<(&Image, &mut CalculatedSize, &Handle<ColorMaterial>)>,
|
||||
) {
|
||||
for (_image, mut calculated_size, material_handle) in &mut query.iter() {
|
||||
materials
|
||||
.get(material_handle)
|
||||
.and_then(|material| material.texture)
|
||||
.and_then(|texture_handle| textures.get(&texture_handle))
|
||||
.map(|texture| {
|
||||
calculated_size.size = Size {
|
||||
width: texture.size.x(),
|
||||
height: texture.size.y(),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
mod button;
|
||||
mod text;
|
||||
mod image;
|
||||
|
||||
pub use button::*;
|
||||
pub use text::*;
|
||||
pub use image::*;
|
||||
|
|
|
@ -10,16 +10,8 @@ fn main() {
|
|||
fn setup(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut textures: ResMut<Assets<Texture>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
let texture_handle = asset_server
|
||||
.load_sync(&mut textures, "assets/branding/bevy_logo_dark_big.png")
|
||||
.unwrap();
|
||||
|
||||
let texture = textures.get(&texture_handle).unwrap();
|
||||
let aspect = texture.aspect();
|
||||
|
||||
commands
|
||||
// ui camera
|
||||
.spawn(UiCameraComponents::default())
|
||||
|
@ -87,7 +79,7 @@ fn setup(
|
|||
material: materials.add(Color::rgb(0.02, 0.02, 0.02).into()),
|
||||
..Default::default()
|
||||
})
|
||||
// Absolute positioning
|
||||
// absolute positioning
|
||||
.spawn(NodeComponents {
|
||||
style: Style {
|
||||
size: Size::new(Val::Px(200.0), Val::Px(200.0)),
|
||||
|
@ -222,12 +214,17 @@ fn setup(
|
|||
})
|
||||
.with_children(|parent| {
|
||||
// bevy logo (image)
|
||||
parent.spawn(NodeComponents {
|
||||
parent.spawn(ImageComponents {
|
||||
style: Style {
|
||||
min_size: Size::new(Val::Px(500.0), Val::Px(500.0 * aspect)),
|
||||
size: Size::new(Val::Px(500.0), Val::Auto),
|
||||
..Default::default()
|
||||
},
|
||||
material: materials.add(ColorMaterial::texture(texture_handle)),
|
||||
material: materials.add(
|
||||
asset_server
|
||||
.load("assets/branding/bevy_logo_dark_big.png")
|
||||
.unwrap()
|
||||
.into(),
|
||||
),
|
||||
draw: Draw {
|
||||
is_transparent: true,
|
||||
..Default::default()
|
||||
|
|
Loading…
Reference in a new issue