mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-30 05:44:52 +00:00
314 lines
8.3 KiB
Rust
314 lines
8.3 KiB
Rust
use core::ptr::NonNull;
|
|
use vtable::*;
|
|
|
|
pub type Rect = euclid::default::Rect<f32>;
|
|
pub type Point = euclid::default::Point2D<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,
|
|
}
|
|
|
|
#[vtable]
|
|
#[repr(C)]
|
|
pub struct ComponentVTable {
|
|
/// Allocate an instance of this component
|
|
pub create: extern "C" fn(&ComponentVTable) -> VBox<ComponentVTable>,
|
|
|
|
/// Destruct this component.
|
|
pub drop: extern "C" fn(VRefMut<ComponentVTable>),
|
|
|
|
/// Returns an array that represent the item tree
|
|
pub item_tree: extern "C" fn(VRef<ComponentVTable>) -> *const ItemTreeNode,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Default)]
|
|
pub struct CachedRenderingData {
|
|
/// Used and modified by the backend, should be initialized to 0 by the user code
|
|
pub(crate) cache_index: usize,
|
|
/// Set to false initially and when changes happen that require updating the cache
|
|
pub(crate) cache_ok: bool,
|
|
}
|
|
|
|
/// The item tree is an array of ItemTreeNode representing a static tree of items
|
|
/// within a component.
|
|
#[repr(C)]
|
|
pub enum ItemTreeNode {
|
|
/// Static item
|
|
Item {
|
|
/// byte offset where we can find the item (from the *ComponentImpl)
|
|
offset: isize,
|
|
/// virtual table of the item
|
|
vtable: *const 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 {
|
|
/// Component vtable.
|
|
/// This component is going to be instantiated as many time as the model tells
|
|
component_type: *const ComponentVTable,
|
|
|
|
/// vtable of the model
|
|
model_type: *const super::model::ModelType,
|
|
|
|
/// byte offset of the ModelImpl within the component.
|
|
/// The model is an instance of the model described by model_type and must be
|
|
/// stored within the component
|
|
model_offset: isize,
|
|
|
|
/// byte offset of the vector of components within the parent component
|
|
/// (ComponentVec)
|
|
/// a ComponentVec must be stored within the component to represent this tree
|
|
components_holder_offset: isize,
|
|
},
|
|
}
|
|
|
|
/// It is supposed to be in static array
|
|
unsafe impl Sync for ItemTreeNode {}
|
|
|
|
#[vtable]
|
|
#[repr(C)]
|
|
pub struct ItemVTable {
|
|
///
|
|
pub geometry: extern "C" fn(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 a rendering info
|
|
pub rendering_info: extern "C" fn(VRef<'_, ItemVTable>) -> RenderingInfo,
|
|
|
|
/// 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),
|
|
}
|
|
|
|
// given an ItemImpl & ItemVTable
|
|
// (1) Identify that the item *is* a rectangle or has everything a rectangle would have
|
|
// (2) change the width
|
|
|
|
#[repr(C)]
|
|
pub struct LayoutInfo {
|
|
min_size: f32,
|
|
//...
|
|
width_offset: isize,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Debug)]
|
|
pub enum RenderingInfo {
|
|
NoContents,
|
|
Rectangle(f32, f32, f32, f32, u32), // Should be a beret structure
|
|
Image(f32, f32, crate::SharedString),
|
|
Text(f32, f32, crate::SharedString, u32),
|
|
/*Path(Vec<PathElement>),
|
|
Image(OpaqueImageHandle, AspectRatio)*/
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum MouseEventType {
|
|
MousePressed,
|
|
MouseReleased,
|
|
MouseMoved,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct MouseEvent {
|
|
pub pos: Point,
|
|
pub what: MouseEventType,
|
|
}
|
|
|
|
/* -- Safe wrappers*/
|
|
|
|
/// Visit each items recursively
|
|
///
|
|
/// The state parametter returned by the visitor is passed to each children.
|
|
pub fn visit_items<State>(
|
|
component: VRef<'_, ComponentVTable>,
|
|
mut visitor: impl FnMut(ItemRef<'_>, &State) -> State,
|
|
state: State,
|
|
) {
|
|
visit_internal(component, &mut visitor, 0, &state)
|
|
}
|
|
|
|
fn visit_internal<State>(
|
|
component: VRef<'_, ComponentVTable>,
|
|
visitor: &mut impl FnMut(ItemRef<'_>, &State) -> State,
|
|
index: isize,
|
|
state: &State,
|
|
) {
|
|
let item_tree = component.item_tree();
|
|
match unsafe { &*item_tree.offset(index) } {
|
|
ItemTreeNode::Item { vtable, offset, children_index, chilren_count } => {
|
|
let item = unsafe {
|
|
ItemRef::from_raw(
|
|
NonNull::new_unchecked(*vtable as *mut _),
|
|
NonNull::new_unchecked(component.as_ptr().offset(*offset) as *mut _),
|
|
)
|
|
};
|
|
let state = visitor(item, state);
|
|
for c in *children_index..(*children_index + *chilren_count) {
|
|
visit_internal(component, visitor, c as isize, &state)
|
|
}
|
|
}
|
|
ItemTreeNode::DynamicTree { .. } => todo!(),
|
|
}
|
|
}
|
|
|
|
pub fn visit_items_mut<State>(
|
|
component: VRefMut<'_, ComponentVTable>,
|
|
mut visitor: impl FnMut(ItemRefMut<'_>, &State) -> State,
|
|
state: State,
|
|
) {
|
|
visit_internal_mut(component, &mut visitor, 0, &state)
|
|
}
|
|
|
|
fn visit_internal_mut<State>(
|
|
mut component: VRefMut<'_, ComponentVTable>,
|
|
visitor: &mut impl FnMut(ItemRefMut<'_>, &State) -> State,
|
|
index: isize,
|
|
state: &State,
|
|
) {
|
|
let item_tree = component.item_tree();
|
|
match unsafe { &*item_tree.offset(index) } {
|
|
ItemTreeNode::Item { vtable, offset, children_index, chilren_count } => {
|
|
let mut item = unsafe {
|
|
ItemRefMut::from_raw(
|
|
NonNull::new_unchecked(*vtable as *mut _),
|
|
NonNull::new_unchecked(
|
|
(component.as_ptr() as *mut u8).offset(*offset) as *mut _
|
|
),
|
|
)
|
|
};
|
|
let state = visitor(item.borrow_mut(), state);
|
|
for c in *children_index..(*children_index + *chilren_count) {
|
|
visit_internal_mut(component.borrow_mut(), visitor, c as isize, &state)
|
|
}
|
|
}
|
|
ItemTreeNode::DynamicTree { .. } => todo!(),
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
/*
|
|
Button { visible: false; text: "foo"}
|
|
|
|
-> ProxyWithVisibility<NativeItem>
|
|
|
|
// Qt style selected:
|
|
fn render_button(item: *const ItemImpl) -> RenderingInfo {
|
|
let button = reinterpret_cast<&Button>(button)
|
|
let text = b.text();
|
|
let isPressed = b.isPressed();
|
|
// ...
|
|
let image = qt_render_button(width, height, isPressed, text)
|
|
|
|
return RenderingInfo::Image(image)
|
|
}
|
|
|
|
// Basic style selected:
|
|
|
|
-> Rectangle / Text
|
|
|
|
fn render_rectangle(item: *const ItemImpl) -> RenderingInfo {
|
|
let rect = reinterpret_cast<&Rectangle>(item)
|
|
...
|
|
return RenderingInfo::Path(rect_path)
|
|
}
|
|
|
|
fn render_text(item: *const ItemImpl) -> RenderInfo {
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
// in corelib/primitives.rs
|
|
|
|
bitflags! {
|
|
enum ItemExtensions {
|
|
HasVisibility,
|
|
HasOpacity
|
|
}
|
|
}
|
|
|
|
struct ItemBase {
|
|
extensions: ItemExtensions,
|
|
x: Property<f32>,
|
|
y: Property<f32>,
|
|
// visible, opacity, ?
|
|
extraData: Vec<...>
|
|
}
|
|
|
|
impl ItemBase {
|
|
pub fn is_visible(&self) -> bool {
|
|
if self.extensions & HasVisibility {
|
|
return self.extraData
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(SixtyFpsItem)]
|
|
/// ```
|
|
/// width: f32
|
|
/// height: f32
|
|
/// ```
|
|
fn render_rectangle(item: *const ItemImpl) -> RenderingInfo {
|
|
//let width = property_at_offset(item, 1);
|
|
let rect : &Rectnalge = unsafe { std::mem::transmute(item) };
|
|
let width = rect.width.get()
|
|
}
|
|
|
|
|
|
pub static RECTANGLE_VTABLE: ItemVTable = ItemVTable {
|
|
rendering_info: render_rectangle,
|
|
}
|
|
|
|
// in styles/qt.rs
|
|
|
|
//#[derive(SixtyFpsItem)]
|
|
struct QtButton {
|
|
text: String,
|
|
is_pressed: bool,
|
|
}
|
|
|
|
|
|
pub static QT_BUTTON_VTABLE: ItemVTable = ItemVTable {
|
|
rendering_info: render_qt_button,
|
|
};
|
|
*/
|
|
|
|
// This is here because for some reason (rust bug?) the ItemVTable_static is not accessible in the other modules
|
|
ItemVTable_static!(crate::abi::primitives::Image);
|
|
ItemVTable_static!(crate::abi::primitives::Rectangle);
|
|
ItemVTable_static!(crate::abi::primitives::Text);
|
|
ItemVTable_static!(crate::abi::primitives::TouchArea);
|