Skip to content

Commit

Permalink
examples: add basic widgets example
Browse files Browse the repository at this point in the history
  • Loading branch information
ahayzen-kdab committed Jan 15, 2024
1 parent 418ee8d commit 8574b42
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"examples/demo_threading/rust",
"examples/qml_features/rust",
"examples/qml_minimal/rust",
"examples/widgets_minimal",

"tests/basic_cxx_only/rust",
"tests/basic_cxx_qt/rust",
Expand Down
25 changes: 25 additions & 0 deletions examples/widgets_minimal/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

[package]
name = "widgets-minimal-no-cmake"
version = "0.1.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 = "2021"
license = "MIT OR Apache-2.0"

[dependencies]
cxx.workspace = true
cxx-qt.workspace = true
cxx-qt-lib.workspace = true

[build-dependencies]
# The link_qt_object_files feature is required for statically linking Qt 6.
cxx-qt-build = { workspace = true, features = [ "link_qt_object_files" ] }
26 changes: 26 additions & 0 deletions examples/widgets_minimal/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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()
// Link Qt's Network library
// - Qt Core is always linked
// - Qt Gui is linked by enabling the qt_gui Cargo feature (default).
// - 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("Widgets")
// Generate C++ from the `#[cxx_qt::bridge]` module
.file("src/qapplication_cxx.rs")
.file("src/qpushbutton_cxx.rs")
.cc_builder(|cc| {
cc.include("./cpp");
cc.file("./cpp/qapplication.cpp");
cc.file("./cpp/qpushbutton.cpp");
})
.build();
}
26 changes: 26 additions & 0 deletions examples/widgets_minimal/cpp/qapplication.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#include "qapplication.h"

#include <cxx-qt-lib/qcoreapplication.h>

::std::unique_ptr<QApplication>
qapplicationNew(const QVector<QByteArray>& args)
{
// Ensure that our QVector has the same lifetime as the QGuiApplication
// by storing it inside a QObject that has QGuiApplication as it's parent
auto argsData = new ::rust::cxxqtlib1::ApplicationArgsData(args);
// Note that QGuiApplication uses a reference to an int for the size here
// so we need to ensure that reference remains valid
auto ptr =
::std::make_unique<QApplication>(argsData->size(), argsData->data());
Q_ASSERT(ptr != nullptr);
argsData->setParent(ptr.get());

return ptr;
}
22 changes: 22 additions & 0 deletions examples/widgets_minimal/cpp/qapplication.h
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 <info@kdab.com>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#pragma once

#include <QtWidgets/QApplication>

#include <memory>

::std::unique_ptr<QApplication>
qapplicationNew(const QVector<QByteArray>& args);

template<typename T>
::std::int32_t
qapplicationExec(T& app)
{
return static_cast<::std::int32_t>(app.exec());
}
14 changes: 14 additions & 0 deletions examples/widgets_minimal/cpp/qpushbutton.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#include "qpushbutton.h"

::std::unique_ptr<QPushButton>
qpushbuttonNew()
{
return ::std::make_unique<QPushButton>();
}
15 changes: 15 additions & 0 deletions examples/widgets_minimal/cpp/qpushbutton.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#pragma once

#include <QtWidgets/QPushButton>

#include <memory>

::std::unique_ptr<QPushButton>
qpushbuttonNew();
38 changes: 38 additions & 0 deletions examples/widgets_minimal/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

//! This example provides demostrations of building a Cargo only CXX-Qt application

mod qapplication_cxx;
mod qpushbutton_cxx;

use cxx_qt_lib::QString;
use qapplication_cxx::QApplication;
use qpushbutton_cxx::QPushButton;

fn main() {
let mut app = QApplication::new();

let mut push_button = QPushButton::new();

if let Some(mut push_button) = push_button.as_mut() {
push_button
.as_mut()
.set_text(&QString::from("Hello World!"));

push_button
.as_mut()
.on_clicked(|_, _| {
println!("Button Clicked!");
})
.release();

push_button.show();
}

if let Some(app) = app.as_mut() {
app.exec();
}
}
59 changes: 59 additions & 0 deletions examples/widgets_minimal/src/qapplication_cxx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#[cxx_qt::bridge(cxx_file_stem = "qapplication_cxx")]
mod ffi {
unsafe extern "C++Qt" {
include!(<QtWidgets/QApplication>);
type QApplication;

include!("cxx-qt-lib/qbytearray.h");
type QByteArray = cxx_qt_lib::QByteArray;
include!("cxx-qt-lib/qvector.h");
type QVector_QByteArray = cxx_qt_lib::QVector<QByteArray>;
}

unsafe extern "C++Qt" {
include!("qapplication.h");
#[doc(hidden)]
#[rust_name = "qapplication_new"]
fn qapplicationNew(args: &QVector_QByteArray) -> UniquePtr<QApplication>;

#[doc(hidden)]
#[rust_name = "qapplication_exec"]
fn qapplicationExec(app: Pin<&mut QApplication>) -> i32;
}
}

impl ffi::QApplication {
pub fn new() -> cxx::UniquePtr<Self> {
let mut vector = cxx_qt_lib::QVector::<ffi::QByteArray>::default();

// Construct an owned QVector of the args
// as we need the args_os data to outlive this method
// so we pass a QVector to C++ which is then stored
for arg in std::env::args_os() {
// Unix OsStrings can be directly converted to bytes.
#[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 bytes.
// https://simonsapin.github.io/wtf-8/
#[cfg(windows)]
let arg = arg.to_string_lossy();

vector.append(ffi::QByteArray::from(arg.as_bytes()));
}

ffi::qapplication_new(&vector)
}

pub fn exec(self: core::pin::Pin<&mut Self>) -> i32 {
ffi::qapplication_exec(self)
}
}

pub use ffi::QApplication;
41 changes: 41 additions & 0 deletions examples/widgets_minimal/src/qpushbutton_cxx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#[cxx_qt::bridge(cxx_file_stem = "qpushbutton_cxx")]
mod ffi {

unsafe extern "C++Qt" {
include!(<QtWidgets/QPushButton>);
type QPushButton;

include!("cxx-qt-lib/qstring.h");
type QString = cxx_qt_lib::QString;

#[qsignal]
#[allow(dead_code)]
fn clicked(self: Pin<&mut QPushButton>, checked: bool);

#[rust_name = "set_text"]
fn setText(self: Pin<&mut QPushButton>, text: &QString);

fn show(self: Pin<&mut QPushButton>);
}

unsafe extern "C++Qt" {
include!("qpushbutton.h");

#[doc(hidden)]
#[cxx_name = "qpushbuttonNew"]
fn qpushbutton_new() -> UniquePtr<QPushButton>;
}
}

impl ffi::QPushButton {
pub fn new() -> cxx::UniquePtr<Self> {
ffi::qpushbutton_new()
}
}

pub use ffi::QPushButton;

0 comments on commit 8574b42

Please sign in to comment.