diff options
Diffstat (limited to 'glutin')
-rw-r--r-- | glutin/Cargo.toml | 30 | ||||
-rw-r--r-- | glutin/README.md | 27 | ||||
-rw-r--r-- | glutin/src/application.rs | 209 | ||||
-rw-r--r-- | glutin/src/lib.rs | 23 |
4 files changed, 289 insertions, 0 deletions
diff --git a/glutin/Cargo.toml b/glutin/Cargo.toml new file mode 100644 index 00000000..4652112c --- /dev/null +++ b/glutin/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "iced_glutin" +version = "0.1.0" +authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] +edition = "2018" +description = "A glutin runtime for Iced" +license = "MIT" +repository = "https://github.com/hecrj/iced" +documentation = "https://docs.rs/iced_glutin" +keywords = ["gui", "ui", "graphics", "interface", "widgets"] +categories = ["gui"] + +[features] +debug = ["iced_winit/debug"] + +[dependencies] +glutin = "0.24" + +[dependencies.iced_native] +version = "0.2" +path = "../native" + +[dependencies.iced_winit] +version = "0.1" +path = "../winit" + +[dependencies.iced_graphics] +version = "0.1" +path = "../graphics" +features = ["opengl"] diff --git a/glutin/README.md b/glutin/README.md new file mode 100644 index 00000000..34dec1b3 --- /dev/null +++ b/glutin/README.md @@ -0,0 +1,27 @@ +# `iced_winit` +[][documentation] +[](https://crates.io/crates/iced_winit) +[](https://github.com/hecrj/iced/blob/master/LICENSE) +[](https://iced.zulipchat.com) + +`iced_winit` offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`]. + +It exposes a renderer-agnostic `Application` trait that can be implemented and then run with a simple call. The use of this trait is optional. A `conversion` module is provided for users that decide to implement a custom event loop. + + + +[documentation]: https://docs.rs/iced_winit +[`iced_native`]: ../native +[`winit`]: https://github.com/rust-windowing/winit + +## Installation +Add `iced_winit` as a dependency in your `Cargo.toml`: + +```toml +iced_winit = "0.1" +``` + +__Iced moves fast and the `master` branch can contain breaking changes!__ If +you want to learn about a specific release, check out [the release list]. + +[the release list]: https://github.com/hecrj/iced/releases diff --git a/glutin/src/application.rs b/glutin/src/application.rs new file mode 100644 index 00000000..c777a13b --- /dev/null +++ b/glutin/src/application.rs @@ -0,0 +1,209 @@ +//! Create interactive, native cross-platform applications. +use crate::{mouse, Executor, Runtime, Size}; +use iced_graphics::window; +use iced_graphics::Viewport; +use iced_winit::application; +use iced_winit::conversion; +use iced_winit::{Clipboard, Debug, Proxy, Settings}; + +pub use iced_winit::Application; +pub use iced_winit::{program, Program}; + +/// Runs an [`Application`] with an executor, compositor, and the provided +/// settings. +/// +/// [`Application`]: trait.Application.html +pub fn run<A, E, C>( + settings: Settings<A::Flags>, + compositor_settings: C::Settings, +) where + A: Application + 'static, + E: Executor + 'static, + C: window::GLCompositor<Renderer = A::Renderer> + 'static, +{ + use glutin::{ + event, + event_loop::{ControlFlow, EventLoop}, + ContextBuilder, + }; + + let mut debug = Debug::new(); + debug.startup_started(); + + let event_loop = EventLoop::with_user_event(); + let mut runtime = { + let executor = E::new().expect("Create executor"); + let proxy = Proxy::new(event_loop.create_proxy()); + + Runtime::new(executor, proxy) + }; + + let flags = settings.flags; + let (application, init_command) = runtime.enter(|| A::new(flags)); + runtime.spawn(init_command); + + let subscription = application.subscription(); + runtime.track(subscription); + + let mut title = application.title(); + let mut mode = application.mode(); + + let context = { + let builder = settings.window.into_builder( + &title, + mode, + event_loop.primary_monitor(), + ); + + let context = ContextBuilder::new() + .with_vsync(true) + .with_multisampling(C::sample_count(&compositor_settings) as u16) + .build_windowed(builder, &event_loop) + .expect("Open window"); + + #[allow(unsafe_code)] + unsafe { + context.make_current().expect("Make OpenGL context current") + } + }; + + let clipboard = Clipboard::new(&context.window()); + let mut mouse_interaction = mouse::Interaction::default(); + let mut modifiers = glutin::event::ModifiersState::default(); + + let physical_size = context.window().inner_size(); + let mut viewport = Viewport::with_physical_size( + Size::new(physical_size.width, physical_size.height), + context.window().scale_factor(), + ); + let mut resized = false; + + #[allow(unsafe_code)] + let (mut compositor, mut renderer) = unsafe { + C::new(compositor_settings, |address| { + context.get_proc_address(address) + }) + }; + + let mut state = program::State::new( + application, + viewport.logical_size(), + &mut renderer, + &mut debug, + ); + debug.startup_finished(); + + event_loop.run(move |event, _, control_flow| match event { + event::Event::MainEventsCleared => { + let command = runtime.enter(|| { + state.update( + clipboard.as_ref().map(|c| c as _), + viewport.logical_size(), + &mut renderer, + &mut debug, + ) + }); + + // If the application was updated + if let Some(command) = command { + runtime.spawn(command); + + let program = state.program(); + + // Update subscriptions + let subscription = program.subscription(); + runtime.track(subscription); + + // Update window title + let new_title = program.title(); + + if title != new_title { + context.window().set_title(&new_title); + + title = new_title; + } + + // Update window mode + let new_mode = program.mode(); + + if mode != new_mode { + context.window().set_fullscreen(conversion::fullscreen( + context.window().current_monitor(), + new_mode, + )); + + mode = new_mode; + } + } + + context.window().request_redraw(); + } + event::Event::UserEvent(message) => { + state.queue_message(message); + } + event::Event::RedrawRequested(_) => { + debug.render_started(); + + if resized { + let physical_size = viewport.physical_size(); + + context.resize(glutin::dpi::PhysicalSize::new( + physical_size.width, + physical_size.height, + )); + + compositor.resize_viewport(physical_size); + + resized = false; + } + + let new_mouse_interaction = compositor.draw( + &mut renderer, + &viewport, + state.primitive(), + &debug.overlay(), + ); + + context.swap_buffers().expect("Swap buffers"); + + debug.render_finished(); + + if new_mouse_interaction != mouse_interaction { + context.window().set_cursor_icon( + conversion::mouse_interaction(new_mouse_interaction), + ); + + mouse_interaction = new_mouse_interaction; + } + + // TODO: Handle animations! + // Maybe we can use `ControlFlow::WaitUntil` for this. + } + event::Event::WindowEvent { + event: window_event, + .. + } => { + application::handle_window_event( + &window_event, + context.window(), + control_flow, + &mut modifiers, + &mut viewport, + &mut resized, + &mut debug, + ); + + if let Some(event) = conversion::window_event( + &window_event, + viewport.scale_factor(), + modifiers, + ) { + state.queue_event(event.clone()); + runtime.broadcast(event); + } + } + _ => { + *control_flow = ControlFlow::Wait; + } + }) +} diff --git a/glutin/src/lib.rs b/glutin/src/lib.rs new file mode 100644 index 00000000..b0e0bdd4 --- /dev/null +++ b/glutin/src/lib.rs @@ -0,0 +1,23 @@ +//! A windowing shell for [`iced`], on top of [`glutin`]. +//! +//! [`iced`]: https://github.com/hecrj/iced +//! [`glutin`]: https://github.com/rust-windowing/glutin +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![deny(unused_results)] +#![deny(unsafe_code)] +#![forbid(rust_2018_idioms)] + +pub use glutin; +#[doc(no_inline)] +pub use iced_native::*; + +pub mod application; + +pub use iced_winit::settings; +pub use iced_winit::Mode; + +#[doc(no_inline)] +pub use application::Application; +#[doc(no_inline)] +pub use settings::Settings; |