diff --git a/crates/gpui/examples/metal_view.rs b/crates/gpui/examples/metal_view.rs index a0bb098d2f443b23f077b094b41c6876f457c09a..ced09c37c197d20b5bd4155a7c66ffcfcfca6ef3 100644 --- a/crates/gpui/examples/metal_view.rs +++ b/crates/gpui/examples/metal_view.rs @@ -1,4 +1,4 @@ -use gpui::{Application, *}; +use gpui::{prelude::*, *}; use std::sync::Arc; #[cfg(target_os = "macos")] @@ -9,6 +9,7 @@ struct MetalViewExample { pipeline_state: Option, #[cfg(target_os = "macos")] device: Option, + epoch: u64, } impl MetalViewExample { @@ -18,46 +19,68 @@ impl MetalViewExample { pipeline_state: None, #[cfg(target_os = "macos")] device: None, + epoch: 0, } } + fn update_epoch(&mut self, cx: &mut Context) { + const MAX_EPOCH: u64 = 1024; + self.epoch = (self.epoch + 1) % MAX_EPOCH; + cx.notify(); + } + #[cfg(target_os = "macos")] fn setup_metal(&mut self) { - // Create Metal device let device = Device::system_default().expect("no Metal device"); - // Create shader library from source + // Shader that properly handles viewport transformation let shader_source = r#" #include using namespace metal; + struct Uniforms { + float2 viewport_size; + float epoch; + }; + struct VertexOut { float4 position [[position]]; float4 color; }; - vertex VertexOut vertex_main(uint vid [[vertex_id]]) { + vertex VertexOut vertex_main( + uint vid [[vertex_id]], + constant Uniforms& uniforms [[buffer(0)]] + ) { VertexOut out; - // Create a rectangle using two triangles - // Triangle 1: top-left, top-right, bottom-left - // Triangle 2: top-right, bottom-right, bottom-left + // Define a quad in pixel coordinates (0,0 to viewport_size) float2 positions[6] = { - float2(-1.0, 1.0), // top-left - float2( 1.0, 1.0), // top-right - float2(-1.0, -1.0), // bottom-left - float2( 1.0, 1.0), // top-right - float2( 1.0, -1.0), // bottom-right - float2(-1.0, -1.0), // bottom-left + float2(0.0, 0.0), // top-left + float2(uniforms.viewport_size.x, 0.0), // top-right + float2(0.0, uniforms.viewport_size.y), // bottom-left + float2(uniforms.viewport_size.x, 0.0), // top-right + float2(uniforms.viewport_size.x, uniforms.viewport_size.y), // bottom-right + float2(0.0, uniforms.viewport_size.y), // bottom-left }; - out.position = float4(positions[vid], 0.0, 1.0); - // Create a gradient color based on position + // Transform from pixel coordinates to normalized device coordinates + float2 pos = positions[vid]; + float2 ndc = (pos / uniforms.viewport_size) * 2.0 - 1.0; + ndc.y = -ndc.y; // Flip Y axis to match screen coordinates + + out.position = float4(ndc, 0.0, 1.0); + + // Create an animated gradient using epoch + float2 uv = pos / uniforms.viewport_size; + float time = uniforms.epoch * 0.01; + + // Animate the gradient with some trigonometric functions out.color = float4( - (positions[vid].x + 1.0) * 0.5, // Red based on X - (positions[vid].y + 1.0) * 0.5, // Green based on Y - 0.7, // Blue constant - 1.0 // Alpha + 0.5 + 0.5 * sin(uv.x * 3.14159 + time), // Red + 0.5 + 0.5 * sin(uv.y * 3.14159 + time * 1.3), // Green + 0.5 + 0.5 * sin((uv.x + uv.y) * 3.14159 - time * 0.7), // Blue + 1.0 // Full opacity ); return out; @@ -80,14 +103,13 @@ impl MetalViewExample { pipeline_descriptor.set_vertex_function(Some(&vertex_function)); pipeline_descriptor.set_fragment_function(Some(&fragment_function)); - // Configure color attachment let color_attachment = pipeline_descriptor .color_attachments() .object_at(0) .unwrap(); color_attachment.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm); - // Enable blending to work with GPUI's existing content + // Enable blending color_attachment.set_blending_enabled(true); color_attachment.set_source_rgb_blend_factor(metal::MTLBlendFactor::SourceAlpha); color_attachment @@ -105,7 +127,7 @@ impl MetalViewExample { } #[cfg(target_os = "macos")] - fn create_render_callback(&self) -> MetalRenderCallback { + fn create_render_callback(&self, epoch: u64) -> MetalRenderCallback { let pipeline_state = self.pipeline_state.clone().unwrap(); Arc::new( @@ -127,7 +149,37 @@ impl MetalViewExample { }; encoder.set_viewport(viewport); - // Draw the rectangle (6 vertices for 2 triangles) + // Set scissor rectangle to clip to bounds + let scissor_rect = metal::MTLScissorRect { + x: (bounds.origin.x.0 * scale_factor) as u64, + y: (bounds.origin.y.0 * scale_factor) as u64, + width: (bounds.size.width.0 * scale_factor) as u64, + height: (bounds.size.height.0 * scale_factor) as u64, + }; + encoder.set_scissor_rect(scissor_rect); + + // Pass viewport size as uniform + #[repr(C)] + struct Uniforms { + viewport_size: [f32; 2], + epoch: f32, + } + + let uniforms = Uniforms { + viewport_size: [ + bounds.size.width.0 * scale_factor, + bounds.size.height.0 * scale_factor, + ], + epoch: epoch as f32, + }; + + encoder.set_vertex_bytes( + 0, + std::mem::size_of::() as u64, + &uniforms as *const Uniforms as *const _, + ); + + // Draw the quad encoder.draw_primitives(MTLPrimitiveType::Triangle, 0, 6); }, ) @@ -135,75 +187,63 @@ impl MetalViewExample { } impl Render for MetalViewExample { - fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { // Initialize Metal on first render if on macOS #[cfg(target_os = "macos")] if self.pipeline_state.is_none() { self.setup_metal(); } + // Update epoch and request animation frame + self.update_epoch(cx); + window.request_animation_frame(); + div() .flex() + .flex_col() .bg(rgb(0x1e1e1e)) .size_full() - .justify_center() - .items_center() + .p_8() + .gap_6() + .child( + div() + .child("Metal View Element") + .text_2xl() + .text_color(rgb(0xffffff)), + ) .child( div() - .flex_col() - .gap_4() - .child( - div().flex().justify_center().child( - div() - .child("Metal View Example") - .text_xl() - .text_color(rgb(0xffffff)), - ), - ) - .child( - div() - .border_1() - .border_color(rgb(0x444444)) - .rounded_md() - .overflow_hidden() - .child( - // The Metal view - #[cfg(target_os = "macos")] - { - let callback = self.create_render_callback(); - metal_view() - .render_with_shared(callback) - .w(px(400.0)) - .h(px(300.0)) - .bg(rgb(0x000000)) - }, - #[cfg(not(target_os = "macos"))] - { - // Fallback for non-macOS platforms - div() - .w(px(400.0)) - .h(px(300.0)) - .bg(rgb(0x222222)) - .flex() - .justify_center() - .items_center() - .child( - div() - .child("Metal rendering is only available on macOS") - .text_color(rgb(0x888888)), - ) - }, - ), - ) - .child( - div().flex().justify_center().child( - div() - .child("A gradient rectangle rendered with custom Metal shaders") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ), - ), + .child("While GPUI normally handles all Metal rendering for you, the metal_view() element gives you direct access to write custom Metal shaders and GPU drawing commands") + .text_color(rgb(0xaaaaaa)), ) + .child( + div() + .child("This is useful for special effects, custom visualizations, or when you need GPU performance that GPUI's standard elements can't provide") + .text_sm() + .text_color(rgb(0x888888)), + ) + .child(div().overflow_hidden().child( + #[cfg(target_os = "macos")] + { + let callback = self.create_render_callback(self.epoch); + metal_view() + .render_with_shared(callback) + .w(px(600.0)) + .h(px(400.0)) + .bg(rgb(0x000000)) + }, + #[cfg(not(target_os = "macos"))] + { + div() + .w(px(600.0)) + .h(px(400.0)) + .bg(rgb(0x222222)) + .flex() + .items_center() + .justify_center() + .child(div().child("Metal (macOS only)").text_color(rgb(0x666666))) + }, + )) } } @@ -211,97 +251,20 @@ fn main() { Application::new().run(|cx: &mut App| { let _ = cx.open_window( WindowOptions { - window_bounds: Some(WindowBounds::Windowed(Bounds { - origin: Point::new(px(100.0), px(100.0)), - size: Size { - width: px(600.0), - height: px(500.0), - }, - })), + window_bounds: Some(WindowBounds::Windowed(Bounds::centered( + None, + size(px(900.0), px(600.0)), + cx, + ))), titlebar: Some(TitlebarOptions { - title: Some("Metal View Example".into()), + title: Some("Metal View Element".into()), ..Default::default() }), ..Default::default() }, |_window, cx| cx.new(|_cx| MetalViewExample::new()), ); - }); -} - -// Additional example: Using MetalView for more complex rendering -#[cfg(target_os = "macos")] -#[allow(dead_code)] -mod advanced_example { - use super::*; - use std::sync::Mutex; - - /// Example of a MetalView that renders an animated scene - pub struct AnimatedMetalView { - device: Device, - pipeline_state: RenderPipelineState, - frame_count: Arc>, - } - impl AnimatedMetalView { - pub fn create_animated_renderer(&self) -> MetalRenderCallback { - let pipeline_state = self.pipeline_state.clone(); - let frame_count = self.frame_count.clone(); - - Arc::new( - move |encoder: &RenderCommandEncoderRef, - _target: &TextureRef, - bounds: Bounds, - scale_factor: f32| { - // Update animation state - let mut count = frame_count.lock().unwrap(); - *count += 0.01; - let time = *count; - - // Set pipeline and viewport - encoder.set_render_pipeline_state(&pipeline_state); - - let viewport = metal::MTLViewport { - originX: bounds.origin.x.0 as f64 * scale_factor as f64, - originY: bounds.origin.y.0 as f64 * scale_factor as f64, - width: bounds.size.width.0 as f64 * scale_factor as f64, - height: bounds.size.height.0 as f64 * scale_factor as f64, - znear: 0.0, - zfar: 1.0, - }; - encoder.set_viewport(viewport); - - // Pass time as a uniform - encoder.set_vertex_bytes( - 0, - std::mem::size_of::() as u64, - &time as *const f32 as *const _, - ); - - // Draw animated geometry - encoder.draw_primitives(MTLPrimitiveType::TriangleStrip, 0, 4); - }, - ) - } - } + cx.activate(false); + }); } - -// Example usage in a component: -// ```rust -// struct MyApp { -// metal_renderer: Option, -// } -// -// impl Render for MyApp { -// fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { -// div() -// .child( -// metal_view() -// .render_with(|encoder, target, bounds, scale_factor| { -// // Your custom Metal rendering code here -// }) -// .size_full() -// ) -// } -// } -// ``` diff --git a/crates/gpui/examples/metal_view_quad.rs b/crates/gpui/examples/metal_view_quad.rs deleted file mode 100644 index a1c5d85b90642a9d2348f6f91334f8d2aabdf369..0000000000000000000000000000000000000000 --- a/crates/gpui/examples/metal_view_quad.rs +++ /dev/null @@ -1,355 +0,0 @@ -use gpui::{prelude::*, *}; -use std::sync::Arc; - -#[cfg(target_os = "macos")] -use metal::{Device, MTLPrimitiveType, RenderCommandEncoderRef, RenderPipelineState, TextureRef}; - -struct MetalQuadExample { - #[cfg(target_os = "macos")] - pipeline_state: Option, - #[cfg(target_os = "macos")] - device: Option, -} - -impl MetalQuadExample { - fn new() -> Self { - Self { - #[cfg(target_os = "macos")] - pipeline_state: None, - #[cfg(target_os = "macos")] - device: None, - } - } - - #[cfg(target_os = "macos")] - fn setup_metal(&mut self) { - let device = Device::system_default().expect("no Metal device"); - - // Shader that properly handles viewport transformation - let shader_source = r#" - #include - using namespace metal; - - struct Uniforms { - float2 viewport_size; - }; - - struct VertexOut { - float4 position [[position]]; - float4 color; - }; - - vertex VertexOut vertex_main( - uint vid [[vertex_id]], - constant Uniforms& uniforms [[buffer(0)]] - ) { - VertexOut out; - - // Define a quad in pixel coordinates (0,0 to viewport_size) - float2 positions[6] = { - float2(0.0, 0.0), // top-left - float2(uniforms.viewport_size.x, 0.0), // top-right - float2(0.0, uniforms.viewport_size.y), // bottom-left - float2(uniforms.viewport_size.x, 0.0), // top-right - float2(uniforms.viewport_size.x, uniforms.viewport_size.y), // bottom-right - float2(0.0, uniforms.viewport_size.y), // bottom-left - }; - - // Transform from pixel coordinates to normalized device coordinates - float2 pos = positions[vid]; - float2 ndc = (pos / uniforms.viewport_size) * 2.0 - 1.0; - ndc.y = -ndc.y; // Flip Y axis to match screen coordinates - - out.position = float4(ndc, 0.0, 1.0); - - // Create a nice gradient - float2 uv = pos / uniforms.viewport_size; - out.color = float4( - uv.x, // Red increases left to right - uv.y, // Green increases top to bottom - 1.0 - uv.x, // Blue decreases left to right - 1.0 // Full opacity - ); - - return out; - } - - fragment float4 fragment_main(VertexOut in [[stage_in]]) { - return in.color; - } - "#; - - let library = device - .new_library_with_source(shader_source, &metal::CompileOptions::new()) - .expect("Failed to create shader library"); - - let vertex_function = library.get_function("vertex_main", None).unwrap(); - let fragment_function = library.get_function("fragment_main", None).unwrap(); - - // Create pipeline state - let pipeline_descriptor = metal::RenderPipelineDescriptor::new(); - pipeline_descriptor.set_vertex_function(Some(&vertex_function)); - pipeline_descriptor.set_fragment_function(Some(&fragment_function)); - - let color_attachment = pipeline_descriptor - .color_attachments() - .object_at(0) - .unwrap(); - color_attachment.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm); - - // Enable blending - color_attachment.set_blending_enabled(true); - color_attachment.set_source_rgb_blend_factor(metal::MTLBlendFactor::SourceAlpha); - color_attachment - .set_destination_rgb_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha); - color_attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::One); - color_attachment - .set_destination_alpha_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha); - - let pipeline_state = device - .new_render_pipeline_state(&pipeline_descriptor) - .expect("Failed to create pipeline state"); - - self.device = Some(device); - self.pipeline_state = Some(pipeline_state); - } - - #[cfg(target_os = "macos")] - fn create_render_callback(&self) -> MetalRenderCallback { - let pipeline_state = self.pipeline_state.clone().unwrap(); - - Arc::new( - move |encoder: &RenderCommandEncoderRef, - _target: &TextureRef, - bounds: Bounds, - scale_factor: f32| { - // Set the pipeline state - encoder.set_render_pipeline_state(&pipeline_state); - - // Set viewport to match element bounds - let viewport = metal::MTLViewport { - originX: bounds.origin.x.0 as f64 * scale_factor as f64, - originY: bounds.origin.y.0 as f64 * scale_factor as f64, - width: bounds.size.width.0 as f64 * scale_factor as f64, - height: bounds.size.height.0 as f64 * scale_factor as f64, - znear: 0.0, - zfar: 1.0, - }; - encoder.set_viewport(viewport); - - // Set scissor rectangle to clip to bounds - let scissor_rect = metal::MTLScissorRect { - x: (bounds.origin.x.0 * scale_factor) as u64, - y: (bounds.origin.y.0 * scale_factor) as u64, - width: (bounds.size.width.0 * scale_factor) as u64, - height: (bounds.size.height.0 * scale_factor) as u64, - }; - encoder.set_scissor_rect(scissor_rect); - - // Pass viewport size as uniform - #[repr(C)] - struct Uniforms { - viewport_size: [f32; 2], - } - - let uniforms = Uniforms { - viewport_size: [ - bounds.size.width.0 * scale_factor, - bounds.size.height.0 * scale_factor, - ], - }; - - encoder.set_vertex_bytes( - 0, - std::mem::size_of::() as u64, - &uniforms as *const Uniforms as *const _, - ); - - // Draw the quad - encoder.draw_primitives(MTLPrimitiveType::Triangle, 0, 6); - }, - ) - } -} - -impl Render for MetalQuadExample { - fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { - #[cfg(target_os = "macos")] - if self.pipeline_state.is_none() { - self.setup_metal(); - } - - div() - .flex() - .flex_col() - .bg(rgb(0x1e1e1e)) - .size_full() - .p_8() - .gap_6() - .child( - div() - .child("Metal Quad Example") - .text_2xl() - .text_color(rgb(0xffffff)), - ) - .child( - div() - .child("This example demonstrates proper coordinate handling in MetalView") - .text_color(rgb(0xaaaaaa)), - ) - .child( - div() - .flex() - .gap_4() - .child( - div() - .flex_col() - .gap_2() - .flex_1() - .child( - div() - .child("Small MetalView (200x150)") - .text_sm() - .text_color(rgb(0xcccccc)), - ) - .child( - div() - .border_1() - .border_color(rgb(0x444444)) - .rounded_md() - .overflow_hidden() - .child( - #[cfg(target_os = "macos")] - { - let callback = self.create_render_callback(); - metal_view() - .render_with_shared(callback) - .w(px(200.0)) - .h(px(150.0)) - .bg(rgb(0x000000)) - }, - #[cfg(not(target_os = "macos"))] - { - div() - .w(px(200.0)) - .h(px(150.0)) - .bg(rgb(0x222222)) - .flex() - .items_center() - .justify_center() - .child( - div() - .child("Metal (macOS only)") - .text_color(rgb(0x666666)), - ) - }, - ), - ), - ) - .child( - div() - .flex_col() - .gap_2() - .flex_1() - .child( - div() - .child("Large MetalView (400x300)") - .text_sm() - .text_color(rgb(0xcccccc)), - ) - .child( - div() - .border_1() - .border_color(rgb(0x444444)) - .rounded_md() - .overflow_hidden() - .child( - #[cfg(target_os = "macos")] - { - let callback = self.create_render_callback(); - metal_view() - .render_with_shared(callback) - .w(px(400.0)) - .h(px(300.0)) - .bg(rgb(0x000000)) - }, - #[cfg(not(target_os = "macos"))] - { - div() - .w(px(400.0)) - .h(px(300.0)) - .bg(rgb(0x222222)) - .flex() - .items_center() - .justify_center() - .child( - div() - .child("Metal (macOS only)") - .text_color(rgb(0x666666)), - ) - }, - ), - ), - ), - ) - .child( - div().p_4().bg(rgb(0x2a2a2a)).rounded_md().child( - div() - .flex() - .flex_col() - .gap_2() - .child( - div() - .child("Key Features:") - .text_base() - .font_weight(FontWeight::SEMIBOLD) - .text_color(rgb(0xffffff)), - ) - .child( - div() - .child("• Proper coordinate transformation from pixels to NDC") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ) - .child( - div() - .child("• Scissor rectangle to clip content to bounds") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ) - .child( - div() - .child("• Viewport size passed as uniform to shader") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ) - .child( - div() - .child("• Gradient fills entire MetalView bounds") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ), - ), - ) - } -} - -fn main() { - Application::new().run(|cx: &mut App| { - let _ = cx.open_window( - WindowOptions { - window_bounds: Some(WindowBounds::Windowed(Bounds::centered( - None, - size(px(900.0), px(600.0)), - cx, - ))), - titlebar: Some(TitlebarOptions { - title: Some("Metal Quad Example".into()), - ..Default::default() - }), - ..Default::default() - }, - |_window, cx| cx.new(|_cx| MetalQuadExample::new()), - ); - }); -} diff --git a/crates/gpui/examples/metal_view_simple.rs b/crates/gpui/examples/metal_view_simple.rs deleted file mode 100644 index f7dfa4e9c23f3a1e33dddd91cb02f389d68f6867..0000000000000000000000000000000000000000 --- a/crates/gpui/examples/metal_view_simple.rs +++ /dev/null @@ -1,198 +0,0 @@ -use gpui::{prelude::*, *}; - -struct MetalViewSimpleExample { - show_metal_view: bool, -} - -impl MetalViewSimpleExample { - fn new() -> Self { - Self { - show_metal_view: true, - } - } -} - -impl Render for MetalViewSimpleExample { - fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { - div() - .flex() - .flex_col() - .bg(rgb(0x1e1e1e)) - .size_full() - .p_8() - .gap_4() - .child( - div() - .child("MetalView Simple Example") - .text_2xl() - .text_color(rgb(0xffffff)), - ) - .child( - div() - .flex() - .gap_2() - .items_center() - .child( - div() - .id("toggle-button") - .px_3() - .py_1() - .bg(rgb(0x3b82f6)) - .hover(|style| style.bg(rgb(0x2563eb))) - .rounded_md() - .cursor_pointer() - .on_click(cx.listener(|this, _event, _window, cx| { - this.show_metal_view = !this.show_metal_view; - cx.notify(); - })) - .child(div().child("Toggle MetalView").text_color(rgb(0xffffff))), - ) - .child( - div() - .child(format!( - "MetalView is: {}", - if self.show_metal_view { - "visible" - } else { - "hidden" - } - )) - .text_color(rgb(0xaaaaaa)), - ), - ) - .child( - div() - .flex() - .flex_col() - .gap_4() - .p_4() - .bg(rgb(0x2a2a2a)) - .rounded_md() - .child( - div() - .child("Container with MetalView") - .text_lg() - .text_color(rgb(0xffffff)), - ) - .when(self.show_metal_view, |parent| { - parent.child( - div() - .border_2() - .border_color(rgb(0x444444)) - .rounded_md() - .overflow_hidden() - .child( - #[cfg(target_os = "macos")] - { - metal_view() - .w_full() - .h(px(200.0)) - .bg(rgb(0x1a1a1a)) - .render_with( - |_encoder, _target, _bounds, _scale_factor| { - // This callback would contain custom Metal rendering code - // For now, it's just a placeholder - }, - ) - }, - #[cfg(not(target_os = "macos"))] - { - div() - .w_full() - .h(px(200.0)) - .bg(rgb(0x1a1a1a)) - .flex() - .items_center() - .justify_center() - .child( - div() - .child("MetalView (macOS only)") - .text_color(rgb(0x666666)), - ) - }, - ), - ) - }) - .child( - div() - .flex() - .gap_4() - .child( - div().flex_1().p_3().bg(rgb(0x333333)).rounded_md().child( - div() - .child("Regular GPUI content") - .text_sm() - .text_color(rgb(0xcccccc)), - ), - ) - .child( - div().flex_1().p_3().bg(rgb(0x333333)).rounded_md().child( - div() - .child("Can be mixed with MetalView") - .text_sm() - .text_color(rgb(0xcccccc)), - ), - ), - ), - ) - .child( - div().mt_4().p_4().bg(rgb(0x2a2a2a)).rounded_md().child( - div() - .flex() - .flex_col() - .gap_2() - .child( - div() - .child("Notes:") - .text_base() - .font_weight(FontWeight::SEMIBOLD) - .text_color(rgb(0xffffff)), - ) - .child( - div() - .child("• MetalView integrates with GPUI's layout system") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ) - .child( - div() - .child("• It can be styled with the same methods as other elements") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ) - .child( - div() - .child("• On macOS, it would render custom Metal content") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ) - .child( - div() - .child("• On other platforms, a fallback can be provided") - .text_sm() - .text_color(rgb(0xaaaaaa)), - ), - ), - ) - } -} - -fn main() { - Application::new().run(|cx: &mut App| { - let _ = cx.open_window( - WindowOptions { - window_bounds: Some(WindowBounds::Windowed(Bounds::centered( - None, - size(px(800.0), px(600.0)), - cx, - ))), - titlebar: Some(TitlebarOptions { - title: Some("MetalView Simple Example".into()), - ..Default::default() - }), - ..Default::default() - }, - |_window, cx| cx.new(|_cx| MetalViewSimpleExample::new()), - ); - }); -}