a lot of setup and testing work for rust
This commit is contained in:
parent
8e58dd89df
commit
8b4c348279
12 changed files with 231 additions and 32 deletions
2
.envrc
2
.envrc
|
@ -1,2 +1,4 @@
|
||||||
export NIXPKGS_ALLOW_INSECURE=1
|
export NIXPKGS_ALLOW_INSECURE=1
|
||||||
|
export QT_AUTO_SCREEN_SCALE_FACTOR=1
|
||||||
|
export QT_SCALE_FACTOR=0.75
|
||||||
use flake . --impure
|
use flake . --impure
|
||||||
|
|
7
build.rs
7
build.rs
|
@ -1,6 +1,9 @@
|
||||||
use cxx_qt_build::CxxQtBuilder;
|
use cxx_qt_build::CxxQtBuilder;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
CxxQtBuilder::new().file("src/rust/cxxqt_object.rs").build();
|
// CxxQtBuilder::new().file("src/rust/my_object.rs").build();
|
||||||
CxxQtBuilder::new().file("src/rust/service_thing.rs").build();
|
CxxQtBuilder::new()
|
||||||
|
.file("src/rust/service_thing.rs")
|
||||||
|
.file("src/rust/file_helper.rs")
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
10
flake.nix
10
flake.nix
|
@ -18,15 +18,15 @@
|
||||||
src = ./.;
|
src = ./.;
|
||||||
rustPkgs = pkgs.rustBuilder.makePackageSet {
|
rustPkgs = pkgs.rustBuilder.makePackageSet {
|
||||||
rustVersion = "1.61.0";
|
rustVersion = "1.61.0";
|
||||||
packageFun = import ./cargo.nix;
|
packageFun = import ./Cargo.nix;
|
||||||
};
|
};
|
||||||
|
|
||||||
in rec
|
in rec
|
||||||
{
|
{
|
||||||
# packages = {
|
packages = {
|
||||||
# crate = (rustPkgs.workspace.qml-minimal { }).bin;
|
crate = (rustPkgs.workspace.libre-presenter { }).bin;
|
||||||
# default = packages.crate;
|
default = packages.crate;
|
||||||
# };
|
};
|
||||||
devShell = import ./shell.nix { inherit pkgs; };
|
devShell = import ./shell.nix { inherit pkgs; };
|
||||||
defaultPackage = pkgs.libsForQt5.callPackage ./default.nix { inherit rustPkgs; };
|
defaultPackage = pkgs.libsForQt5.callPackage ./default.nix { inherit rustPkgs; };
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,9 @@
|
||||||
#include "cpp/slide.h"
|
#include "cpp/slide.h"
|
||||||
|
|
||||||
// RUST
|
// RUST
|
||||||
#include "cxx-qt-gen/my_object.cxxqt.h"
|
// #include "cxx-qt-gen/my_object.cxxqt.h"
|
||||||
#include "cxx-qt-gen/service_thing.cxxqt.h"
|
#include "cxx-qt-gen/service_thing.cxxqt.h"
|
||||||
|
#include "cxx-qt-gen/file_helper.cxxqt.h"
|
||||||
|
|
||||||
static void connectToDatabase() {
|
static void connectToDatabase() {
|
||||||
// let's setup our sql database
|
// let's setup our sql database
|
||||||
|
@ -97,7 +98,7 @@ int main(int argc, char *argv[])
|
||||||
QCoreApplication::setOrganizationName(QStringLiteral("librepresenter"));
|
QCoreApplication::setOrganizationName(QStringLiteral("librepresenter"));
|
||||||
QCoreApplication::setOrganizationDomain(QStringLiteral("tfcconnection.org"));
|
QCoreApplication::setOrganizationDomain(QStringLiteral("tfcconnection.org"));
|
||||||
QCoreApplication::setApplicationName(QStringLiteral("Libre Presenter"));
|
QCoreApplication::setApplicationName(QStringLiteral("Libre Presenter"));
|
||||||
qSetMessagePattern("[%{type} %{time h:m:s ap}: %{function} in %{file}]: %{message}\n");
|
// qSetMessagePattern("[%{type} %{time h:m:s ap}: %{function} in %{file}]: %{message}\n");
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
QIcon::setFallbackThemeName("breeze");
|
QIcon::setFallbackThemeName("breeze");
|
||||||
|
@ -132,7 +133,7 @@ int main(int argc, char *argv[])
|
||||||
qmlRegisterType<ImageSqlModel>("org.presenter", 1, 0, "ImageSqlModel");
|
qmlRegisterType<ImageSqlModel>("org.presenter", 1, 0, "ImageSqlModel");
|
||||||
qmlRegisterType<PresentationSqlModel>("org.presenter", 1, 0, "PresentationSqlModel");
|
qmlRegisterType<PresentationSqlModel>("org.presenter", 1, 0, "PresentationSqlModel");
|
||||||
qmlRegisterType<ServiceItemModel>("org.presenter", 1, 0, "ServiceItemModel");
|
qmlRegisterType<ServiceItemModel>("org.presenter", 1, 0, "ServiceItemModel");
|
||||||
qmlRegisterType<MyObject>("org.presenter", 1, 0, "MyObject");
|
qmlRegisterType<FileHelper>("org.presenter", 1, 0, "FileHelper");
|
||||||
qmlRegisterType<ServiceThing>("org.presenter", 1, 0, "ServiceThing");
|
qmlRegisterType<ServiceThing>("org.presenter", 1, 0, "ServiceThing");
|
||||||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "SlideObject", slide.get());
|
qmlRegisterSingletonInstance("org.presenter", 1, 0, "SlideObject", slide.get());
|
||||||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "FileManager", filemanager.get());
|
qmlRegisterSingletonInstance("org.presenter", 1, 0, "FileManager", filemanager.get());
|
||||||
|
|
|
@ -129,6 +129,10 @@ Kirigami.ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileHelper {
|
||||||
|
id: fileHelper
|
||||||
|
}
|
||||||
|
|
||||||
FileDialog {
|
FileDialog {
|
||||||
id: loadFileDialog
|
id: loadFileDialog
|
||||||
title: "Load"
|
title: "Load"
|
||||||
|
@ -180,12 +184,6 @@ Kirigami.ApplicationWindow {
|
||||||
/* print(loaded[0].audio); */
|
/* print(loaded[0].audio); */
|
||||||
}
|
}
|
||||||
|
|
||||||
MyObject {
|
|
||||||
id: myObject
|
|
||||||
number: 7
|
|
||||||
string: "HI from rust in my proj: " + myObject.number
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
/* showPassiveNotification(Kirigami.Settings.style); */
|
/* showPassiveNotification(Kirigami.Settings.style); */
|
||||||
/* Kirigami.Settings.style = "Plasma"; */
|
/* Kirigami.Settings.style = "Plasma"; */
|
||||||
|
|
|
@ -149,6 +149,10 @@ Controls.Page {
|
||||||
id: serviceItemModel
|
id: serviceItemModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServiceThing {
|
||||||
|
id: serviceThing
|
||||||
|
}
|
||||||
|
|
||||||
function changeServiceItem(index) {
|
function changeServiceItem(index) {
|
||||||
const item = serviceItemModel.getItem(index);
|
const item = serviceItemModel.getItem(index);
|
||||||
currentServiceItem = index;
|
currentServiceItem = index;
|
||||||
|
|
|
@ -45,19 +45,19 @@ FocusScope {
|
||||||
text: "Solo"
|
text: "Solo"
|
||||||
icon.name: "viewimage"
|
icon.name: "viewimage"
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onClicked: myObject.slapVariantAround(imagesqlmodel.getImage(1).title);
|
onClicked: serviceThing.slapVariantAround(imagesqlmodel.getImage(1).title);
|
||||||
}
|
}
|
||||||
Controls.ToolButton {
|
Controls.ToolButton {
|
||||||
text: "Grid"
|
text: "Grid"
|
||||||
icon.name: "view-app-grid-symbolic"
|
icon.name: "view-app-grid-symbolic"
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onClicked: myObject.sayHi(myObject.string, myObject.number);
|
onClicked: serviceThing.checkActive();
|
||||||
}
|
}
|
||||||
Controls.ToolButton {
|
Controls.ToolButton {
|
||||||
text: "Details"
|
text: "Details"
|
||||||
icon.name: "view-list-details"
|
icon.name: "view-list-details"
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onClicked: showPassiveNotification(myObject.string);
|
onClicked: serviceThing.activate();
|
||||||
}
|
}
|
||||||
Controls.ToolSeparator {}
|
Controls.ToolSeparator {}
|
||||||
Item { Layout.fillWidth: true }
|
Item { Layout.fillWidth: true }
|
||||||
|
|
45
src/rust/file_helper.rs
Normal file
45
src/rust/file_helper.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#[cxx_qt::bridge]
|
||||||
|
mod file_helper {
|
||||||
|
use cxx::{CxxString, CxxVector};
|
||||||
|
unsafe extern "C++" {
|
||||||
|
include!("cxx-qt-lib/qstring.h");
|
||||||
|
type QString = cxx_qt_lib::QString;
|
||||||
|
include!("cxx-qt-lib/qurl.h");
|
||||||
|
type QUrl = cxx_qt_lib::QUrl;
|
||||||
|
include!("cxx-qt-lib/qvariant.h");
|
||||||
|
type QVariant = cxx_qt_lib::QVariant;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
#[cxx_qt::qobject]
|
||||||
|
pub struct FileHelper {
|
||||||
|
#[qproperty]
|
||||||
|
name: QString,
|
||||||
|
#[qproperty]
|
||||||
|
file_path: QString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FileHelper {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: QString::from(""),
|
||||||
|
file_path: QString::from(""),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl qobject::FileHelper {
|
||||||
|
#[qinvokable]
|
||||||
|
pub fn save(self: Pin<&mut Self>, file: QUrl, _service_list: QVariant) -> bool {
|
||||||
|
println!("{}", file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[qinvokable]
|
||||||
|
pub fn load(self: Pin<&mut Self>, file: QUrl) -> Vec<String> {
|
||||||
|
println!("{}", file);
|
||||||
|
let vc = vec![String::new()];
|
||||||
|
return vc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,5 +13,6 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod cxxqt_object;
|
// mod my_object;
|
||||||
|
mod file_helper;
|
||||||
mod service_thing;
|
mod service_thing;
|
||||||
|
|
142
src/rust/service_item_model.rs
Normal file
142
src/rust/service_item_model.rs
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
use cxx::{type_id, ExternType};
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
|
// Define a QModelIndex that is trivial for CXX
|
||||||
|
//
|
||||||
|
// TODO: later this will likely be in cxx-qt-lib
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct QModelIndex {
|
||||||
|
_space: MaybeUninit<[usize; 3]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety:
|
||||||
|
//
|
||||||
|
// Static checks on the C++ side to ensure the size is the same.
|
||||||
|
// TODO: later this will likely be in cxx-qt-lib
|
||||||
|
unsafe impl ExternType for QModelIndex {
|
||||||
|
type Id = type_id!("QModelIndex");
|
||||||
|
type Kind = cxx::kind::Trivial;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ANCHOR: book_macro_code
|
||||||
|
#[cxx_qt::bridge(cxx_file_stem = "service_item_model")]
|
||||||
|
mod service_item_model {
|
||||||
|
// ANCHOR: book_base_include
|
||||||
|
unsafe extern "C++" {
|
||||||
|
include!("serviceitemmodel.h");
|
||||||
|
// ANCHOR_END: book_base_include
|
||||||
|
|
||||||
|
include!("cxx-qt-lib/qvariant.h");
|
||||||
|
type QVariant = cxx_qt_lib::QVariant;
|
||||||
|
|
||||||
|
// Define the interface of the QModelIndex
|
||||||
|
type QModelIndex = super::QModelIndex;
|
||||||
|
fn row(self: &QModelIndex) -> i32;
|
||||||
|
|
||||||
|
#[cxx_name = "beginInsertRows"]
|
||||||
|
fn begin_insert_rows(self: Pin<&mut CustomBaseClassQt>, first: i32, last: i32);
|
||||||
|
#[cxx_name = "endInsertRows"]
|
||||||
|
fn end_insert_rows(self: Pin<&mut CustomBaseClassQt>);
|
||||||
|
|
||||||
|
#[cxx_name = "beginRemoveRows"]
|
||||||
|
fn begin_remove_rows(self: Pin<&mut CustomBaseClassQt>, first: i32, last: i32);
|
||||||
|
#[cxx_name = "endRemoveRows"]
|
||||||
|
fn end_remove_rows(self: Pin<&mut CustomBaseClassQt>);
|
||||||
|
|
||||||
|
#[cxx_name = "beginResetModel"]
|
||||||
|
fn begin_reset_model(self: Pin<&mut CustomBaseClassQt>);
|
||||||
|
#[cxx_name = "endResetModel"]
|
||||||
|
fn end_reset_model(self: Pin<&mut CustomBaseClassQt>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ANCHOR: book_qobject_base
|
||||||
|
#[cxx_qt::qobject(base = "ServiceItemModel")]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ServiceItemModel {
|
||||||
|
// ANCHOR_END: book_qobject_base
|
||||||
|
id: u32,
|
||||||
|
vector: Vec<(u32, f64)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl qobject::ServiceItemModel {
|
||||||
|
#[qinvokable]
|
||||||
|
pub fn add(self: Pin<&mut Self>) {
|
||||||
|
self.add_cpp_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[qinvokable]
|
||||||
|
pub fn add_on_thread(self: Pin<&mut Self>, mut counter: i32) {
|
||||||
|
let qt_thread = self.qt_thread();
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
while counter > 0 {
|
||||||
|
counter -= 1;
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||||
|
|
||||||
|
// Use our add helper to add a row on the Qt event loop
|
||||||
|
// as seen in the threading demo channels could be used to pass info
|
||||||
|
qt_thread
|
||||||
|
.queue(|custom_base_class| {
|
||||||
|
custom_base_class.add_cpp_context();
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_cpp_context(mut self: Pin<&mut Self>) {
|
||||||
|
let count = self.vector().len();
|
||||||
|
self.as_mut().begin_insert_rows(count as i32, count as i32);
|
||||||
|
let id = *self.id();
|
||||||
|
self.as_mut().set_id(id + 1);
|
||||||
|
self.as_mut().vector_mut().push((id, (id as f64) / 3.0));
|
||||||
|
self.as_mut().end_insert_rows();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[qinvokable]
|
||||||
|
pub fn clear(mut self: Pin<&mut Self>) {
|
||||||
|
self.as_mut().begin_reset_model();
|
||||||
|
self.as_mut().set_id(0);
|
||||||
|
self.as_mut().vector_mut().clear();
|
||||||
|
self.as_mut().end_reset_model();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[qinvokable]
|
||||||
|
pub fn remove(mut self: Pin<&mut Self>, index: i32) {
|
||||||
|
if index < 0 || (index as usize) >= self.vector().len() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.as_mut().begin_remove_rows(index, index);
|
||||||
|
self.as_mut().vector_mut().remove(index as usize);
|
||||||
|
self.as_mut().end_remove_rows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QAbstractListModel implementation
|
||||||
|
impl qobject::ServiceItemModel {
|
||||||
|
#[qinvokable(cxx_override)]
|
||||||
|
fn data(&self, index: &QModelIndex, role: i32) -> QVariant {
|
||||||
|
if let Some((id, value)) = self.rust().vector.get(index.row() as usize) {
|
||||||
|
return match role {
|
||||||
|
0 => QVariant::from(*id),
|
||||||
|
1 => QVariant::from(*value),
|
||||||
|
_ => QVariant::default(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[qinvokable(cxx_override)]
|
||||||
|
pub fn role_names_as_vec(&self) -> Vec<String> {
|
||||||
|
vec!["id".to_owned(), "value".to_owned()]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[qinvokable(cxx_override)]
|
||||||
|
pub fn row_count(&self, _parent: &QModelIndex) -> i32 {
|
||||||
|
self.rust().vector.len() as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ANCHOR_END: book_macro_code
|
|
@ -9,6 +9,7 @@ mod service_thing {
|
||||||
type QVariant = cxx_qt_lib::QVariant;
|
type QVariant = cxx_qt_lib::QVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
#[cxx_qt::qobject]
|
#[cxx_qt::qobject]
|
||||||
pub struct ServiceThing {
|
pub struct ServiceThing {
|
||||||
#[qproperty]
|
#[qproperty]
|
||||||
|
@ -53,28 +54,30 @@ mod service_thing {
|
||||||
impl qobject::ServiceThing {
|
impl qobject::ServiceThing {
|
||||||
#[qinvokable]
|
#[qinvokable]
|
||||||
pub fn activate(self: Pin<&mut Self>) {
|
pub fn activate(self: Pin<&mut Self>) {
|
||||||
self.set_active(true);
|
println!("{}", self.active());
|
||||||
|
let active: bool = *self.active();
|
||||||
|
self.set_active(!active);
|
||||||
|
println!("{}", !active);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[qinvokable]
|
#[qinvokable]
|
||||||
pub fn say_hi(self: Pin<&mut Self>, string: &QString, number: i32) {
|
pub fn check_active(self: Pin<&mut Self>) {
|
||||||
println!(
|
println!("Are we active?: {}", self.active());
|
||||||
"Hi from Rust! String is '{}' and number is {}",
|
|
||||||
string, number
|
|
||||||
);
|
|
||||||
println!("length is: {}", string.to_string().len());
|
|
||||||
let mut nstr: String = string.to_string();
|
|
||||||
nstr.push_str(" hi");
|
|
||||||
self.set_name(QString::from(nstr.as_str()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[qinvokable]
|
#[qinvokable]
|
||||||
pub fn slap_variant_around(self: Pin<&mut Self>, variant: &QVariant) {
|
pub fn slap_variant_around(self: Pin<&mut Self>, variant: &QVariant) {
|
||||||
println!("wow!");
|
println!("wow!");
|
||||||
|
let sname: String;
|
||||||
match variant.value() {
|
match variant.value() {
|
||||||
QVariantValue::QString(string) => self.set_name(string),
|
QVariantValue::QString(string) => {
|
||||||
|
let nstr = string.to_string();
|
||||||
|
self.set_name(QString::from(nstr.as_str()));
|
||||||
|
sname = nstr;
|
||||||
|
println!("New name is: {}", sname);
|
||||||
|
}
|
||||||
_ => println!("Unknown QVariant type"),
|
_ => println!("Unknown QVariant type"),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue