Skip to content

Commit

Permalink
cxx-qt-lib: add QQmlEngine
Browse files Browse the repository at this point in the history
Related to KDAB#291
Related to KDAB#113
  • Loading branch information
ahayzen-kdab committed Jan 12, 2023
1 parent 6a7944c commit f087752
Show file tree
Hide file tree
Showing 16 changed files with 173 additions and 12 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Added

- Support for container types: `QSet<T>`, `QHash<K, V>`, `QList<T>`, `QMap<K, V>`, `QVector<T>`
- Support for further types: `QByteArray`, `QCoreApplication`, `QGuiApplication`, `QModelIndex`, `QPersistentModelIndex`, `QStringList`, `QVector2D`, `QVector3D`, `QVector4D`
- Support for further types: `QByteArray`, `QCoreApplication`, `QGuiApplication`, `QModelIndex`, `QPersistentModelIndex`, `QQmlEngine`, `QStringList`, `QVector2D`, `QVector3D`, `QVector4D`
- Support for nesting objects in properties, invokables, and signals with `*mut T`

### Changed

- `QVariant` now has a uses a `QVariantValue` trait for supported types, allowing custom types to be used with QVariant
- `QtGui` types in cxx-qt-lib are now behind a feature `qt_gui`
- `QtGui` and `QtQml` types in cxx-qt-lib are now behind the features `qt_gui` and `qt_qml`

### Fixed

Expand Down
3 changes: 2 additions & 1 deletion crates/cxx-qt-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ quote.workspace = true
qt-build-utils.workspace = true

