summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Cargo.toml1
-rw-r--r--examples/README.md1
-rw-r--r--examples/integration/Cargo.toml11
-rw-r--r--examples/integration/src/controls.rs102
-rw-r--r--examples/integration/src/main.rs204
-rw-r--r--examples/integration/src/scene.rs119
-rw-r--r--examples/integration/src/shader/frag.spvbin0 -> 352 bytes
-rw-r--r--examples/integration/src/shader/vert.spvbin0 -> 904 bytes
-rw-r--r--native/src/user_interface.rs8
-rw-r--r--native/src/window.rs4
-rw-r--r--native/src/window/backend.rs55
-rw-r--r--native/src/window/renderer.rs58
-rw-r--r--src/application.rs2
-rw-r--r--wgpu/src/lib.rs10
-rw-r--r--wgpu/src/renderer.rs117
-rw-r--r--wgpu/src/renderer/target.rs91
-rw-r--r--wgpu/src/target.rs14
-rw-r--r--wgpu/src/viewport.rs29
-rw-r--r--wgpu/src/window.rs6
-rw-r--r--wgpu/src/window/backend.rs101
-rw-r--r--wgpu/src/window/swap_chain.rs55
-rw-r--r--winit/src/application.rs187
-rw-r--r--winit/src/conversion.rs92
-rw-r--r--winit/src/debug/null.rs2
-rw-r--r--winit/src/lib.rs1
25 files changed, 893 insertions, 377 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 39c5957a..11cca8b3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -40,6 +40,7 @@ members = [
"examples/custom_widget",
"examples/events",
"examples/geometry",
+ "examples/integration",
"examples/pokedex",
"examples/progress_bar",
"examples/stopwatch",
diff --git a/examples/README.md b/examples/README.md
index 8f2eba3e..a9ab546f 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -74,6 +74,7 @@ A bunch of simpler examples exist:
- [`custom_widget`](custom_widget), a demonstration of how to build a custom widget that draws a circle.
- [`events`](events), a log of native events displayed using a conditional `Subscription`.
- [`geometry`](geometry), a custom widget showcasing how to draw geometry with the `Mesh2D` primitive in [`iced_wgpu`](../wgpu).
+- [`integration`](integration), a demonstration of how to integrate Iced in an existing graphical application.
- [`pokedex`](pokedex), an application that displays a random Pokédex entry (sprite included!) by using the [PokéAPI].
- [`progress_bar`](progress_bar), a simple progress bar that can be filled by using a slider.
- [`stopwatch`](stopwatch), a watch with start/stop and reset buttons showcasing how to listen to time.
diff --git a/examples/integration/Cargo.toml b/examples/integration/Cargo.toml
new file mode 100644
index 00000000..afc2c791
--- /dev/null
+++ b/examples/integration/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "integration"
+version = "0.1.0"
+authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+iced_winit = { path = "../../winit" }
+iced_wgpu = { path = "../../wgpu" }
+env_logger = "0.7"
diff --git a/examples/integration/src/controls.rs b/examples/integration/src/controls.rs
new file mode 100644
index 00000000..0457a058
--- /dev/null
+++ b/examples/integration/src/controls.rs
@@ -0,0 +1,102 @@
+use crate::Scene;
+
+use iced_wgpu::Renderer;
+use iced_winit::{
+ slider, Align, Color, Column, Element, Length, Row, Slider, Text,
+};
+
+pub struct Controls {
+ sliders: [slider::State; 3],
+}
+
+#[derive(Debug)]
+pub enum Message {
+ BackgroundColorChanged(Color),
+}
+
+impl Controls {
+ pub fn new() -> Controls {
+ Controls {
+ sliders: Default::default(),
+ }
+ }
+
+ pub fn update(&self, message: Message, scene: &mut Scene) {
+ match message {
+ Message::BackgroundColorChanged(color) => {
+ scene.background_color = color;
+ }
+ }
+ }
+
+ pub fn view<'a>(
+ &'a mut self,
+ scene: &Scene,
+ ) -> Element<'a, Message, Renderer> {
+ let [r, g, b] = &mut self.sliders;
+ let background_color = scene.background_color;
+
+ let sliders = Row::new()
+ .width(Length::Units(500))
+ .spacing(20)
+ .push(Slider::new(
+ r,
+ 0.0..=1.0,
+ scene.background_color.r,
+ move |r| {
+ Message::BackgroundColorChanged(Color {
+ r,
+ ..background_color
+ })
+ },
+ ))
+ .push(Slider::new(
+ g,
+ 0.0..=1.0,
+ scene.background_color.g,
+ move |g| {
+ Message::BackgroundColorChanged(Color {
+ g,
+ ..background_color
+ })
+ },
+ ))
+ .push(Slider::new(
+ b,
+ 0.0..=1.0,
+ scene.background_color.b,
+ move |b| {
+ Message::BackgroundColorChanged(Color {
+ b,
+ ..background_color
+ })
+ },
+ ));
+
+ Row::new()
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .align_items(Align::End)
+ .push(
+ Column::new()
+ .width(Length::Fill)
+ .align_items(Align::End)
+ .push(
+ Column::new()
+ .padding(10)
+ .spacing(10)
+ .push(
+ Text::new("Background color")
+ .color(Color::WHITE),
+ )
+ .push(sliders)
+ .push(
+ Text::new(format!("{:?}", background_color))
+ .size(14)
+ .color(Color::WHITE),
+ ),
+ ),
+ )
+ .into()
+ }
+}
diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs
new file mode 100644
index 00000000..ed36f736
--- /dev/null
+++ b/examples/integration/src/main.rs
@@ -0,0 +1,204 @@
+mod controls;
+mod scene;
+
+use controls::Controls;
+use scene::Scene;
+
+use iced_wgpu::{
+ wgpu, window::SwapChain, Primitive, Renderer, Settings, Target,
+};
+use iced_winit::{winit, Cache, Clipboard, MouseCursor, Size, UserInterface};
+
+use winit::{
+ event::{DeviceEvent, Event, ModifiersState, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+};
+
+pub fn main() {
+ env_logger::init();
+
+ // Initialize winit
+ let event_loop = EventLoop::new();
+ let window = winit::window::Window::new(&event_loop).unwrap();
+ let mut logical_size =
+ window.inner_size().to_logical(window.scale_factor());
+ let mut modifiers = ModifiersState::default();
+
+ // Initialize WGPU
+ let adapter = wgpu::Adapter::request(&wgpu::RequestAdapterOptions {
+ power_preference: wgpu::PowerPreference::Default,
+ backends: wgpu::BackendBit::PRIMARY,
+ })
+ .expect("Request adapter");
+
+ let (mut device, mut queue) =
+ adapter.request_device(&wgpu::DeviceDescriptor {
+ extensions: wgpu::Extensions {
+ anisotropic_filtering: false,
+ },
+ limits: wgpu::Limits::default(),
+ });
+
+ let surface = wgpu::Surface::create(&window);
+
+ let mut swap_chain = {
+ let size = window.inner_size();
+
+ SwapChain::new(&device, &surface, size.width, size.height)
+ };
+ let mut resized = false;
+
+ // Initialize iced
+ let mut events = Vec::new();
+ let mut cache = Some(Cache::default());
+ let mut renderer = Renderer::new(&mut device, Settings::default());
+ let mut output = (Primitive::None, MouseCursor::OutOfBounds);
+ let clipboard = Clipboard::new(&window);
+
+ // Initialize scene and GUI controls
+ let mut scene = Scene::new(&device);
+ let mut controls = Controls::new();
+
+ // Run event loop
+ event_loop.run(move |event, _, control_flow| {
+ // You should change this if you want to render continuosly
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::DeviceEvent {
+ event: DeviceEvent::ModifiersChanged(new_modifiers),
+ ..
+ } => {
+ modifiers = new_modifiers;
+ }
+ Event::WindowEvent { event, .. } => {
+ match event {
+ WindowEvent::Resized(new_size) => {
+ logical_size =
+ new_size.to_logical(window.scale_factor());
+ resized = true;
+ }
+ WindowEvent::CloseRequested => {
+ *control_flow = ControlFlow::Exit;
+ }
+ _ => {}
+ }
+
+ // Map window event to iced event
+ if let Some(event) = iced_winit::conversion::window_event(
+ event,
+ window.scale_factor(),
+ modifiers,
+ ) {
+ events.push(event);
+ }
+ }
+ Event::MainEventsCleared => {
+ // If no relevant events happened, we can simply skip this
+ if events.is_empty() {
+ return;
+ }
+
+ // We need to:
+ // 1. Process events of our user interface.
+ // 2. Update state as a result of any interaction.
+ // 3. Generate a new output for our renderer.
+
+ // First, we build our user interface.
+ let mut user_interface = UserInterface::build(
+ controls.view(&scene),
+ Size::new(logical_size.width, logical_size.height),
+ cache.take().unwrap(),
+ &mut renderer,
+ );
+
+ // Then, we process the events, obtaining messages in return.
+ let messages = user_interface.update(
+ events.drain(..),
+ clipboard.as_ref().map(|c| c as _),
+ &renderer,
+ );
+
+ let user_interface = if messages.is_empty() {
+ // If there are no messages, no interactions we care about have
+ // happened. We can simply leave our user interface as it is.
+ user_interface
+ } else {
+ // If there are messages, we need to update our state
+ // accordingly and rebuild our user interface.
+ // We can only do this if we drop our user interface first
+ // by turning it into its cache.
+ cache = Some(user_interface.into_cache());
+
+ // In this example, `Controls` is the only part that cares
+ // about messages, so updating our state is pretty
+ // straightforward.
+ for message in messages {
+ controls.update(message, &mut scene);
+ }
+
+ // Once the state has been changed, we rebuild our updated
+ // user interface.
+ UserInterface::build(
+ controls.view(&scene),
+ Size::new(logical_size.width, logical_size.height),
+ cache.take().unwrap(),
+ &mut renderer,
+ )
+ };
+
+ // Finally, we just need to draw a new output for our renderer,
+ output = user_interface.draw(&mut renderer);
+
+ // update our cache,
+ cache = Some(user_interface.into_cache());
+
+ // and request a redraw
+ window.request_redraw();
+ }
+ Event::RedrawRequested(_) => {
+ if resized {
+ let size = window.inner_size();
+
+ swap_chain = SwapChain::new(
+ &device,
+ &surface,
+ size.width,
+ size.height,
+ );
+ }
+
+ let (frame, viewport) = swap_chain.next_frame();
+
+ let mut encoder = device.create_command_encoder(
+ &wgpu::CommandEncoderDescriptor { todo: 0 },
+ );
+
+ // We draw the scene first
+ scene.draw(&mut encoder, &frame.view);
+
+ // And then iced on top
+ let mouse_cursor = renderer.draw(
+ &mut device,
+ &mut encoder,
+ Target {
+ texture: &frame.view,
+ viewport,
+ },
+ &output,
+ window.scale_factor(),
+ &["Some debug information!"],
+ );
+
+ // Then we submit the work
+ queue.submit(&[encoder.finish()]);
+
+ // And update the mouse cursor
+ window.set_cursor_icon(iced_winit::conversion::mouse_cursor(
+ mouse_cursor,
+ ));
+ }
+ _ => {}
+ }
+ })
+}
diff --git a/examples/integration/src/scene.rs b/examples/integration/src/scene.rs
new file mode 100644
index 00000000..efb1921b
--- /dev/null
+++ b/examples/integration/src/scene.rs
@@ -0,0 +1,119 @@
+use iced_wgpu::wgpu;
+use iced_winit::Color;
+
+pub struct Scene {
+ pub background_color: Color,
+ pipeline: wgpu::RenderPipeline,
+ bind_group: wgpu::BindGroup,
+}
+
+impl Scene {
+ pub fn new(device: &wgpu::Device) -> Scene {
+ let (pipeline, bind_group) = build_pipeline(device);
+
+ Scene {
+ background_color: Color::BLACK,
+ pipeline,
+ bind_group,
+ }
+ }
+
+ pub fn draw(
+ &self,
+ encoder: &mut wgpu::CommandEncoder,
+ target: &wgpu::TextureView,
+ ) {
+ let mut rpass =
+ encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+ color_attachments: &[
+ wgpu::RenderPassColorAttachmentDescriptor {
+ attachment: target,
+ resolve_target: None,
+ load_op: wgpu::LoadOp::Clear,
+ store_op: wgpu::StoreOp::Store,
+ clear_color: {
+ let [r, g, b, a] =
+ self.background_color.into_linear();
+
+ wgpu::Color {
+ r: r as f64,
+ g: g as f64,
+ b: b as f64,
+ a: a as f64,
+ }
+ },
+ },
+ ],
+ depth_stencil_attachment: None,
+ });
+
+ rpass.set_pipeline(&self.pipeline);
+ rpass.set_bind_group(0, &self.bind_group, &[]);
+ rpass.draw(0..3, 0..1);
+ }
+}
+
+fn build_pipeline(
+ device: &wgpu::Device,
+) -> (wgpu::RenderPipeline, wgpu::BindGroup) {
+ let vs = include_bytes!("shader/vert.spv");
+ let fs = include_bytes!("shader/frag.spv");
+
+ let vs_module = device.create_shader_module(
+ &wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap(),
+ );
+
+ let fs_module = device.create_shader_module(
+ &wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap(),
+ );
+
+ let bind_group_layout =
+ device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
+ bindings: &[],
+ });
+
+ let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+ layout: &bind_group_layout,
+ bindings: &[],
+ });
+
+ let pipeline_layout =
+ device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
+ bind_group_layouts: &[&bind_group_layout],
+ });
+
+ let pipeline =
+ device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
+ layout: &pipeline_layout,
+ vertex_stage: wgpu::ProgrammableStageDescriptor {
+ module: &vs_module,
+ entry_point: "main",
+ },
+ fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
+ module: &fs_module,
+ entry_point: "main",
+ }),
+ rasterization_state: Some(wgpu::RasterizationStateDescriptor {
+ front_face: wgpu::FrontFace::Ccw,
+ cull_mode: wgpu::CullMode::None,
+ depth_bias: 0,
+ depth_bias_slope_scale: 0.0,
+ depth_bias_clamp: 0.0,
+ }),
+ primitive_topology: wgpu::PrimitiveTopology::TriangleList,
+ color_states: &[wgpu::ColorStateDescriptor {
+ format: wgpu::TextureFormat::Bgra8UnormSrgb,
+ color_blend: wgpu::BlendDescriptor::REPLACE,
+ alpha_blend: wgpu::BlendDescriptor::REPLACE,
+ write_mask: wgpu::ColorWrite::ALL,
+ }],
+ depth_stencil_state: None,
+ index_format: wgpu::IndexFormat::Uint16,
+ vertex_buffers: &[],
+ sample_count: 1,
+ sample_mask: !0,
+ alpha_to_coverage_enabled: false,
+ });
+
+ (pipeline, bind_group)
+}
diff --git a/examples/integration/src/shader/frag.spv b/examples/integration/src/shader/frag.spv
new file mode 100644
index 00000000..9d6807c9
--- /dev/null
+++ b/examples/integration/src/shader/frag.spv
Binary files differ
diff --git a/examples/integration/src/shader/vert.spv b/examples/integration/src/shader/vert.spv
new file mode 100644
index 00000000..0cabc9c0
--- /dev/null
+++ b/examples/integration/src/shader/vert.spv
Binary files differ
diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs
index 53b36240..08914bed 100644
--- a/native/src/user_interface.rs
+++ b/native/src/user_interface.rs
@@ -162,7 +162,7 @@ where
/// );
///
/// // Update the user interface
- /// let messages = user_interface.update(&renderer, None, events.drain(..));
+ /// let messages = user_interface.update(events.drain(..), None, &renderer);
///
/// cache = user_interface.into_cache();
///
@@ -174,9 +174,9 @@ where
/// ```
pub fn update(
&mut self,
- renderer: &Renderer,
- clipboard: Option<&dyn Clipboard>,
events: impl IntoIterator<Item = Event>,
+ clipboard: Option<&dyn Clipboard>,
+ renderer: &Renderer,
) -> Vec<Message> {
let mut messages = Vec::new();
@@ -246,7 +246,7 @@ where
/// &mut renderer,
/// );
///
- /// let messages = user_interface.update(&renderer, None, events.drain(..));
+ /// let messages = user_interface.update(events.drain(..), None, &renderer);
///
/// // Draw the user interface
/// let mouse_cursor = user_interface.draw(&mut renderer);
diff --git a/native/src/window.rs b/native/src/window.rs
index db9226dc..4dcae62f 100644
--- a/native/src/window.rs
+++ b/native/src/window.rs
@@ -1,6 +1,6 @@
//! Build window-based GUI applications.
+mod backend;
mod event;
-mod renderer;
+pub use backend::Backend;
pub use event::Event;
-pub use renderer::{Renderer, Target};
diff --git a/native/src/window/backend.rs b/native/src/window/backend.rs
new file mode 100644
index 00000000..3bc691cd
--- /dev/null
+++ b/native/src/window/backend.rs
@@ -0,0 +1,55 @@
+use crate::MouseCursor;
+
+use raw_window_handle::HasRawWindowHandle;
+
+/// A graphics backend that can render to windows.
+pub trait Backend: Sized {
+ /// The settings of the backend.
+ type Settings: Default;
+
+ /// The iced renderer of the backend.
+ type Renderer: crate::Renderer;
+
+ /// The surface of the backend.
+ type Surface;
+
+ /// The swap chain of the backend.
+ type SwapChain;
+
+ /// Creates a new [`Backend`] and an associated iced renderer.
+ ///
+ /// [`Backend`]: trait.Backend.html
+ fn new(settings: Self::Settings) -> (Self, Self::Renderer);
+
+ /// Crates a new [`Surface`] for the given window.
+ ///
+ /// [`Surface`]: #associatedtype.Surface
+ fn create_surface<W: HasRawWindowHandle>(
+ &mut self,
+ window: &W,
+ ) -> Self::Surface;
+
+ /// Crates a new [`SwapChain`] for the given [`Surface`].
+ ///
+ /// [`SwapChain`]: #associatedtype.SwapChain
+ /// [`Surface`]: #associatedtype.Surface
+ fn create_swap_chain(
+ &mut self,
+ surface: &Self::Surface,
+ width: u32,
+ height: u32,
+ ) -> Self::SwapChain;
+
+ /// Draws the output primitives to the next frame of the given [`SwapChain`].
+ ///
+ /// [`SwapChain`]: #associatedtype.SwapChain
+ /// [`Surface`]: #associatedtype.Surface
+ fn draw<T: AsRef<str>>(
+ &mut self,
+ renderer: &mut Self::Renderer,
+ swap_chain: &mut Self::SwapChain,
+ output: &<Self::Renderer as crate::Renderer>::Output,
+ scale_factor: f64,
+ overlay: &[T],
+ ) -> MouseCursor;
+}
diff --git a/native/src/window/renderer.rs b/native/src/window/renderer.rs
deleted file mode 100644
index a3cbb8ce..00000000
--- a/native/src/window/renderer.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-use crate::MouseCursor;
-
-use raw_window_handle::HasRawWindowHandle;
-
-/// A renderer that can target windows.
-pub trait Renderer: crate::Renderer + Sized {
- /// The settings of the renderer.
- type Settings: Default;
-
- /// The type of target.
- type Target: Target<Renderer = Self>;
-
- /// Creates a new window [`Renderer`].
- ///
- /// [`Renderer`]: trait.Renderer.html
- fn new(settings: Self::Settings) -> Self;
-
- /// Performs the drawing operations described in the output on the given
- /// target.
- ///
- /// The overlay can be a bunch of debug text logs. It should be rendered on
- /// top of the GUI on most scenarios.
- fn draw<T: AsRef<str>>(
- &mut self,
- output: &Self::Output,
- overlay: &[T],
- target: &mut Self::Target,
- ) -> MouseCursor;
-}
-
-/// A rendering target.
-pub trait Target {
- /// The renderer of this target.
- type Renderer;
-
- /// Creates a new rendering [`Target`] from the given window handle, width,
- /// height and dpi factor.
- ///
- /// [`Target`]: trait.Target.html
- fn new<W: HasRawWindowHandle>(
- window: &W,
- width: u32,
- height: u32,
- scale_factor: f64,
- renderer: &Self::Renderer,
- ) -> Self;
-
- /// Resizes the current [`Target`].
- ///
- /// [`Target`]: trait.Target.html
- fn resize(
- &mut self,
- width: u32,
- height: u32,
- scale_factor: f64,
- renderer: &Self::Renderer,
- );
-}
diff --git a/src/application.rs b/src/application.rs
index 926a2986..0a4b6d9e 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -193,7 +193,7 @@ impl<A> iced_winit::Application for Instance<A>
where
A: Application,
{
- type Renderer = iced_wgpu::Renderer;
+ type Backend = iced_wgpu::window::Backend;
type Executor = A::Executor;
type Message = A::Message;
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index b8cd3fce..e4834818 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -27,19 +27,27 @@
pub mod defaults;
pub mod triangle;
pub mod widget;
+pub mod window;
mod image;
mod primitive;
mod quad;
mod renderer;
mod settings;
+mod target;
mod text;
mod transformation;
+mod viewport;
+
+pub use wgpu;
pub use defaults::Defaults;
pub use primitive::Primitive;
-pub use renderer::{Renderer, Target};
+pub use renderer::Renderer;
pub use settings::Settings;
+pub use target::Target;
+pub use viewport::Viewport;
+
#[doc(no_inline)]
pub use widget::*;
diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs
index 93d2bb13..e93090b8 100644
--- a/wgpu/src/renderer.rs
+++ b/wgpu/src/renderer.rs
@@ -1,29 +1,20 @@
use crate::{
image, quad, text, triangle, Defaults, Image, Primitive, Quad, Settings,
- Transformation,
+ Target, Transformation,
};
use iced_native::{
- layout, window, Background, Color, Layout, MouseCursor, Point, Rectangle,
- Vector, Widget,
+ layout, Background, Color, Layout, MouseCursor, Point, Rectangle, Vector,
+ Widget,
};
use std::sync::Arc;
-use wgpu::{
- Adapter, BackendBit, CommandEncoderDescriptor, Device, DeviceDescriptor,
- Extensions, Limits, PowerPreference, Queue, RequestAdapterOptions,
-};
-mod target;
mod widget;
-pub use target::Target;
-
/// A [`wgpu`] renderer.
///
/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
#[derive(Debug)]
pub struct Renderer {
- device: Device,
- queue: Queue,
quad_pipeline: quad::Pipeline,
image_pipeline: image::Pipeline,
text_pipeline: text::Pipeline,
@@ -53,29 +44,16 @@ impl<'a> Layer<'a> {
}
impl Renderer {
- fn new(settings: Settings) -> Self {
- let adapter = Adapter::request(&RequestAdapterOptions {
- power_preference: PowerPreference::Default,
- backends: BackendBit::all(),
- })
- .expect("Request adapter");
-
- let (mut device, queue) = adapter.request_device(&DeviceDescriptor {
- extensions: Extensions {
- anisotropic_filtering: false,
- },
- limits: Limits { max_bind_groups: 2 },
- });
-
- let text_pipeline =
- text::Pipeline::new(&mut device, settings.default_font);
- let quad_pipeline = quad::Pipeline::new(&mut device);
- let image_pipeline = crate::image::Pipeline::new(&mut device);
- let triangle_pipeline = triangle::Pipeline::new(&mut device);
+ /// Creates a new [`Renderer`].
+ ///
+ /// [`Renderer`]: struct.Renderer.html
+ pub fn new(device: &mut wgpu::Device, settings: Settings) -> Self {
+ let text_pipeline = text::Pipeline::new(device, settings.default_font);
+ let quad_pipeline = quad::Pipeline::new(device);
+ let image_pipeline = crate::image::Pipeline::new(device);
+ let triangle_pipeline = triangle::Pipeline::new(device);
Self {
- device,
- queue,
quad_pipeline,
image_pipeline,
text_pipeline,
@@ -83,38 +61,26 @@ impl Renderer {
}
}
- fn draw<T: AsRef<str>>(
+ /// Draws the provided primitives in the given [`Target`].
+ ///
+ /// The text provided as overlay will be renderer on top of the primitives.
+ /// This is useful for rendering debug information.
+ ///
+ /// [`Target`]: struct.Target.html
+ pub fn draw<T: AsRef<str>>(
&mut self,
+ device: &mut wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ target: Target<'_>,
(primitive, mouse_cursor): &(Primitive, MouseCursor),
+ scale_factor: f64,
overlay: &[T],
- target: &mut Target,
) -> MouseCursor {
log::debug!("Drawing");
- let (width, height) = target.dimensions();
- let scale_factor = target.scale_factor();
- let transformation = target.transformation();
- let frame = target.next_frame();
-
- let mut encoder = self
- .device
- .create_command_encoder(&CommandEncoderDescriptor { todo: 0 });
-
- let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
- color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
- attachment: &frame.view,
- resolve_target: None,
- load_op: wgpu::LoadOp::Clear,
- store_op: wgpu::StoreOp::Store,
- clear_color: wgpu::Color {
- r: 1.0,
- g: 1.0,
- b: 1.0,
- a: 1.0,
- },
- }],
- depth_stencil_attachment: None,
- });
+ let (width, height) = target.viewport.dimensions();
+ let scale_factor = scale_factor as f32;
+ let transformation = target.viewport.transformation();
let mut layers = Vec::new();
@@ -133,15 +99,15 @@ impl Renderer {
for layer in layers {
self.flush(
+ device,
scale_factor,
transformation,
&layer,
- &mut encoder,
- &frame.view,
+ encoder,
+ target.texture,
);
}
- self.queue.submit(&[encoder.finish()]);
self.image_pipeline.trim_cache();
*mouse_cursor
@@ -336,6 +302,7 @@ impl Renderer {
fn flush(
&mut self,
+ device: &mut wgpu::Device,
scale_factor: f32,
transformation: Transformation,
layer: &Layer<'_>,
@@ -352,7 +319,7 @@ impl Renderer {
);
self.triangle_pipeline.draw(
- &mut self.device,
+ device,
encoder,
target,
translated,
@@ -364,7 +331,7 @@ impl Renderer {
if layer.quads.len() > 0 {
self.quad_pipeline.draw(
- &mut self.device,
+ device,
encoder,
&layer.quads,
transformation,
@@ -383,7 +350,7 @@ impl Renderer {
);
self.image_pipeline.draw(
- &mut self.device,
+ device,
encoder,
&layer.images,
translated_and_scaled,
@@ -429,7 +396,7 @@ impl Renderer {
}
self.text_pipeline.draw_queued(
- &mut self.device,
+ device,
encoder,
target,
transformation,
@@ -461,24 +428,6 @@ impl iced_native::Renderer for Renderer {
}
}
-impl window::Renderer for Renderer {
- type Settings = Settings;
- type Target = Target;
-
- fn new(settings: Settings) -> Self {
- Self::new(settings)
- }
-
- fn draw<T: AsRef<str>>(
- &mut self,
- output: &Self::Output,
- overlay: &[T],
- target: &mut Target,
- ) -> MouseCursor {
- self.draw(output, overlay, target)
- }
-}
-
impl layout::Debugger for Renderer {
fn explain<Message>(
&mut self,
diff --git a/wgpu/src/renderer/target.rs b/wgpu/src/renderer/target.rs
deleted file mode 100644
index 20974976..00000000
--- a/wgpu/src/renderer/target.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-use crate::{Renderer, Transformation};
-use iced_native::window;
-
-use raw_window_handle::HasRawWindowHandle;
-
-/// A rendering target.
-#[derive(Debug)]
-pub struct Target {
- surface: wgpu::Surface,
- width: u32,
- height: u32,
- scale_factor: f32,
- transformation: Transformation,
- swap_chain: wgpu::SwapChain,
-}
-
-impl Target {
- pub(crate) fn dimensions(&self) -> (u32, u32) {
- (self.width, self.height)
- }
-
- pub(crate) fn scale_factor(&self) -> f32 {
- self.scale_factor
- }
-
- pub(crate) fn transformation(&self) -> Transformation {
- self.transformation
- }
-
- pub(crate) fn next_frame(&mut self) -> wgpu::SwapChainOutput<'_> {
- self.swap_chain.get_next_texture()
- }
-}
-
-impl window::Target for Target {
- type Renderer = Renderer;
-
- fn new<W: HasRawWindowHandle>(
- window: &W,
- width: u32,
- height: u32,
- scale_factor: f64,
- renderer: &Renderer,
- ) -> Target {
- let surface = wgpu::Surface::create(window);
- let swap_chain =
- new_swap_chain(&surface, width, height, &renderer.device);
-
- Target {
- surface,
- width,
- height,
- scale_factor: scale_factor as f32,
- transformation: Transformation::orthographic(width, height),
- swap_chain,
- }
- }
-
- fn resize(
- &mut self,
- width: u32,
- height: u32,
- scale_factor: f64,
- renderer: &Renderer,
- ) {
- self.width = width;
- self.height = height;
- self.scale_factor = scale_factor as f32;
- self.transformation = Transformation::orthographic(width, height);
- self.swap_chain =
- new_swap_chain(&self.surface, width, height, &renderer.device);
- }
-}
-
-fn new_swap_chain(
- surface: &wgpu::Surface,
- width: u32,
- height: u32,
- device: &wgpu::Device,
-) -> wgpu::SwapChain {
- device.create_swap_chain(
- &surface,
- &wgpu::SwapChainDescriptor {
- usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
- format: wgpu::TextureFormat::Bgra8UnormSrgb,
- width,
- height,
- present_mode: wgpu::PresentMode::Vsync,
- },
- )
-}
diff --git a/wgpu/src/target.rs b/wgpu/src/target.rs
new file mode 100644
index 00000000..1e72c0c3
--- /dev/null
+++ b/wgpu/src/target.rs
@@ -0,0 +1,14 @@
+use crate::Viewport;
+
+/// A rendering target.
+#[derive(Debug)]
+pub struct Target<'a> {
+ /// The texture where graphics will be rendered.
+ pub texture: &'a wgpu::TextureView,
+
+ /// The viewport of the target.
+ ///
+ /// Most of the time, you will want this to match the dimensions of the
+ /// texture.
+ pub viewport: &'a Viewport,
+}
diff --git a/wgpu/src/viewport.rs b/wgpu/src/viewport.rs
new file mode 100644
index 00000000..66242468
--- /dev/null
+++ b/wgpu/src/viewport.rs
@@ -0,0 +1,29 @@
+use crate::Transformation;
+
+/// A viewing region for displaying computer graphics.
+#[derive(Debug)]
+pub struct Viewport {
+ width: u32,
+ height: u32,
+ transformation: Transformation,
+}
+
+impl Viewport {
+ /// Creates a new [`Viewport`] with the given dimensions.
+ pub fn new(width: u32, height: u32) -> Viewport {
+ Viewport {
+ width,
+ height,
+ transformation: Transformation::orthographic(width, height),
+ }
+ }
+
+ /// Returns the dimensions of the [`Viewport`].
+ pub fn dimensions(&self) -> (u32, u32) {
+ (self.width, self.height)
+ }
+
+ pub(crate) fn transformation(&self) -> Transformation {
+ self.transformation
+ }
+}
diff --git a/wgpu/src/window.rs b/wgpu/src/window.rs
new file mode 100644
index 00000000..b7adad82
--- /dev/null
+++ b/wgpu/src/window.rs
@@ -0,0 +1,6 @@
+//! Display rendering results on windows.
+mod backend;
+mod swap_chain;
+
+pub use backend::Backend;
+pub use swap_chain::SwapChain;
diff --git a/wgpu/src/window/backend.rs b/wgpu/src/window/backend.rs
new file mode 100644
index 00000000..6f8a0bb0
--- /dev/null
+++ b/wgpu/src/window/backend.rs
@@ -0,0 +1,101 @@
+use crate::{window::SwapChain, Renderer, Settings, Target};
+
+use iced_native::MouseCursor;
+use raw_window_handle::HasRawWindowHandle;
+
+/// A window graphics backend for iced powered by `wgpu`.
+#[derive(Debug)]
+pub struct Backend {
+ device: wgpu::Device,
+ queue: wgpu::Queue,
+}
+
+impl iced_native::window::Backend for Backend {
+ type Settings = Settings;
+ type Renderer = Renderer;
+ type Surface = wgpu::Surface;
+ type SwapChain = SwapChain;
+
+ fn new(settings: Self::Settings) -> (Backend, Renderer) {
+ let adapter = wgpu::Adapter::request(&wgpu::RequestAdapterOptions {
+ power_preference: wgpu::PowerPreference::Default,
+ backends: wgpu::BackendBit::all(),
+ })
+ .expect("Request adapter");
+
+ let (mut device, queue) =
+ adapter.request_device(&wgpu::DeviceDescriptor {
+ extensions: wgpu::Extensions {
+ anisotropic_filtering: false,
+ },
+ limits: wgpu::Limits { max_bind_groups: 2 },
+ });
+
+ let renderer = Renderer::new(&mut device, settings);
+
+ (Backend { device, queue }, renderer)
+ }
+
+ fn create_surface<W: HasRawWindowHandle>(
+ &mut self,
+ window: &W,
+ ) -> wgpu::Surface {
+ wgpu::Surface::create(window)
+ }
+
+ fn create_swap_chain(
+ &mut self,
+ surface: &Self::Surface,
+ width: u32,
+ height: u32,
+ ) -> SwapChain {
+ SwapChain::new(&self.device, surface, width, height)
+ }
+
+ fn draw<T: AsRef<str>>(
+ &mut self,
+ renderer: &mut Self::Renderer,
+ swap_chain: &mut SwapChain,
+ output: &<Self::Renderer as iced_native::Renderer>::Output,
+ scale_factor: f64,
+ overlay: &[T],
+ ) -> MouseCursor {
+ let (frame, viewport) = swap_chain.next_frame();
+
+ let mut encoder = self.device.create_command_encoder(
+ &wgpu::CommandEncoderDescriptor { todo: 0 },
+ );
+
+ let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+ color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
+ attachment: &frame.view,
+ resolve_target: None,
+ load_op: wgpu::LoadOp::Clear,
+ store_op: wgpu::StoreOp::Store,
+ clear_color: wgpu::Color {
+ r: 1.0,
+ g: 1.0,
+ b: 1.0,
+ a: 1.0,
+ },
+ }],
+ depth_stencil_attachment: None,
+ });
+
+ let mouse_cursor = renderer.draw(
+ &mut self.device,
+ &mut encoder,
+ Target {
+ texture: &frame.view,
+ viewport,
+ },
+ output,
+ scale_factor,
+ overlay,
+ );
+
+ self.queue.submit(&[encoder.finish()]);
+
+ mouse_cursor
+ }
+}
diff --git a/wgpu/src/window/swap_chain.rs b/wgpu/src/window/swap_chain.rs
new file mode 100644
index 00000000..6f545fce
--- /dev/null
+++ b/wgpu/src/window/swap_chain.rs
@@ -0,0 +1,55 @@
+use crate::Viewport;
+
+/// The rendering target of a window.
+///
+/// It represents a series of virtual framebuffers with a scale factor.
+#[derive(Debug)]
+pub struct SwapChain {
+ raw: wgpu::SwapChain,
+ viewport: Viewport,
+}
+
+impl SwapChain {}
+
+impl SwapChain {
+ /// Creates a new [`SwapChain`] for the given surface.
+ ///
+ /// [`SwapChain`]: struct.SwapChain.html
+ pub fn new(
+ device: &wgpu::Device,
+ surface: &wgpu::Surface,
+ width: u32,
+ height: u32,
+ ) -> SwapChain {
+ SwapChain {
+ raw: new_swap_chain(surface, width, height, device),
+ viewport: Viewport::new(width, height),
+ }
+ }
+
+ /// Returns the next frame of the [`SwapChain`] alongside its [`Viewport`].
+ ///
+ /// [`SwapChain`]: struct.SwapChain.html
+ /// [`Viewport`]: ../struct.Viewport.html
+ pub fn next_frame(&mut self) -> (wgpu::SwapChainOutput<'_>, &Viewport) {
+ (self.raw.get_next_texture(), &self.viewport)
+ }
+}
+
+fn new_swap_chain(
+ surface: &wgpu::Surface,
+ width: u32,
+ height: u32,
+ device: &wgpu::Device,
+) -> wgpu::SwapChain {
+ device.create_swap_chain(
+ &surface,
+ &wgpu::SwapChainDescriptor {
+ usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
+ format: wgpu::TextureFormat::Bgra8UnormSrgb,
+ width,
+ height,
+ present_mode: wgpu::PresentMode::Vsync,
+ },
+ )
+}
diff --git a/winit/src/application.rs b/winit/src/application.rs
index 3c0332ed..35a36434 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -1,8 +1,7 @@
use crate::{
- conversion,
- input::{keyboard, mouse},
- window, Cache, Clipboard, Command, Debug, Element, Event, Executor, Mode,
- MouseCursor, Proxy, Runtime, Settings, Size, Subscription, UserInterface,
+ conversion, size::Size, window, Cache, Clipboard, Command, Debug, Element,
+ Executor, Mode, MouseCursor, Proxy, Runtime, Settings, Subscription,
+ UserInterface,
};
/// An interactive, native cross-platform application.
@@ -14,10 +13,10 @@ use crate::{
/// An [`Application`](trait.Application.html) can execute asynchronous actions
/// by returning a [`Command`](struct.Command.html) in some of its methods.
pub trait Application: Sized {
- /// The renderer to use to draw the [`Application`].
+ /// The graphics backend to use to draw the [`Application`].
///
/// [`Application`]: trait.Application.html
- type Renderer: window::Renderer;
+ type Backend: window::Backend;
/// The [`Executor`] that will run commands and subscriptions.
///
@@ -75,7 +74,9 @@ pub trait Application: Sized {
/// These widgets can produce __messages__ based on user interaction.
///
/// [`Application`]: trait.Application.html
- fn view(&mut self) -> Element<'_, Self::Message, Self::Renderer>;
+ fn view(
+ &mut self,
+ ) -> Element<'_, Self::Message, <Self::Backend as window::Backend>::Renderer>;
/// Returns the current [`Application`] mode.
///
@@ -99,11 +100,11 @@ pub trait Application: Sized {
/// [`Application`]: trait.Application.html
fn run(
settings: Settings,
- renderer_settings: <Self::Renderer as window::Renderer>::Settings,
+ backend_settings: <Self::Backend as window::Backend>::Settings,
) where
Self: 'static,
{
- use window::{Renderer as _, Target as _};
+ use window::Backend as _;
use winit::{
event::{self, WindowEvent},
event_loop::{ControlFlow, EventLoop},
@@ -162,17 +163,17 @@ pub trait Application: Sized {
let mut resized = false;
let clipboard = Clipboard::new(&window);
- let mut renderer = Self::Renderer::new(renderer_settings);
+ let (mut backend, mut renderer) = Self::Backend::new(backend_settings);
- let mut target = {
+ let surface = backend.create_surface(&window);
+
+ let mut swap_chain = {
let physical_size = size.physical();
- <Self::Renderer as window::Renderer>::Target::new(
- &window,
+ backend.create_swap_chain(
+ &surface,
physical_size.width,
physical_size.height,
- size.scale_factor(),
- &renderer,
)
};
@@ -198,8 +199,7 @@ pub trait Application: Sized {
event_loop.run(move |event, _, control_flow| match event {
event::Event::MainEventsCleared => {
- if events.is_empty() && external_messages.is_empty() && !resized
- {
+ if events.is_empty() && external_messages.is_empty() {
return;
}
@@ -223,11 +223,11 @@ pub trait Application: Sized {
.for_each(|event| runtime.broadcast(event));
let mut messages = user_interface.update(
- &renderer,
+ events.drain(..),
clipboard
.as_ref()
.map(|c| c as &dyn iced_native::Clipboard),
- events.drain(..),
+ &renderer,
);
messages.extend(external_messages.drain(..));
debug.event_processing_finished();
@@ -306,18 +306,22 @@ pub trait Application: Sized {
if resized {
let physical_size = size.physical();
- target.resize(
+ swap_chain = backend.create_swap_chain(
+ &surface,
physical_size.width,
physical_size.height,
- size.scale_factor(),
- &renderer,
);
resized = false;
}
- let new_mouse_cursor =
- renderer.draw(&primitive, &debug.overlay(), &mut target);
+ let new_mouse_cursor = backend.draw(
+ &mut renderer,
+ &mut swap_chain,
+ &primitive,
+ size.scale_factor(),
+ &debug.overlay(),
+ );
debug.render_finished();
@@ -335,106 +339,37 @@ pub trait Application: Sized {
event::Event::WindowEvent {
event: window_event,
..
- } => match window_event {
- WindowEvent::Resized(new_size) => {
- size = Size::new(new_size, size.scale_factor());
-
- events.push(Event::Window(window::Event::Resized {
- width: size.logical().width.round() as u32,
- height: size.logical().height.round() as u32,
- }));
-
- resized = true;
- }
- WindowEvent::CloseRequested => {
- *control_flow = ControlFlow::Exit;
- }
- WindowEvent::CursorMoved { position, .. } => {
- let position =
- position.to_logical::<f64>(size.scale_factor());
-
- events.push(Event::Mouse(mouse::Event::CursorMoved {
- x: position.x as f32,
- y: position.y as f32,
- }));
- }
- WindowEvent::MouseInput { button, state, .. } => {
- events.push(Event::Mouse(mouse::Event::Input {
- button: conversion::mouse_button(button),
- state: conversion::button_state(state),
- }));
- }
- WindowEvent::MouseWheel { delta, .. } => match delta {
- winit::event::MouseScrollDelta::LineDelta(
- delta_x,
- delta_y,
- ) => {
- events.push(Event::Mouse(
- mouse::Event::WheelScrolled {
- delta: mouse::ScrollDelta::Lines {
- x: delta_x,
- y: delta_y,
- },
- },
- ));
+ } => {
+ match window_event {
+ WindowEvent::Resized(new_size) => {
+ size = Size::new(new_size, window.scale_factor());
+ resized = true;
}
- winit::event::MouseScrollDelta::PixelDelta(position) => {
- events.push(Event::Mouse(
- mouse::Event::WheelScrolled {
- delta: mouse::ScrollDelta::Pixels {
- x: position.x as f32,
- y: position.y as f32,
- },
- },
- ));
+ WindowEvent::CloseRequested => {
+ *control_flow = ControlFlow::Exit;
}
- },
- WindowEvent::ReceivedCharacter(c)
- if !is_private_use_character(c) =>
- {
- events.push(Event::Keyboard(
- keyboard::Event::CharacterReceived(c),
- ));
+ #[cfg(feature = "debug")]
+ WindowEvent::KeyboardInput {
+ input:
+ winit::event::KeyboardInput {
+ virtual_keycode:
+ Some(winit::event::VirtualKeyCode::F12),
+ state: winit::event::ElementState::Pressed,
+ ..
+ },
+ ..
+ } => debug.toggle(),
+ _ => {}
}
- WindowEvent::KeyboardInput {
- input:
- winit::event::KeyboardInput {
- virtual_keycode: Some(virtual_keycode),
- state,
- ..
- },
- ..
- } => {
- match (virtual_keycode, state) {
- (
- winit::event::VirtualKeyCode::F12,
- winit::event::ElementState::Pressed,
- ) => debug.toggle(),
- _ => {}
- }
- events.push(Event::Keyboard(keyboard::Event::Input {
- key_code: conversion::key_code(virtual_keycode),
- state: conversion::button_state(state),
- modifiers: conversion::modifiers_state(modifiers),
- }));
- }
- WindowEvent::HoveredFile(path) => {
- events
- .push(Event::Window(window::Event::FileHovered(path)));
+ if let Some(event) = conversion::window_event(
+ window_event,
+ size.scale_factor(),
+ modifiers,
+ ) {
+ events.push(event);
}
- WindowEvent::DroppedFile(path) => {
- events
- .push(Event::Window(window::Event::FileDropped(path)));
- }
- WindowEvent::HoveredFileCancelled => {
- events.push(Event::Window(window::Event::FilesHoveredLeft));
- }
- WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
- size = Size::new(size.physical(), scale_factor);
- }
- _ => {}
- },
+ }
event::Event::DeviceEvent {
event: event::DeviceEvent::ModifiersChanged(new_modifiers),
..
@@ -451,10 +386,10 @@ pub trait Application: Sized {
fn build_user_interface<'a, A: Application>(
application: &'a mut A,
cache: Cache,
- renderer: &mut A::Renderer,
+ renderer: &mut <A::Backend as window::Backend>::Renderer,
size: winit::dpi::LogicalSize<f64>,
debug: &mut Debug,
-) -> UserInterface<'a, A::Message, A::Renderer> {
+) -> UserInterface<'a, A::Message, <A::Backend as window::Backend>::Renderer> {
debug.view_started();
let view = application.view();
debug.view_finished();
@@ -473,13 +408,3 @@ fn build_user_interface<'a, A: Application>(
user_interface
}
-
-// As defined in: http://www.unicode.org/faq/private_use.html
-fn is_private_use_character(c: char) -> bool {
- match c {
- '\u{E000}'..='\u{F8FF}'
- | '\u{F0000}'..='\u{FFFFD}'
- | '\u{100000}'..='\u{10FFFD}' => true,
- _ => false,
- }
-}
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index af0c4c9f..b6a0b64b 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -4,12 +4,90 @@
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
use crate::{
input::{
- keyboard::{KeyCode, ModifiersState},
+ keyboard::{self, KeyCode, ModifiersState},
mouse, ButtonState,
},
- Mode, MouseCursor,
+ window, Event, Mode, MouseCursor,
};
+/// Converts a winit window event into an iced event.
+pub fn window_event(
+ event: winit::event::WindowEvent<'_>,
+ scale_factor: f64,
+ modifiers: winit::event::ModifiersState,
+) -> Option<Event> {
+ use winit::event::WindowEvent;
+
+ match event {
+ WindowEvent::Resized(new_size) => {
+ let logical_size = new_size.to_logical(scale_factor);
+
+ Some(Event::Window(window::Event::Resized {
+ width: logical_size.width,
+ height: logical_size.height,
+ }))
+ }
+ WindowEvent::CursorMoved { position, .. } => {
+ let position = position.to_logical::<f64>(scale_factor);
+
+ Some(Event::Mouse(mouse::Event::CursorMoved {
+ x: position.x as f32,
+ y: position.y as f32,
+ }))
+ }
+ WindowEvent::MouseInput { button, state, .. } => {
+ Some(Event::Mouse(mouse::Event::Input {
+ button: mouse_button(button),
+ state: button_state(state),
+ }))
+ }
+ WindowEvent::MouseWheel { delta, .. } => match delta {
+ winit::event::MouseScrollDelta::LineDelta(delta_x, delta_y) => {
+ Some(Event::Mouse(mouse::Event::WheelScrolled {
+ delta: mouse::ScrollDelta::Lines {
+ x: delta_x,
+ y: delta_y,
+ },
+ }))
+ }
+ winit::event::MouseScrollDelta::PixelDelta(position) => {
+ Some(Event::Mouse(mouse::Event::WheelScrolled {
+ delta: mouse::ScrollDelta::Pixels {
+ x: position.x as f32,
+ y: position.y as f32,
+ },
+ }))
+ }
+ },
+ WindowEvent::ReceivedCharacter(c) if !is_private_use_character(c) => {
+ Some(Event::Keyboard(keyboard::Event::CharacterReceived(c)))
+ }
+ WindowEvent::KeyboardInput {
+ input:
+ winit::event::KeyboardInput {
+ virtual_keycode: Some(virtual_keycode),
+ state,
+ ..
+ },
+ ..
+ } => Some(Event::Keyboard(keyboard::Event::Input {
+ key_code: key_code(virtual_keycode),
+ state: button_state(state),
+ modifiers: modifiers_state(modifiers),
+ })),
+ WindowEvent::HoveredFile(path) => {
+ Some(Event::Window(window::Event::FileHovered(path)))
+ }
+ WindowEvent::DroppedFile(path) => {
+ Some(Event::Window(window::Event::FileDropped(path)))
+ }
+ WindowEvent::HoveredFileCancelled => {
+ Some(Event::Window(window::Event::FilesHoveredLeft))
+ }
+ _ => None,
+ }
+}
+
/// Converts a [`Mode`] to a [`winit`] fullscreen mode.
///
/// [`Mode`]:
@@ -254,3 +332,13 @@ pub fn key_code(virtual_keycode: winit::event::VirtualKeyCode) -> KeyCode {
winit::event::VirtualKeyCode::Cut => KeyCode::Cut,
}
}
+
+// As defined in: http://www.unicode.org/faq/private_use.html
+pub(crate) fn is_private_use_character(c: char) -> bool {
+ match c {
+ '\u{E000}'..='\u{F8FF}'
+ | '\u{F0000}'..='\u{FFFFD}'
+ | '\u{100000}'..='\u{10FFFD}' => true,
+ _ => false,
+ }
+}
diff --git a/winit/src/debug/null.rs b/winit/src/debug/null.rs
index 9c809dd4..2a9430cd 100644
--- a/winit/src/debug/null.rs
+++ b/winit/src/debug/null.rs
@@ -6,8 +6,6 @@ impl Debug {
Self
}
- pub fn toggle(&mut self) {}
-
pub fn startup_started(&mut self) {}
pub fn startup_finished(&mut self) {}
diff --git a/winit/src/lib.rs b/winit/src/lib.rs
index 225907a4..f99e1290 100644
--- a/winit/src/lib.rs
+++ b/winit/src/lib.rs
@@ -50,4 +50,3 @@ pub use settings::Settings;
use debug::Debug;
use proxy::Proxy;
-use size::Size;