use super::scenegraph::*;
use super::*;
static HAS_ENGINE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
cpp! {{
#include <memory>
#include <QtQuick/QtQuick>
#include <QtCore/QDebug>
#include <QtWidgets/QApplication>
#include <QtQml/QQmlComponent>
struct SingleApplicationGuard {
SingleApplicationGuard() {
rust!(Rust_QmlEngineHolder_ctor[] {
HAS_ENGINE.compare_exchange(false, true, std::sync::atomic::Ordering::SeqCst, std::sync::atomic::Ordering::SeqCst)
.expect("There can only be one QmlEngine in the process");
});
}
~SingleApplicationGuard() {
rust!(Rust_QmlEngineHolder_dtor[] {
HAS_ENGINE.compare_exchange(true, false, std::sync::atomic::Ordering::SeqCst, std::sync::atomic::Ordering::SeqCst)
.unwrap();
});
}
};
struct QmlEngineHolder : SingleApplicationGuard {
std::unique_ptr<QApplication> app;
std::unique_ptr<QQmlApplicationEngine> engine;
std::unique_ptr<QQuickView> view;
static QApplication* createApplication() {
static int argc = 1;
static char name[] = "rust";
static char *argv[] = { name };
return new QApplication(argc, argv);
}
QmlEngineHolder() : app(createApplication()), engine(new QQmlApplicationEngine) { }
};
}}
cpp_class!(
pub unsafe struct QmlEngine as "QmlEngineHolder"
);
impl QmlEngine {
pub fn new() -> QmlEngine {
Default::default()
}
pub fn load_file(&mut self, path: QString) {
unsafe {
cpp!([self as "QmlEngineHolder*", path as "QString"] {
self->engine->load(path);
})
}
}
pub fn load_data(&mut self, data: QByteArray) {
unsafe {
cpp!([self as "QmlEngineHolder*", data as "QByteArray"] {
self->engine->loadData(data);
})
}
}
pub fn load_data_as(&mut self, data: QByteArray, url: QUrl) {
unsafe {
cpp!([self as "QmlEngineHolder*", data as "QByteArray", url as "QUrl"] {
self->engine->loadData(data, url);
})
}
}
pub fn exec(&self) {
unsafe { cpp!([self as "QmlEngineHolder*"] { self->app->exec(); }) }
}
pub fn quit(&self) {
unsafe { cpp!([self as "QmlEngineHolder*"] { self->app->quit(); }) }
}
pub fn set_property(&mut self, name: QString, value: QVariant) {
unsafe {
cpp!([self as "QmlEngineHolder*", name as "QString", value as "QVariant"] {
self->engine->rootContext()->setContextProperty(name, value);
})
}
}
pub fn set_object_property<T: QObject + Sized>(
&mut self,
name: QString,
obj: QObjectPinned<T>,
) {
let obj_ptr = obj.get_or_create_cpp_object();
cpp!(unsafe [self as "QmlEngineHolder*", name as "QString", obj_ptr as "QObject*"] {
self->engine->rootContext()->setContextProperty(name, obj_ptr);
})
}
pub fn invoke_method(&mut self, name: QByteArray, args: &[QVariant]) -> QVariant {
let args_size = args.len();
let args_ptr = args.as_ptr();
unsafe {
cpp!([self as "QmlEngineHolder*", name as "QByteArray", args_size as "size_t", args_ptr as "QVariant*"]
-> QVariant as "QVariant" {
auto robjs = self->engine->rootObjects();
if (robjs.isEmpty())
return {};
QVariant ret;
QGenericArgument args[9] = {};
for (uint i = 0; i < args_size; ++i)
args[i] = Q_ARG(QVariant, args_ptr[i]);
QMetaObject::invokeMethod(robjs.first(), name, Q_RETURN_ARG(QVariant,ret),
args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
return ret;
})
}
}
pub fn new_qobject<T: QObject>(&mut self, obj: T) -> QJSValue {
let obj_ptr = into_leaked_cpp_ptr(obj);
unsafe {
cpp!([self as "QmlEngineHolder*", obj_ptr as "QObject*"] -> QJSValue as "QJSValue" {
return self->engine->newQObject(obj_ptr);
})
}
}
pub fn add_import_path(&mut self, path: QString) {
unsafe {
cpp!([self as "QmlEngineHolder*", path as "QString"] {
self->engine->addImportPath(path);
})
}
}
}
pub struct QQuickView {
engine: QmlEngine,
}
impl QQuickView {
pub fn new() -> QQuickView {
let mut engine = QmlEngine::new();
unsafe {
cpp!([mut engine as "QmlEngineHolder"] {
engine.view = std::unique_ptr<QQuickView>(new QQuickView(engine.engine.get(), nullptr));
engine.view->setResizeMode(QQuickView::SizeRootObjectToView);
} )
};
QQuickView { engine }
}
pub fn engine(&mut self) -> &mut QmlEngine {
&mut self.engine
}
pub fn show(&mut self) {
let engine = self.engine();
unsafe {
cpp!([engine as "QmlEngineHolder*"] {
engine->view->show();
} )
};
}
pub fn set_source(&mut self, url: QString) {
let engine = self.engine();
unsafe {
cpp!([engine as "QmlEngineHolder*", url as "QString"] {
engine->view->setSource(url);
} )
};
}
}
impl Default for QQuickView {
fn default() -> Self {
Self::new()
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CompilationMode {
PreferSynchronous,
Asynchronous,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ComponentStatus {
Null,
Ready,
Loading,
Error,
}
cpp! {{
struct QQmlComponentHolder {
std::unique_ptr<QQmlComponent> component;
QQmlComponentHolder(QQmlEngine *e) : component(new QQmlComponent(e)) {}
};
}}
cpp_class!(
pub unsafe struct QmlComponent as "QQmlComponentHolder"
);
impl QmlComponent {
pub fn new(engine: &QmlEngine) -> QmlComponent {
unsafe {
cpp!([engine as "QmlEngineHolder*"] -> QmlComponent as "QQmlComponentHolder" {
return QQmlComponentHolder(engine->engine.get());
})
}
}
pub fn get_cpp_object(&self) -> *mut c_void {
unsafe { cpp!([self as "QQmlComponentHolder*"] -> *mut c_void as "QQmlComponent*" {
return self->component.get();
})}
}
pub fn load_url(&mut self, url: QUrl, compilation_mode: CompilationMode) {
unsafe { cpp!([self as "QQmlComponentHolder*", url as "QUrl", compilation_mode as "QQmlComponent::CompilationMode"]{
self->component->loadUrl(url, compilation_mode);
})}
}
pub fn set_data(&mut self, data: QByteArray) {
unsafe { cpp!([self as "QQmlComponentHolder*", data as "QByteArray"]{
self->component->setData(data, QUrl());
})}
}
pub fn set_data_as(&mut self, data: QByteArray, url: QUrl) {
unsafe { cpp!([self as "QQmlComponentHolder*", data as "QByteArray", url as "QUrl"]{
self->component->setData(data, url);
})}
}
pub fn create(&mut self) -> *mut c_void {
unsafe { cpp!([self as "QQmlComponentHolder*"] -> *mut c_void as "QObject*" {
return self->component->create();
})}
}
pub fn status(&self) -> ComponentStatus {
unsafe { cpp!([self as "QQmlComponentHolder*"] -> ComponentStatus as "QQmlComponent::Status" {
return self->component->status();
})}
}
pub fn status_changed_signal() -> CppSignal<fn(status: ComponentStatus)> {
unsafe { CppSignal::new(cpp!([] -> SignalCppRepresentation as "SignalCppRepresentation" {
return &QQmlComponent::statusChanged;
}))}
}
}
pub fn qml_register_type<T: QObject + Default + Sized>(
uri: &std::ffi::CStr,
version_major: u32,
version_minor: u32,
qml_name: &std::ffi::CStr,
) {
let uri_ptr = uri.as_ptr();
let qml_name_ptr = qml_name.as_ptr();
let meta_object = T::static_meta_object();
extern "C" fn extra_destruct(c: *mut c_void) {
unsafe { cpp!([c as "QObject*"]{ QQmlPrivate::qdeclarativeelement_destructor(c); }) }
}
extern "C" fn creator_fn<T: QObject + Default + Sized>(c: *mut c_void) {
let b: Box<RefCell<T>> = Box::new(RefCell::new(T::default()));
let ed: extern "C" fn(c: *mut c_void) = extra_destruct;
unsafe {
T::qml_construct(&b, c, ed);
}
std::boxed::Box::into_raw(b);
};
let creator_fn: extern "C" fn(c: *mut c_void) = creator_fn::<T>;
let size = T::cpp_size();
unsafe { cpp!([qml_name_ptr as "char*", uri_ptr as "char*", version_major as "int",
version_minor as "int", meta_object as "const QMetaObject *",
creator_fn as "CreatorFunction", size as "size_t"]{
const char *className = qml_name_ptr;
const int nameLen = int(strlen(className));
QVarLengthArray<char,48> pointerName(nameLen+2);
memcpy(pointerName.data(), className, size_t(nameLen));
pointerName[nameLen] = '*';
pointerName[nameLen+1] = '\0';
auto ptrType = QMetaType::registerNormalizedType(pointerName.constData(),
QtMetaTypePrivate::QMetaTypeFunctionHelper<void*>::Destruct,
QtMetaTypePrivate::QMetaTypeFunctionHelper<void*>::Construct,
int(sizeof(void*)), QMetaType::MovableType | QMetaType::PointerToQObject,
meta_object);
int parserStatusCast = meta_object && meta_object->inherits(&QQuickItem::staticMetaObject)
? QQmlPrivate::StaticCastSelector<QQuickItem,QQmlParserStatus>::cast() : -1;
QQmlPrivate::RegisterType type = {
0 , ptrType, 0,
int(size), creator_fn,
QString(),
uri_ptr, version_major, version_minor, qml_name_ptr, meta_object,
nullptr, nullptr,
parserStatusCast, -1, -1,
nullptr, nullptr,
nullptr,
0
};
QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
})}
}
pub fn qml_register_enum<T: QEnum>(
uri: &std::ffi::CStr,
version_major: u32,
version_minor: u32,
qml_name: &std::ffi::CStr,
) {
let uri_ptr = uri.as_ptr();
let qml_name_ptr = qml_name.as_ptr();
let meta_object = T::static_meta_object();
unsafe {
cpp!([qml_name_ptr as "char*", uri_ptr as "char*", version_major as "int",
version_minor as "int", meta_object as "const QMetaObject *"]{
qmlRegisterUncreatableMetaObject(*meta_object, uri_ptr, version_major,
version_minor, qml_name_ptr, "Access to enums & flags only");
})
}
}
pub trait QQuickItem: QObject {
fn get_object_description() -> &'static QObjectDescription
where
Self: Sized,
{
unsafe {
&*cpp!([]-> *const QObjectDescription as "RustObjectDescription const*" {
return rustObjectDescription<Rust_QQuickItem>();
} )
}
}
fn class_begin(&mut self) {}
fn component_complete(&mut self) {}
fn mouse_event(&mut self, _event: QMouseEvent) -> bool {
false
}
fn geometry_changed(&mut self, _new_geometry: QRectF, _old_geometry: QRectF) {}
fn update_paint_node(&mut self, node: SGNode<ContainerNode>) -> SGNode<ContainerNode> {
node
}
}
cpp! {{
#include <qmetaobject_rust.hpp>
#include <QtQuick/QQuickItem>
struct Rust_QQuickItem : RustObject<QQuickItem> {
void classBegin() override {
QQuickItem::classBegin();
rust!(Rust_QQuickItem_classBegin[rust_object : QObjectPinned<dyn QQuickItem> as "TraitObject"] {
rust_object.borrow_mut().class_begin();
});
}
void componentComplete() override {
QQuickItem::componentComplete();
rust!(Rust_QQuickItem_componentComplete[rust_object : QObjectPinned<dyn QQuickItem> as "TraitObject"] {
rust_object.borrow_mut().component_complete();
});
}
void mousePressEvent(QMouseEvent *event) override { handleMouseEvent(event); }
void mouseMoveEvent(QMouseEvent *event) override { handleMouseEvent(event); }
void mouseReleaseEvent(QMouseEvent *event) override { handleMouseEvent(event); }
void handleMouseEvent(QMouseEvent *event) {
if (!rust!(Rust_QQuickItem_mousePressEvent[
rust_object : QObjectPinned<dyn QQuickItem> as "TraitObject",
event : QMouseEvent as "QMouseEvent*"
] -> bool as "bool" {
rust_object.borrow_mut().mouse_event(event)
})) { event->ignore(); }
}
virtual void geometryChanged(const QRectF &new_geometry,
const QRectF &old_geometry) {
rust!(Rust_QQuickItem_geometryChanged[rust_object : QObjectPinned<dyn QQuickItem> as "TraitObject",
new_geometry : QRectF as "QRectF", old_geometry : QRectF as "QRectF"] {
rust_object.borrow_mut().geometry_changed(new_geometry, old_geometry);
});
QQuickItem::geometryChanged(new_geometry, old_geometry);
}
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override {
return rust!(Rust_QQuickItem_updatePaintNode[rust_object : QObjectPinned<dyn QQuickItem> as "TraitObject",
node : *mut c_void as "QSGNode*"] -> SGNode<ContainerNode> as "QSGNode*" {
rust_object.borrow_mut().update_paint_node(unsafe { SGNode::<ContainerNode>::from_raw(node) })
});
}
};
}}
impl<'a> dyn QQuickItem + 'a {
pub fn bounding_rect(&self) -> QRectF {
let obj = self.get_cpp_object();
cpp!(unsafe [obj as "Rust_QQuickItem*"] -> QRectF as "QRectF" {
return obj ? obj->boundingRect() : QRectF();
})
}
pub fn update(&self) {
let obj = self.get_cpp_object();
cpp!(unsafe [obj as "Rust_QQuickItem*"] { if (obj) obj->update(); });
}
}
#[repr(u32)]
pub enum QMouseEventType {
MouseButtonPress = 2,
MouseButtonRelease = 3,
MouseMove = 5,
}
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct QMouseEvent<'a>(*const c_void, std::marker::PhantomData<&'a u32>);
impl<'a> QMouseEvent<'a> {
pub fn event_type(self) -> QMouseEventType {
cpp!(unsafe [self as "QMouseEvent*"] -> QMouseEventType as "int" { return self->type(); })
}
pub fn position(self) -> QPointF {
cpp!(unsafe [self as "QMouseEvent*"] -> QPointF as "QPointF" { return self->localPos(); })
}
}
cpp_class!(
pub unsafe struct QJSValue as "QJSValue"
);
impl QJSValue {
pub fn to_string(&self) -> QString {
unsafe {
cpp!([self as "const QJSValue*"] -> QString as "QString" { return self->toString(); })
}
}
pub fn to_bool(&self) -> bool {
unsafe { cpp!([self as "const QJSValue*"] -> bool as "bool" { return self->toBool(); }) }
}
pub fn to_number(&self) -> f64 {
unsafe { cpp!([self as "const QJSValue*"] -> f64 as "double" { return self->toNumber(); }) }
}
pub fn to_variant(&self) -> QVariant {
unsafe {
cpp!([self as "const QJSValue*"] -> QVariant as "QVariant" { return self->toVariant(); })
}
}
pub fn to_qobject<'a, T: QObject + 'a>(&'a self) -> Option<QObjectPinned<'a, T>> {
let mo = T::static_meta_object();
let obj = unsafe {
cpp!([self as "const QJSValue*", mo as "const QMetaObject*"] -> *mut c_void as "QObject*" {
QObject *obj = self->toQObject();
return obj && obj->metaObject()->inherits(mo) ? obj : nullptr;
})
};
if obj.is_null() {
return None;
}
Some(unsafe { T::get_from_cpp(obj) })
}
}
impl From<QString> for QJSValue {
fn from(a: QString) -> QJSValue {
unsafe { cpp!([a as "QString"] -> QJSValue as "QJSValue" { return QJSValue(a); }) }
}
}
impl From<i32> for QJSValue {
fn from(a: i32) -> QJSValue {
unsafe { cpp!([a as "int"] -> QJSValue as "QJSValue" { return QJSValue(a); }) }
}
}
impl From<u32> for QJSValue {
fn from(a: u32) -> QJSValue {
unsafe { cpp!([a as "uint"] -> QJSValue as "QJSValue" { return QJSValue(a); }) }
}
}
impl From<f64> for QJSValue {
fn from(a: f64) -> QJSValue {
unsafe { cpp!([a as "double"] -> QJSValue as "QJSValue" { return QJSValue(a); }) }
}
}
impl From<bool> for QJSValue {
fn from(a: bool) -> QJSValue {
unsafe { cpp!([a as "bool"] -> QJSValue as "QJSValue" { return QJSValue(a); }) }
}
}
#[cfg(test)]
mod qjsvalue_tests {
use super::*;
#[test]
fn test_qjsvalue() {
let foo = QJSValue::from(45);
assert_eq!(foo.to_number(), 45 as f64);
assert_eq!(foo.to_string(), "45".into());
assert_eq!(foo.to_variant().to_qbytearray(), "45".into());
}
#[test]
fn test_qvariantlist_from_iter() {
let v = vec![1u32, 2u32, 3u32];
let qvl: QVariantList = v.iter().collect();
assert_eq!(qvl.len(), 3);
assert_eq!(qvl[1].to_qbytearray().to_string(), "2");
}
}
pub trait QQmlExtensionPlugin: QObject {
#[doc(hidden)]
fn get_object_description() -> &'static QObjectDescription
where
Self: Sized,
{
unsafe {
&*cpp!([]-> *const QObjectDescription as "RustObjectDescription const*" {
return rustObjectDescription<Rust_QQmlExtensionPlugin>();
} )
}
}
fn register_types(&mut self, uri: &std::ffi::CStr);
}
cpp! {{
#include <qmetaobject_rust.hpp>
#include <QtQml/QQmlExtensionPlugin>
struct Rust_QQmlExtensionPlugin : RustObject<QQmlExtensionPlugin> {
void registerTypes(const char *uri) override {
rust!(Rust_QQmlExtensionPlugin_registerTypes[rust_object : QObjectPinned<dyn QQmlExtensionPlugin> as "TraitObject",
uri : *const std::os::raw::c_char as "const char*"] {
rust_object.borrow_mut().register_types(unsafe { std::ffi::CStr::from_ptr(uri) });
});
}
};
}}