[features]
default = ["qt_gui"]
default = ["qt_gui", "qt_qml"]
qt_gui = ["cxx-qt-lib-headers/qt_gui"]
qt_qml = ["cxx-qt-lib-headers/qt_qml"]
5 changes: 5 additions & 0 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ impl CxxQtBuilder {
qt_modules.insert("Core".to_owned());
#[cfg(feature = "qt_gui")]
qt_modules.insert("Gui".to_owned());
#[cfg(feature = "qt_qml")]
qt_modules.insert("Qml".to_owned());
Self {
rust_sources: vec![],
qobject_headers: vec![],
Expand Down Expand Up @@ -360,6 +362,9 @@ impl CxxQtBuilder {
// Enable Qt Gui in C++ if the feature is enabled
#[cfg(feature = "qt_gui")]
self.cc_builder.define("CXX_QT_GUI_FEATURE", None);
// Enable Qt Gui in C++ if the feature is enabled
#[cfg(feature = "qt_qml")]
self.cc_builder.define("CXX_QT_QML_FEATURE", None);

let mut qtbuild = qt_build_utils::QtBuild::new(self.qt_modules.into_iter().collect())
.expect("Could not find Qt installation");
Expand Down
1 change: 1 addition & 0 deletions crates/cxx-qt-lib-headers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ repository.workspace = true
[features]
default = []
qt_gui = []
qt_qml = []
24 changes: 24 additions & 0 deletions crates/cxx-qt-lib-headers/include/qml/qqmlengine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#ifdef CXX_QT_QML_FEATURE

#include <memory>

#include <QtQml/QQmlEngine>

namespace rust {
namespace cxxqtlib1 {

::std::unique_ptr<QQmlEngine>
qqmlengineNew();

}
}

#endif
2 changes: 2 additions & 0 deletions crates/cxx-qt-lib-headers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ pub fn write_headers(directory: impl AsRef<Path>) {
(include_str!("../include/gui/qvector3d.h"), "qvector3d.h"),
#[cfg(feature = "qt_gui")]
(include_str!("../include/gui/qvector4d.h"), "qvector4d.h"),
#[cfg(feature = "qt_qml")]
(include_str!("../include/qml/qqmlengine.h"), "qqmlengine.h"),
(include_str!("../include/common.h"), "common.h"),
(include_str!("../include/convert.h"), "convert.h"),
(include_str!("../include/cxxqt_thread.h"), "cxxqt_thread.h"),
Expand Down
3 changes: 2 additions & 1 deletion crates/cxx-qt-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ cxx-qt-lib-headers.workspace = true
qt-build-utils.workspace = true

[features]
default = ["qt_gui"]
default = ["qt_gui", "qt_qml"]
qt_gui = ["cxx-qt-lib-headers/qt_gui"]
qt_qml = ["cxx-qt-lib-headers/qt_qml"]
21 changes: 21 additions & 0 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@

fn main() {
let feature_qt_gui_enabled = std::env::var("CARGO_FEATURE_QT_GUI").is_ok();
let feature_qt_qml_enabled = std::env::var("CARGO_FEATURE_QT_QML").is_ok();

let mut qt_modules = vec!["Core".to_owned()];
if feature_qt_gui_enabled {
qt_modules.push("Gui".to_owned());
}
if feature_qt_qml_enabled {
qt_modules.push("Qml".to_owned());
}

let qtbuild = qt_build_utils::QtBuild::new(qt_modules).expect("Could not find Qt installation");
qtbuild.cargo_link_libraries();
Expand Down Expand Up @@ -144,6 +148,12 @@ fn main() {
]);
}

if feature_qt_qml_enabled {
rust_bridges.extend([
"qml/qqmlengine",
]);
}

for bridge in &rust_bridges {
println!("cargo:rerun-if-changed=src/{bridge}.rs");
}
Expand Down Expand Up @@ -192,6 +202,12 @@ fn main() {
]);
}

if feature_qt_qml_enabled {
cpp_files.extend([
"qml/qqmlengine",
]);
}

for cpp_file in &cpp_files {
builder.file(format!("src/{cpp_file}.cpp"));
println!("cargo:rerun-if-changed=src/{cpp_file}.cpp");
Expand All @@ -210,6 +226,11 @@ fn main() {
builder.define("CXX_QT_GUI_FEATURE", None);
}

// Enable Qt Qml in C++ if the feature is enabled
if feature_qt_gui_enabled {
builder.define("CXX_QT_QML_FEATURE", None);
}

// MSVC
builder.flag_if_supported("/std:c++17");
builder.flag_if_supported("/Zc:__cplusplus");
Expand Down
5 changes: 5 additions & 0 deletions crates/cxx-qt-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ pub use crate::core::*;
mod gui;
#[cfg(feature = "qt_gui")]
pub use crate::gui::*;

#[cfg(feature = "qt_qml")]
mod qml;
#[cfg(feature = "qt_qml")]
pub use crate::qml::*;
7 changes: 7 additions & 0 deletions crates/cxx-qt-lib/src/qml/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

mod qqmlengine;
pub use qqmlengine::QQmlEngine;
22 changes: 22 additions & 0 deletions crates/cxx-qt-lib/src/qml/qqmlengine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#ifdef CXX_QT_GUI_FEATURE
#include "cxx-qt-lib/qqmlengine.h"

namespace rust {
namespace cxxqtlib1 {

::std::unique_ptr<QQmlEngine>
qqmlengineNew()
{
return ::std::make_unique<QQmlEngine>();
}

}
}
#endif
70 changes: 70 additions & 0 deletions crates/cxx-qt-lib/src/qml/qqmlengine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = crate::QString;
include!("cxx-qt-lib/qstringlist.h");
type QStringList = crate::QStringList;
include!("cxx-qt-lib/qurl.h");
type QUrl = crate::QUrl;

include!("cxx-qt-lib/qqmlengine.h");
type QQmlEngine;

/// 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 QQmlEngine>, path: &QString);

/// Adds path as a directory where the engine searches for native plugins for imported modules (referenced in the qmldir file).
#[rust_name = "add_plugin_path"]
fn addPluginPath(self: Pin<&mut QQmlEngine>, path: &QString);

/// Return the base URL for this engine.
/// The base URL is only used to resolve components when a relative URL is passed to the QQmlComponent constructor.
#[rust_name = "base_url"]
fn baseUrl(self: &QQmlEngine) -> QUrl;

/// Returns the list of directories where the engine searches for installed modules in a URL-based directory structure.
#[rust_name = "import_path_list"]
fn importPathList(self: &QQmlEngine) -> QStringList;

/// Returns the list of directories where the engine searches for native plugins for imported modules (referenced in the qmldir file).
#[rust_name = "plugin_path_list"]
fn pluginPathList(self: &QQmlEngine) -> QStringList;

/// Set the base URL for this engine to url.
#[rust_name = "set_base_url"]
fn setBaseUrl(self: Pin<&mut QQmlEngine>, url: &QUrl);

/// Sets paths as the list of directories where the engine searches for installed modules in a URL-based directory structure.
#[rust_name = "set_import_path_list"]
fn setImportPathList(self: Pin<&mut QQmlEngine>, paths: &QStringList);

/// Sets the list of directories where the engine searches for native plugins for imported modules (referenced in the qmldir file) to paths.
#[rust_name = "set_plugin_path_list"]
fn setPluginPathList(self: Pin<&mut QQmlEngine>, paths: &QStringList);
}

#[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
#[doc(hidden)]
#[rust_name = "qqmlengine_new"]
fn qqmlengineNew() -> UniquePtr<QQmlEngine>;
}

