use crate::theme::ComponentColor;
use std::path::Path;
use wgpu::{Device, Queue, RenderPipeline, Surface, TextureFormat};
use winit::dpi::PhysicalSize;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::platform::windows::WindowExtWindows;
use winit::window::{CursorIcon, WindowBuilder};
use winit::window::Window;
pub type ID = i32;
pub enum CloseOperation {
ExitAndClose,
HideAndClose,
}
pub struct FrameEvent<'a> {
frame: &'a RFrame,
id: &'a ID,
}
impl<'a> FrameEvent<'a> {
pub fn new(frame: &'a RFrame, id: &'a ID) -> Self {
Self { frame, id }
}
pub fn get_frame(&self) -> &'a RFrame {
self.frame
}
pub fn get_id(&self) -> ID {
*self.id
}
}
pub struct RFrame {
id: ID,
handle: Window,
event_loop: Option<EventLoop<()>>,
close_operation: CloseOperation,
window_listener: Box<dyn crate::event::WindowListener>,
color:wgpu::Color,
surface: Surface,
surface_format: TextureFormat,
device: Device,
queue: Queue,
pipeline: RenderPipeline,
}
impl RFrame {
pub fn new(title: impl Into<String>, id: ID, width: u32, height: u32) -> Self {
let event_loop = EventLoop::new();
let window_size: PhysicalSize<u32> = (width, height).into();
let window = WindowBuilder::new()
.with_fullscreen(None)
.with_inner_size(window_size)
.with_title(title)
.with_visible(false)
.build(&event_loop)
.unwrap();
let instance = wgpu::Instance::new(wgpu::Backends::all());
dbg!(instance.generate_report());
let surface = unsafe { instance.create_surface(&window) };
let adapter_options = wgpu::RequestAdapterOptions {
compatible_surface: Some(&surface),
..Default::default()
};
let adapter_future = instance.request_adapter(&adapter_options);
let adapter = pollster::block_on(adapter_future).unwrap();
println!("Selected adapter: {}", adapter.get_info().name);
let device_descriptor = wgpu::DeviceDescriptor::default();
let device_future = adapter.request_device(&device_descriptor, None);
let (device, queue) = pollster::block_on(device_future).unwrap();
let shader_code = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/shader.wgsl"));
let descriptor = wgpu::ShaderModuleDescriptor {
label: None,
source: wgpu::ShaderSource::Wgsl(shader_code.into()),
};
let shader_module = device.create_shader_module(descriptor);
let surface_format = surface.get_supported_formats(&adapter)[0];
let color_target = wgpu::ColorTargetState {
format: surface_format,
blend: None,
write_mask: Default::default(),
};
let color_targets = [Some(color_target)];
let descriptor = wgpu::RenderPipelineDescriptor {
label: None,
primitive: Default::default(),
vertex: wgpu::VertexState {
buffers: &[],
module: &shader_module,
entry_point: "vs_main",
},
fragment: Some(wgpu::FragmentState {
targets: &color_targets,
module: &shader_module,
entry_point: "fs_main",
}),
layout: None,
depth_stencil: None,
multisample: Default::default(),
multiview: None,
};
let pipeline = device.create_render_pipeline(&descriptor);
Self {
id,
handle: window,
event_loop: Some(event_loop),
close_operation: CloseOperation::ExitAndClose,
window_listener: Box::new(crate::event::DefaultWindowListener {}),
color: crate::wgpu::parse_color(ComponentColor::WhiteGray),
surface,
surface_format,
device,
queue,
pipeline,
}
}
pub fn add_window_listener(&mut self, listener: (impl crate::event::WindowListener + 'static)) {
self.window_listener = Box::new(listener);
}
pub fn set_enable(&self) {
self.handle.set_enable(true);
}
pub fn set_disable(&self) {
self.handle.set_enable(false);
}
pub fn set_title(&self, title: &str) {
self.handle.set_title(title);
}
pub fn set_size(&self, width: i32, height: i32) {
let window_size: PhysicalSize<u32> = (width, height).into();
self.handle.set_inner_size(window_size);
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: self.surface_format,
width: window_size.width,
height: window_size.height,
present_mode: wgpu::PresentMode::Fifo,
alpha_mode: wgpu::CompositeAlphaMode::Auto,
};
self.surface.configure(&self.device, &config);
}
pub fn set_location(&self, x: i32, y: i32) {
self.handle
.set_outer_position(winit::dpi::LogicalPosition::new(x, y));
}
pub fn set_maximum_window_size(&self,width:u32,height:u32) {
self.handle.set_max_inner_size(Some(PhysicalSize::new(width,height)));
}
pub fn set_minimum_window_size(&self,width:u32,height:u32) {
self.handle.set_min_inner_size(Some(PhysicalSize::new(width,height)));
}
pub fn set_resizable(&self) {
self.handle.set_resizable(true);
}
pub fn set_non_resizable(&self) {
self.handle.set_resizable(false);
}
pub fn set_icon(&self, icon: winit::window::Icon) {
self.handle.set_window_icon(Some(icon));
}
pub fn set_taskbar_icon(&self,icon: winit::window::Icon) {
self.handle.set_taskbar_icon(Some(icon));
}
pub fn set_default_close_operation(&mut self, operation: CloseOperation) {
self.close_operation = operation;
}
pub fn set_cursor_icon(&self,icon:crate::CursorIcon) {
self.handle.set_cursor_icon(match icon {
crate::CursorIcon::Arrow => {CursorIcon::Arrow}
crate::CursorIcon::ScrollAll => {CursorIcon::AllScroll}
crate::CursorIcon::CrossHair => {CursorIcon::Crosshair}
crate::CursorIcon::Hand => {CursorIcon::Hand}
crate::CursorIcon::Help => {CursorIcon::Help}
crate::CursorIcon::NotAllowed => {CursorIcon::NotAllowed}
crate::CursorIcon::Progress => {CursorIcon::Progress}
});
}
pub fn set_background_color(&mut self,color: ComponentColor) {
self.color = crate::wgpu::parse_color(color);
}
pub fn enable_ime(&self) {
self.handle.set_ime_allowed(true);
}
pub fn disable_ime(&self) {
self.handle.set_ime_allowed(false);
}
pub fn run(mut self) {
let event_loop = self.event_loop.take().unwrap();
let frame_event = FrameEvent::new(&self, &self.id);
self.handle.set_visible(true);
self.window_listener.window_opened(&frame_event);
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::MainEventsCleared => {
let frame = self.surface.get_current_texture().unwrap();
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(self.color),
store: true,
},
})],
depth_stencil_attachment: None,
});
rpass.set_pipeline(&self.pipeline);
}
let command_buffer = encoder.finish();
self.queue.submit(Some(command_buffer));
frame.present();
}
Event::WindowEvent {
event: WindowEvent::Focused(is_focused),
..
} => {
if is_focused == true {
self.window_listener
.window_focused(&FrameEvent::new(&self, &self.id));
}
}
Event::WindowEvent {
event: WindowEvent::Moved(pos),
..
} => {
self.window_listener
.window_moved(pos,&FrameEvent::new(&self, &self.id));
}
Event::WindowEvent {
event: WindowEvent::DroppedFile(pathbuf),
..
} => {
self.window_listener
.window_dropped_file(pathbuf, &FrameEvent::new(&self, &self.id));
}
Event::WindowEvent {
event: WindowEvent::ReceivedCharacter(character),
..
} => {
self.window_listener
.window_received_character(character, &FrameEvent::new(&self, &self.id));
}
Event::WindowEvent {
event: WindowEvent::Resized(window_size),
..
} => {
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: wgpu::PresentMode::Fifo,
alpha_mode: wgpu::CompositeAlphaMode::Auto,
};
self.surface.configure(&self.device, &config);
self.window_listener
.window_resized(&FrameEvent::new(&self, &self.id));
}
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
self.window_listener
.window_closed(&FrameEvent::new(&self, &self.id));
*control_flow = ControlFlow::Exit;
}
_ => {}
}
});
}
pub fn show(&self) {
self.handle.set_visible(true);
}
pub fn hide(&self) {
self.handle.set_visible(false);
}
pub fn set_maximized(&self) {
self.handle.set_maximized(true);
}
pub fn set_minimized(&self) {
if self.handle.is_maximized() == false {
self.handle.set_minimized(true);
} else {
self.handle.set_maximized(false);
}
}
}