Add the ability to pass a prebuilt canvas (#1394)

This allows Winit to take control of existing canvas elements in the
DOM, which is useful for web applications with other content in the
page.
This commit is contained in:
Ryan G 2020-01-15 21:20:14 -05:00 committed by GitHub
parent 9daa0738a9
commit 1fe4a7a4ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 69 additions and 23 deletions

View file

@ -9,6 +9,7 @@
- `WindowBuilder` now implements `Default`.
- **Breaking:** `WindowEvent::CursorMoved` changed to `f64` units, preserving high-precision data supplied by most backends
- On Wayland, fix coordinates in mouse events when scale factor isn't 1
- On Web, add the ability to provide a custom canvas
# 0.20.0 (2020-01-05)

View file

@ -3,7 +3,10 @@
//! The web target does not automatically insert the canvas element object into the web page, to
//! allow end users to determine how the page should be laid out. Use the `WindowExtStdweb` or
//! `WindowExtWebSys` traits (depending on your web backend) to retrieve the canvas from the
//! Window.
//! Window. Alternatively, use the `WindowBuilderExtStdweb` or `WindowBuilderExtWebSys` to provide
//! your own canvas.
use crate::window::WindowBuilder;
#[cfg(feature = "stdweb")]
use stdweb::web::html_element::CanvasElement;
@ -20,3 +23,31 @@ use web_sys::HtmlCanvasElement;
pub trait WindowExtWebSys {
fn canvas(&self) -> HtmlCanvasElement;
}
#[cfg(feature = "stdweb")]
pub trait WindowBuilderExtStdweb {
fn with_canvas(self, canvas: Option<CanvasElement>) -> Self;
}
#[cfg(feature = "stdweb")]
impl WindowBuilderExtStdweb for WindowBuilder {
fn with_canvas(mut self, canvas: Option<CanvasElement>) -> Self {
self.platform_specific.canvas = canvas;
self
}
}
#[cfg(feature = "web-sys")]
pub trait WindowBuilderExtWebSys {
fn with_canvas(self, canvas: Option<HtmlCanvasElement>) -> Self;
}
#[cfg(feature = "web-sys")]
impl WindowBuilderExtWebSys for WindowBuilder {
fn with_canvas(mut self, canvas: Option<HtmlCanvasElement>) -> Self {
self.platform_specific.canvas = canvas;
self
}
}

View file

@ -2,7 +2,7 @@ use super::event;
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE;
use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode};
use crate::platform_impl::OsError;
use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes};
use std::cell::RefCell;
use std::rc::Rc;
@ -43,12 +43,15 @@ impl Drop for Canvas {
}
impl Canvas {
pub fn create() -> Result<Self, RootOE> {
let canvas: CanvasElement = document()
.create_element("canvas")
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?
.try_into()
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?;
pub fn create(attr: PlatformSpecificWindowBuilderAttributes) -> Result<Self, RootOE> {
let canvas = match attr.canvas {
Some(canvas) => canvas,
None => document()
.create_element("canvas")
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?
.try_into()
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?,
};
// A tabindex is needed in order to capture local keyboard events.
// A "0" value means that the element should be focusable in

View file

@ -72,3 +72,5 @@ pub fn is_fullscreen(canvas: &CanvasElement) -> bool {
None => false,
}
}
pub type RawCanvasType = CanvasElement;

View file

@ -2,7 +2,7 @@ use super::event;
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE;
use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode};
use crate::platform_impl::OsError;
use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes};
use std::cell::RefCell;
use std::rc::Rc;
@ -35,18 +35,23 @@ impl Drop for Canvas {
}
impl Canvas {
pub fn create() -> Result<Self, RootOE> {
let window =
web_sys::window().ok_or(os_error!(OsError("Failed to obtain window".to_owned())))?;
pub fn create(attr: PlatformSpecificWindowBuilderAttributes) -> Result<Self, RootOE> {
let canvas = match attr.canvas {
Some(canvas) => canvas,
None => {
let window = web_sys::window()
.ok_or(os_error!(OsError("Failed to obtain window".to_owned())))?;
let document = window
.document()
.ok_or(os_error!(OsError("Failed to obtain document".to_owned())))?;
let document = window
.document()
.ok_or(os_error!(OsError("Failed to obtain document".to_owned())))?;
let canvas: HtmlCanvasElement = document
.create_element("canvas")
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?
.unchecked_into();
document
.create_element("canvas")
.map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?
.unchecked_into()
}
};
// A tabindex is needed in order to capture local keyboard events.
// A "0" value means that the element should be focusable in

View file

@ -91,3 +91,5 @@ pub fn is_fullscreen(canvas: &HtmlCanvasElement) -> bool {
None => false,
}
}
pub type RawCanvasType = HtmlCanvasElement;

View file

@ -23,13 +23,13 @@ impl Window {
pub fn new<T>(
target: &EventLoopWindowTarget<T>,
attr: WindowAttributes,
_: PlatformSpecificBuilderAttributes,
platform_attr: PlatformSpecificBuilderAttributes,
) -> Result<Self, RootOE> {
let runner = target.runner.clone();
let id = target.generate_id();
let mut canvas = backend::Canvas::create()?;
let mut canvas = backend::Canvas::create(platform_attr)?;
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
@ -281,5 +281,7 @@ impl Id {
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlatformSpecificBuilderAttributes;
#[derive(Default, Clone)]
pub struct PlatformSpecificBuilderAttributes {
pub(crate) canvas: Option<backend::RawCanvasType>,
}