diff --git a/bevy_kayak_ui/src/render/unified/font/extract.rs b/bevy_kayak_ui/src/render/unified/font/extract.rs index 5948efc52b5af61e915b904c7be8bf431dfcf9ca..43bce7d403757fe05d37f183525f19f4003290b2 100644 --- a/bevy_kayak_ui/src/render/unified/font/extract.rs +++ b/bevy_kayak_ui/src/render/unified/font/extract.rs @@ -138,6 +138,8 @@ pub fn extract_texts( type_index: 0, border_radius: (0.0, 0.0, 0.0, 0.0), image: None, + uv_max: None, + uv_min: None, }, }); diff --git a/bevy_kayak_ui/src/render/unified/font/font_texture_cache.rs b/bevy_kayak_ui/src/render/unified/font/font_texture_cache.rs index 572627267a4a4011ecd6518ec43fb8bb0906daa7..f9d526c3a8bacd28907f885bcaff608bb1831ae6 100644 --- a/bevy_kayak_ui/src/render/unified/font/font_texture_cache.rs +++ b/bevy_kayak_ui/src/render/unified/font/font_texture_cache.rs @@ -305,7 +305,6 @@ impl FontTextureCache { atlas_texture: &GpuImage, size: Vec2, ) { - dbg!(size); Self::create_texture( images, font_handle.clone_weak(), diff --git a/bevy_kayak_ui/src/render/unified/font/mod.rs b/bevy_kayak_ui/src/render/unified/font/mod.rs index 1ae275c690267860df26b5dc60f641c700a4a052..8b2a9fff050a30a686c6dd3d4c92c376f2159046 100644 --- a/bevy_kayak_ui/src/render/unified/font/mod.rs +++ b/bevy_kayak_ui/src/render/unified/font/mod.rs @@ -90,14 +90,11 @@ pub fn set_font_texture( ) { // quick and dirty, run this for all textures anytime a texture is created. for event in texture_events.iter() { - dbg!(&event); match event { AssetEvent::Created { handle } => { let handle_path = asset_server.get_handle_path(handle).unwrap(); - dbg!(&handle_path); if handle_path.path().to_str().unwrap().contains("roboto") { if let Some(mut texture) = textures.get_mut(handle) { - dbg!("Setting font texture!"); texture.texture_descriptor.format = TextureFormat::Rgba8Unorm; texture.sampler_descriptor.min_filter = FilterMode::Linear; texture.sampler_descriptor.mipmap_filter = FilterMode::Linear; diff --git a/bevy_kayak_ui/src/render/unified/image/extract.rs b/bevy_kayak_ui/src/render/unified/image/extract.rs index fee53b688ede10e56af934611176b295eb0c97c5..dfee468af1f4e1c74d456fcae9c05923d5b9f68f 100644 --- a/bevy_kayak_ui/src/render/unified/image/extract.rs +++ b/bevy_kayak_ui/src/render/unified/image/extract.rs @@ -51,6 +51,8 @@ pub fn extract_images( image: image_manager .get_handle(handle) .and_then(|a| Some(a.clone_weak())), + uv_max: None, + uv_min: None, }, }); } diff --git a/bevy_kayak_ui/src/render/unified/image/image_manager.rs b/bevy_kayak_ui/src/render/unified/image/image_manager.rs index b92b08e5ce9a0db06b16b2399cbd93aefce1c4db..0493f8dbc26fe3322fc17b0b36dc4e379383675f 100644 --- a/bevy_kayak_ui/src/render/unified/image/image_manager.rs +++ b/bevy_kayak_ui/src/render/unified/image/image_manager.rs @@ -22,7 +22,7 @@ impl ImageManager { } else { let id = self.count; self.count += 1; - self.mapping.insert(id, image_handle.clone_weak()); + self.mapping.insert(id, image_handle.clone()); self.reverse_mapping.insert(image_handle.clone_weak(), id); return id; } diff --git a/bevy_kayak_ui/src/render/unified/mod.rs b/bevy_kayak_ui/src/render/unified/mod.rs index c6ce51ce23c0d449835082a6f5eab7ec51138405..152bdd7eb1a26c1f0fb6ac31e5fa56be8b51fdb9 100644 --- a/bevy_kayak_ui/src/render/unified/mod.rs +++ b/bevy_kayak_ui/src/render/unified/mod.rs @@ -13,6 +13,7 @@ use self::pipeline::ImageBindGroups; pub mod font; pub mod image; +mod nine_patch; mod pipeline; mod quad; @@ -46,6 +47,7 @@ impl Plugin for UnifiedRenderPlugin { app.add_plugin(font::TextRendererPlugin) .add_plugin(quad::QuadRendererPlugin) - .add_plugin(image::ImageRendererPlugin); + .add_plugin(image::ImageRendererPlugin) + .add_plugin(nine_patch::NinePatchRendererPlugin); } } diff --git a/bevy_kayak_ui/src/render/unified/nine_patch/extract.rs b/bevy_kayak_ui/src/render/unified/nine_patch/extract.rs new file mode 100644 index 0000000000000000000000000000000000000000..c2d75f93c997255de0d2027eecf8a171ee6df4a1 --- /dev/null +++ b/bevy_kayak_ui/src/render/unified/nine_patch/extract.rs @@ -0,0 +1,260 @@ +use bevy::{ + math::Vec2, + prelude::{Assets, Commands, Res}, + render2::{color::Color, texture::Image}, + sprite2::Rect, +}; +use kayak_core::render_primitive::RenderPrimitive; + +use crate::{ + render::unified::pipeline::{ExtractQuadBundle, ExtractedQuad, UIQuadType}, + BevyContext, ImageManager, +}; + +pub fn extract_nine_patch( + mut commands: Commands, + context: Res<BevyContext>, + image_manager: Res<ImageManager>, + images: Res<Assets<Image>>, +) { + let render_commands = if let Ok(context) = context.kayak_context.read() { + context.widget_manager.build_render_primitives() + } else { + vec![] + }; + + let image_commands: Vec<&RenderPrimitive> = render_commands + .iter() + .filter(|command| matches!(command, RenderPrimitive::NinePatch { .. })) + .collect::<Vec<_>>(); + + let mut extracted_quads = Vec::new(); + for render_primitive in image_commands { + let (layout, handle, border) = match render_primitive { + RenderPrimitive::NinePatch { + layout, + handle, + border, + } => (layout, handle, border), + _ => panic!(""), + }; + + let image_handle = image_manager + .get_handle(handle) + .and_then(|a| Some(a.clone_weak())); + + let image = images.get(image_handle.as_ref().unwrap()); + + if image.is_none() { + dbg!("Uh oh no image! :("); + continue; + } + + let image_size = image + .and_then(|i| { + Some(Vec2::new( + i.texture_descriptor.size.width as f32, + i.texture_descriptor.size.height as f32, + )) + }) + .unwrap(); + + let extracted_quad_template = ExtractedQuad { + rect: Rect { + min: Vec2::ZERO, + max: Vec2::ZERO, + }, + color: Color::WHITE, + vertex_index: 0, + char_id: 0, + z_index: layout.z_index, + font_handle: None, + quad_type: UIQuadType::Image, + type_index: 0, + border_radius: (0.0, 0.0, 0.0, 0.0), + image: image_handle, + uv_max: None, + uv_min: None, + }; + + // TOP + let top_left_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(layout.posx, layout.posy), + max: Vec2::new(layout.posx + border.left, layout.posy + border.top), + }, + uv_min: Some(Vec2::new(0.0, border.top / image_size.y)), + uv_max: Some(Vec2::new(border.left / image_size.x, 0.0)), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(top_left_quad); + + let top_right_pos_x = (layout.posx + layout.width) - border.left; + let top_right_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(top_right_pos_x, layout.posy), + max: Vec2::new(top_right_pos_x + border.left, layout.posy + border.top), + }, + uv_min: Some(Vec2::new( + (image_size.x - border.left) / image_size.x, + border.top / image_size.y, + )), + uv_max: Some(Vec2::new(1.0, 0.0)), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(top_right_quad); + + let top_middle_pos_x = layout.posx + border.left; + let top_middle_size_x = layout.width - (border.left + border.right); + let top_middle_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(top_middle_pos_x, layout.posy), + max: Vec2::new( + top_middle_pos_x + top_middle_size_x, + layout.posy + border.top, + ), + }, + uv_min: Some(Vec2::new( + border.left / image_size.x, + border.top / image_size.y, + )), + uv_max: Some(Vec2::new((image_size.x - border.left) / image_size.x, 0.0)), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(top_middle_quad); + + // Bottom + let bottom_y_pos = layout.posy + (layout.width - border.bottom); + let bottom_left_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(layout.posx, bottom_y_pos), + max: Vec2::new(layout.posx + border.left, bottom_y_pos + border.bottom), + }, + uv_min: Some(Vec2::new(0.0, 1.0)), + uv_max: Some(Vec2::new( + border.left / image_size.x, + (image_size.y - border.bottom) / image_size.y, + )), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(bottom_left_quad); + + let bottom_right_pos_x = (layout.posx + layout.width) - border.left; + let bottom_right_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(bottom_right_pos_x, bottom_y_pos), + max: Vec2::new(bottom_right_pos_x + border.left, bottom_y_pos + border.top), + }, + uv_min: Some(Vec2::new((image_size.x - border.left) / image_size.x, 1.0)), + uv_max: Some(Vec2::new( + 1.0, + (image_size.y - border.bottom) / image_size.y, + )), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(bottom_right_quad); + + let bottom_middle_pos_x = layout.posx + border.left; + let bottom_middle_size_x = layout.width - (border.left + border.right); + let bottom_middle_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(bottom_middle_pos_x, bottom_y_pos), + max: Vec2::new( + bottom_middle_pos_x + bottom_middle_size_x, + bottom_y_pos + border.top, + ), + }, + uv_min: Some(Vec2::new(border.left / image_size.x, 1.0)), + uv_max: Some(Vec2::new( + (image_size.x - border.left) / image_size.x, + (image_size.y - border.bottom) / image_size.y, + )), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(bottom_middle_quad); + + // Left + Right center + let left_middle_pos_y = layout.posy + border.top; + let left_middle_size_y = layout.height - (border.top + border.bottom); + let left_middle_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(layout.posx, left_middle_pos_y), + max: Vec2::new( + layout.posx + border.left, + left_middle_pos_y + left_middle_size_y, + ), + }, + uv_min: Some(Vec2::new( + 0.0, + (image_size.y - border.bottom) / image_size.y, + )), + uv_max: Some(Vec2::new( + border.left / image_size.x, + border.top / image_size.y, + )), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(left_middle_quad); + + let right_middle_pos_x = layout.posx + (layout.width - border.right); + let right_middle_pos_y = layout.posy + border.top; + let right_middle_size_y = layout.height - (border.top + border.bottom); + let right_middle_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(right_middle_pos_x, right_middle_pos_y), + max: Vec2::new( + right_middle_pos_x + border.left, + right_middle_pos_y + right_middle_size_y, + ), + }, + uv_min: Some(Vec2::new( + (image_size.x - border.left) / image_size.x, + (image_size.y - border.bottom) / image_size.y, + )), + uv_max: Some(Vec2::new(1.0, border.top / image_size.y)), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(right_middle_quad); + + // Last quad in middle. + let middle_pos_x = layout.posx + border.left; + let middle_pos_y = layout.posy + border.top; + let middle_size_x = layout.width - (border.left + border.right); + let middle_size_y = layout.height - (border.top + border.bottom); + let middle_quad = ExtractQuadBundle { + extracted_quad: ExtractedQuad { + rect: Rect { + min: Vec2::new(middle_pos_x, middle_pos_y), + max: Vec2::new(middle_pos_x + middle_size_x, middle_pos_y + middle_size_y), + }, + uv_min: Some(Vec2::new( + border.left / image_size.x, + border.bottom / image_size.y, + )), + uv_max: Some(Vec2::new( + (image_size.x - border.right) / image_size.x, + (image_size.y - border.bottom) / image_size.y, + )), + ..extracted_quad_template.clone() + }, + }; + extracted_quads.push(middle_quad); + } + commands.spawn_batch(extracted_quads); +} diff --git a/bevy_kayak_ui/src/render/unified/nine_patch/mod.rs b/bevy_kayak_ui/src/render/unified/nine_patch/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..dfaec008a1ea982b0d6781f75d977a639ea2fc6b --- /dev/null +++ b/bevy_kayak_ui/src/render/unified/nine_patch/mod.rs @@ -0,0 +1,15 @@ +use bevy::{ + prelude::Plugin, + render2::{RenderApp, RenderStage}, +}; + +mod extract; + +pub struct NinePatchRendererPlugin; + +impl Plugin for NinePatchRendererPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + let render_app = app.sub_app(RenderApp); + render_app.add_system_to_stage(RenderStage::Extract, extract::extract_nine_patch); + } +} diff --git a/bevy_kayak_ui/src/render/unified/pipeline.rs b/bevy_kayak_ui/src/render/unified/pipeline.rs index 483983c32551ca37914d26473d9c1e3b63fede5b..a787e7152ef7f32786639027c9b2d475acdfc320 100644 --- a/bevy_kayak_ui/src/render/unified/pipeline.rs +++ b/bevy_kayak_ui/src/render/unified/pipeline.rs @@ -4,7 +4,7 @@ use bevy::{ lifetimeless::{Read, SQuery, SRes}, SystemState, }, - math::{const_vec3, Mat4, Quat, Vec3, Vec4}, + math::{const_vec3, Mat4, Quat, Vec2, Vec3, Vec4}, prelude::{Bundle, Component, Entity, FromWorld, Handle, Query, Res, ResMut, World}, render2::{ color::Color, @@ -289,7 +289,7 @@ impl FromWorld for UnifiedPipeline { } } -#[derive(Bundle)] +#[derive(Debug, Bundle)] pub struct ExtractQuadBundle { pub(crate) extracted_quad: ExtractedQuad, } @@ -301,7 +301,7 @@ pub enum UIQuadType { Image, } -#[derive(Component)] +#[derive(Debug, Component, Clone)] pub struct ExtractedQuad { pub rect: Rect, pub color: Color, @@ -313,6 +313,8 @@ pub struct ExtractedQuad { pub type_index: u32, pub border_radius: (f32, f32, f32, f32), pub image: Option<Handle<Image>>, + pub uv_min: Option<Vec2>, + pub uv_max: Option<Vec2>, } #[repr(C)] @@ -390,27 +392,30 @@ pub fn prepare_quads( UIQuadType::Image => extracted_sprite.type_index = image_type_offset, }; + let uv_min = extracted_sprite.uv_min.unwrap_or(Vec2::ZERO); + let uv_max = extracted_sprite.uv_max.unwrap_or(Vec2::ONE); + let bottom_left = Vec4::new( - 0.0, - 1.0, + uv_min.x, + uv_max.y, extracted_sprite.char_id as f32, extracted_sprite.border_radius.0, ); let top_left = Vec4::new( - 0.0, - 0.0, + uv_min.x, + uv_min.y, extracted_sprite.char_id as f32, extracted_sprite.border_radius.1, ); let top_right = Vec4::new( - 1.0, - 0.0, + uv_max.x, + uv_min.y, extracted_sprite.char_id as f32, extracted_sprite.border_radius.2, ); let bottom_right = Vec4::new( - 1.0, - 1.0, + uv_max.x, + uv_max.y, extracted_sprite.char_id as f32, extracted_sprite.border_radius.3, ); diff --git a/bevy_kayak_ui/src/render/unified/quad/extract.rs b/bevy_kayak_ui/src/render/unified/quad/extract.rs index b81a7d0d9e18bec63f715dc0d4b210e7b61487b9..1a9fcf4ebb4a6e9aec7dd775cb8e8ea78c412002 100644 --- a/bevy_kayak_ui/src/render/unified/quad/extract.rs +++ b/bevy_kayak_ui/src/render/unified/quad/extract.rs @@ -48,6 +48,8 @@ pub fn extract_quads(mut commands: Commands, context: Res<BevyContext>) { type_index: 0, border_radius: *border_radius, image: None, + uv_max: None, + uv_min: None, }, }); } diff --git a/bevy_kayak_ui/src/render/unified/shader.wgsl b/bevy_kayak_ui/src/render/unified/shader.wgsl index 92b5463abf2909538a8d7ec6f1278d0961aa7f6d..c32bbb8bba67c9980d61303ece5c64507e576933 100644 --- a/bevy_kayak_ui/src/render/unified/shader.wgsl +++ b/bevy_kayak_ui/src/render/unified/shader.wgsl @@ -38,7 +38,6 @@ fn vertex( out.uv = vertex_uv.xyz; out.size = vertex_pos_size.zw; out.border_radius = vertex_uv.w; - return out; } diff --git a/examples/nine_patch.rs b/examples/nine_patch.rs new file mode 100644 index 0000000000000000000000000000000000000000..0a14f1a27c83ee6cbbd0787d724d51b7e6216c88 --- /dev/null +++ b/examples/nine_patch.rs @@ -0,0 +1,98 @@ +use bevy::{ + math::Vec2, + prelude::{App as BevyApp, AssetServer, Commands, Handle, Res, ResMut}, + window::{WindowDescriptor, Windows}, + PipelinedDefaultPlugins, +}; +use bevy_kayak_ui::{BevyContext, BevyKayakUIPlugin, ImageManager, UICameraBundle}; +use kayak_components::NinePatch; +use kayak_core::{ + layout_cache::Space, + styles::{Style, StyleProp, Units}, + Index, +}; +use kayak_ui::components::App; +use kayak_ui::core::rsx; + +fn startup( + mut commands: Commands, + windows: Res<Windows>, + asset_server: Res<AssetServer>, + mut image_manager: ResMut<ImageManager>, +) { + commands.spawn_bundle(UICameraBundle::new()); + + let window_size = if let Some(window) = windows.get_primary() { + Vec2::new(window.width(), window.height()) + } else { + panic!("Couldn't find primary window!"); + }; + + let handle: Handle<bevy::render2::texture::Image> = asset_server.load("panel.png"); + let ui_image_handle = image_manager.get(&handle); + + let context = BevyContext::new(window_size.x, window_size.y, |styles, context| { + // Hack to trick the proc macro for right now.. + let parent_id: Option<Index> = None; + + // The border prop splits up the image into 9 quadrants like so: + // 1----2----3 + // | | + // 4 9 5 + // | | + // 6----7----8 + // The sizes of sprites for a 15 pixel border are as follows: + // TopLeft = (15, 15) + // TopRight = (15, 15) + // LeftCenter = (15, image_height) + // RightCenter = (15, image_height) + // TopCenter = (image_width, 15) + // BottomCenter = (image_width, 15) + // BottomRight = (15, 15) + // BottomLeft = (15, 15) + // Middle = ( + // 30 being left border + right border + // image_width - 30 + // 30 being top border + bottom border + // image_height - 30 + // ) + // + + let nine_patch_styles = Style { + width: StyleProp::Value(Units::Pixels(512.0)), + height: StyleProp::Value(Units::Pixels(512.0)), + ..Style::default() + }; + + rsx! { + <App styles={Some(styles.clone())}> + <NinePatch + styles={Some(nine_patch_styles)} + border={Space { + left: 15.0, + right: 15.0, + top: 15.0, + bottom: 15.0, + }} + handle={ui_image_handle} + /> + </App> + } + }); + + commands.insert_resource(context); +} + +fn main() { + BevyApp::new() + .insert_resource(WindowDescriptor { + width: 1270.0, + height: 720.0, + title: String::from("UI Example"), + ..Default::default() + }) + .add_plugins(PipelinedDefaultPlugins) + .add_plugin(BevyKayakUIPlugin) + .add_startup_system(startup) + .run(); +} diff --git a/kayak_components/src/lib.rs b/kayak_components/src/lib.rs index 47472bd1936959d912f6b79d91d9e5cf40feb7c6..d59d930cb5444d0dce0afb700c63c784fa066f6e 100644 --- a/kayak_components/src/lib.rs +++ b/kayak_components/src/lib.rs @@ -3,6 +3,7 @@ mod background; mod button; mod clip; mod image; +mod nine_patch; mod text; mod window; @@ -11,5 +12,6 @@ pub use background::*; pub use button::*; pub use clip::*; pub use image::*; +pub use nine_patch::*; pub use text::*; pub use window::*; diff --git a/kayak_components/src/nine_patch.rs b/kayak_components/src/nine_patch.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d652ab6ebd018b6f4de826fa0b99e491e2318b5 --- /dev/null +++ b/kayak_components/src/nine_patch.rs @@ -0,0 +1,24 @@ +use kayak_core::{ + layout_cache::Space, + render_command::RenderCommand, + rsx, + styles::{Style, StyleProp}, + widget, Children, +}; + +#[widget] +pub fn NinePatch(handle: u16, border: Space, children: Children) { + *styles = Some(Style { + render_command: StyleProp::Value(RenderCommand::NinePatch { + handle: *handle, + border: *border, + }), + ..styles.clone().unwrap_or_default() + }); + + rsx! { + <> + {children} + </> + } +} diff --git a/kayak_core/src/layout_cache.rs b/kayak_core/src/layout_cache.rs index c843be7332f35973d4dd37bd0a0d705ab5925962..9b31c08c8b4bfdedb474ceec4c6843787e504380 100644 --- a/kayak_core/src/layout_cache.rs +++ b/kayak_core/src/layout_cache.rs @@ -20,7 +20,7 @@ impl Rect { } } -#[derive(Debug, Default, Clone, Copy)] +#[derive(Debug, Default, Clone, Copy, PartialEq)] pub struct Space { pub left: f32, pub right: f32, diff --git a/kayak_core/src/render_command.rs b/kayak_core/src/render_command.rs index cb6839f829e54b80adcb4910028ed9ed6084ef12..c717a2f23aa8706a9bb8a17c163f1fdb668c59f4 100644 --- a/kayak_core/src/render_command.rs +++ b/kayak_core/src/render_command.rs @@ -1,3 +1,5 @@ +use crate::layout_cache::Space; + #[derive(Debug, Clone, PartialEq)] pub enum RenderCommand { Empty, @@ -12,6 +14,10 @@ pub enum RenderCommand { Image { handle: u16, }, + NinePatch { + border: Space, + handle: u16, + }, } impl Default for RenderCommand { diff --git a/kayak_core/src/render_primitive.rs b/kayak_core/src/render_primitive.rs index 457c75e4cfb5791651a653b2847281255fe519fc..54b3224809697e9b06401be84786874482bed734 100644 --- a/kayak_core/src/render_primitive.rs +++ b/kayak_core/src/render_primitive.rs @@ -1,6 +1,6 @@ use crate::{ color::Color, - layout_cache::Rect, + layout_cache::{Rect, Space}, render_command::RenderCommand, styles::{Style, StyleProp}, }; @@ -27,6 +27,11 @@ pub enum RenderPrimitive { layout: Rect, handle: u16, }, + NinePatch { + border: Space, + layout: Rect, + handle: u16, + }, } impl RenderPrimitive { @@ -36,6 +41,7 @@ impl RenderPrimitive { RenderPrimitive::Quad { layout, .. } => *layout = new_layout, RenderPrimitive::Text { layout, .. } => *layout = new_layout, RenderPrimitive::Image { layout, .. } => *layout = new_layout, + RenderPrimitive::NinePatch { layout, .. } => *layout = new_layout, _ => (), } } @@ -77,6 +83,11 @@ impl From<&Style> for RenderPrimitive { layout: Rect::default(), handle, }, + RenderCommand::NinePatch { handle, border } => Self::NinePatch { + border, + layout: Rect::default(), + handle, + }, } } }