clat_gui 0.1.3

High-performance, cross-platform Rust desktop GUI framework.
Documentation
use anyhow::{Result, anyhow};
use futures;
use std::sync::Arc;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window as WinitWindow, WindowBuilder};
use wgpu::Instance;

// 定义窗口类型
pub struct Window {
    window: Arc<WinitWindow>,
    surface: wgpu::Surface<'static>,
    device: wgpu::Device,
    queue: wgpu::Queue,
    config: Option<wgpu::SurfaceConfiguration>,
    surface_format: wgpu::TextureFormat,
    surface_caps: wgpu::SurfaceCapabilities,
}

// 定义应用程序类型
pub struct Application {
    event_loop: Option<EventLoop<()>>,
    windows: Vec<Window>,
}

// 应用程序实现
impl Application {
    // 创建新的应用程序实例
    pub fn new() -> Result<Self> {
        Ok(Self {
            event_loop: Some(EventLoop::new()?),
            windows: Vec::new(),
        })
    }
    
    // 创建新窗口
    pub fn create_window(&mut self, title: &str, width: u32, height: u32) -> Result<()> {
        if let Some(event_loop) = self.event_loop.as_ref() {
            let window = WindowBuilder::new()
                .with_title(title)
                .with_inner_size(winit::dpi::LogicalSize::new(width, height))
                .build(event_loop)?;
            
            // 包装为Arc以便共享
            let window_arc = Arc::new(window);
            
            // 初始化wgpu相关资源
            let instance = Instance::default();
            // 创建surface,使用unsafe块将引用转换为'static
            // 这是安全的,因为window_arc将被保存在Window结构体中
            // 只要Window存在,window_arc就会存在
            let surface = unsafe {
                // 创建一个具有'static生命周期的引用
                let static_ref: &Arc<WinitWindow> = &window_arc;
                let static_ref_ptr = static_ref as *const Arc<WinitWindow>;
                &*static_ref_ptr
            };
            let surface = instance.create_surface(surface)?;
            let adapter = futures::executor::block_on(instance.request_adapter(
                &wgpu::RequestAdapterOptions {
                    power_preference: wgpu::PowerPreference::default(),
                    compatible_surface: Some(&surface),
                    force_fallback_adapter: false,
                },
            )).ok_or_else(|| anyhow::anyhow!("Failed to find an appropriate adapter"))?;
            
            let (device, queue) = futures::executor::block_on(adapter.request_device(
                &wgpu::DeviceDescriptor {
                    required_features: wgpu::Features::empty(),
                    required_limits: wgpu::Limits::default(),
                    label: Some("Device"),
                },
                None,
            ))?;
            
            let surface_caps = surface.get_capabilities(&adapter);
            let surface_format = surface_caps.formats.iter()
                .copied()
                .find(|f| f.is_srgb())
                .unwrap_or(surface_caps.formats[0]);
            
            // 不在创建窗口时立即配置surface,而是存储必要的配置信息
            // 将窗口添加到应用程序,暂时不配置surface
            self.windows.push(Window {
                window: window_arc,
                surface,
                device,
                queue,
                config: None,
                surface_format,
                surface_caps,
            });
        }
        
        Ok(())
    }
    
    // 运行应用程序
    pub fn run(mut self) -> Result<()> {
        let event_loop = self.event_loop.take().expect("Event loop already taken");
        
        event_loop.run(move |event, target| {
            target.set_control_flow(ControlFlow::Wait);
            
            match event {
                Event::WindowEvent { event, window_id } => {
                    match event {
                        WindowEvent::CloseRequested => {
                            // 正确的控制流变体
                            target.set_control_flow(ControlFlow::WaitUntil(std::time::Instant::now()));
                        },
                        WindowEvent::Resized(new_size) => {
            // 更新窗口大小
            for window in &mut self.windows {
                if window.window.id() == window_id {
                    // 检查窗口大小是否有效
                    if new_size.width > 0 && new_size.height > 0 {
                        // 创建或更新surface配置
                        let config = wgpu::SurfaceConfiguration {
                            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
                            format: window.surface_format,
                            width: new_size.width,
                            height: new_size.height,
                            present_mode: window.surface_caps.present_modes[0],
                            alpha_mode: window.surface_caps.alpha_modes[0],
                            view_formats: vec![],
                            desired_maximum_frame_latency: 2,
                        };
                        
                        // 先配置surface,再保存config
                        window.surface.configure(&window.device, &config);
                        window.config = Some(config);
                        window.window.request_redraw();
                    }
                }
            }
        },
                        WindowEvent::RedrawRequested => {
                            // 渲染窗口内容
                            for window in &mut self.windows {
                                if window.window.id() == window_id {
                                    if let Err(err) = window.render() {
                                        eprintln!("Error during rendering: {:?}", err);
                                    }
                                }
                            }
                        },
                        _ => {},
                    }
                },
                // 在新版本winit中,RedrawRequested是通过不同方式处理的
                Event::AboutToWait => {
                    // 为所有窗口请求重绘
                    for window in &self.windows {
                        window.window.request_redraw();
                    }
                },
                _ => {},
            }        }).map_err(|e| anyhow!("Event loop error: {:?}", e))
    }
}

// 窗口实现
impl Window {
    // 渲染窗口内容
    pub fn render(&mut self) -> Result<()> {
        // 检查是否需要配置surface
        if self.config.is_none() {
            let window_size = self.window.inner_size();
            
            // 只有当窗口大小有效时才配置surface
            if window_size.width > 0 && window_size.height > 0 {
                let config = wgpu::SurfaceConfiguration {
                    usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
                    format: self.surface_format,
                    width: window_size.width,
                    height: window_size.height,
                    present_mode: self.surface_caps.present_modes[0],
                    alpha_mode: self.surface_caps.alpha_modes[0],
                    view_formats: vec![],
                    desired_maximum_frame_latency: 2,
                };
                
                // 先配置surface,再保存config
                self.surface.configure(&self.device, &config);
                self.config = Some(config);
            } else {
                // 窗口大小无效,跳过渲染
                return Ok(());
            }
        }
        
        // 尝试获取当前纹理
        let output = match self.surface.get_current_texture() {
            Ok(output) => output,
            Err(wgpu::SurfaceError::Outdated) | Err(wgpu::SurfaceError::Lost) => {
                // 如果surface过期或丢失,尝试重新配置
                if let Some(config) = &self.config {
                    self.surface.configure(&self.device, config);
                }
                return Ok(());
            },
            Err(err) => return Err(err.into()),
        };
        
        let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
        
        let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
            label: Some("Render Encoder"),
        });
        
        // 清除屏幕(这里使用简单的背景色)
        {
            let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                label: Some("Render Pass"),
                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                    view: &view,
                    resolve_target: None,
                    ops: wgpu::Operations {
                        load: wgpu::LoadOp::Clear(wgpu::Color {
                            r: 0.1,
                            g: 0.2,
                            b: 0.3,
                            a: 1.0,
                        }),
                        store: wgpu::StoreOp::Store,
                    },
                })],
                depth_stencil_attachment: None,
                timestamp_writes: None,
                occlusion_query_set: None,
            });
            // 这里可以添加更多渲染代码
            drop(render_pass);
        }
        
        self.queue.submit(std::iter::once(encoder.finish()));
        output.present();
        
        Ok(())
    }
}