ui: feed computed image size into bevy_ui flex

This commit is contained in:
Carter Anderson 2020-07-28 00:37:25 -07:00
parent cf9501a50e
commit 4a8c6c335a
6 changed files with 124 additions and 39 deletions

View file

@ -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,

View file

@ -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);
}
}

View file

@ -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();

View 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(),
};
});
}
}

View file

@ -1,5 +1,7 @@
mod button;
mod text;
mod image;
pub use button::*;
pub use text::*;
pub use image::*;

View file

@ -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()