mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00

This intends to provide a configurable rectangular "drop shadow". The API is modeled after CSS/HTML5 Canvas where the element can be "bound" to an existing rectangular shape (geometry and radius), the offset can be used to place the shadow and color and blur configure the shadow. The shadow's color fades into transparent. TODO (in subsequent changes): * Documentation * Qt implementation
847 lines
26 KiB
Rust
847 lines
26 KiB
Rust
/* LICENSE BEGIN
|
|
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
|
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
|
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
|
|
|
SPDX-License-Identifier: GPL-3.0-only
|
|
This file is also available under commercial licensing terms.
|
|
Please contact info@sixtyfps.io for more information.
|
|
LICENSE END */
|
|
/*!
|
|
This module contains the builtin items, either in this file or in sub-modules.
|
|
|
|
When adding an item or a property, it needs to be kept in sync with different place.
|
|
(This is less than ideal and maybe we can have some automation later)
|
|
|
|
- It needs to be changed in this module
|
|
- In the compiler: builtins.60
|
|
- In the interpreter (new item only): dynamic_component.rs
|
|
- For the C++ code (new item only): the cbindgen.rs to export the new item, and the `using` declaration in sixtyfps.h
|
|
- Don't forget to update the documentation
|
|
*/
|
|
|
|
#![allow(unsafe_code)]
|
|
#![allow(non_upper_case_globals)]
|
|
#![allow(missing_docs)] // because documenting each property of items is redundent
|
|
|
|
use crate::component::ComponentVTable;
|
|
use crate::graphics::{Color, PathData, Point, Rect, Size};
|
|
use crate::input::{
|
|
FocusEvent, InputEventResult, KeyEvent, KeyEventResult, KeyEventType, MouseEvent,
|
|
MouseEventType,
|
|
};
|
|
use crate::item_rendering::CachedRenderingData;
|
|
use crate::layout::LayoutInfo;
|
|
#[cfg(feature = "rtti")]
|
|
use crate::rtti::*;
|
|
use crate::window::ComponentWindow;
|
|
use crate::{Callback, Property, SharedString};
|
|
use const_field_offset::FieldOffsets;
|
|
use core::pin::Pin;
|
|
use sixtyfps_corelib_macros::*;
|
|
use vtable::*;
|
|
|
|
mod text;
|
|
pub use text::*;
|
|
mod image;
|
|
pub use self::image::*;
|
|
|
|
/// Alias for `&mut dyn ItemRenderer`. Required so cbingen generates the ItemVTable
|
|
/// despite the presence of trait object
|
|
type ItemRendererRef<'a> = &'a mut dyn crate::item_rendering::ItemRenderer;
|
|
|
|
/// Workarounds for cbindgen
|
|
pub type VoidArg = ();
|
|
type KeyEventArg = (KeyEvent,);
|
|
|
|
/// Items are the nodes in the render tree.
|
|
#[vtable]
|
|
#[repr(C)]
|
|
pub struct ItemVTable {
|
|
/// This function is called by the run-time after the memory for the item
|
|
/// has been allocated and initialized. It will be called before any user specified
|
|
/// bindings are set.
|
|
pub init: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, window: &ComponentWindow),
|
|
|
|
/// 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)]
|
|
#[field_offset(CachedRenderingData)]
|
|
pub cached_rendering_data_offset: usize,
|
|
|
|
/// We would need max/min/preferred size, and all layout info
|
|
pub layouting_info:
|
|
extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, window: &ComponentWindow) -> LayoutInfo,
|
|
|
|
pub implicit_size:
|
|
extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, window: &ComponentWindow) -> Size,
|
|
|
|
/// input event
|
|
pub input_event: extern "C" fn(
|
|
core::pin::Pin<VRef<ItemVTable>>,
|
|
MouseEvent,
|
|
window: &ComponentWindow,
|
|
self_rc: &ItemRc,
|
|
) -> InputEventResult,
|
|
|
|
pub focus_event:
|
|
extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, &FocusEvent, window: &ComponentWindow),
|
|
|
|
pub key_event: extern "C" fn(
|
|
core::pin::Pin<VRef<ItemVTable>>,
|
|
&KeyEvent,
|
|
window: &ComponentWindow,
|
|
) -> KeyEventResult,
|
|
|
|
pub render:
|
|
extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, pos: Point, backend: &mut ItemRendererRef),
|
|
}
|
|
|
|
/// Alias for `vtable::VRef<ItemVTable>` which represent a pointer to a `dyn Item` with
|
|
/// the associated vtable
|
|
pub type ItemRef<'a> = vtable::VRef<'a, ItemVTable>;
|
|
|
|
/// A ItemRc is holding a reference to a component containing the item, and the index of this item
|
|
#[repr(C)]
|
|
#[derive(Clone)]
|
|
pub struct ItemRc {
|
|
component: vtable::VRc<ComponentVTable>,
|
|
index: usize,
|
|
}
|
|
|
|
impl ItemRc {
|
|
/// Create an ItemRc from a component and an index
|
|
pub fn new(component: vtable::VRc<ComponentVTable>, index: usize) -> Self {
|
|
Self { component, index }
|
|
}
|
|
/// Return a `Pin<ItemRef<'a>>`
|
|
pub fn borrow<'a>(&'a self) -> Pin<ItemRef<'a>> {
|
|
let comp_ref_pin = vtable::VRc::borrow_pin(&self.component);
|
|
let result = comp_ref_pin.as_ref().get_item_ref(self.index);
|
|
// Safety: we can expand the lifetime of the ItemRef because we know it lives for at least the
|
|
// lifetime of the component, which is 'a. Pin::as_ref removes the lifetime, but we can just put it back.
|
|
unsafe { core::mem::transmute::<Pin<ItemRef<'_>>, Pin<ItemRef<'a>>>(result) }
|
|
}
|
|
pub fn downgrade(&self) -> ItemWeak {
|
|
ItemWeak { component: VRc::downgrade(&self.component), index: self.index }
|
|
}
|
|
/// Return the parent Item in the item tree.
|
|
/// This is weak because it can be null if there is no parent
|
|
pub fn parent_item(&self) -> ItemWeak {
|
|
let comp_ref_pin = vtable::VRc::borrow_pin(&self.component);
|
|
let mut r = ItemWeak::default();
|
|
comp_ref_pin.as_ref().parent_item(self.index, &mut r);
|
|
r
|
|
}
|
|
}
|
|
|
|
/// A Weak reference to an item that can be constructed from an ItemRc.
|
|
#[derive(Default, Clone)]
|
|
#[repr(C)]
|
|
pub struct ItemWeak {
|
|
component: crate::component::ComponentWeak,
|
|
index: usize,
|
|
}
|
|
|
|
impl ItemWeak {
|
|
pub fn upgrade(&self) -> Option<ItemRc> {
|
|
self.component.upgrade().map(|c| ItemRc::new(c, self.index))
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
/// The implementation of the `Rectangle` element
|
|
pub struct Rectangle {
|
|
pub color: Property<Color>,
|
|
pub x: Property<f32>,
|
|
pub y: Property<f32>,
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for Rectangle {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo { horizontal_stretch: 1., vertical_stretch: 1., ..LayoutInfo::default() }
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
_: MouseEvent,
|
|
_window: &ComponentWindow,
|
|
_self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
InputEventResult::EventIgnored
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, _: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
KeyEventResult::EventIgnored
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
|
|
|
|
fn render(self: Pin<&Self>, pos: Point, backend: &mut ItemRendererRef) {
|
|
(*backend).draw_rectangle(pos, self)
|
|
}
|
|
}
|
|
|
|
impl ItemConsts for Rectangle {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<
|
|
Rectangle,
|
|
CachedRenderingData,
|
|
> = Rectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `Rectangle`
|
|
#[no_mangle]
|
|
pub static RectangleVTable for Rectangle
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
/// The implementation of the `BorderRectangle` element
|
|
pub struct BorderRectangle {
|
|
pub color: Property<Color>,
|
|
pub x: Property<f32>,
|
|
pub y: Property<f32>,
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
pub border_width: Property<f32>,
|
|
pub border_radius: Property<f32>,
|
|
pub border_color: Property<Color>,
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for BorderRectangle {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo { horizontal_stretch: 1., vertical_stretch: 1., ..LayoutInfo::default() }
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
_: MouseEvent,
|
|
_window: &ComponentWindow,
|
|
_self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
InputEventResult::EventIgnored
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, _: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
KeyEventResult::EventIgnored
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
|
|
|
|
fn render(self: Pin<&Self>, pos: Point, backend: &mut ItemRendererRef) {
|
|
(*backend).draw_border_rectangle(pos, self)
|
|
}
|
|
}
|
|
|
|
impl ItemConsts for BorderRectangle {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<
|
|
BorderRectangle,
|
|
CachedRenderingData,
|
|
> = BorderRectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `BorderRectangle`
|
|
#[no_mangle]
|
|
pub static BorderRectangleVTable for BorderRectangle
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `Image`
|
|
#[no_mangle]
|
|
pub static ImageVTable for Image
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `ClippedImage`
|
|
#[no_mangle]
|
|
pub static ClippedImageVTable for ClippedImage
|
|
}
|
|
|
|
/// The implementation of the `TouchArea` element
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
pub struct TouchArea {
|
|
pub x: Property<f32>,
|
|
pub y: Property<f32>,
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
/// FIXME: We should anotate this as an "output" property.
|
|
pub pressed: Property<bool>,
|
|
pub has_hover: Property<bool>,
|
|
/// FIXME: there should be just one property for the point istead of two.
|
|
/// Could even be merged with pressed in a Property<Option<Point>> (of course, in the
|
|
/// implementation item only, for the compiler it would stay separate properties)
|
|
pub pressed_x: Property<f32>,
|
|
pub pressed_y: Property<f32>,
|
|
/// FIXME: should maybe be as parameter to the mouse event instead. Or at least just one property
|
|
pub mouse_x: Property<f32>,
|
|
pub mouse_y: Property<f32>,
|
|
pub clicked: Callback<VoidArg>,
|
|
/// FIXME: remove this
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for TouchArea {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo::default()
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
event: MouseEvent,
|
|
_window: &ComponentWindow,
|
|
_self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
Self::FIELD_OFFSETS.mouse_x.apply_pin(self).set(event.pos.x);
|
|
Self::FIELD_OFFSETS.mouse_y.apply_pin(self).set(event.pos.y);
|
|
Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(event.what != MouseEventType::MouseExit);
|
|
|
|
let result = if matches!(event.what, MouseEventType::MouseReleased) {
|
|
Self::FIELD_OFFSETS.clicked.apply_pin(self).call(&());
|
|
InputEventResult::EventAccepted
|
|
} else {
|
|
InputEventResult::GrabMouse
|
|
};
|
|
|
|
Self::FIELD_OFFSETS.pressed.apply_pin(self).set(match event.what {
|
|
MouseEventType::MousePressed => {
|
|
Self::FIELD_OFFSETS.pressed_x.apply_pin(self).set(event.pos.x);
|
|
Self::FIELD_OFFSETS.pressed_y.apply_pin(self).set(event.pos.y);
|
|
true
|
|
}
|
|
MouseEventType::MouseExit | MouseEventType::MouseReleased => false,
|
|
MouseEventType::MouseMoved => {
|
|
return if self.pressed() {
|
|
InputEventResult::GrabMouse
|
|
} else {
|
|
InputEventResult::ObserveHover
|
|
}
|
|
}
|
|
});
|
|
result
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, _: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
KeyEventResult::EventIgnored
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
|
|
|
|
fn render(self: Pin<&Self>, _pos: Point, _backend: &mut ItemRendererRef) {}
|
|
}
|
|
|
|
impl ItemConsts for TouchArea {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<
|
|
TouchArea,
|
|
CachedRenderingData,
|
|
> = TouchArea::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `TouchArea`
|
|
#[no_mangle]
|
|
pub static TouchAreaVTable for TouchArea
|
|
}
|
|
|
|
/// A runtime item that exposes key
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
pub struct FocusScope {
|
|
pub x: Property<f32>,
|
|
pub y: Property<f32>,
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
pub has_focus: Property<bool>,
|
|
pub key_pressed: Callback<KeyEventArg>,
|
|
pub key_released: Callback<KeyEventArg>,
|
|
/// FIXME: remove this
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for FocusScope {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo::default()
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
event: MouseEvent,
|
|
window: &ComponentWindow,
|
|
self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
/*if !self.enabled() {
|
|
return InputEventResult::EventIgnored;
|
|
}*/
|
|
if matches!(event.what, MouseEventType::MousePressed) {
|
|
if !self.has_focus() {
|
|
window.set_focus_item(self_rc);
|
|
}
|
|
}
|
|
InputEventResult::EventAccepted
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, event: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
match event.event_type {
|
|
KeyEventType::KeyPressed => {
|
|
Self::FIELD_OFFSETS.key_pressed.apply_pin(self).call(&(event.clone(),));
|
|
}
|
|
KeyEventType::KeyReleased => {
|
|
Self::FIELD_OFFSETS.key_released.apply_pin(self).call(&(event.clone(),));
|
|
}
|
|
};
|
|
KeyEventResult::EventAccepted
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, event: &FocusEvent, _window: &ComponentWindow) {
|
|
match event {
|
|
FocusEvent::FocusIn | FocusEvent::WindowReceivedFocus => {
|
|
self.has_focus.set(true);
|
|
}
|
|
FocusEvent::FocusOut | FocusEvent::WindowLostFocus => {
|
|
self.has_focus.set(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn render(self: Pin<&Self>, _pos: Point, _backend: &mut ItemRendererRef) {}
|
|
}
|
|
|
|
impl ItemConsts for FocusScope {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<
|
|
FocusScope,
|
|
CachedRenderingData,
|
|
> = FocusScope::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `FocusScope`
|
|
#[no_mangle]
|
|
pub static FocusScopeVTable for FocusScope
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
/// The implementation of the `Clip` element
|
|
pub struct Clip {
|
|
pub x: Property<f32>,
|
|
pub y: Property<f32>,
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for Clip {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo { horizontal_stretch: 1., vertical_stretch: 1., ..LayoutInfo::default() }
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
_: MouseEvent,
|
|
_window: &ComponentWindow,
|
|
_self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
InputEventResult::EventIgnored
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, _: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
KeyEventResult::EventIgnored
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
|
|
|
|
fn render(self: Pin<&Self>, pos: Point, backend: &mut ItemRendererRef) {
|
|
(*backend).combine_clip(pos, self)
|
|
}
|
|
}
|
|
|
|
impl ItemConsts for Clip {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<Clip, CachedRenderingData> =
|
|
Clip::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `Clip`
|
|
#[no_mangle]
|
|
pub static ClipVTable for Clip
|
|
}
|
|
|
|
/// The implementation of the `Path` element
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
pub struct Path {
|
|
pub x: Property<f32>,
|
|
pub y: Property<f32>,
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
pub elements: Property<PathData>,
|
|
pub fill_color: Property<Color>,
|
|
pub stroke_color: Property<Color>,
|
|
pub stroke_width: Property<f32>,
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for Path {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(self.x(), self.y(), 0., 0.)
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo::default()
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
_: MouseEvent,
|
|
_window: &ComponentWindow,
|
|
_self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
InputEventResult::EventIgnored
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, _: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
KeyEventResult::EventIgnored
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
|
|
|
|
fn render(self: Pin<&Self>, pos: Point, backend: &mut ItemRendererRef) {
|
|
(*backend).draw_path(pos, self)
|
|
}
|
|
}
|
|
|
|
impl ItemConsts for Path {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<Path, CachedRenderingData> =
|
|
Path::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `Path`
|
|
#[no_mangle]
|
|
pub static PathVTable for Path
|
|
}
|
|
|
|
/// The implementation of the `Flickable` element
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
pub struct Flickable {
|
|
pub x: Property<f32>,
|
|
pub y: Property<f32>,
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
pub viewport: Rectangle,
|
|
pub interactive: Property<bool>,
|
|
data: FlickableDataBox,
|
|
|
|
/// FIXME: remove this
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for Flickable {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo::default()
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
event: MouseEvent,
|
|
_window: &ComponentWindow,
|
|
_self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
if !self.interactive() {
|
|
return InputEventResult::EventIgnored;
|
|
}
|
|
self.data.handle_mouse(self, event);
|
|
|
|
if event.what == MouseEventType::MousePressed || event.what == MouseEventType::MouseMoved {
|
|
// FIXME
|
|
InputEventResult::GrabMouse
|
|
} else {
|
|
InputEventResult::EventAccepted
|
|
}
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, _: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
KeyEventResult::EventIgnored
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
|
|
|
|
fn render(self: Pin<&Self>, _pos: Point, _backend: &mut ItemRendererRef) {}
|
|
}
|
|
|
|
impl ItemConsts for Flickable {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
|
|
Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `Flickable`
|
|
#[no_mangle]
|
|
pub static FlickableVTable for Flickable
|
|
}
|
|
|
|
pub use crate::SharedVector;
|
|
|
|
#[repr(C)]
|
|
/// Wraps the internal datastructure for the Flickable
|
|
pub struct FlickableDataBox(core::ptr::NonNull<crate::flickable::FlickableData>);
|
|
|
|
impl Default for FlickableDataBox {
|
|
fn default() -> Self {
|
|
FlickableDataBox(Box::leak(Box::new(crate::flickable::FlickableData::default())).into())
|
|
}
|
|
}
|
|
impl Drop for FlickableDataBox {
|
|
fn drop(&mut self) {
|
|
// Safety: the self.0 was constructed from a Box::leak in FlickableDataBox::default
|
|
unsafe {
|
|
Box::from_raw(self.0.as_ptr());
|
|
}
|
|
}
|
|
}
|
|
impl core::ops::Deref for FlickableDataBox {
|
|
type Target = crate::flickable::FlickableData;
|
|
fn deref(&self) -> &Self::Target {
|
|
// Safety: initialized in FlickableDataBox::default
|
|
unsafe { self.0.as_ref() }
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn sixtyfps_flickable_data_init(data: *mut FlickableDataBox) {
|
|
std::ptr::write(data, FlickableDataBox::default());
|
|
}
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn sixtyfps_flickable_data_free(data: *mut FlickableDataBox) {
|
|
std::ptr::read(data);
|
|
}
|
|
|
|
/// The implementation of the `PropertyAnimation` element
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement, Clone, Debug)]
|
|
#[pin]
|
|
pub struct PropertyAnimation {
|
|
#[rtti_field]
|
|
pub duration: i32,
|
|
#[rtti_field]
|
|
pub loop_count: i32,
|
|
#[rtti_field]
|
|
pub easing: crate::animations::EasingCurve,
|
|
}
|
|
|
|
/// The implementation of the `Window` element
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
pub struct Window {
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
pub color: Property<Color>,
|
|
pub title: Property<SharedString>,
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for Window {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(0., 0., self.width(), self.height())
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo::default()
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
_event: MouseEvent,
|
|
_window: &ComponentWindow,
|
|
_self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
InputEventResult::EventIgnored
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, _: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
KeyEventResult::EventIgnored
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
|
|
|
|
fn render(self: Pin<&Self>, _pos: Point, _backend: &mut ItemRendererRef) {}
|
|
}
|
|
|
|
impl ItemConsts for Window {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
|
|
Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `Window`
|
|
#[no_mangle]
|
|
pub static WindowVTable for Window
|
|
}
|
|
|
|
/// The implementation of the `BoxShadow` element
|
|
#[repr(C)]
|
|
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
|
#[pin]
|
|
pub struct BoxShadow {
|
|
// Rectangle properties
|
|
pub x: Property<f32>,
|
|
pub y: Property<f32>,
|
|
pub width: Property<f32>,
|
|
pub height: Property<f32>,
|
|
pub radius: Property<f32>,
|
|
// Shadow specific properties
|
|
pub offset_x: Property<f32>,
|
|
pub offset_y: Property<f32>,
|
|
pub color: Property<Color>,
|
|
pub blur: Property<f32>,
|
|
pub cached_rendering_data: CachedRenderingData,
|
|
}
|
|
|
|
impl Item for BoxShadow {
|
|
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
|
|
|
fn geometry(self: Pin<&Self>) -> Rect {
|
|
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
|
}
|
|
|
|
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
|
LayoutInfo::default()
|
|
}
|
|
|
|
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
|
Default::default()
|
|
}
|
|
|
|
fn input_event(
|
|
self: Pin<&Self>,
|
|
_event: MouseEvent,
|
|
_window: &ComponentWindow,
|
|
_self_rc: &ItemRc,
|
|
) -> InputEventResult {
|
|
InputEventResult::EventIgnored
|
|
}
|
|
|
|
fn key_event(self: Pin<&Self>, _: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
|
KeyEventResult::EventIgnored
|
|
}
|
|
|
|
fn focus_event(self: Pin<&Self>, _: &FocusEvent, _window: &ComponentWindow) {}
|
|
|
|
fn render(self: Pin<&Self>, pos: Point, backend: &mut ItemRendererRef) {
|
|
(*backend).draw_box_shadow(pos, self)
|
|
}
|
|
}
|
|
|
|
impl ItemConsts for BoxShadow {
|
|
const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
|
|
Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `BoxShadow`
|
|
#[no_mangle]
|
|
pub static BoxShadowVTable for BoxShadow
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `Text`
|
|
#[no_mangle]
|
|
pub static TextVTable for Text
|
|
}
|
|
|
|
ItemVTable_static! {
|
|
/// The VTable for `TextInput`
|
|
#[no_mangle]
|
|
pub static TextInputVTable for TextInput
|
|
}
|