ui: feed computed image size into bevy_ui flex
This commit is contained in:
		
							parent
							
								
									cf9501a50e
								
							
						
					
					
						commit
						4a8c6c335a
					
				@ -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 {
 | 
			
		||||
        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,
 | 
			
		||||
                        })
 | 
			
		||||
                    }),
 | 
			
		||||
                )
 | 
			
		||||
                .unwrap();
 | 
			
		||||
            stretch_node
 | 
			
		||||
            };
 | 
			
		||||
            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 New Issue
	
	Block a user