mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-29 21:34:50 +00:00
776 lines
25 KiB
Rust
776 lines
25 KiB
Rust
//! This module contains the basic datastructures that are exposed to the C API
|
|
|
|
use super::slice::Slice;
|
|
use core::pin::Pin;
|
|
use std::cell::Cell;
|
|
use vtable::*;
|
|
|
|
#[cfg(feature = "rtti")]
|
|
use crate::rtti::{BuiltinItem, FieldInfo, FieldOffset, PropertyInfo, ValueType};
|
|
use const_field_offset::FieldOffsets;
|
|
use corelib_macro::*;
|
|
|
|
/// 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>>),
|
|
}
|
|
|
|
/// This structure must be present in items that are Rendered and contains information.
|
|
/// Used by the backend.
|
|
#[derive(Default, Debug)]
|
|
#[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, vtable::PinnedFlag>,
|
|
|
|
/// 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 instantiated 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(core::pin::Pin<VRef<ItemVTable>>) -> 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(core::pin::Pin<VRef<ItemVTable>>) -> RenderingPrimitive,
|
|
|
|
/// We would need max/min/preferred size, and all layout info
|
|
pub layouting_info: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>) -> LayoutInfo,
|
|
|
|
/// input event
|
|
pub input_event: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, MouseEvent),
|
|
}
|
|
|
|
/// 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, Default)]
|
|
#[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)
|
|
}
|
|
|
|
/// Returns `(alpha, red, green, blue)` encoded as u32
|
|
pub fn as_argb_encoded(&self) -> u32 {
|
|
((self.red as u32) << 16)
|
|
| ((self.green as u32) << 8)
|
|
| (self.blue as u32)
|
|
| ((self.alpha as u32) << 24)
|
|
}
|
|
|
|
/// 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 constant for the transparent color
|
|
pub const TRANSPARENT: Color = Color::from_rgba(0, 0, 0, 0);
|
|
}
|
|
|
|
impl From<u32> for Color {
|
|
fn from(encoded: u32) -> Self {
|
|
Color::from_argb_encoded(encoded)
|
|
}
|
|
}
|
|
|
|
impl crate::abi::properties::InterpolatedPropertyValue for Color {
|
|
fn interpolate(self, target_value: Self, t: f32) -> Self {
|
|
Self {
|
|
red: self.red.interpolate(target_value.red, t),
|
|
green: self.green.interpolate(target_value.green, t),
|
|
blue: self.blue.interpolate(target_value.blue, t),
|
|
alpha: self.alpha.interpolate(target_value.alpha, t),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Color {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "argb({}, {}, {}, {})", self.alpha, self.red, self.green, self.blue)
|
|
}
|
|
}
|
|
|
|
/// 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
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, BuiltinItem, Clone, Debug, PartialEq)]
|
|
#[pin]
|
|
/// PathLineTo describes the event of moving the cursor on the path to the specified location
|
|
/// along a straight line.
|
|
pub struct PathLineTo {
|
|
#[rtti_field]
|
|
/// The x coordinate where the line should go to.
|
|
pub x: f32,
|
|
#[rtti_field]
|
|
/// The y coordinate where the line should go to.
|
|
pub y: f32,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, BuiltinItem, Clone, Debug, PartialEq)]
|
|
#[pin]
|
|
/// PathArcTo describes the event of moving the cursor on the path across an arc to the specified
|
|
/// x/y coordinates, with the specified x/y radius and additional properties.
|
|
pub struct PathArcTo {
|
|
#[rtti_field]
|
|
/// The x coordinate where the arc should end up.
|
|
pub x: f32,
|
|
#[rtti_field]
|
|
/// The y coordinate where the arc should end up.
|
|
pub y: f32,
|
|
#[rtti_field]
|
|
/// The radius on the x-axis of the arc.
|
|
pub radius_x: f32,
|
|
#[rtti_field]
|
|
/// The radius on the y-axis of the arc.
|
|
pub radius_y: f32,
|
|
#[rtti_field]
|
|
/// The rotation along the x-axis of the arc in degress.
|
|
pub x_rotation: f32,
|
|
#[rtti_field]
|
|
/// large_arc indicates whether to take the long or the shorter path to complete the arc.
|
|
pub large_arc: bool,
|
|
#[rtti_field]
|
|
/// sweep indicates the direction of the arc. If true, a clockwise direction is chosen,
|
|
/// otherwise counter-clockwise.
|
|
pub sweep: bool,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
/// PathElement describes a single element on a path, such as move-to, line-to, etc.
|
|
pub enum PathElement {
|
|
/// The LineTo variant describes a line.
|
|
LineTo(PathLineTo),
|
|
/// The PathArcTo variant describes an arc.
|
|
ArcTo(PathArcTo),
|
|
/// Indicates that the path should be closed now by connecting to the starting point.
|
|
Close,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
/// PathEvent is a low-level data structure describing the composition of a path. Typically it is
|
|
/// generated at compile time from a higher-level description, such as SVG commands.
|
|
pub enum PathEvent {
|
|
/// The beginning of the path.
|
|
Begin,
|
|
/// A straight line on the path.
|
|
Line,
|
|
/// A quadratic bezier curve on the path.
|
|
Quadratic,
|
|
/// A cubic bezier curve on the path.
|
|
Cubic,
|
|
/// The end of the path that remains open.
|
|
EndOpen,
|
|
/// The end of a path that is closed.
|
|
EndClosed,
|
|
}
|
|
|
|
struct ToLyonPathEventIterator<'a> {
|
|
events_it: std::slice::Iter<'a, PathEvent>,
|
|
coordinates_it: std::slice::Iter<'a, Point>,
|
|
first: Option<&'a Point>,
|
|
last: Option<&'a Point>,
|
|
}
|
|
|
|
impl<'a> Iterator for ToLyonPathEventIterator<'a> {
|
|
type Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>;
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
use lyon::path::Event;
|
|
|
|
self.events_it.next().map(|event| match event {
|
|
PathEvent::Begin => Event::Begin { at: self.coordinates_it.next().unwrap().clone() },
|
|
PathEvent::Line => Event::Line {
|
|
from: self.coordinates_it.next().unwrap().clone(),
|
|
to: self.coordinates_it.next().unwrap().clone(),
|
|
},
|
|
PathEvent::Quadratic => Event::Quadratic {
|
|
from: self.coordinates_it.next().unwrap().clone(),
|
|
ctrl: self.coordinates_it.next().unwrap().clone(),
|
|
to: self.coordinates_it.next().unwrap().clone(),
|
|
},
|
|
PathEvent::Cubic => Event::Cubic {
|
|
from: self.coordinates_it.next().unwrap().clone(),
|
|
ctrl1: self.coordinates_it.next().unwrap().clone(),
|
|
ctrl2: self.coordinates_it.next().unwrap().clone(),
|
|
to: self.coordinates_it.next().unwrap().clone(),
|
|
},
|
|
PathEvent::EndOpen => Event::End {
|
|
first: self.first.unwrap().clone(),
|
|
last: self.last.unwrap().clone(),
|
|
close: false,
|
|
},
|
|
PathEvent::EndClosed => Event::End {
|
|
first: self.first.unwrap().clone(),
|
|
last: self.last.unwrap().clone(),
|
|
close: true,
|
|
},
|
|
})
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
self.events_it.size_hint()
|
|
}
|
|
}
|
|
|
|
impl<'a> ExactSizeIterator for ToLyonPathEventIterator<'a> {}
|
|
|
|
struct TransformedLyonPathIterator<EventIt> {
|
|
it: EventIt,
|
|
transform: lyon::math::Transform,
|
|
}
|
|
|
|
impl<EventIt: Iterator<Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>>> Iterator
|
|
for TransformedLyonPathIterator<EventIt>
|
|
{
|
|
type Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>;
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.it.next().map(|ev| ev.transformed(&self.transform))
|
|
}
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
self.it.size_hint()
|
|
}
|
|
}
|
|
|
|
impl<EventIt: Iterator<Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>>>
|
|
ExactSizeIterator for TransformedLyonPathIterator<EventIt>
|
|
{
|
|
}
|
|
|
|
/// LyonPathIterator is a data structure that acts as starting point for iterating
|
|
/// through the low-level events of a path. If the path was constructed from said
|
|
/// events, then it is a very thin abstraction. If the path was created from higher-level
|
|
/// elements, then an intermediate lyon path is required/built.
|
|
pub struct LyonPathIterator<'a> {
|
|
it: LyonPathIteratorVariant<'a>,
|
|
transform: Option<lyon::math::Transform>,
|
|
}
|
|
|
|
enum LyonPathIteratorVariant<'a> {
|
|
FromPath(lyon::path::Path),
|
|
FromEvents(&'a crate::SharedArray<PathEvent>, &'a crate::SharedArray<Point>),
|
|
}
|
|
|
|
impl<'a> LyonPathIterator<'a> {
|
|
/// Create a new iterator for path traversal.
|
|
pub fn iter(
|
|
&'a self,
|
|
) -> Box<dyn Iterator<Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>> + 'a>
|
|
{
|
|
match &self.it {
|
|
LyonPathIteratorVariant::FromPath(path) => self.apply_transform(path.iter()),
|
|
LyonPathIteratorVariant::FromEvents(events, coordinates) => {
|
|
Box::new(self.apply_transform(ToLyonPathEventIterator {
|
|
events_it: events.iter(),
|
|
coordinates_it: coordinates.iter(),
|
|
first: coordinates.first(),
|
|
last: coordinates.last(),
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// This function changes the iterator to be one that applies a transformation to make the path fit into the specified bounds.
|
|
pub fn fitted(mut self, width: f32, height: f32) -> LyonPathIterator<'a> {
|
|
if width > 0. || height > 0. {
|
|
let br = lyon::algorithms::aabb::bounding_rect(self.iter());
|
|
self.transform = Some(lyon::algorithms::fit::fit_rectangle(
|
|
&br,
|
|
&Rect::from_size(Size::new(width, height)),
|
|
lyon::algorithms::fit::FitStyle::Min,
|
|
));
|
|
}
|
|
|
|
self
|
|
}
|
|
|
|
fn apply_transform(
|
|
&'a self,
|
|
event_it: impl Iterator<Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>> + 'a,
|
|
) -> Box<dyn Iterator<Item = lyon::path::Event<lyon::math::Point, lyon::math::Point>> + 'a>
|
|
{
|
|
match self.transform {
|
|
Some(transform) => Box::new(TransformedLyonPathIterator { it: event_it, transform }),
|
|
None => Box::new(event_it),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
/// PathData represents a path described by either high-level elements or low-level
|
|
/// events and coordinates.
|
|
pub enum PathData {
|
|
/// None is the variant when the path is empty.
|
|
None,
|
|
/// The Elements variant is used to make a Path from shared arrays of elements.
|
|
Elements(crate::SharedArray<PathElement>),
|
|
/// The Events variant describes the path as a series of low-level events and
|
|
/// associated coordinates.
|
|
Events(crate::SharedArray<PathEvent>, crate::SharedArray<Point>),
|
|
}
|
|
|
|
impl Default for PathData {
|
|
fn default() -> Self {
|
|
Self::None
|
|
}
|
|
}
|
|
|
|
impl PathData {
|
|
/// This function returns an iterator that allows traversing the path by means of lyon events.
|
|
pub fn iter(&self) -> LyonPathIterator {
|
|
LyonPathIterator {
|
|
it: match self {
|
|
PathData::None => LyonPathIteratorVariant::FromPath(lyon::path::Path::new()),
|
|
PathData::Elements(elements) => LyonPathIteratorVariant::FromPath(
|
|
PathData::build_path(elements.as_slice().iter()),
|
|
),
|
|
PathData::Events(events, coordinates) => {
|
|
LyonPathIteratorVariant::FromEvents(events, coordinates)
|
|
}
|
|
},
|
|
transform: None,
|
|
}
|
|
}
|
|
|
|
fn build_path(element_it: std::slice::Iter<PathElement>) -> lyon::path::Path {
|
|
use lyon::geom::SvgArc;
|
|
use lyon::math::{Angle, Point, Vector};
|
|
use lyon::path::{
|
|
builder::{Build, FlatPathBuilder, SvgBuilder},
|
|
ArcFlags,
|
|
};
|
|
|
|
let mut path_builder = lyon::path::Path::builder().with_svg();
|
|
for element in element_it {
|
|
match element {
|
|
PathElement::LineTo(PathLineTo { x, y }) => {
|
|
path_builder.line_to(Point::new(*x, *y))
|
|
}
|
|
PathElement::ArcTo(PathArcTo {
|
|
x,
|
|
y,
|
|
radius_x,
|
|
radius_y,
|
|
x_rotation,
|
|
large_arc,
|
|
sweep,
|
|
}) => {
|
|
let radii = Vector::new(*radius_x, *radius_y);
|
|
let x_rotation = Angle::degrees(*x_rotation);
|
|
let flags = ArcFlags { large_arc: *large_arc, sweep: *sweep };
|
|
let to = Point::new(*x, *y);
|
|
|
|
let svg_arc = SvgArc {
|
|
from: path_builder.current_position(),
|
|
radii,
|
|
x_rotation,
|
|
flags,
|
|
to,
|
|
};
|
|
|
|
if svg_arc.is_straight_line() {
|
|
path_builder.line_to(to);
|
|
} else {
|
|
path_builder.arc_to(radii, x_rotation, flags, to)
|
|
}
|
|
}
|
|
PathElement::Close => path_builder.close(),
|
|
}
|
|
}
|
|
|
|
path_builder.build()
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
/// This function is used for the low-level C++ interface to allocate the backing vector for a shared path element array.
|
|
pub unsafe extern "C" fn sixtyfps_new_path_elements(
|
|
out: *mut c_void,
|
|
first_element: *const PathElement,
|
|
count: usize,
|
|
) {
|
|
let arr = crate::SharedArray::from(std::slice::from_raw_parts(first_element, count));
|
|
core::ptr::write(out as *mut crate::SharedArray<PathElement>, arr.clone());
|
|
}
|
|
|
|
#[no_mangle]
|
|
/// This function is used for the low-level C++ interface to allocate the backing vector for a shared path event array.
|
|
pub unsafe extern "C" fn sixtyfps_new_path_events(
|
|
out_events: *mut c_void,
|
|
out_coordinates: *mut c_void,
|
|
first_event: *const PathEvent,
|
|
event_count: usize,
|
|
first_coordinate: *const Point,
|
|
coordinate_count: usize,
|
|
) {
|
|
let events = crate::SharedArray::from(std::slice::from_raw_parts(first_event, event_count));
|
|
core::ptr::write(out_events as *mut crate::SharedArray<PathEvent>, events.clone());
|
|
let coordinates =
|
|
crate::SharedArray::from(std::slice::from_raw_parts(first_coordinate, coordinate_count));
|
|
core::ptr::write(out_coordinates as *mut crate::SharedArray<Point>, coordinates.clone());
|
|
}
|
|
|
|
/// 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,
|
|
},
|
|
Path {
|
|
x: f32,
|
|
y: f32,
|
|
width: f32,
|
|
height: f32,
|
|
elements: crate::PathData,
|
|
fill_color: Color,
|
|
stroke_color: Color,
|
|
stroke_width: f32,
|
|
},
|
|
}
|
|
|
|
/// 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,
|
|
}
|
|
|
|
#[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: Option<&'a crate::Property<f32>>,
|
|
/// A reference to the property that is supposed to be kept up-to-date with the height
|
|
/// of the window.
|
|
pub height: Option<&'a crate::Property<f32>>,
|
|
|
|
/// A reference to the property that is supposed to be kept up-to-date with the current
|
|
/// screen dpi
|
|
pub dpi: Option<&'a crate::Property<f32>>,
|
|
}
|
|
|
|
/// 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>>, props: &WindowProperties) {
|
|
let event_loop = crate::eventloop::EventLoop::new();
|
|
self.0.clone().map_window(&event_loop);
|
|
|
|
event_loop.run(component, &props);
|
|
}
|
|
}
|
|
|
|
#[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) {
|
|
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>>,
|
|
window_props: *mut WindowProperties,
|
|
) {
|
|
let window = &*(handle as *const ComponentWindow);
|
|
let window_props = &*(window_props as *const WindowProperties);
|
|
window.run(component, &window_props);
|
|
}
|
|
|
|
#[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: Pin<VRef<ItemVTable>>,
|
|
),
|
|
/// Destructor
|
|
drop: fn(VRefMut<ItemVisitorVTable>),
|
|
}
|
|
|
|
impl<T: FnMut(crate::ComponentRefPin, isize, Pin<ItemRef>)> ItemVisitor for T {
|
|
fn visit_item(&mut self, component: crate::ComponentRefPin, index: isize, item: Pin<ItemRef>) {
|
|
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(
|
|
Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
|
|
component,
|
|
item_tree.as_slice(),
|
|
index,
|
|
visitor,
|
|
|a, b, c| visit_dynamic(a.get_ref(), 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
|
|
}
|
|
ItemVTable_static! {
|
|
/// The VTable for `Path`
|
|
#[no_mangle]
|
|
pub static PathVTable for crate::abi::primitives::Path
|
|
}
|