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; | 