impl UniquePtr<QQmlEngine> {}
}

pub use ffi::QQmlEngine;

impl QQmlEngine {
/// Create a new QQmlEngine
pub fn new() -> cxx::UniquePtr<Self> {
ffi::qqmlengine_new()
}
}
3 changes: 1 addition & 2 deletions examples/cargo_without_cmake/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ use cxx_qt_build::CxxQtBuilder;

fn main() {
CxxQtBuilder::new()
// Link Qt's Qml and Network libraries. Qt Core and Gui are always
// Link Qt's Network libraries. Qt Core, Gui, and Qml are always
// linked, so there is no need to specify them here.
.qt_module("Qml")
.qt_module("Network")
// Generate C++ from the `#[cxx_qt::bridge]` module
.file("src/cxxqt_object.rs")
Expand Down
5 changes: 3 additions & 2 deletions tests/basic_cxx_only/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if(NOT USE_QT5)
find_package(Qt6 COMPONENTS Core Gui Test)
find_package(Qt6 COMPONENTS Core Gui Qml Test)
endif()
if(NOT Qt6_FOUND)
find_package(Qt5 5.15 COMPONENTS Core Gui Test REQUIRED)
find_package(Qt5 5.15 COMPONENTS Core Gui Qml Test REQUIRED)
endif()
get_target_property(QMAKE Qt::qmake IMPORTED_LOCATION)

Expand All @@ -36,6 +36,7 @@ target_include_directories(${CRATE} INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
target_link_libraries(${CRATE} INTERFACE
Qt::Core
Qt::Gui
Qt::Qml
)

add_executable(${APP_NAME}
Expand Down
5 changes: 3 additions & 2 deletions tests/basic_cxx_qt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if(NOT USE_QT5)
find_package(Qt6 COMPONENTS Core Gui Test)
find_package(Qt6 COMPONENTS Core Gui Qml Test)
endif()
if(NOT Qt6_FOUND)
find_package(Qt5 5.15 COMPONENTS Core Gui Test REQUIRED)
find_package(Qt5 5.15 COMPONENTS Core Gui Qml Test REQUIRED)
endif()
get_target_property(QMAKE Qt::qmake IMPORTED_LOCATION)

Expand All @@ -35,6 +35,7 @@ target_include_directories(${CRATE} INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
target_link_libraries(${CRATE} INTERFACE
Qt::Core
Qt::Gui
Qt::Qml
)

add_executable(${APP_NAME} cpp/main.cpp)
Expand Down
5 changes: 3 additions & 2 deletions tests/qt_types_standalone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if(NOT USE_QT5)
find_package(Qt6 COMPONENTS Core Gui Test)
find_package(Qt6 COMPONENTS Core Gui Qml Test)
endif()
if(NOT Qt6_FOUND)
find_package(Qt5 5.15 COMPONENTS Core Gui Test REQUIRED)
find_package(Qt5 5.15 COMPONENTS Core Gui Qml Test REQUIRED)
endif()
get_target_property(QMAKE Qt::qmake IMPORTED_LOCATION)

Expand All @@ -36,6 +36,7 @@ target_include_directories(${CRATE} INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
target_link_libraries(${CRATE} INTERFACE
Qt::Core
Qt::Gui
Qt::Qml
)

add_executable(${APP_NAME}
Expand Down

0 comments on commit f087752

Please sign in to comment.