slint/sixtyfps_runtime/corelib/abi/datastructures.rs
Olivier Goffart caca0d0ba4 Put the component in a Pin<>
Removed the drop and create from the ComponentVTable:
since we are not using VBox<ComponentVTable>, this simplifies a bit
the code of the interpreter and everything else.

But there is still a lot of changes everywhere to support that the Component
is pinned.
This is just for the component. Which would be required if later we want
to access the properties as Pin<Property<_>>. But we have not yet ability
to do projections
2020-06-24 14:13:27 +02:00

394 lines
12 KiB
Rust

//! This module contains the basic datastructures that are exposed to the C API
use super::slice::Slice;
use crate::EvaluationContext;
use core::pin::Pin;
use std::cell::Cell;
use vtable::*;
/// 2D Rectangle
pub type Rect = euclid::default::Rect<f32>;
/// 2D Point
pub type Point = euclid::default::Point2D<f32>;
/// 2D Size
pub type Size = euclid::default::Size2D<f32>;
/// Expand Rect so that cbindgen can see it. ( is in fact euclid::default::Rect<f32>)
#[cfg(cbindgen)]
#[repr(C)]
struct Rect {
x: f32,
y: f32,
width: f32,
height: f32,
}
/// Expand Point so that cbindgen can see it. ( is in fact euclid::default::PointD2<f32>)
#[cfg(cbindgen)]
#[repr(C)]
struct Point {
x: f32,
y: f32,
}
/// A Component is representing an unit that is allocated together
#[vtable]
#[repr(C)]
pub struct ComponentVTable {
/// Visit the children of the item at index `index`.
/// Note that the root item is at index 0, so passing 0 would visit the item under root (the children of root).
/// If you want to visit the root item, you need to pass -1 as an index
pub visit_children_item: extern "C" fn(
core::pin::Pin<VRef<ComponentVTable>>,
index: isize,
visitor: VRefMut<ItemVisitorVTable>,
),
/// Returns the layout info for this component
pub layout_info: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>) -> LayoutInfo,
/// Will compute the layout of
pub compute_layout:
extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>, eval_context: &EvaluationContext),
}
/// This structure must be present in items that are Rendered and contains information.
/// Used by the backend.
#[derive(Default)]
#[repr(C)]
pub struct CachedRenderingData {
/// Used and modified by the backend, should be initialized to 0 by the user code
pub(crate) cache_index: Cell<usize>,
/// Set to false initially and when changes happen that require updating the cache
pub(crate) cache_ok: Cell<bool>,
}
impl CachedRenderingData {
pub(crate) fn low_level_rendering_primitive<
'a,
GraphicsBackend: crate::graphics::GraphicsBackend,
>(
&self,
cache: &'a crate::graphics::RenderingCache<GraphicsBackend>,
) -> Option<&'a GraphicsBackend::LowLevelRenderingPrimitive> {
if !self.cache_ok.get() {
return None;
}
Some(cache.entry_at(self.cache_index.get()))
}
}
/// The item tree is an array of ItemTreeNode representing a static tree of items
/// within a component.
#[repr(u8)]
pub enum ItemTreeNode<T> {
/// Static item
Item {
/// byte offset where we can find the item (from the *ComponentImpl)
item: vtable::VOffset<T, ItemVTable>,
/// number of children
chilren_count: u32,
/// index of the first children within the item tree
children_index: u32,
},
/// A placeholder for many instance of item in their own component which
/// are instentiated according to a model.
DynamicTree {
/// the undex which is passed in the visit_dynamic callback.
index: usize,
},
}
/// Items are the nodes in the render tree.
#[vtable]
#[repr(C)]
pub struct ItemVTable {
/// Returns the geometry of this item (relative to its parent item)
pub geometry: extern "C" fn(VRef<'_, ItemVTable>, context: &crate::EvaluationContext) -> Rect,
/// offset in bytes fromthe *const ItemImpl.
/// isize::MAX means None
#[allow(non_upper_case_globals)]
#[offset(CachedRenderingData)]
pub cached_rendering_data_offset: usize,
/// Return the rendering primitive used to display this item.
pub rendering_primitive: extern "C" fn(
VRef<'_, ItemVTable>,
context: &crate::EvaluationContext,
) -> RenderingPrimitive,
/// We would need max/min/preferred size, and all layout info
pub layouting_info: extern "C" fn(VRef<'_, ItemVTable>) -> LayoutInfo,
/// input event
pub input_event: extern "C" fn(VRef<'_, ItemVTable>, MouseEvent, &crate::EvaluationContext),
}
/// The constraint that applies to an item
#[repr(C)]
#[derive(Clone)]
pub struct LayoutInfo {
min_width: f32,
max_width: f32,
min_height: f32,
max_height: f32,
}
impl Default for LayoutInfo {
fn default() -> Self {
LayoutInfo { min_width: 0., max_width: f32::MAX, min_height: 0., max_height: f32::MAX }
}
}
/// RGBA color
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(C)]
pub struct Color {
red: u8,
green: u8,
blue: u8,
alpha: u8,
}
impl Color {
/// Construct a color from an integer encoded as `0xAARRGGBB`
pub const fn from_argb_encoded(encoded: u32) -> Color {
Color {
red: (encoded >> 16) as u8,
green: (encoded >> 8) as u8,
blue: encoded as u8,
alpha: (encoded >> 24) as u8,
}
}
/// Construct a color from its RGBA components as u8
pub const fn from_rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Color {
Color { red, green, blue, alpha }
}
/// Construct a color from its RGB components as u8
pub const fn from_rgb(red: u8, green: u8, blue: u8) -> Color {
Color::from_rgba(red, green, blue, 0xff)
}
/// Returns `(red, green, blue, alpha)` encoded as f32
pub fn as_rgba_f32(&self) -> (f32, f32, f32, f32) {
(
(self.red as f32) / 255.0,
(self.green as f32) / 255.0,
(self.blue as f32) / 255.0,
(self.alpha as f32) / 255.0,
)
}
/// Returns `(red, green, blue, alpha)` encoded as u8
pub fn as_rgba_u8(&self) -> (u8, u8, u8, u8) {
(self.red, self.green, self.blue, self.alpha)
}
/// A constant for the black color
pub const BLACK: Color = Color::from_rgb(0, 0, 0);
/// A constant for the white color
pub const WHITE: Color = Color::from_rgb(255, 255, 255);
}
/// A resource is a reference to binary data, for example images. They can be accessible on the file
/// system or embedded in the resulting binary. Or they might be URLs to a web server and a downloaded
/// is necessary before they can be used.
#[derive(Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum Resource {
/// A resource that does not represent any data.
None,
/// A resource that points to a file in the file system
AbsoluteFilePath(crate::SharedString),
/// A resource that is embedded in the program and accessible via pointer
EmbeddedData(super::slice::Slice<'static, u8>),
}
impl Default for Resource {
fn default() -> Self {
Resource::None
}
}
/// Each item return a RenderingPrimitive to the backend with information about what to draw.
#[derive(PartialEq, Debug)]
#[repr(C)]
#[allow(missing_docs)]
pub enum RenderingPrimitive {
/// There is nothing to draw
NoContents,
Rectangle {
x: f32,
y: f32,
width: f32,
height: f32,
color: Color,
},
Image {
x: f32,
y: f32,
source: crate::Resource,
},
Text {
x: f32,
y: f32,
text: crate::SharedString,
font_family: crate::SharedString,
font_pixel_size: f32,
color: Color,
},
}
/// The type of a MouseEvent
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub enum MouseEventType {
/// The mouse was pressed
MousePressed,
/// The mouse was relased
MouseReleased,
/// The mouse position has changed
MouseMoved,
}
/// Structur representing a mouse event
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct MouseEvent {
/// The position of the cursor
pub pos: Point,
/// The action performed (pressed/released/moced)
pub what: MouseEventType,
}
/// The ComponentWindow is the (rust) facing public type that can render the items
/// of components to the screen.
#[repr(C)]
#[derive(Clone)]
pub struct ComponentWindow(std::rc::Rc<dyn crate::eventloop::GenericWindow>);
impl ComponentWindow {
/// Creates a new instance of a CompomentWindow based on the given window implementation. Only used
/// internally.
pub fn new(window_impl: std::rc::Rc<dyn crate::eventloop::GenericWindow>) -> Self {
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>>) {
let event_loop = crate::eventloop::EventLoop::new();
self.0.clone().map_window(&event_loop);
event_loop.run(component);
}
}
#[allow(non_camel_case_types)]
type c_void = ();
/// Same layout as ComponentWindow (fat pointer)
#[repr(C)]
pub struct ComponentWindowOpaque(*const c_void, *const c_void);
/// Releases the reference to the component window held by handle.
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_component_window_drop(handle: *mut ComponentWindowOpaque) {
println!("sixtyfps_component_window_drop()");
assert_eq!(
core::mem::size_of::<ComponentWindow>(),
core::mem::size_of::<ComponentWindowOpaque>()
);
core::ptr::read(handle as *mut ComponentWindow);
}
/// Spins an event loop and renders the items of the provided component in this window.
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_component_window_run(
handle: *mut ComponentWindowOpaque,
component: Pin<VRef<ComponentVTable>>,
) {
let window = &*(handle as *const ComponentWindow);
window.run(component);
}
#[repr(C)]
#[vtable]
/// Object to be passed in visit_item_children method of the Component.
pub struct ItemVisitorVTable {
/// Called for each children of the visited item
///
/// The `component` parameter is the component in which the item live which might not be the same
/// as the parent's component.
/// `index` is to be used again in the visit_item_children function of the Component (the one passed as parameter)
/// and `item` is a reference to the item itself
visit_item: fn(
VRefMut<ItemVisitorVTable>,
component: Pin<VRef<ComponentVTable>>,
index: isize,
item: VRef<ItemVTable>,
),
/// Destructor
drop: fn(VRefMut<ItemVisitorVTable>),
}
impl<T: FnMut(crate::ComponentRefPin, isize, VRef<ItemVTable>)> ItemVisitor for T {
fn visit_item(
&mut self,
component: crate::ComponentRefPin,
index: isize,
item: VRef<ItemVTable>,
) {
self(component, index, item)
}
}
/// Expose `crate::item_tree::visit_item_tree` to C++
///
/// Safety: Assume a correct implementation of the item_tree array
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_visit_item_tree(
component: Pin<VRef<ComponentVTable>>,
item_tree: Slice<ItemTreeNode<u8>>,
index: isize,
visitor: VRefMut<ItemVisitorVTable>,
visit_dynamic: extern "C" fn(
base: &u8,
visitor: vtable::VRefMut<ItemVisitorVTable>,
dyn_index: usize,
),
) {
crate::item_tree::visit_item_tree(
&*(component.as_ptr() as *const u8),
component,
item_tree.as_slice(),
index,
visitor,
|a, b, c| visit_dynamic(a, b, c),
)
}
// This is here because for some reason (rust bug?) the ItemVTable_static is not accessible in the other modules
ItemVTable_static! {
/// The VTable for `Image`
#[no_mangle]
pub static ImageVTable for crate::abi::primitives::Image
}
ItemVTable_static! {
/// The VTable for `Rectangle`
#[no_mangle]
pub static RectangleVTable for crate::abi::primitives::Rectangle
}
ItemVTable_static! {
/// The VTable for `Text`
#[no_mangle]
pub static TextVTable for crate::abi::primitives::Text
}
ItemVTable_static! {
/// The VTable for `TouchArea`
#[no_mangle]
pub static TouchAreaVTable for crate::abi::primitives::TouchArea
}