2019-06-25 03:15:34 +02:00
|
|
|
use crate::dpi::{LogicalPosition, LogicalSize};
|
|
|
|
|
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
|
|
|
|
|
use crate::icon::Icon;
|
|
|
|
|
use crate::monitor::MonitorHandle as RootMH;
|
2019-09-24 19:39:13 -04:00
|
|
|
use crate::window::{CursorIcon, Fullscreen, WindowAttributes, WindowId as RootWI};
|
|
|
|
|
|
2019-09-24 19:41:59 -04:00
|
|
|
use raw_window_handle::web::WebHandle;
|
2019-06-25 03:15:34 +02:00
|
|
|
|
|
|
|
|
use super::{backend, monitor, EventLoopWindowTarget};
|
|
|
|
|
|
|
|
|
|
use std::cell::RefCell;
|
|
|
|
|
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
|
|
|
|
use std::collections::VecDeque;
|
|
|
|
|
|
|
|
|
|
pub struct Window {
|
|
|
|
|
canvas: backend::Canvas,
|
|
|
|
|
previous_pointer: RefCell<&'static str>,
|
2020-01-04 01:33:07 -05:00
|
|
|
position: RefCell<LogicalPosition<f64>>,
|
2019-09-19 18:40:18 -04:00
|
|
|
id: Id,
|
2019-09-23 09:14:26 -04:00
|
|
|
register_redraw_request: Box<dyn Fn()>,
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Window {
|
|
|
|
|
pub fn new<T>(
|
|
|
|
|
target: &EventLoopWindowTarget<T>,
|
|
|
|
|
attr: WindowAttributes,
|
|
|
|
|
_: PlatformSpecificBuilderAttributes,
|
|
|
|
|
) -> Result<Self, RootOE> {
|
2019-06-25 18:39:41 +02:00
|
|
|
let runner = target.runner.clone();
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2019-09-19 18:40:18 -04:00
|
|
|
let id = target.generate_id();
|
|
|
|
|
|
2019-09-23 09:14:26 -04:00
|
|
|
let mut canvas = backend::Canvas::create()?;
|
|
|
|
|
|
|
|
|
|
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2019-09-19 18:40:18 -04:00
|
|
|
target.register(&mut canvas, id);
|
2019-06-25 03:15:34 +02:00
|
|
|
|
|
|
|
|
let window = Window {
|
|
|
|
|
canvas,
|
|
|
|
|
previous_pointer: RefCell::new("auto"),
|
|
|
|
|
position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }),
|
2019-09-19 18:40:18 -04:00
|
|
|
id,
|
2019-09-23 09:14:26 -04:00
|
|
|
register_redraw_request,
|
2019-06-25 03:15:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.set_inner_size(attr.inner_size.unwrap_or(LogicalSize {
|
|
|
|
|
width: 1024.0,
|
|
|
|
|
height: 768.0,
|
|
|
|
|
}));
|
|
|
|
|
window.set_title(&attr.title);
|
|
|
|
|
window.set_maximized(attr.maximized);
|
|
|
|
|
window.set_visible(attr.visible);
|
|
|
|
|
window.set_window_icon(attr.window_icon);
|
|
|
|
|
|
|
|
|
|
Ok(window)
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 18:07:47 +02:00
|
|
|
pub fn canvas(&self) -> &backend::Canvas {
|
|
|
|
|
&self.canvas
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
pub fn set_title(&self, title: &str) {
|
2019-06-25 21:01:13 +02:00
|
|
|
self.canvas.set_attribute("alt", title);
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_visible(&self, _visible: bool) {
|
|
|
|
|
// Intentionally a no-op
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn request_redraw(&self) {
|
2019-09-23 09:14:26 -04:00
|
|
|
(self.register_redraw_request)();
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn outer_position(&self) -> Result<LogicalPosition<f64>, NotSupportedError> {
|
2019-06-25 03:15:34 +02:00
|
|
|
let (x, y) = self.canvas.position();
|
|
|
|
|
|
|
|
|
|
Ok(LogicalPosition { x, y })
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn inner_position(&self) -> Result<LogicalPosition<f64>, NotSupportedError> {
|
2019-06-25 03:15:34 +02:00
|
|
|
Ok(*self.position.borrow())
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn set_outer_position(&self, position: LogicalPosition<f64>) {
|
2019-06-25 03:15:34 +02:00
|
|
|
*self.position.borrow_mut() = position;
|
|
|
|
|
|
|
|
|
|
self.canvas.set_attribute("position", "fixed");
|
|
|
|
|
self.canvas.set_attribute("left", &position.x.to_string());
|
|
|
|
|
self.canvas.set_attribute("top", &position.y.to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn inner_size(&self) -> LogicalSize<f64> {
|
2019-06-25 03:15:34 +02:00
|
|
|
LogicalSize {
|
|
|
|
|
width: self.canvas.width() as f64,
|
|
|
|
|
height: self.canvas.height() as f64,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn outer_size(&self) -> LogicalSize<f64> {
|
2019-06-25 03:15:34 +02:00
|
|
|
LogicalSize {
|
|
|
|
|
width: self.canvas.width() as f64,
|
|
|
|
|
height: self.canvas.height() as f64,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn set_inner_size(&self, size: LogicalSize<f64>) {
|
2019-06-25 03:15:34 +02:00
|
|
|
self.canvas.set_size(size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn set_min_inner_size(&self, _dimensions: Option<LogicalSize<f64>>) {
|
2019-06-25 03:15:34 +02:00
|
|
|
// Intentionally a no-op: users can't resize canvas elements
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn set_max_inner_size(&self, _dimensions: Option<LogicalSize<f64>>) {
|
2019-06-25 03:15:34 +02:00
|
|
|
// Intentionally a no-op: users can't resize canvas elements
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_resizable(&self, _resizable: bool) {
|
|
|
|
|
// Intentionally a no-op: users can't resize canvas elements
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn hidpi_factor(&self) -> f64 {
|
|
|
|
|
1.0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
|
|
|
|
let text = match cursor {
|
|
|
|
|
CursorIcon::Default => "auto",
|
|
|
|
|
CursorIcon::Crosshair => "crosshair",
|
|
|
|
|
CursorIcon::Hand => "pointer",
|
|
|
|
|
CursorIcon::Arrow => "default",
|
|
|
|
|
CursorIcon::Move => "move",
|
|
|
|
|
CursorIcon::Text => "text",
|
|
|
|
|
CursorIcon::Wait => "wait",
|
|
|
|
|
CursorIcon::Help => "help",
|
|
|
|
|
CursorIcon::Progress => "progress",
|
|
|
|
|
|
|
|
|
|
CursorIcon::NotAllowed => "not-allowed",
|
|
|
|
|
CursorIcon::ContextMenu => "context-menu",
|
|
|
|
|
CursorIcon::Cell => "cell",
|
|
|
|
|
CursorIcon::VerticalText => "vertical-text",
|
|
|
|
|
CursorIcon::Alias => "alias",
|
|
|
|
|
CursorIcon::Copy => "copy",
|
|
|
|
|
CursorIcon::NoDrop => "no-drop",
|
|
|
|
|
CursorIcon::Grab => "grab",
|
|
|
|
|
CursorIcon::Grabbing => "grabbing",
|
|
|
|
|
CursorIcon::AllScroll => "all-scroll",
|
|
|
|
|
CursorIcon::ZoomIn => "zoom-in",
|
|
|
|
|
CursorIcon::ZoomOut => "zoom-out",
|
|
|
|
|
|
|
|
|
|
CursorIcon::EResize => "e-resize",
|
|
|
|
|
CursorIcon::NResize => "n-resize",
|
|
|
|
|
CursorIcon::NeResize => "ne-resize",
|
|
|
|
|
CursorIcon::NwResize => "nw-resize",
|
|
|
|
|
CursorIcon::SResize => "s-resize",
|
|
|
|
|
CursorIcon::SeResize => "se-resize",
|
|
|
|
|
CursorIcon::SwResize => "sw-resize",
|
|
|
|
|
CursorIcon::WResize => "w-resize",
|
|
|
|
|
CursorIcon::EwResize => "ew-resize",
|
|
|
|
|
CursorIcon::NsResize => "ns-resize",
|
|
|
|
|
CursorIcon::NeswResize => "nesw-resize",
|
|
|
|
|
CursorIcon::NwseResize => "nwse-resize",
|
|
|
|
|
CursorIcon::ColResize => "col-resize",
|
|
|
|
|
CursorIcon::RowResize => "row-resize",
|
|
|
|
|
};
|
|
|
|
|
*self.previous_pointer.borrow_mut() = text;
|
2019-06-29 17:48:01 +02:00
|
|
|
self.canvas
|
|
|
|
|
.set_attribute("style", &format!("cursor: {}", text));
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn set_cursor_position(
|
|
|
|
|
&self,
|
|
|
|
|
_position: LogicalPosition<f64>,
|
|
|
|
|
) -> Result<(), ExternalError> {
|
2019-09-24 19:33:32 -04:00
|
|
|
// Intentionally a no-op, as the web does not support setting cursor positions
|
2019-06-25 03:15:34 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> {
|
2019-09-24 19:33:32 -04:00
|
|
|
// Intentionally a no-op, as the web does not (properly) support grabbing the cursor
|
2019-06-25 03:15:34 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_cursor_visible(&self, visible: bool) {
|
|
|
|
|
if !visible {
|
|
|
|
|
self.canvas.set_attribute("cursor", "none");
|
|
|
|
|
} else {
|
|
|
|
|
self.canvas
|
|
|
|
|
.set_attribute("cursor", *self.previous_pointer.borrow());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-22 01:04:11 -05:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_minimized(&self, _minimized: bool) {
|
|
|
|
|
// Intentionally a no-op, as canvases cannot be 'minimized'
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_maximized(&self, _maximized: bool) {
|
2019-09-24 19:33:32 -04:00
|
|
|
// Intentionally a no-op, as canvases cannot be 'maximized'
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-09-24 19:39:13 -04:00
|
|
|
pub fn fullscreen(&self) -> Option<Fullscreen> {
|
2019-10-11 11:45:07 -04:00
|
|
|
if self.canvas.is_fullscreen() {
|
|
|
|
|
Some(Fullscreen::Borderless(self.current_monitor()))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-10-11 11:45:07 -04:00
|
|
|
pub fn set_fullscreen(&self, monitor: Option<Fullscreen>) {
|
|
|
|
|
if monitor.is_some() {
|
|
|
|
|
self.canvas.request_fullscreen();
|
|
|
|
|
} else if self.canvas.is_fullscreen() {
|
|
|
|
|
backend::exit_fullscreen();
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_decorations(&self, _decorations: bool) {
|
|
|
|
|
// Intentionally a no-op, no canvas decorations
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_always_on_top(&self, _always_on_top: bool) {
|
|
|
|
|
// Intentionally a no-op, no window ordering
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_window_icon(&self, _window_icon: Option<Icon>) {
|
|
|
|
|
// Currently an intentional no-op
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn set_ime_position(&self, _position: LogicalPosition<f64>) {
|
2019-09-24 19:33:32 -04:00
|
|
|
// Currently a no-op as it does not seem there is good support for this on web
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn current_monitor(&self) -> RootMH {
|
|
|
|
|
RootMH {
|
|
|
|
|
inner: monitor::Handle,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn available_monitors(&self) -> VecDequeIter<monitor::Handle> {
|
|
|
|
|
VecDeque::new().into_iter()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn primary_monitor(&self) -> monitor::Handle {
|
|
|
|
|
monitor::Handle
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn id(&self) -> Id {
|
2019-09-19 18:40:18 -04:00
|
|
|
return self.id;
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
2019-09-24 19:39:13 -04:00
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
|
|
|
|
|
let handle = WebHandle {
|
|
|
|
|
id: self.id.0,
|
|
|
|
|
..WebHandle::empty()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
raw_window_handle::RawWindowHandle::Web(handle)
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
2019-09-19 18:40:18 -04:00
|
|
|
pub struct Id(pub(crate) u32);
|
2019-06-25 03:15:34 +02:00
|
|
|
|
|
|
|
|
impl Id {
|
|
|
|
|
pub unsafe fn dummy() -> Id {
|
2019-09-19 18:40:18 -04:00
|
|
|
Id(0)
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
pub struct PlatformSpecificBuilderAttributes;
|