diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/imfile.iml b/.idea/imfile.iml new file mode 100644 index 0000000..7c12fe5 --- /dev/null +++ b/.idea/imfile.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..5266892 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index b502869..130da2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "imfile" -version = "0.1.0" +version = "0.1.1" edition = "2021" license = "MIT" -description = "A simple and customizable file dialog for imgui-rs written entirely in Rust." -authors = [ "Aggelos Tselios " ] +description = "A simple and customizable file dialog for imgui-rs written entirely in Rust. Fork with Trevor's Changes" +authors = [ "Aggelos Tselios ", "Trevor Merritt " ] repository = "https://github.com/tseli0s/imfile" keywords = [ "imgui", @@ -15,17 +15,23 @@ keywords = [ ] [dependencies] -imgui = "0.11" log = "0.4" +winit = { version = "0.30", features = ["x11", "mint"] } +imgui-glium-renderer = { version = "0.12.0" } +imgui-winit-support = { version = "0.12.0" } +glium = { version = "0.34.0", default-features = true } +image = { version = "0.23", optional = true } +imgui = { version = "0.12.0", features = ["tables-api"] } +copypasta = { version = "0.10.1" } [dev-dependencies] -env_logger = "0.10" +env_logger = "0.11.5" error-iter = "0.4" -imgui = "0.11" -imgui-winit-support = "0.11" -pixels = "0.12.1" -winit = "0.27" -winit_input_helper = "0.13" +imgui = "0.12.0" +imgui-winit-support = "0.12.0" +pixels = "0.13.0" +winit = "0.30" +winit_input_helper = "0.16.0" [dev-dependencies.imgui-wgpu] -git = "https://github.com/Yatekii/imgui-wgpu-rs.git" \ No newline at end of file +git = "https://github.com/Yatekii/imgui-wgpu-rs.git" diff --git a/examples/basic.rs b/examples/basic.rs index 000084e..8eadc4e 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -1,210 +1,175 @@ -use pixels::{wgpu, PixelsContext}; -use std::process::abort; +use std::fs::File; +use glium::glutin::surface::WindowSurface; +use glium::{Display, Surface}; +use imgui::{Condition, Context, FontConfig, FontGlyphRanges, FontSource, Ui}; +use imgui_glium_renderer::Renderer; +use imgui_winit_support::winit::event::{Event, WindowEvent}; +use imgui_winit_support::winit::event_loop::EventLoop; +use imgui_winit_support::winit::window::WindowBuilder; +use imgui_winit_support::{HiDpiMode, WinitPlatform}; +use std::path::Path; use std::time::Instant; -use pixels::{Error, Pixels, SurfaceTexture}; -use winit::dpi::LogicalSize; -use winit::event::{Event, VirtualKeyCode}; -use winit::event_loop::{ControlFlow, EventLoop}; -use winit::window::WindowBuilder; -use winit_input_helper::WinitInputHelper; - -pub(crate) struct Gui { - imgui: imgui::Context, - platform: imgui_winit_support::WinitPlatform, - renderer: imgui_wgpu::Renderer, - last_frame: Instant, - last_cursor: Option, - open_file_dialog: bool, + +use copypasta::{ClipboardContext, ClipboardProvider}; +use imgui::ClipboardBackend; +use imfile::FileDialog; + +pub const FONT_SIZE: f32 = 13.0; + +pub fn init() -> Option { + ClipboardContext::new().ok().map(ClipboardSupport) } -impl Gui { - /// Create Dear ImGui. - pub(crate) fn new(window: &winit::window::Window, pixels: &pixels::Pixels) -> Self { - // Create Dear ImGui context - let mut imgui = imgui::Context::create(); - imgui.set_ini_filename(None); - - // Initialize winit platform support - let mut platform = imgui_winit_support::WinitPlatform::init(&mut imgui); - platform.attach_window( - imgui.io_mut(), - window, - imgui_winit_support::HiDpiMode::Default, - ); - - // Configure Dear ImGui fonts - let hidpi_factor = window.scale_factor(); - let font_size = (13.0 * hidpi_factor) as f32; - imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32; - imgui - .fonts() - .add_font(&[imgui::FontSource::DefaultFontData { - config: Some(imgui::FontConfig { - oversample_h: 1, - pixel_snap_h: true, - size_pixels: font_size, - ..Default::default() - }), - }]); - - // Create Dear ImGui WGPU renderer - let device = pixels.device(); - let queue = pixels.queue(); - let config = imgui_wgpu::RendererConfig { - texture_format: pixels.render_texture_format(), - ..Default::default() - }; - let renderer = imgui_wgpu::Renderer::new(&mut imgui, device, queue, config); - - // Return GUI context - Self { - open_file_dialog: true, - imgui, - platform, - renderer, - last_frame: Instant::now(), - last_cursor: None, - } - } +pub struct ClipboardSupport(pub ClipboardContext); - /// Prepare Dear ImGui. - pub(crate) fn prepare( - &mut self, - window: &winit::window::Window, - ) -> Result<(), winit::error::ExternalError> { - // Prepare Dear ImGui - let now = Instant::now(); - self.imgui.io_mut().update_delta_time(now - self.last_frame); - self.last_frame = now; - self.platform.prepare_frame(self.imgui.io_mut(), window) - } +pub fn clipboard_init() -> Option { + ClipboardContext::new().ok().map(ClipboardSupport) +} - /// Render Dear ImGui. - pub(crate) fn render( - &mut self, - window: &winit::window::Window, - encoder: &mut wgpu::CommandEncoder, - render_target: &wgpu::TextureView, - context: &PixelsContext, - ) -> imgui_wgpu::RendererResult<()> { - // Start a new Dear ImGui frame and update the cursor - let ui = self.imgui.new_frame(); - - let mouse_cursor = ui.mouse_cursor(); - if self.last_cursor != mouse_cursor { - self.last_cursor = mouse_cursor; - self.platform.prepare_render(ui, window); - } - - if self.open_file_dialog == true { - if let Some(file) = imfile::FileDialog::new() - .accept_text("Open file") - .for_save() - .cancel_text("Close") - .title("Open File") - .spawn(&ui) - { - println!("Filename: {}", file.display()); - self.open_file_dialog = false; - } - } - - // Render Dear ImGui with WGPU - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("imgui"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: render_target, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, - })], - depth_stencil_attachment: None, - }); - - self.renderer.render( - self.imgui.render(), - &context.queue, - &context.device, - &mut rpass, - ) +impl ClipboardBackend for ClipboardSupport { + fn get(&mut self) -> Option { + self.0.get_contents().ok() } - - /// Handle any outstanding events. - pub(crate) fn handle_event( - &mut self, - window: &winit::window::Window, - event: &winit::event::Event<()>, - ) { - self.platform - .handle_event(self.imgui.io_mut(), window, event); + fn set(&mut self, text: &str) { + // ignore errors? + let _ = self.0.set_contents(text.to_owned()); } } -fn main() -> Result<(), Error> { - env_logger::init(); - let event_loop = EventLoop::new(); - let mut input = WinitInputHelper::new(); - let window = { - let size = LogicalSize::new(1280 as f64, 720 as f64); - WindowBuilder::new() - .with_title("ImFile example") - .with_inner_size(size) - .with_min_inner_size(size) - .build(&event_loop) - .unwrap() - }; - let mut scale_factor = window.scale_factor(); - let mut pixels = { - let window_size = window.inner_size(); - let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window); - Pixels::new(1280, 720, surface_texture)? +#[allow(dead_code)] // annoyingly, RA yells that this is unusued +pub fn simple_init(title: &str, run_ui: F) { + init_with_startup(title, |_, _, _| {}, run_ui); +} + +pub fn init_with_startup(title: &str, mut startup: FInit, mut run_ui: FUi) + where + FInit: FnMut(&mut Context, &mut Renderer, &Display) + 'static, + FUi: FnMut(&mut bool, &mut Ui) + 'static, +{ + let mut imgui = create_context(); + + let title = match Path::new(&title).file_name() { + Some(file_name) => file_name.to_str().unwrap(), + None => title, }; - - let mut gui = Gui::new(&window, &pixels); - - event_loop.run(move |event, _, control_flow| { - // Draw the current frame - if let Event::RedrawRequested(_) = event { - pixels.frame_mut().into_iter().for_each(|pix| *pix = 0x0); - gui.prepare(&window).expect("gui.prepare() failed"); - let render_result = pixels.render_with(|encoder, render_target, context| { - context.scaling_renderer.render(encoder, render_target); - gui.render(&window, encoder, render_target, context)?; - - Ok(()) - }); - if render_result.is_err() { - log::error!("Can't render!"); - abort(); + let event_loop = EventLoop::new().expect("Failed to create EventLoop"); + + let builder = WindowBuilder::new() + .with_maximized(false) + .with_title(title); + // .with_inner_size(LogicalSize::new(1024, 768)); + let (window, display) = glium::backend::glutin::SimpleWindowBuilder::new() + .set_window_builder(builder) + .build(&event_loop); + let mut renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer"); + + if let Some(backend) = clipboard_init() { + imgui.set_clipboard_backend(backend); + } else { + eprintln!("Failed to initialize clipboard"); + } + + let mut platform = WinitPlatform::init(&mut imgui); + { + let dpi_mode = if let Ok(factor) = std::env::var("IMGUI_EXAMPLE_FORCE_DPI_FACTOR") { + // Allow forcing of HiDPI factor for debugging purposes + match factor.parse::() { + Ok(f) => HiDpiMode::Locked(f), + Err(e) => panic!("Invalid scaling factor: {}", e), } - } + } else { + HiDpiMode::Default + }; + + platform.attach_window(imgui.io_mut(), &window, dpi_mode); + } + + let mut last_frame = Instant::now(); - gui.handle_event(&window, &event); - if input.update(&event) { - if input.key_pressed(VirtualKeyCode::Escape) || input.quit() { - *control_flow = ControlFlow::Exit; - return; + startup(&mut imgui, &mut renderer, &display); + + event_loop + .run(move |event, window_target| match event { + Event::NewEvents(_) => { + let now = Instant::now(); + imgui.io_mut().update_delta_time(now - last_frame); + last_frame = now; + } + Event::AboutToWait => { + platform + .prepare_frame(imgui.io_mut(), &window) + .expect("Failed to prepare frame"); + window.request_redraw(); } + Event::WindowEvent { + event: WindowEvent::RedrawRequested, + .. + } => { + let ui = imgui.frame(); + + let mut run = true; + run_ui(&mut run, ui); + if !run { + window_target.exit(); + } - if let Some(factor) = input.scale_factor() { - scale_factor = factor; + let mut target = display.draw(); + target.clear_color_srgb(1.0, 1.0, 1.0, 1.0); + platform.prepare_render(ui, &window); + let draw_data = imgui.render(); + renderer + .render(&mut target, draw_data) + .expect("Rendering failed"); + target.finish().expect("Failed to swap buffers"); } + Event::WindowEvent { + event: WindowEvent::Resized(new_size), + .. + } => { + if new_size.width > 0 && new_size.height > 0 { + display.resize((new_size.width, new_size.height)); + } + platform.handle_event(imgui.io_mut(), &window, &event); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => window_target.exit(), + event => { + platform.handle_event(imgui.io_mut(), &window, &event); + } + }) + .expect("EventLoop error"); +} - if let Some(size) = input.window_resized() { - if size.width > 0 && size.height > 0 { - pixels.resize_surface(size.width, size.height).expect("resize error"); +/// Creates the imgui context +pub fn create_context() -> imgui::Context { + let mut imgui = Context::create(); + imgui.set_ini_filename(None); + imgui +} - let LogicalSize { width, height } = size.to_logical(scale_factor); - if let Err(err) = pixels.resize_buffer(width, height) { - panic!("Error: {err}"); +fn main() { + let mut need_dialog = true; + + simple_init("GuiFileSlicer", move |_, ui| { + let dialog = FileDialog::new(); + ui.window("My Window") + .size(ui.io().display_size, Condition::Always) + .no_decoration() + .position([0.0, 0.0], Condition::Always) + .build( || { + if need_dialog { + if let Some(file) = dialog.spawn(&ui) // Create the dialog using the imgui::Ui + { + println!("File chosen: {}", file.display()); + need_dialog = false; + } else { + // println!("No file selected."); } } - } - window.request_redraw(); - } - }); -} \ No newline at end of file + }); + }) +}