Replies: 2 comments 2 replies
-
We don't have a documented helper yet for creating C++ Qt objects from Rust (it is something we are considering automatically implementing). For now you could just add a C++ trampoline which creates the object, you could also use the template from cxx-qt-lib to do this. #[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
include!("cxx-qt-lib/common.h");
#[rust_name = "imageprovider_init_default"]
fn construct() -> ImageProvider;
} Adding this block may then allow you to use unsafe extern "C++" {
include!("helper.h");
#[rust_name = "imageprovider_new"]
fn imageProviderNew() -> UniquePtr<ImageProvider>;
} then have a C++ #include <memory>
class ImageProvider;
::std::unique_ptr<ImageProvider>
imageProviderNew(); and a C++ #include "helper.h"
#include "cxx-qt-gen/image_provider.h"
::std::unique_ptr<ImageProvider>
imageProviderNew()
{
return ::std::make_unique<ImageProvider>();
} Then ensure that the C++ header and source is included in your CxxQtBuilder::new()
...
.cc_builder(|cc| {
cc.include("../cpp");
cc.file("../cpp/helper.cpp");
}) Then you can use the UniquePtr type in Rust to reach the raw pointer :-) @LeonMatthesKDAB this seems to be a good argument for use generating a |
Beta Was this translation helpful? Give feedback.
-
Thanks. After adding the custom constructor and hacking the system's Qt qquickimageprovider.h header file to make requestImage const (see below) I have the following code working. image_provider.rs #[cxx_qt::bridge(cxx_file_stem = "image_provider")]
pub mod qobject {
#[repr(i32)]
#[derive(Debug)]
pub enum QQmlImageProviderBaseImageType {
Invalid=0,
Image,
Pixmap,
Texture,
ImageResponse,
}
#[repr(i32)]
#[derive(Debug)]
pub enum QQmlImageProviderBaseFlag {
ForceAsynchronousImageLoading=1
}
// Expose C++ types
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = cxx_qt_lib::QString;
include!("cxx-qt-lib/qimage.h");
type QImage = cxx_qt_lib::QImage;
include!("cxx-qt-lib/qsize.h");
type QSize = cxx_qt_lib::QSize;
include!(<QtQuick/QQuickImageProvider>);
type QQuickImageProvider;
}
//
extern "RustQt" {
#[qobject]
#[base = "QQuickImageProvider"]
type ImageProvider = super::ImageProviderRust;
}
unsafe extern "RustQt" {
#[cxx_override]
unsafe fn request_image(self: &ImageProvider, id: &QString, size: *mut QSize, requested_size: &QSize) -> QImage;
}
unsafe extern "C++" {
include!("cxx-qt-lib/common.h");
type QQmlImageProviderBaseImageType;
type QQmlImageProviderBaseFlag;
include!("helper.h");
#[rust_name = "imageprovider_new"]
fn imageProviderNew(img_type: QQmlImageProviderBaseImageType) -> UniquePtr<ImageProvider>;
}
impl cxx_qt::Constructor<(QQmlImageProviderBaseImageType,), BaseArguments=(QQmlImageProviderBaseImageType,)> for ImageProvider {}
impl cxx_qt::Threading for ImageProvider {}
impl UniquePtr<ImageProvider> {}
}
use cxx_qt_lib::{QColor, QImage, QImageFormat, QString, QSize, QQmlImageProviderBasePointer, QQuickImageProvider};
use qobject::QQmlImageProviderBaseImageType;
#[derive(Default)]
pub struct ImageProviderRust;
impl qobject::ImageProvider {
pub fn new(img_type: QQmlImageProviderBaseImageType) -> QQmlImageProviderBasePointer {
QQmlImageProviderBasePointer::QQuickImageProvider(qobject::imageprovider_new(img_type).into_raw() as *mut QQuickImageProvider)
}
pub fn request_image(&self, id: &QString, _size: *mut QSize, requested_size: &QSize) -> QImage {
println!("Rust: request_image size {}, {}", requested_size.width(), requested_size.height());
let id2: i32 = String::from(id).parse().unwrap_or(0) % 3;
let color = match id2 {
0 => { QColor::from_rgb(255, 0, 0) },
1 => { QColor::from_rgb(0, 255, 0) },
_ => { QColor::from_rgb(0, 0, 255) },
};
let mut qimage = QImage::from_height_width_and_format(requested_size.width(), requested_size.height(), QImageFormat::Format_ARGB32);
qimage.fill(&color);
qimage
}
}
impl cxx_qt::Constructor<(QQmlImageProviderBaseImageType,)> for qobject::ImageProvider {
type BaseArguments = (QQmlImageProviderBaseImageType,);
type InitializeArguments = ();
type NewArguments = ();
fn route_arguments(args: (QQmlImageProviderBaseImageType,)) -> (
Self::NewArguments,
Self::BaseArguments,
Self::InitializeArguments
) {
((), args, ())
}
fn new(():()) -> ImageProviderRust {
ImageProviderRust {}
}
} main.rs mod bridge;
mod process;
mod utils;
mod image_provider;
use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl, QString};
use crate::image_provider::qobject::{QQmlImageProviderBaseImageType, ImageProvider};
fn main() {
// Create the application and engine
let mut app = QGuiApplication::new();
let mut engine = QQmlApplicationEngine::new();
// Set the image provider
if let Some(engine) = engine.as_mut() {
// Create an image provider and add it to the engine
let provider = ImageProvider::new(QQmlImageProviderBaseImageType::Image);
unsafe {
engine.add_image_provider(&QString::from("myprovider"), provider);
}
}
// Load the QML path into the engine
if let Some(engine) = engine.as_mut() {
engine.load(&QUrl::from("qrc:/qt/qml/com/github/mneilly/mvd/qml/main.qml"));
}
// Start the app
if let Some(app) = app.as_mut() {
app.exec();
}
} cxx-qt-lib diff diff --git a/crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h b/crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h
index ea7cafa1..119353bc 100644
--- a/crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h
+++ b/crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h
@@ -11,6 +11,7 @@
#include <memory>
#include <QtQml/QQmlApplicationEngine>
+#include <QtQuick/QQuickImageProvider>
namespace rust {
namespace cxxqtlib1 {
diff --git a/crates/cxx-qt-lib/src/gui/mod.rs b/crates/cxx-qt-lib/src/gui/mod.rs
index 49052357..6fcc8cc2 100644
--- a/crates/cxx-qt-lib/src/gui/mod.rs
+++ b/crates/cxx-qt-lib/src/gui/mod.rs
@@ -19,4 +19,4 @@ mod qvector4d;
pub use qvector4d::QVector4D;
mod qimage;
-pub use qimage::QImage;
+pub use qimage::{QImage, ffi::QImageFormat};
diff --git a/crates/cxx-qt-lib/src/gui/qimage.rs b/crates/cxx-qt-lib/src/gui/qimage.rs
index 278606a7..db5c9ab3 100644
--- a/crates/cxx-qt-lib/src/gui/qimage.rs
+++ b/crates/cxx-qt-lib/src/gui/qimage.rs
@@ -7,7 +7,7 @@ use cxx::{type_id, ExternType};
use std::mem::MaybeUninit;
#[cxx::bridge]
-mod ffi {
+pub(crate) mod ffi {
#[namespace = "Qt"]
unsafe extern "C++" {
include!("cxx-qt-lib/qt.h");
@@ -19,7 +19,7 @@ mod ffi {
#[repr(i32)]
#[namespace = "rust::cxxqtlib1"]
#[derive(Debug)]
- enum QImageFormat {
+ pub enum QImageFormat {
Format_Invalid,
Format_Mono,
Format_MonoLSB,
diff --git a/crates/cxx-qt-lib/src/qml/mod.rs b/crates/cxx-qt-lib/src/qml/mod.rs
index 589405e4..050ba042 100644
--- a/crates/cxx-qt-lib/src/qml/mod.rs
+++ b/crates/cxx-qt-lib/src/qml/mod.rs
@@ -4,7 +4,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
mod qqmlapplicationengine;
-pub use qqmlapplicationengine::QQmlApplicationEngine;
+pub use qqmlapplicationengine::{QQmlApplicationEngine, QQmlImageProviderBasePointer, ffi::QQuickImageProvider};
mod qqmlengine;
pub use qqmlengine::QQmlEngine;
diff --git a/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs b/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs
index 6440f6fc..54ebf9a1 100644
--- a/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs
+++ b/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs
@@ -4,7 +4,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
#[cxx::bridge]
-mod ffi {
+pub(crate) mod ffi {
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = crate::QString;
@@ -12,10 +12,20 @@ mod ffi {
type QStringList = crate::QStringList;
include!("cxx-qt-lib/qurl.h");
type QUrl = crate::QUrl;
+ include!(<QQmlImageProviderBase>);
+ type QQmlImageProviderBase;
+ include!(<QtQuick/QQuickImageProvider>);
+ type QQuickImageProvider;
+ include!(<QtQuick/QQuickAsyncImageProvider>);
+ type QQuickAsyncImageProvider;
include!("cxx-qt-lib/qqmlapplicationengine.h");
type QQmlApplicationEngine;
+ /// Sets the provider to use for images requested via the image: url scheme, with host providerId.
+ #[rust_name = "add_image_provider_internal"]
+ unsafe fn addImageProvider(self: Pin<&mut QQmlApplicationEngine>, provider_id: &QString, provider: *mut QQmlImageProviderBase);
+
/// Adds path as a directory where the engine searches for installed modules in a URL-based directory structure.
#[rust_name = "add_import_path"]
fn addImportPath(self: Pin<&mut QQmlApplicationEngine>, path: &QString);
@@ -75,11 +85,32 @@ mod ffi {
impl UniquePtr<QQmlApplicationEngine> {}
}
+use std::pin::Pin;
pub use ffi::QQmlApplicationEngine;
+use crate::QString;
+use ffi::QQmlImageProviderBase;
+
+#[allow(dead_code)]
+pub enum QQmlImageProviderBasePointer {
+ QQuickImageProvider(*mut ffi::QQuickImageProvider),
+ QQuickAsyncImageProvider(*mut ffi::QQuickAsyncImageProvider)
+}
impl QQmlApplicationEngine {
/// Create a new QQmlApplicationEngine
pub fn new() -> cxx::UniquePtr<Self> {
ffi::qqmlapplicationengine_new()
}
+
+ pub unsafe fn add_image_provider(self: Pin<&mut QQmlApplicationEngine>, provider_id: &QString, provider: QQmlImageProviderBasePointer) {
+ let ptr = match provider {
+ QQmlImageProviderBasePointer::QQuickAsyncImageProvider(ptr) => {
+ ptr as *mut QQmlImageProviderBase
+ },
+ QQmlImageProviderBasePointer::QQuickImageProvider(ptr) => {
+ ptr as *mut QQmlImageProviderBase
+ }
+ };
+ self.add_image_provider_internal(provider_id, ptr);
+ }
}
diff --git a/examples/cargo_without_cmake/build.rs b/examples/cargo_without_cmake/build.rs
index 79a91b6a..2db073d0 100644
--- a/examples/cargo_without_cmake/build.rs
+++ b/examples/cargo_without_cmake/build.rs
@@ -14,6 +14,7 @@ fn main() {
// - Qt Qml is linked by enabling the qt_qml Cargo feature (default).
// - Qt Qml requires linking Qt Network on macOS
.qt_module("Network")
+ .qt_module("Quick")
.qml_module(QmlModule {
uri: "com.kdab.cxx_qt.demo",
rust_files: &["src/cxxqt_object.rs"], The generated image_provider.cxxqt.h declares requestImage as
I hacked the system file just to prove it would compile and work. Is there a way to control the const qualifier in the generated code? |
Beta Was this translation helpful? Give feedback.
-
I'm attempting to use QQuickImageProvider. I'm also using a Cargo without CMake build. I've hacked cxx-qt-lib (main) locally to provide addImageProvider then created my bridge to override requestImage. There doesn't seem to be a way to create an instance of my image provider on the Rust side to pass to addImageProvider.
I've made the following mods to cxx-qt to support addImageProvider (plan was to appropriately replace the c_void later):
Then, I inherit from QQuickImageProvider and override requestImage:
Then was expecting to use it as follows:
But of course ImageProvider::new() doesn't exist. Is there any way to create an instance with the request_image override?
I'm wondering if creating a CxxQtQQuickImageProvider subclass of QQuickImageProvider which overrides requestImage in C++ and calls a Rust function is the way to go? Then a CxxQtQQuickImageProviderNew function can be provided similar to what is done for QQmlApplicationEngine.
Beta Was this translation helpful? Give feedback.
All reactions