Also make the ui available in a widget version

master
Jos van den Oever 2017-08-20 23:36:33 +02:00
parent 4724f2c62f
commit fd2ff179d8
7 changed files with 240 additions and 93 deletions

View File

@ -3,34 +3,18 @@ project (rust_qt_binding_generator)
cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
cmake_policy(SET CMP0046 NEW)
cmake_policy(SET CMP0063 NEW)
set(QT_MIN_VERSION "5.3.0")
set(KF5_MIN_VERSION "5.2.0")
set(QT_MIN_VERSION "5.6.0")
find_package(ECM 1.0.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(ExternalProject)
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings)
include(FeatureSummary)
set_directory_properties(PROPERTIES EP_PREFIX ${CMAKE_BINARY_DIR}/Rust)
# Find Qt modules
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
Core # QCommandLineParser, QStringLiteral
Quick
Core
Test
Widgets # QApplication
)
# Find KDE modules
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
CoreAddons # KAboutData
I18n # KLocalizedString
WidgetsAddons # KMessageBox
)
find_package(Qt5Widgets ${QT_MIN_VERSION} CONFIG)
find_package(Qt5Quick ${QT_MIN_VERSION} CONFIG)
set(CMAKE_AUTOMOC ON)
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
@ -44,6 +28,10 @@ else()
endif()
add_subdirectory(rust_qt_binding_generator)
enable_testing()
add_subdirectory(tests)
add_subdirectory(demo)
if(Qt5Widgets_FOUND)
add_subdirectory(demo)
endif()

View File

