2018-07-11 09:34:33 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <QQmlEngine>
|
|
|
|
#include <QQuickItem>
|
|
|
|
|
2022-04-09 00:24:15 +00:00
|
|
|
#ifdef MAP_SUPPORT
|
2018-07-11 10:17:06 +00:00
|
|
|
#include "map-widget/qmlmapwidgethelper.h"
|
|
|
|
#include "qt-models/maplocationmodel.h"
|
2022-02-09 23:56:36 +00:00
|
|
|
#endif
|
|
|
|
|
statistics: convert chart to QQuickItem
It turns out that the wrong base class was used for the chart.
QQuickWidget can only be used on desktop, not in a mobile UI.
Therefore, turn this into a QQuickItem and move the container
QQuickWidget into desktop-only code.
Currently, this code is insane: The chart is rendered onto a
QGraphicsScene (as it was before), which is then rendered into
a QImage, which is transformed into a QSGTexture, which is then
projected onto the device. This is performed on every mouse
move event, since these events in general change the position
of the info-box.
The plan is to slowly convert elements such as the info-box into
QQuickItems. Browsing the QtQuick documentation, this will
not be much fun.
Also note that the rendering currently tears, flickers and has
antialiasing artifacts, most likely owing to integer (QImage)
to floating point (QGraphicsScene, QQuickItem) conversion
problems. The data flow is
QGraphicsScene (float) -> QImage (int) -> QQuickItem (float).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-07 13:38:37 +00:00
|
|
|
#include "stats/statsview.h"
|
computer configuration: use value semantics for DeviceDetails
The memory managements for DeviceDetails was very sketchy.
First of all, sharing a pointer to a structure between threads
seems like a recipe for disaster. Secondly, the structure was
a QObject and when first generated included in the (silly)
Qt object tree, but when generated in the threads it was not.
Clearly, this leaks.
Instead, use value semantics and use local copies of the
structure. I didn't go full length and use std::move to
move the data, because this doesn't work through signals
(which are the wrong abstraction here, but OK) and secondly
I didn't have time to analyze whether the caller still
needs the data after passing it down to the worker thread.
To be able to pass an object through signals, the class
has to be registered in the Qt MetaType system. Super
ugly, but fine for now. Ultimately, this whole thing should
probably be replaced by futures, co-routines, or whatever.
Moreover, this removes the prefix from number of "m_*"
function parameters. By convention, "m_" marks member
variables, which function parameters are not.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
make DeviceDetails a metatype
So that we can pass it as value through the signal/slot system.
(squash with original commit)
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-03-16 08:29:54 +00:00
|
|
|
#include "core/devicedetails.h"
|
2024-03-24 20:03:08 +00:00
|
|
|
#include "core/errorhelper.h"
|
2022-03-12 17:30:23 +00:00
|
|
|
#include "core/globals.h"
|
2018-07-11 09:34:33 +00:00
|
|
|
#include "core/qt-gui.h"
|
|
|
|
#include "core/settings/qPref.h"
|
2018-07-11 10:17:06 +00:00
|
|
|
|
2018-07-11 09:34:33 +00:00
|
|
|
#ifdef SUBSURFACE_MOBILE
|
2019-09-28 19:04:52 +00:00
|
|
|
#include <QApplication>
|
2018-07-11 10:17:06 +00:00
|
|
|
#include <QQmlApplicationEngine>
|
|
|
|
#include <QQmlContext>
|
2020-01-13 13:45:32 +00:00
|
|
|
#include "mobile-widgets/themeinterface.h"
|
2018-07-11 09:34:33 +00:00
|
|
|
#include "mobile-widgets/qmlmanager.h"
|
2020-01-04 08:47:10 +00:00
|
|
|
#include "mobile-widgets/qmlinterface.h"
|
2021-01-07 14:12:25 +00:00
|
|
|
#include "mobile-widgets/statsmanager.h"
|
2021-01-12 16:53:38 +00:00
|
|
|
#include "stats/chartlistmodel.h"
|
2020-02-08 11:06:57 +00:00
|
|
|
#include "qt-models/divesummarymodel.h"
|
2018-07-11 10:17:06 +00:00
|
|
|
#include "qt-models/messagehandlermodel.h"
|
2019-11-12 05:35:20 +00:00
|
|
|
#include "qt-models/mobilelistmodel.h"
|
2018-07-11 09:34:33 +00:00
|
|
|
#include "profile-widget/qmlprofile.h"
|
|
|
|
#include "core/downloadfromdcthread.h"
|
2020-10-25 12:57:18 +00:00
|
|
|
#include "core/subsurfacestartup.h" // for testqml
|
2021-01-14 11:54:28 +00:00
|
|
|
#include "core/metrics.h"
|
2018-07-11 09:34:33 +00:00
|
|
|
#include "qt-models/diveimportedmodel.h"
|
2018-07-11 10:17:06 +00:00
|
|
|
#else
|
|
|
|
#include "desktop-widgets/mainwindow.h"
|
2018-07-11 10:09:36 +00:00
|
|
|
#endif
|
2018-07-11 10:17:06 +00:00
|
|
|
|
2019-09-19 00:39:52 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
|
|
|
QString getAndroidHWInfo(); // from android.cpp
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QFontDatabase>
|
|
|
|
#endif /* Q_OS_ANDROID */
|
|
|
|
|
2018-07-11 10:17:06 +00:00
|
|
|
QObject *qqWindowObject = NULL;
|
|
|
|
|
2018-09-12 10:22:11 +00:00
|
|
|
// Forward declaration
|
|
|
|
static void register_qml_types(QQmlEngine *);
|
2018-07-15 15:56:18 +00:00
|
|
|
static void register_meta_types();
|
2018-09-12 10:22:11 +00:00
|
|
|
|
2020-11-27 21:05:39 +00:00
|
|
|
#ifdef SUBSURFACE_MOBILE
|
|
|
|
#include <QtPlugin>
|
2020-11-24 18:50:26 +00:00
|
|
|
Q_IMPORT_PLUGIN(KirigamiPlugin)
|
2020-11-27 21:05:39 +00:00
|
|
|
#endif
|
2020-11-24 18:50:26 +00:00
|
|
|
|
2018-07-11 10:17:06 +00:00
|
|
|
void init_ui()
|
|
|
|
{
|
|
|
|
init_qt_late();
|
2018-07-15 15:56:18 +00:00
|
|
|
register_meta_types();
|
2018-07-11 10:17:06 +00:00
|
|
|
#ifndef SUBSURFACE_MOBILE
|
2018-09-12 10:22:11 +00:00
|
|
|
register_qml_types(NULL);
|
2018-07-11 10:17:06 +00:00
|
|
|
|
2022-03-13 17:45:50 +00:00
|
|
|
MainWindow *window = make_global<MainWindow>();
|
2018-07-11 10:17:06 +00:00
|
|
|
window->setTitle();
|
2018-07-12 16:22:56 +00:00
|
|
|
#endif // SUBSURFACE_MOBILE
|
2018-07-11 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void exit_ui()
|
|
|
|
{
|
2022-03-12 17:30:23 +00:00
|
|
|
free_globals();
|
2018-07-11 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SUBSURFACE_MOBILE
|
2021-01-15 01:08:13 +00:00
|
|
|
void run_mobile_ui(double initial_font_size)
|
2021-01-15 01:04:37 +00:00
|
|
|
{
|
2019-09-28 19:03:55 +00:00
|
|
|
#if defined(Q_OS_ANDROID)
|
2020-11-25 00:01:55 +00:00
|
|
|
// work around an odd interaction between the OnePlus flavor of Android and Qt font handling
|
2019-09-28 19:03:55 +00:00
|
|
|
if (getAndroidHWInfo().contains("/OnePlus/")) {
|
2021-01-14 11:54:28 +00:00
|
|
|
QFontInfo qfi(defaultModelFont());
|
|
|
|
double basePointSize = qfi.pointSize();
|
2019-09-28 19:03:55 +00:00
|
|
|
QFontDatabase db;
|
|
|
|
int id = QFontDatabase::addApplicationFont(":/fonts/Roboto-Regular.ttf");
|
2020-11-20 18:08:17 +00:00
|
|
|
QStringList fontFamilies = QFontDatabase::applicationFontFamilies(id);
|
|
|
|
if (fontFamilies.count() > 0) {
|
|
|
|
QString family = fontFamilies.at(0);
|
|
|
|
QFont newDefaultFont;
|
|
|
|
newDefaultFont.setFamily(family);
|
2021-01-14 11:54:28 +00:00
|
|
|
newDefaultFont.setPointSize(basePointSize);
|
2020-11-20 18:08:17 +00:00
|
|
|
(static_cast<QApplication *>(QCoreApplication::instance()))->setFont(newDefaultFont);
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("Detected OnePlus device, trying to force bundled font %s", qPrintable(family));
|
2020-11-20 18:08:17 +00:00
|
|
|
QFont defaultFont = (static_cast<QApplication *>(QCoreApplication::instance()))->font();
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("Qt reports default font is set as", qPrintable(defaultFont.family()));
|
2020-11-20 18:08:17 +00:00
|
|
|
} else {
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("Detected OnePlus device, but can't determine font family used");
|
2020-11-20 18:08:17 +00:00
|
|
|
}
|
2019-09-28 19:03:55 +00:00
|
|
|
}
|
|
|
|
#endif
|
2019-09-28 19:04:52 +00:00
|
|
|
QScreen *appScreen = QApplication::screens().at(0);
|
|
|
|
int availableScreenWidth = appScreen->availableSize().width();
|
2018-07-11 10:17:06 +00:00
|
|
|
QQmlApplicationEngine engine;
|
2020-03-30 19:48:29 +00:00
|
|
|
QQmlContext *ctxt = engine.rootContext();
|
|
|
|
|
|
|
|
// Register qml interface classes
|
|
|
|
QMLInterface::setup(ctxt);
|
2018-09-04 09:18:43 +00:00
|
|
|
register_qml_types(&engine);
|
2018-07-11 10:17:06 +00:00
|
|
|
#if defined(__APPLE__) && !defined(Q_OS_IOS)
|
|
|
|
// when running the QML UI on a Mac the deployment of the QML Components seems
|
|
|
|
// to fail and the search path for the components is rather odd - simply the
|
|
|
|
// same directory the executable was started from <bundle>/Contents/MacOS/
|
|
|
|
// To work around this we need to manually copy the components at install time
|
|
|
|
// to Contents/Frameworks/qml and make sure that we add the correct import path
|
2019-04-01 20:15:19 +00:00
|
|
|
const QStringList importPathList = engine.importPathList();
|
|
|
|
for (QString importPath: importPathList) {
|
2018-07-11 10:17:06 +00:00
|
|
|
if (importPath.contains("MacOS"))
|
|
|
|
engine.addImportPath(importPath.replace("MacOS", "Frameworks"));
|
|
|
|
}
|
2018-07-12 16:22:56 +00:00
|
|
|
#endif // __APPLE__ not Q_OS_IOS
|
2020-11-24 23:57:29 +00:00
|
|
|
// this is frustrating, but we appear to need different import paths on different OSs
|
|
|
|
engine.addImportPath(":");
|
2018-07-11 10:17:06 +00:00
|
|
|
engine.addImportPath("qrc://imports");
|
|
|
|
ctxt->setContextProperty("vendorList", vendorList);
|
2020-03-06 11:48:47 +00:00
|
|
|
ctxt->setContextProperty("swipeModel", MobileModels::instance()->swipeModel());
|
2019-12-11 09:37:50 +00:00
|
|
|
ctxt->setContextProperty("diveModel", MobileModels::instance()->listModel());
|
2018-07-11 10:17:06 +00:00
|
|
|
set_non_bt_addresses();
|
|
|
|
|
2021-01-15 01:08:13 +00:00
|
|
|
// we need to setup the initial font size before the QML UI is instantiated
|
|
|
|
ThemeInterface *themeInterface = ThemeInterface::instance();
|
|
|
|
themeInterface->setInitialFontSize(initial_font_size);
|
|
|
|
|
2018-07-11 10:17:06 +00:00
|
|
|
ctxt->setContextProperty("connectionListModel", &connectionListModel);
|
|
|
|
ctxt->setContextProperty("logModel", MessageHandlerModel::self());
|
2021-01-15 01:08:13 +00:00
|
|
|
ctxt->setContextProperty("subsurfaceTheme", themeInterface);
|
2018-07-11 10:17:06 +00:00
|
|
|
|
2019-11-19 18:54:15 +00:00
|
|
|
qmlRegisterUncreatableType<QMLManager>("org.subsurfacedivelog.mobile",1,0,"ExportType","Enum is not a type");
|
|
|
|
|
2019-11-23 12:09:25 +00:00
|
|
|
#ifdef SUBSURFACE_MOBILE_DESKTOP
|
2024-02-28 19:07:39 +00:00
|
|
|
if (!testqml.empty()) {
|
|
|
|
QString fileLoad(testqml.c_str());
|
2019-11-23 12:09:25 +00:00
|
|
|
fileLoad += "/main.qml";
|
|
|
|
engine.load(QUrl(fileLoad));
|
|
|
|
} else {
|
|
|
|
engine.load(QUrl(QStringLiteral("qrc:///qml/main.qml")));
|
|
|
|
}
|
|
|
|
#else
|
2018-07-11 10:17:06 +00:00
|
|
|
engine.load(QUrl(QStringLiteral("qrc:///qml/main.qml")));
|
2019-11-23 12:09:25 +00:00
|
|
|
#endif
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("loaded main.qml");
|
2018-07-11 10:17:06 +00:00
|
|
|
qqWindowObject = engine.rootObjects().value(0);
|
|
|
|
if (!qqWindowObject) {
|
2024-03-24 20:03:08 +00:00
|
|
|
report_info("can't create window object");
|
2018-07-11 10:17:06 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
QQuickWindow *qml_window = qobject_cast<QQuickWindow *>(qqWindowObject);
|
|
|
|
qml_window->setIcon(QIcon(":subsurface-mobile-icon"));
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("qqwindow devicePixelRatio %f %f", qml_window->devicePixelRatio(), qml_window->screen()->devicePixelRatio());
|
2018-07-11 10:17:06 +00:00
|
|
|
QScreen *screen = qml_window->screen();
|
2019-09-28 19:04:52 +00:00
|
|
|
int qmlWW = qml_window->width();
|
|
|
|
int qmlSW = screen->size().width();
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("qml_window reports width as %d associated screen width %d Qt screen reports width as %d", qmlWW, qmlSW, availableScreenWidth);
|
2018-07-11 10:17:06 +00:00
|
|
|
QObject::connect(qml_window, &QQuickWindow::screenChanged, QMLManager::instance(), &QMLManager::screenChanged);
|
|
|
|
QMLManager *manager = QMLManager::instance();
|
|
|
|
|
|
|
|
manager->setDevicePixelRatio(qml_window->devicePixelRatio(), qml_window->screen());
|
2018-10-20 15:53:36 +00:00
|
|
|
manager->qmlWindow = qqWindowObject;
|
2018-07-11 10:17:06 +00:00
|
|
|
manager->screenChanged(screen);
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("qqwindow screen has ldpi/pdpi %f %f", screen->logicalDotsPerInch(), screen->physicalDotsPerInch());
|
2018-07-11 10:17:06 +00:00
|
|
|
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
2019-09-13 19:41:42 +00:00
|
|
|
int width = 800;
|
2020-02-12 06:15:32 +00:00
|
|
|
int height = 1200;
|
2019-09-13 19:41:42 +00:00
|
|
|
if (qEnvironmentVariableIsSet("SUBSURFACE_MOBILE_WIDTH")) {
|
|
|
|
bool ok;
|
|
|
|
int width_override = qEnvironmentVariableIntValue("SUBSURFACE_MOBILE_WIDTH", &ok);
|
|
|
|
if (ok) {
|
|
|
|
width = width_override;
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("overriding window width: %d", width);
|
2019-09-13 19:41:42 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-12 06:15:32 +00:00
|
|
|
if (qEnvironmentVariableIsSet("SUBSURFACE_MOBILE_HEIGHT")) {
|
|
|
|
bool ok;
|
|
|
|
int height_override = qEnvironmentVariableIntValue("SUBSURFACE_MOBILE_HEIGHT", &ok);
|
|
|
|
if (ok) {
|
|
|
|
height = height_override;
|
2024-03-24 20:15:36 +00:00
|
|
|
report_info("overriding window height: %d", height);
|
2020-02-12 06:15:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
qml_window->setHeight(height);
|
2019-09-13 19:41:42 +00:00
|
|
|
qml_window->setWidth(width);
|
2018-07-12 16:22:56 +00:00
|
|
|
#endif // not Q_OS_ANDROID and not Q_OS_IOS
|
2018-07-11 10:17:06 +00:00
|
|
|
qml_window->show();
|
2021-01-15 01:04:37 +00:00
|
|
|
qApp->exec();
|
|
|
|
}
|
|
|
|
#else // SUBSURFACE_MOBILE
|
|
|
|
// just run the desktop UI
|
|
|
|
void run_ui()
|
|
|
|
{
|
2018-07-11 10:17:06 +00:00
|
|
|
MainWindow::instance()->show();
|
|
|
|
qApp->exec();
|
|
|
|
}
|
2021-01-15 01:04:37 +00:00
|
|
|
#endif // SUBSURFACE_MOBILE
|
2018-07-15 15:56:18 +00:00
|
|
|
|
|
|
|
Q_DECLARE_METATYPE(duration_t)
|
|
|
|
static void register_meta_types()
|
|
|
|
{
|
|
|
|
qRegisterMetaType<duration_t>();
|
computer configuration: use value semantics for DeviceDetails
The memory managements for DeviceDetails was very sketchy.
First of all, sharing a pointer to a structure between threads
seems like a recipe for disaster. Secondly, the structure was
a QObject and when first generated included in the (silly)
Qt object tree, but when generated in the threads it was not.
Clearly, this leaks.
Instead, use value semantics and use local copies of the
structure. I didn't go full length and use std::move to
move the data, because this doesn't work through signals
(which are the wrong abstraction here, but OK) and secondly
I didn't have time to analyze whether the caller still
needs the data after passing it down to the worker thread.
To be able to pass an object through signals, the class
has to be registered in the Qt MetaType system. Super
ugly, but fine for now. Ultimately, this whole thing should
probably be replaced by futures, co-routines, or whatever.
Moreover, this removes the prefix from number of "m_*"
function parameters. By convention, "m_" marks member
variables, which function parameters are not.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
make DeviceDetails a metatype
So that we can pass it as value through the signal/slot system.
(squash with original commit)
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-03-16 08:29:54 +00:00
|
|
|
qRegisterMetaType<DeviceDetails>();
|
2018-07-15 15:56:18 +00:00
|
|
|
}
|
2018-07-12 16:22:56 +00:00
|
|
|
|
2020-03-30 20:12:54 +00:00
|
|
|
template <typename T>
|
|
|
|
static void register_qml_type(const char *name)
|
|
|
|
{
|
|
|
|
if(qmlRegisterType<T>("org.subsurfacedivelog.mobile", 1, 0, name) < 0)
|
|
|
|
qWarning("ERROR: Cannot register %s, QML will not work!!", name);
|
|
|
|
}
|
2018-07-28 17:24:55 +00:00
|
|
|
|
2020-03-30 20:12:54 +00:00
|
|
|
static void register_qml_types(QQmlEngine *engine)
|
2018-07-12 16:22:56 +00:00
|
|
|
{
|
2018-08-31 09:57:28 +00:00
|
|
|
// register qPref*
|
2019-04-03 21:28:26 +00:00
|
|
|
qPref::registerQML(engine);
|
2018-07-12 16:22:56 +00:00
|
|
|
|
|
|
|
#ifdef SUBSURFACE_MOBILE
|
2020-03-30 20:12:54 +00:00
|
|
|
register_qml_type<QMLManager>("QMLManager");
|
2021-01-07 14:12:25 +00:00
|
|
|
register_qml_type<StatsManager>("StatsManager");
|
2020-03-30 20:12:54 +00:00
|
|
|
register_qml_type<QMLProfile>("QMLProfile");
|
|
|
|
register_qml_type<DiveImportedModel>("DCImportModel");
|
|
|
|
register_qml_type<DiveSummaryModel>("DiveSummaryModel");
|
2021-01-12 16:53:38 +00:00
|
|
|
register_qml_type<ChartListModel>("ChartListModel");
|
2018-07-12 16:22:56 +00:00
|
|
|
#endif // not SUBSURFACE_MOBILE
|
|
|
|
|
2022-04-09 00:24:15 +00:00
|
|
|
#ifdef MAP_SUPPORT
|
2020-03-30 20:12:54 +00:00
|
|
|
register_qml_type<MapWidgetHelper>("MapWidgetHelper");
|
|
|
|
register_qml_type<MapLocationModel>("MapLocationModel");
|
2022-02-09 23:56:36 +00:00
|
|
|
#endif
|
statistics: convert chart to QQuickItem
It turns out that the wrong base class was used for the chart.
QQuickWidget can only be used on desktop, not in a mobile UI.
Therefore, turn this into a QQuickItem and move the container
QQuickWidget into desktop-only code.
Currently, this code is insane: The chart is rendered onto a
QGraphicsScene (as it was before), which is then rendered into
a QImage, which is transformed into a QSGTexture, which is then
projected onto the device. This is performed on every mouse
move event, since these events in general change the position
of the info-box.
The plan is to slowly convert elements such as the info-box into
QQuickItems. Browsing the QtQuick documentation, this will
not be much fun.
Also note that the rendering currently tears, flickers and has
antialiasing artifacts, most likely owing to integer (QImage)
to floating point (QGraphicsScene, QQuickItem) conversion
problems. The data flow is
QGraphicsScene (float) -> QImage (int) -> QQuickItem (float).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-07 13:38:37 +00:00
|
|
|
register_qml_type<StatsView>("StatsView");
|
2018-07-12 16:22:56 +00:00
|
|
|
}
|