use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, prelude::*, }; use bevy_ninepatch::*; fn main() -> Result<(), Box> { App::default() .add_plugins(DefaultPlugins) // Add the `NinePatchPlugin` plugin .add_plugin(NinePatchPlugin::::default()) .add_plugin(FrameTimeDiagnosticsPlugin::default()) // Adds a system that prints diagnostics to the console .add_plugin(LogDiagnosticsPlugin::default()) .add_startup_system(setup) .add_system(set_content) .add_system(update_size) .run(); Ok(()) } fn setup( mut commands: Commands, asset_server: Res, mut nine_patches: ResMut>>, ) { // load the assets let cornered_panel_texture_handle = asset_server.load("metalPanel_yellowCorner.png"); let panel_nine_patch_handle = nine_patches.add(NinePatchBuilder::from_patches(vec![ vec![ // top left corner patch Patch { original_size: IVec2::new(30, 35), target_size: Size::new(Val::Undefined, Val::Undefined), content: None, }, // top middle-left patch. This patch width can grow, and will contain the content for // `PanelContent::Title` Patch { original_size: IVec2::new(15, 35), target_size: Size::new(Val::Percent(30.), Val::Undefined), content: Some(Content::Title), }, // top middle patch. In the original PNG, it's the yellow titled part Patch { original_size: IVec2::new(25, 35), target_size: Size::new(Val::Undefined, Val::Undefined), content: None, }, // top middle-right patch. This patch width can grow Patch { original_size: IVec2::new(20, 35), target_size: Size::new(Val::Percent(70.), Val::Undefined), content: None, }, // top right corner Patch { original_size: IVec2::new(10, 35), target_size: Size::new(Val::Undefined, Val::Undefined), content: None, }, ], vec![ // left border. This patch height can grow Patch { original_size: IVec2::new(10, -45), target_size: Size::new(Val::Undefined, Val::Percent(100.)), content: None, }, // center. This patch can grow both in height and width, and will contain `PanelContent::Body` Patch { original_size: IVec2::new(-20, -45), target_size: Size::new(Val::Percent(100.), Val::Percent(100.)), content: Some(Content::Content), }, // right border. This patch height can grow Patch { original_size: IVec2::new(10, -45), target_size: Size::new(Val::Undefined, Val::Percent(100.)), content: None, }, ], vec![ // bottom left corner Patch { original_size: IVec2::new(10, 10), target_size: Size::new(Val::Undefined, Val::Undefined), content: None, }, // bottom middle. This patch width can grow Patch { original_size: IVec2::new(-20, 10), target_size: Size::new(Val::Percent(100.), Val::Undefined), content: None, }, // bottom right corner Patch { original_size: IVec2::new(10, 10), target_size: Size::new(Val::Undefined, Val::Undefined), content: None, }, ], ])); commands.spawn(( // this component bundle will be detected by the plugin, and the 9-Patch UI element will be added as a child // of this entity NinePatchBundle { style: Style { margin: UiRect::all(Val::Auto), justify_content: JustifyContent::Center, align_items: AlignItems::Center, size: Size::new(Val::Px(900.), Val::Px(600.)), ..Default::default() }, nine_patch_data: NinePatchData { nine_patch: panel_nine_patch_handle, texture: cornered_panel_texture_handle, ..Default::default() }, ..Default::default() }, UiElement::Panel, )); commands.spawn(Camera2dBundle::default()); } fn set_content( mut commands: Commands, asset_server: Res, mut nine_patches: ResMut>>, mut patch_content: Query<(Entity, &mut NinePatchContent)>, ui_element_query: Query<&UiElement>, mut font: Local>, ) { *font = asset_server.load("Kenney Future Narrow.ttf"); for (entity, mut nine_patch_content) in &mut patch_content.iter_mut() { if !nine_patch_content.loaded { match ( *ui_element_query .get_component::(nine_patch_content.parent) .unwrap(), &nine_patch_content.content, ) { (UiElement::Panel, Content::Content) => { let panel_texture_handle: Handle = asset_server.load("glassPanel_corners.png"); // load the 9-Patch as an assets and keep an `Handle>` let nine_patch_handle = nine_patches.add( NinePatchBuilder::by_margins_with_content(20, 20, 20, 20, Content::Content), ); let content_entity = commands .spawn(( // this component bundle will be detected by the plugin, and the 9-Patch UI element will be added as a child // of this entity NinePatchBundle { style: Style { margin: UiRect::all(Val::Auto), justify_content: JustifyContent::Center, align_items: AlignItems::Center, size: Size::new(Val::Px(850.), Val::Px(550.)), ..Default::default() }, nine_patch_data: NinePatchData { nine_patch: nine_patch_handle, texture: panel_texture_handle, ..Default::default() }, ..Default::default() }, UiElement::InnerPanel, )) .id(); commands.entity(entity).push_children(&[content_entity]); nine_patch_content.loaded = true; } (UiElement::Panel, Content::Title) => { let content_entity = commands .spawn( TextBundle::from_section( "Example Title", TextStyle { font: font.clone(), font_size: 25.0, color: Color::BLUE, }, ) .with_style(Style { margin: UiRect { left: Val::Undefined, right: Val::Auto, top: Val::Px(8.), bottom: Val::Auto, }, ..Default::default() }), ) .id(); commands.entity(entity).push_children(&[content_entity]); nine_patch_content.loaded = true; } (UiElement::InnerPanel, _) => { // prepare the button let button_texture_handle = asset_server.load("blue_button02.png"); let button_nine_patch_handle = nine_patches.add( NinePatchBuilder::by_margins_with_content(5, 10, 6, 6, Content::Content), ); let button_cancel_entity = commands .spawn(( // this component bundle will be detected by the plugin, and the 9-Patch UI element will be added as a child // of this entity NinePatchBundle { style: Style { margin: UiRect { left: Val::Px(0.), right: Val::Auto, top: Val::Auto, bottom: Val::Px(0.), }, size: Size::new(Val::Px(300.), Val::Px(80.)), justify_content: JustifyContent::Center, align_items: AlignItems::Center, ..Default::default() }, nine_patch_data: NinePatchData { nine_patch: button_nine_patch_handle.clone(), texture: button_texture_handle.clone(), ..Default::default() }, ..Default::default() }, UiElement::ButtonCancel, )) .id(); let button_ok_entity = commands .spawn(( // this component bundle will be detected by the plugin, and the 9-Patch UI element will be added as a child // of this entity NinePatchBundle { style: Style { margin: UiRect { left: Val::Auto, right: Val::Px(0.), top: Val::Auto, bottom: Val::Px(0.), }, justify_content: JustifyContent::Center, align_items: AlignItems::Center, size: Size::new(Val::Px(300.), Val::Px(80.)), ..Default::default() }, nine_patch_data: NinePatchData { nine_patch: button_nine_patch_handle, texture: button_texture_handle, ..Default::default() }, ..Default::default() }, UiElement::ButtonOK, )) .id(); commands .entity(entity) .push_children(&[button_cancel_entity, button_ok_entity]); nine_patch_content.loaded = true; } (UiElement::ButtonOK, _) => { let content_entity = commands .spawn( TextBundle::from_section( "OK", TextStyle { font: font.clone(), font_size: 50.0, color: Color::GREEN, }, ) .with_style(Style { margin: UiRect { left: Val::Px(110.), right: Val::Auto, top: Val::Px(10.), bottom: Val::Auto, }, ..Default::default() }), ) .id(); commands.entity(entity).push_children(&[content_entity]); nine_patch_content.loaded = true; } (UiElement::ButtonCancel, _) => { let content_entity = commands .spawn( TextBundle::from_section( "CANCEL", TextStyle { font: font.clone(), font_size: 50.0, color: Color::RED, }, ) .with_style(Style { margin: UiRect { left: Val::Px(50.), right: Val::Auto, top: Val::Px(10.), bottom: Val::Auto, }, ..Default::default() }), ) .id(); commands.entity(entity).push_children(&[content_entity]); nine_patch_content.loaded = true; } } } } } #[derive(Clone, PartialEq, Eq, std::hash::Hash)] enum Content { Title, Content, } #[derive(Clone, Copy, Component)] enum UiElement { Panel, InnerPanel, ButtonOK, ButtonCancel, } // by changing the component `Style.size`, the 9-Patch UI element will be resized fn update_size(time: Res