@ -1,5 +1,6 @@
set(CMAKE_AUTORCC ON)
# generate c++ and rust code from fibonacci.json
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust/src/fibonacci_interface.rs"
"${CMAKE_CURRENT_SOURCE_DIR}/rust/src/fibonacci_types.rs"
@ -10,6 +11,7 @@ add_custom_command(
DEPENDS rust_qt_binding_generator fibonacci.json
)
# generate c++ and rust code from tree.json
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust/src/interface.rs"
"${CMAKE_CURRENT_SOURCE_DIR}/rust/src/types.rs"
@ -20,6 +22,7 @@ add_custom_command(
DEPENDS rust_qt_binding_generator tree.json
)
# compile the rust code into a static library
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/rust/${RUST_TARGET_DIR}/librust.a"
COMMAND cargo build ${RUST_BUILD_FLAG}
@ -34,6 +37,11 @@ add_custom_command(
)
add_custom_target(rust_target DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/rust/${RUST_TARGET_DIR}/librust.a")
if(Qt5Quick_FOUND)
add_definitions(-DQTQUICK)
set(Qt5Quick_LIBS Qt5::Quick)
endif()
set(Demo_SRCS src/main.cpp src/Tree.cpp src/Fibonacci.cpp
resource_file.qrc)
@ -41,11 +49,8 @@ add_executable(Demo ${Demo_SRCS})
add_dependencies(Demo rust_target)
target_link_libraries(Demo
Qt5::Quick
"${Qt5Quick_LIBS}"
Qt5::Widgets
KF5::CoreAddons
KF5::I18n
KF5::WidgetsAddons
"${CMAKE_CURRENT_SOURCE_DIR}/rust/${RUST_TARGET_DIR}/librust.a"
)

View File

@ -5,18 +5,32 @@ import QtQuick.Layouts 1.3
import rust 1.0
ApplicationWindow {
width: 500
height: 480
id: application
x: windowX
y: windowY
width: windowWidth
height: windowHeight
visible: true
ItemSelectionModel {
id: selectionModel
model: fsModel
}
FibonacciList {
id: fibonacciList
}
TabView {
anchors.fill: parent
Tab {
title: "style"
ComboBox {
currentIndex: qtquickIndex
model: styles
textRole: "display"
onCurrentIndexChanged: {
if (currentText && currentText != "QtQuick") {
widgets.currentText = currentText;
application.close();
}
}
}
}
Tab {
title: "object"
RowLayout {
@ -24,14 +38,12 @@ ApplicationWindow {
id: fibonacciInput
placeholderText: "Your number"
validator: IntValidator {bottom: 0; top: 100;}
Component.onCompleted: { text = fibonacci.input }
onTextChanged: { fibonacci.input = parseInt(text, 10) }
}
Text {
text: "The Fibonacci number: " + fibonacci.result
}
Fibonacci {
id: fibonacci
input: parseInt(fibonacciInput.text, 10)
}
}
}
Tab {

View File

@ -1,5 +1,6 @@
<RCC>
<qresource prefix="/">
<file>demo.qml</file>
<file>demo-qtquick2.qml</file>
</qresource>
</RCC>

View File

@ -1,77 +1,214 @@
#include "Tree.h"
#include "Fibonacci.h"
#include <cstdlib>
#include <KAboutData>
#include <KLocalizedString>
#include <KMessageBox>
#include <QApplication>
#include <QCommandLineParser>
#include <QTreeView>
#include <QHeaderView>
#ifdef QTQUICK
#include <QQmlApplicationEngine>
#include <QtQml/qqml.h>
#include <QQmlContext>
#include <QQuickView>
#include <QQuickItem>
#endif
#include <QApplication>
#include <QComboBox>
#include <QCommandLineParser>
#include <QDebug>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QIntValidator>
#include <QLabel>
#include <QLineEdit>
#include <QListView>
#include <QSortFilterProxyModel>
#include <QStringListModel>
#include <QStyleFactory>
#include <QTabWidget>
#include <QTreeView>
#include <QWindow>
#include <cstdlib>
struct Models {
Tree tree;
QSortFilterProxyModel sortedTree;
Fibonacci fibonacci;
FibonacciList fibonacciList;
QStringListModel styles;
};
void setStyle(QWidget* w, QStyle* style) {
for (QObject* o: w->children()) {
QWidget* c = dynamic_cast<QWidget*>(o);
if (c) {
setStyle(c, style);
}
}
w->setStyle(style);
}
QWindow* getWindow(QWidget* w) {
QWidget* top = w;
while (top && top->parentWidget()) {
top = top->parentWidget();
}
return top->windowHandle();
}
#ifdef QTQUICK
void copyWindowGeometry(QWidget* w, QQmlContext* c) {
QWindow* window = getWindow(w);
if (window) {
c->setContextProperty("windowX", window->x());
c->setContextProperty("windowY", window->y());
c->setContextProperty("windowWidth", window->width());
c->setContextProperty("windowHeight", window->height());
}
}
void createQtQuick(Models* models, QWidget* widgets) {
QQmlApplicationEngine* engine = new QQmlApplicationEngine();
QQmlContext* c = engine->rootContext();
c->setContextProperty("fsModel", &models->tree);
c->setContextProperty("sortedFsModel", &models->sortedTree);
c->setContextProperty("fibonacci", &models->fibonacci);
c->setContextProperty("fibonacciList", &models->fibonacciList);
c->setContextProperty("styles", &models->styles);
c->setContextProperty("widgets", widgets);
c->setContextProperty("qtquickIndex",
QVariant(models->styles.stringList().indexOf("QtQuick")));
copyWindowGeometry(widgets, engine->rootContext());
engine->load(QUrl(QStringLiteral("qrc:///demo.qml")));
}
#endif
QComboBox* createStyleComboBox(Models* models) {
QComboBox* box = new QComboBox();
box->setModel(&models->styles);
auto styles = QStyleFactory::keys();
QString currentStyle = QApplication::style()->objectName().toLower();
for (auto v: styles) {
box->addItem("QWidgets " + v);
if (v.toLower() == currentStyle) {
box->setCurrentText(v);
}
}
#ifdef QTQUICK
box->addItem("QtQuick");
#endif
return box;
}
QWidget* createStyleTab(Models* models, QWidget* tabs) {
QComboBox* box = createStyleComboBox(models);
QRect windowRect;
box->connect(box, &QComboBox::currentTextChanged, box, [windowRect, box, tabs, models](const QString &text) mutable {
QWindow* window = getWindow(tabs);
bool visible = tabs->isVisible();
if (text.startsWith("QWidgets ")) {
tabs->setVisible(true);
if (window && !visible) {
window->setX(windowRect.x());
window->setY(windowRect.y());
window->setWidth(windowRect.width());
window->setHeight(windowRect.height());
}
setStyle(tabs, QStyleFactory::create(text.mid(9)));
#ifdef QTQUICK
} else {
if (window) {
windowRect.setX(window->x());
windowRect.setY(window->y());
windowRect.setWidth(window->width());
windowRect.setHeight(window->height());
}
tabs->setVisible(false);
createQtQuick(models, box);
#endif
}
});
return box;
}
QWidget* createObjectTab(Models* models) {
QWidget* view = new QWidget;
Fibonacci* fibonacci = &models->fibonacci;
QLineEdit* input = new QLineEdit;
input->setPlaceholderText("Your number");
input->setValidator(new QIntValidator(0, 100));
input->connect(input, &QLineEdit::textChanged, fibonacci,
[fibonacci](const QString& text) {
fibonacci->setInput(text.toInt());
});
fibonacci->connect(fibonacci, &Fibonacci::inputChanged, input,
[input, fibonacci]() {
input->setText(QString::number(fibonacci->input()));
});
QLabel* label = new QLabel;
fibonacci->connect(fibonacci, &Fibonacci::resultChanged, label,
[label, fibonacci]() {
label->setText("The Fibonacci number: "
+ QString::number(fibonacci->result()));
});
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(input);
layout->addWidget(label);
view->setLayout(layout);
return view;
}
QWidget* createListTab(Models* models) {
QListView* view = new QListView();
view->setModel(&models->fibonacciList);
return view;
}
QWidget* createTreeTab(Models* models) {
QTreeView* view = new QTreeView();
view->setUniformRowHeights(true);
view->setSortingEnabled(true);
view->setModel(&models->sortedTree);
auto root = models->sortedTree.index(0, 0);
view->expand(root);
view->sortByColumn(0, Qt::AscendingOrder);
view->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
return view;
}
void createWidgets(Models* models) {
QTabWidget* tabs = new QTabWidget();
tabs->addTab(createStyleTab(models, tabs), "style");
tabs->addTab(createObjectTab(models), "object");
tabs->addTab(createListTab(models), "list");
tabs->addTab(createTreeTab(models), "tree");
tabs->setMinimumSize(QSize(500, 500));
tabs->show();
}
int main (int argc, char *argv[])
{
QApplication app(argc, argv);
KLocalizedString::setApplicationDomain("Demo");
KAboutData aboutData(
// The program name used internally. (componentName)
QStringLiteral("Demo"),
// A displayable program name string. (displayName)
i18n("Demo"),
// The program version string. (version)
QStringLiteral("0.1"),
// Short description of what the app does. (shortDescription)
i18n("Demo application for Rust bindings"),
// The license this code is released under
KAboutLicense::GPL,
// Copyright Statement (copyrightStatement = QString())
i18n("(c) 2017"),
// Optional text shown in the About box.
// Can contain any information desired. (otherText)
i18n("Some text..."),
// The program homepage string. (homePageAddress = QString())
QStringLiteral("http://kde.org/"),
// The bug report email address
// (bugsEmailAddress = QLatin1String("submit@bugs.kde.org")
QStringLiteral("submit@bugs.kde.org"));
aboutData.addAuthor(i18n("Jos van den Oever"), i18n("Task"), QStringLiteral("your@email.com"),
QStringLiteral("http://vandenoever.info"), QStringLiteral("OSC Username"));
KAboutData::setApplicationData(aboutData);
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
aboutData.setupCommandLine(&parser);
parser.process(app);
aboutData.processCommandLine(&parser);
#ifdef QTQUICK
qmlRegisterType<QSortFilterProxyModel>("org.qtproject.example", 1, 0, "SortFilterProxyModel");
qmlRegisterType<Fibonacci>("rust", 1, 0, "Fibonacci");
qmlRegisterType<FibonacciList>("rust", 1, 0, "FibonacciList");
Tree model;
#endif
Models models;
Tree& model = models.tree;
QSortFilterProxyModel& sortedModel = models.sortedTree;
model.setPath("/");
QSortFilterProxyModel sortedModel;
sortedModel.setSourceModel(&model);
sortedModel.setDynamicSortFilter(true);
QTreeView view;
view.setUniformRowHeights(true);
view.setSortingEnabled(true);
view.setModel(&sortedModel);
auto root = sortedModel.index(0, 0);
view.expand(root);
view.sortByColumn(0, Qt::AscendingOrder);
view.show();
view.header()->setSectionResizeMode(QHeaderView::ResizeToContents);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("fsModel", &model);
engine.rootContext()->setContextProperty("sortedFsModel", &sortedModel);
engine.load(QUrl(QStringLiteral("qrc:///demo.qml")));
createWidgets(&models);
return app.exec();
}

4
dev
View File

@ -10,8 +10,8 @@ if [ -z "${1-}" ]; then
else
# run with NixPkgs master that has Qt5.9 and QtCharts
export NIX_PATH=nixpkgs=$HOME/nixpkgs
export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:/nix/store/cmnbj3s42vfwfkibr9ksv28g44iqbq1y-qtquickcontrols2-5.9.1-bin/lib/qt-5.9/qml/:/nix/store/cv2ayyx56jsqifb1b65ksm0n522ji733-kirigami2-2.1.0/lib/qt-5.9/qml
# export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:/nix/store/cmnbj3s42vfwfkibr9ksv28g44iqbq1y-qtquickcontrols2-5.9.1-bin/lib/qt-5.9/qml/:/nix/store/cv2ayyx56jsqifb1b65ksm0n522ji733-kirigami2-2.1.0/lib/qt-5.9/qml
charts="qt5.qtcharts libsForQt5.kirigami_2"
fi
nix-shell -p qtcreator cmake ninja gcc rustc cargo qt5.full extra-cmake-modules kdeFrameworks.kwidgetsaddons kdeFrameworks.kcoreaddons kdeFrameworks.ki18n appstream cmakeCurses kdeFrameworks.ktexteditor qt5.qtquickcontrols2 $charts
nix-shell -p cmake ninja gcc rustc cargo qt5.full extra-cmake-modules kdeFrameworks.kwidgetsaddons kdeFrameworks.kcoreaddons kdeFrameworks.ki18n appstream cmakeCurses kdeFrameworks.ktexteditor qt5.qtquickcontrols2 $charts

View File

@ -1,6 +1,6 @@
enable_testing()
SET(GENERATOR "${CMAKE_BINARY_DIR}/rust_qt_binding_generator/rust_qt_binding_generator")
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
add_custom_target("clean-rust")
@ -33,6 +33,10 @@ function(rust_test NAME DIRECTORY)
DEPENDS "${DIR}/${RUST_TARGET_DIR}/librust.a")
add_executable("${NAME}" "${NAME}.cpp" "${NAME}_rust.cpp" "${NAME}_rust.h")
set_target_properties("${NAME}" PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
)
add_dependencies("${NAME}" "test_${DIRECTORY}")
target_link_libraries("${NAME}"
Qt5::Core