Skip to content

Commit

Permalink
add example application built entirely with Cargo
Browse files Browse the repository at this point in the history
  • Loading branch information
Be-ing committed Aug 26, 2022
1 parent 5a089ae commit 5764feb
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"cxx-qt-lib",
"cxx-qt-lib-headers",

"examples/cargo_without_cmake",
"examples/demo_threading",
"examples/qml_extension_plugin/core",
"examples/qml_features",
Expand Down
24 changes: 24 additions & 0 deletions examples/cargo_without_cmake/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
# SPDX-FileContributor: Gerhard de Clercq <gerhard.declercq@kdab.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0
[package]
name = "qml-minimal-no-cmake"
version = "0.3.0"
authors = [
"Andrew Hayzen <andrew.hayzen@kdab.com>",
"Be Wilson <be.wilson@kdab.com>",
"Gerhard de Clercq <gerhard.declercq@kdab.com>",
"Leon Matthes <leon.matthes@kdab.com>"
]
edition = "2018"
license = "MIT OR Apache-2.0"

[dependencies]
cxx = "1.0"
cxx-qt = { path = "../../cxx-qt" }
cxx-qt-lib = { path = "../../cxx-qt-lib" }

[build-dependencies]
cxx-qt-build = { path = "../../cxx-qt-build" }
18 changes: 18 additions & 0 deletions examples/cargo_without_cmake/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Be Wilson <be.wilson@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use cxx_qt_build::CxxQtBuilder;

fn main() {
CxxQtBuilder::new()
.qt_modules(&["Qml", "Network"])
.file("src/cxxqt_object.rs")
.qrc("src/qml.qrc")
.cc_builder(|cc| {
cc.file("src/run.cpp");
println!("cargo:rerun-if-changed=src/run.cpp");
})
.build();
}
47 changes: 47 additions & 0 deletions examples/cargo_without_cmake/src/cxxqt_object.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Be Wilson <be.wilson@kdab.com>
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
// SPDX-FileContributor: Gerhard de Clercq <gerhard.declercq@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#[cxx_qt::bridge]
mod ffi {
unsafe extern "C++" {
include!("cxx-qt-lib/include/qt_types.h");
type QString = cxx_qt_lib::QString;
}

pub struct Data {
number: i32,
string: UniquePtr<QString>,
}

impl Default for Data {
fn default() -> Self {
Self {
number: 0,
string: QString::from_str(""),
}
}
}

#[cxx_qt::qobject]
#[derive(Default)]
pub struct MyObject;
impl cxx_qt::QObject<MyObject> {
#[qinvokable]
pub fn increment_number(self: Pin<&mut Self>) {
let previous = self.as_ref().number();
self.set_number(previous + 1);
}

#[qinvokable]
pub fn say_hi(&self, string: &QString, number: i32) {
println!(
"Hi from Rust! String is '{}' and number is {}",
string, number
);
}
}
}
50 changes: 50 additions & 0 deletions examples/cargo_without_cmake/src/main.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
// SPDX-FileContributor: Gerhard de Clercq <gerhard.declercq@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12

import com.kdab.cxx_qt.demo 1.0

Window {
height: 480
title: qsTr("Hello World")
visible: true
width: 640

MyObject {
id: myObject
number: 1
string: "My String with my number: " + myObject.number
}

Column {
anchors.fill: parent
anchors.margins: 10
spacing: 10

Label {
text: "Number: " + myObject.number
}

Label {
text: "String: " + myObject.string
}

Button {
text: "Increment Number"

onClicked: myObject.incrementNumber()
}

Button {
text: "Say Hi!"

onClicked: myObject.sayHi(myObject.string, myObject.number)
}
}
}
39 changes: 39 additions & 0 deletions examples/cargo_without_cmake/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Be Wilson <be.wilson@kdab.com>
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
// SPDX-FileContributor: Gerhard de Clercq <gerhard.declercq@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

mod cxxqt_object;

use std::{convert::TryInto, ffi::CString, os::raw::c_char, os::raw::c_int, ptr};

extern "C" {
fn run_cpp(argc: c_int, argv: *const *const c_char) -> c_int;
}

fn main() {
let args: Vec<CString> = std::env::args_os()
.map(|string| {
// Unix OsStrings can be directly converted to CStrings.
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;

// Windows OsStrings are WTF-8 encoded, so they need to be
// converted to UTF-8 Strings before being converted to CStrings.
// https://simonsapin.github.io/wtf-8/
#[cfg(windows)]
let string = string.to_string_lossy();

CString::new(string.as_bytes()).unwrap()
})
.collect();

let mut c_args: Vec<*const c_char> = args.iter().map(|arg| arg.as_ptr()).collect();
c_args.push(ptr::null());

unsafe {
run_cpp(args.len().try_into().unwrap(), c_args.as_ptr());
}
}
13 changes: 13 additions & 0 deletions examples/cargo_without_cmake/src/qml.qrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE RCC>
<!--
SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
SPDX-FileContributor: Gerhard de Clercq <gerhard.declercq@kdab.com>

SPDX-License-Identifier: MIT OR Apache-2.0
-->
<RCC version="1.0">
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>
48 changes: 48 additions & 0 deletions examples/cargo_without_cmake/src/run.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// clang-format off
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// clang-format on
// SPDX-FileContributor: Be Wilson <be.wilson@kdab.com>
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
// SPDX-FileContributor: Gerhard de Clercq <gerhard.declercq@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#include <QtGui/QGuiApplication>
#include <QtQml/QQmlApplicationEngine>

#include "cxx-qt-gen/include/my_object.cxxqt.h"

// Include the C++ code generated by rcc from the .qrc file
#include "qml.qrc.cpp"

extern "C" int
run_cpp(int argc, char* argv[])
{
// Normally in a C++ program, global variables for the Qt Resource System are
// initialized before the C++ main function runs. However, when building a
// Rust executable with Cargo, the Qt Resource System needs to be initialized
// manually.
// https://doc.qt.io/qt-6/resources.html#explicit-loading-and-unloading-of-embedded-resources
qInitResources();

QGuiApplication app(argc, argv);

QQmlApplicationEngine engine;

const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreated,
&app,
[url](QObject* obj, const QUrl& objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
},
Qt::QueuedConnection);

qmlRegisterType<MyObject>("com.kdab.cxx_qt.demo", 1, 0, "MyObject");

engine.load(url);

return app.exec();
}

0 comments on commit 5764feb

Please sign in to comment.