Get rid of abi::datastructures::WindowProperties

Instead, pass a reference to the root item when mapping the window,
at which point we can downcast to the new Window item. If we have one,
then we'll read its width/height (for initial values) and install
bindings to keep them up-to-date.
This commit is contained in:
Simon Hausmann 2020-08-11 16:05:16 +02:00
parent 3d5d112deb
commit aafb96cb93
14 changed files with 150 additions and 116 deletions

View file

@ -73,22 +73,6 @@ pub struct ItemVTable {
/// the associated vtable
pub type ItemRef<'a> = vtable::VRef<'a, ItemVTable>;
/// Alias for Option<Pin<&'a Property<T>>> to faciliate cbindgen.
pub type PinnedOptionalProp<'a, T> = Option<core::pin::Pin<&'a crate::Property<T>>>;
#[repr(C)]
#[derive(Default)]
/// WindowProperties is used to pass the references to properties of the instantiated
/// component that the run-time will keep up-to-date.
pub struct WindowProperties<'a> {
/// A reference to the property that is supposed to be kept up-to-date with the width
/// of the window.
pub width: PinnedOptionalProp<'a, f32>,
/// A reference to the property that is supposed to be kept up-to-date with the height
/// of the window.
pub height: PinnedOptionalProp<'a, f32>,
}
// This is here because for some reason (rust bug?) the ItemVTable_static is not accessible in the other modules
ItemVTable_static! {
@ -127,3 +111,9 @@ ItemVTable_static! {
#[no_mangle]
pub static FlickableVTable for crate::items::Flickable
}
ItemVTable_static! {
/// The VTable for `Window`
#[no_mangle]
pub static WindowVTable for crate::items::Window
}

View file

@ -19,6 +19,7 @@ fn main() {
"EasingCurve",
"TextHorizontalAlignment",
"TextVerticalAlignment",
"Window",
]
.iter()
.map(|x| x.to_string())
@ -33,7 +34,6 @@ fn main() {
"PathElement",
"sixtyfps_new_path_elements",
"sixtyfps_new_path_events",
"PinnedOptionalProp",
]
.iter()
.map(|x| x.to_string())
@ -186,7 +186,7 @@ fn main() {
.with_include("sixtyfps_color.h")
.with_include("sixtyfps_pathdata.h")
.with_after_include(format!(
"namespace sixtyfps {{ enum class VersionCheck {{ Major = {}, Minor = {}, Patch = {} }}; }}\nnamespace sixtyfps {{ namespace internal {{ template <typename T> using PinnedOptionalProp = Property<T> *; }} }}",
"namespace sixtyfps {{ enum class VersionCheck {{ Major = {}, Minor = {}, Patch = {} }}; }}",
env!("CARGO_PKG_VERSION_MAJOR"),
env!("CARGO_PKG_VERSION_MINOR"),
env!("CARGO_PKG_VERSION_PATCH")

View file

@ -1,4 +1,4 @@
use crate::abi::datastructures::{ComponentVTable, WindowProperties};
use crate::abi::datastructures::{ComponentVTable, ItemRef};
use std::cell::RefCell;
use std::{
pin::Pin,
@ -19,11 +19,13 @@ pub trait GenericWindow {
component: core::pin::Pin<crate::abi::datastructures::ComponentRef>,
);
fn window_handle(&self) -> std::cell::Ref<'_, winit::window::Window>;
fn map_window(self: Rc<Self>, event_loop: &EventLoop, props: &WindowProperties);
fn map_window(self: Rc<Self>, event_loop: &EventLoop, root_item: Pin<ItemRef>);
fn unmap_window(self: Rc<Self>);
fn request_redraw(&self);
fn scale_factor(&self) -> f32;
fn set_scale_factor(&self, factor: f32);
fn set_width(&self, width: f32);
fn set_height(&self, height: f32);
}
/// The ComponentWindow is the (rust) facing public type that can render the items
@ -39,12 +41,12 @@ impl ComponentWindow {
Self(window_impl)
}
/// Spins an event loop and renders the items of the provided component in this window.
pub fn run(&self, component: Pin<VRef<ComponentVTable>>, props: &WindowProperties) {
pub fn run(&self, component: Pin<VRef<ComponentVTable>>, root_item: Pin<ItemRef>) {
let event_loop = crate::eventloop::EventLoop::new();
self.0.clone().map_window(&event_loop, props);
self.0.clone().map_window(&event_loop, root_item);
event_loop.run(component, &props);
event_loop.run(component);
self.0.clone().unmap_window();
}
@ -83,11 +85,7 @@ impl EventLoop {
Self { winit_loop: winit::event_loop::EventLoop::new() }
}
#[allow(unused_mut)] // mut need changes for wasm
pub fn run(
mut self,
component: core::pin::Pin<crate::abi::datastructures::ComponentRef>,
window_properties: &crate::abi::datastructures::WindowProperties,
) {
pub fn run(mut self, component: core::pin::Pin<crate::abi::datastructures::ComponentRef>) {
use winit::event::Event;
use winit::event_loop::{ControlFlow, EventLoopWindowTarget};
let layout_listener = Rc::pin(PropertyListenerScope::default());
@ -122,19 +120,14 @@ impl EventLoop {
event: winit::event::WindowEvent::Resized(size),
window_id,
} => {
if let Some(width_property) = window_properties.width {
width_property.set(size.width as f32)
}
if let Some(height_property) = window_properties.height {
height_property.set(size.height as f32)
}
ALL_WINDOWS.with(|windows| {
if let Some(Some(window)) =
windows.borrow().get(&window_id).map(|weakref| weakref.upgrade())
{
let platform_window = window.window_handle();
window.set_scale_factor(platform_window.scale_factor() as f32)
window.set_scale_factor(platform_window.scale_factor() as f32);
window.set_width(size.width as f32);
window.set_height(size.height as f32);
}
});
}
@ -146,17 +139,13 @@ impl EventLoop {
},
window_id,
} => {
if let Some(width_property) = window_properties.width {
width_property.set(size.width as f32)
}
if let Some(height_property) = window_properties.height {
height_property.set(size.height as f32)
}
ALL_WINDOWS.with(|windows| {
if let Some(Some(window)) =
windows.borrow().get(&window_id).map(|weakref| weakref.upgrade())
{
window.set_scale_factor(scale_factor as f32)
window.set_scale_factor(scale_factor as f32);
window.set_width(size.width as f32);
window.set_height(size.height as f32);
}
});
}
@ -280,6 +269,7 @@ pub mod ffi {
#![allow(unsafe_code)]
use super::*;
use crate::abi::datastructures::ItemVTable;
#[allow(non_camel_case_types)]
type c_void = ();
@ -303,11 +293,10 @@ pub mod ffi {
pub unsafe extern "C" fn sixtyfps_component_window_run(
handle: *mut ComponentWindowOpaque,
component: Pin<VRef<ComponentVTable>>,
window_props: *mut WindowProperties,
root_item: Pin<VRef<ItemVTable>>,
) {
let window = &*(handle as *const ComponentWindow);
let window_props = &*(window_props as *const WindowProperties);
window.run(component, &window_props);
window.run(component, root_item);
}
/// Returns the window scale factor.

View file

@ -3,7 +3,7 @@ use crate::input::{MouseEvent, MouseEventType};
use crate::properties::{InterpolatedPropertyValue, Property};
#[cfg(feature = "rtti")]
use crate::rtti::{BuiltinItem, FieldInfo, FieldOffset, PropertyInfo, ValueType};
use crate::SharedArray;
use crate::{abi::datastructures::ItemRef, SharedArray};
use cgmath::Matrix4;
use const_field_offset::FieldOffsets;
@ -366,11 +366,29 @@ impl<Backend: GraphicsBackend + 'static> GraphicsWindowBackendState<Backend> {
}
}
#[derive(FieldOffsets)]
#[repr(C)]
#[pin]
struct WindowProperties {
scale_factor: Property<f32>,
width: Property<f32>,
height: Property<f32>,
}
impl Default for WindowProperties {
fn default() -> Self {
Self {
scale_factor: Property::new(1.0),
width: Property::new(800.),
height: Property::new(600.),
}
}
}
pub struct GraphicsWindow<Backend: GraphicsBackend + 'static> {
window_factory: Box<WindowFactoryFn<Backend>>,
map_state: RefCell<GraphicsWindowBackendState<Backend>>,
/// Turn into a struct when we get more properties later.
scale_factor: Pin<Box<Property<f32>>>,
properties: Pin<Box<WindowProperties>>,
}
impl<Backend: GraphicsBackend + 'static> GraphicsWindow<Backend> {
@ -381,7 +399,7 @@ impl<Backend: GraphicsBackend + 'static> GraphicsWindow<Backend> {
Rc::new(Self {
window_factory: Box::new(graphics_backend_factory),
map_state: RefCell::new(GraphicsWindowBackendState::Unmapped),
scale_factor: Box::pin(Property::new(1.0)),
properties: Box::pin(WindowProperties::default()),
})
}
@ -455,7 +473,7 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
fn map_window(
self: Rc<Self>,
event_loop: &crate::eventloop::EventLoop,
props: &crate::abi::datastructures::WindowProperties,
root_item: Pin<ItemRef>,
) {
if matches!(&*self.map_state.borrow(), GraphicsWindowBackendState::Mapped(..)) {
return;
@ -476,31 +494,49 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
// the scale factor.
// We could pass the logical requested size at window builder time, *if* we knew what the values are.
{
self.scale_factor.as_ref().set(platform_window.scale_factor() as _);
self.properties.as_ref().scale_factor.set(platform_window.scale_factor() as _);
let existing_size = platform_window.inner_size();
let mut new_size = existing_size;
if let Some(width_property) = props.width {
let width = width_property.get();
if let Some(window_item) = ItemRef::downcast_pin(root_item) {
let width =
crate::items::Window::FIELD_OFFSETS.width.apply_pin(window_item).get();
if width > 0. {
new_size.width = width as _;
}
}
if let Some(height_property) = props.height {
let height = height_property.get();
let height =
crate::items::Window::FIELD_OFFSETS.height.apply_pin(window_item).get();
if height > 0. {
new_size.height = height as _;
}
{
let window = self.clone();
window_item.as_ref().width.set_binding(move || {
WindowProperties::FIELD_OFFSETS
.width
.apply_pin(window.properties.as_ref())
.get()
});
}
{
let window = self.clone();
window_item.as_ref().height.set_binding(move || {
WindowProperties::FIELD_OFFSETS
.height
.apply_pin(window.properties.as_ref())
.get()
});
}
}
// Either request a new size or update width/height to the size given by the window manager.
if new_size != existing_size {
platform_window.set_inner_size(new_size)
} else {
props.width.map(|p| p.set(existing_size.width as _));
props.height.map(|p| p.set(existing_size.height as _));
}
self.properties.as_ref().width.set(new_size.width as _);
self.properties.as_ref().height.set(new_size.height as _);
}
self.map_state.replace(GraphicsWindowBackendState::Mapped(MappedWindow {
@ -529,11 +565,19 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
}
fn scale_factor(&self) -> f32 {
self.scale_factor.as_ref().get()
WindowProperties::FIELD_OFFSETS.scale_factor.apply_pin(self.properties.as_ref()).get()
}
fn set_scale_factor(&self, factor: f32) {
self.scale_factor.as_ref().set(factor);
self.properties.as_ref().scale_factor.set(factor);
}
fn set_width(&self, width: f32) {
self.properties.as_ref().width.set(width);
}
fn set_height(&self, height: f32) {
self.properties.as_ref().height.set(height);
}
}

View file

@ -566,3 +566,44 @@ pub struct PropertyAnimation {
#[rtti_field]
pub easing: crate::animations::EasingCurve,
}
/// The implementation of the `Window` element
#[repr(C)]
#[derive(FieldOffsets, Default, BuiltinItem)]
#[pin]
pub struct Window {
pub width: Property<f32>,
pub height: Property<f32>,
pub cached_rendering_data: CachedRenderingData,
}
impl Item for Window {
fn geometry(self: Pin<&Self>) -> Rect {
euclid::rect(
0.,
0.,
Self::FIELD_OFFSETS.width.apply_pin(self).get(),
Self::FIELD_OFFSETS.height.apply_pin(self).get(),
)
}
fn rendering_primitive(self: Pin<&Self>) -> HighLevelRenderingPrimitive {
HighLevelRenderingPrimitive::NoContents
}
fn rendering_variables(self: Pin<&Self>) -> SharedArray<RenderingVariable> {
SharedArray::from(&[])
}
fn layouting_info(self: Pin<&Self>) -> LayoutInfo {
LayoutInfo::default()
}
fn input_event(self: Pin<&Self>, _event: MouseEvent) -> InputEventResult {
InputEventResult::EventIgnored
}
}
impl ItemConsts for Window {
const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
}