├── lqtutils_fsm.cpp
├── LQtUtilsQuick
├── lquicksettings.cpp
├── qml.qrc
├── ltestsignals.cpp
├── ltestsignals.h
├── lquicksettings.h
├── main.cpp
├── main.qml
├── .gitignore
└── CMakeLists.txt
├── docs
├── cutouts.webp
└── cutouts_horizontal.webp
├── fontawesome
├── Font Awesome 6 Free-Solid-900.otf
├── Font Awesome 6 Brands-Regular-400.otf
├── Font Awesome 6 Free-Regular-400.otf
├── LQTFontAwesomeFreeRegular.qml
├── LQTFontAwesomeBrandsRegular.qml
└── LQTFontAwesomeFreeSolid.qml
├── lqtutils_sslcheck.h
├── .gitignore
├── LICENSE
├── lqtutils_qsl.h
├── lqtutils_fa.h
├── lqtutils_time.h
├── lqtutils.pri
├── qt5
└── CMakeLists.txt
├── lqtutils_freq.h
├── lqtutils_autoexec.h
├── lqtutils
├── CMakeLists.txt
└── tst_lqtutils.cpp
├── lqtutils_misc.h
├── lqtutils_fsm.h
├── CMakeLists_qt5.txt
├── qt6
└── CMakeLists.txt
├── lqtutils_freq.cpp
├── lqtutils_math.h
├── lqtutils_ui.mm
├── lqtutils_models.h
├── lqtutils_enum.h
├── lqtutils_perf.h
├── lqtutils_logging.h
├── lqtutils_fa.cpp
├── lqtutils_net.h
├── lqtutils_system.h
├── CMakeLists.txt
├── lqtutils_ui_apple.mm
├── lqtutils_threading.h
├── lqtutils_net.cpp
├── lqtutils_ui.h
├── lqtutils_bqueue.h
├── .gitlab-ci.yml
├── lqtutils_string.h
├── lqtutils_settings.h
├── lqtutils_data.h
├── lqtutils_prop.h
├── README.md
└── lqtutils_ui.cpp
/lqtutils_fsm.cpp:
--------------------------------------------------------------------------------
1 | #include "lqtutils_fsm.h"
--------------------------------------------------------------------------------
/LQtUtilsQuick/lquicksettings.cpp:
--------------------------------------------------------------------------------
1 | #include "lquicksettings.h"
2 |
--------------------------------------------------------------------------------
/docs/cutouts.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carlonluca/lqtutils/HEAD/docs/cutouts.webp
--------------------------------------------------------------------------------
/docs/cutouts_horizontal.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carlonluca/lqtutils/HEAD/docs/cutouts_horizontal.webp
--------------------------------------------------------------------------------
/LQtUtilsQuick/qml.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | main.qml
4 |
5 |
6 |
--------------------------------------------------------------------------------
/fontawesome/Font Awesome 6 Free-Solid-900.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carlonluca/lqtutils/HEAD/fontawesome/Font Awesome 6 Free-Solid-900.otf
--------------------------------------------------------------------------------
/fontawesome/Font Awesome 6 Brands-Regular-400.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carlonluca/lqtutils/HEAD/fontawesome/Font Awesome 6 Brands-Regular-400.otf
--------------------------------------------------------------------------------
/fontawesome/Font Awesome 6 Free-Regular-400.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/carlonluca/lqtutils/HEAD/fontawesome/Font Awesome 6 Free-Regular-400.otf
--------------------------------------------------------------------------------
/lqtutils_sslcheck.h:
--------------------------------------------------------------------------------
1 | #ifndef LQTUTILS_SSL_H
2 | #define LQTUTILS_SSL_H
3 |
4 | #ifdef QT_NO_SSL
5 | #error SSL support missing in this Qt build
6 | #endif
7 |
8 | #endif // LQTUTILS_SSL_H
9 |
--------------------------------------------------------------------------------
/LQtUtilsQuick/ltestsignals.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "lquicksettings.h"
4 | #include "ltestsignals.h"
5 |
6 | LTestSignals::LTestSignals(QObject *parent) : QObject(parent)
7 | {
8 | connect(&LQuickSettings::notifier(), &LQuickSettings::appWidthChanged, this, [] (int width) {
9 | qDebug() << "C++ app width changed:" << width;
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/LQtUtilsQuick/ltestsignals.h:
--------------------------------------------------------------------------------
1 | #ifndef LTESTSIGNALS_H
2 | #define LTESTSIGNALS_H
3 |
4 | #include
5 |
6 | #include <../lqtutils_enum.h>
7 |
8 | L_DECLARE_ENUM(MySharedEnum,
9 | Value1,
10 | Value2,
11 | Value6 = 6)
12 |
13 | Q_NAMESPACE
14 |
15 | class LTestSignals : public QObject
16 | {
17 | Q_OBJECT
18 | public:
19 | explicit LTestSignals(QObject* parent = nullptr);
20 | };
21 |
22 | #endif // LTESTSIGNALS_H
23 |
--------------------------------------------------------------------------------
/fontawesome/LQTFontAwesomeFreeRegular.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.15
2 |
3 | Item {
4 | property alias iconColor: innerText.color
5 | property alias iconUtf8: innerText.text
6 | property alias innerTextElement: innerText
7 |
8 | Text {
9 | id: innerText
10 | font.family: fontAwesomeFreeRegular.family
11 | font.styleName: fontAwesomeFreeRegular.styleName
12 | font.weight: fontAwesomeFreeRegular.weight
13 | font.pixelSize: height
14 | anchors.fill: parent
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/fontawesome/LQTFontAwesomeBrandsRegular.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.15
2 |
3 | Item {
4 | property alias iconColor: innerText.color
5 | property alias iconUtf8: innerText.text
6 | property alias innerTextElement: innerText
7 |
8 | Text {
9 | id: innerText
10 | font.family: fontAwesomeBrandsRegular.family
11 | font.styleName: fontAwesomeBrandsRegular.styleName
12 | font.weight: fontAwesomeBrandsRegular.weight
13 | font.pixelSize: height
14 | anchors.fill: parent
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/LQtUtilsQuick/lquicksettings.h:
--------------------------------------------------------------------------------
1 | #ifndef LQUICKSETTINGS_H
2 | #define LQUICKSETTINGS_H
3 |
4 | #include
5 |
6 | #include "../lqtutils_settings.h"
7 | #include "../lqtutils_prop.h"
8 | #include "../lqtutils_string.h"
9 |
10 | Q_NAMESPACE
11 |
12 | L_DECLARE_SETTINGS(LQuickSettings, new QSettings(QSL("settings.ini"), QSettings::IniFormat))
13 | L_DEFINE_VALUE(int, appWidth, 200)
14 | L_DEFINE_VALUE(int, appHeight, 200)
15 | L_DEFINE_VALUE(int, appX, 100)
16 | L_DEFINE_VALUE(int, appY, 100)
17 | L_END_CLASS
18 |
19 | #endif // LQUICKSETTINGS_H
20 |
--------------------------------------------------------------------------------
/fontawesome/LQTFontAwesomeFreeSolid.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.15
2 |
3 | Item {
4 | property alias iconColor: innerText.color
5 | property alias iconUtf8: innerText.text
6 | property alias innerTextElement: innerText
7 |
8 | Text {
9 | id: innerText
10 | font.family: fontAwesomeFreeSolid.family
11 | font.styleName: fontAwesomeFreeSolid.styleName
12 | font.weight: fontAwesomeFreeSolid.weight
13 | font.pixelSize: height
14 | anchors.fill: parent
15 | horizontalAlignment: Text.AlignHCenter
16 | verticalAlignment: Text.AlignHCenter
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/LQtUtilsQuick/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "../lqtutils_settings.h"
6 | #include "../lqtutils_prop.h"
7 |
8 | #include "ltestsignals.h"
9 | #include "lquicksettings.h"
10 |
11 | int main(int argc, char *argv[])
12 | {
13 | QGuiApplication app(argc, argv);
14 | MySharedEnum::qmlRegisterMySharedEnum("com.luke", 1, 0);
15 | QQmlApplicationEngine engine;
16 | engine.rootContext()->setContextProperty("settings", &LQuickSettings::notifier());
17 | const QUrl url(QStringLiteral("qrc:/main.qml"));
18 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
19 | &app, [url](QObject *obj, const QUrl &objUrl) {
20 | if (!obj && url == objUrl)
21 | QCoreApplication::exit(-1);
22 | }, Qt::QueuedConnection);
23 | engine.load(url);
24 | return app.exec();
25 | }
26 |
--------------------------------------------------------------------------------
/LQtUtilsQuick/main.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.12
2 | import QtQuick.Window 2.12
3 | import com.luke 1.0
4 |
5 | Window {
6 | property int enumValue: MySharedEnum.Value6
7 | property bool doBind: false
8 |
9 | visible: true
10 |
11 | Component.onCompleted: {
12 | console.log("Enum value:", enumValue)
13 | x = settings.appX
14 | y = settings.appY
15 | width = settings.appWidth
16 | height = settings.appHeight
17 | doBind = true
18 | }
19 |
20 | Connections {
21 | target: settings
22 | onAppWidthChanged: (w) => console.log("App width saved:", w)
23 | onAppHeightChanged: (h) => console.log("App height saved:", h)
24 | }
25 |
26 | Binding { when: doBind; target: settings; property: "appWidth"; value: width }
27 | Binding { when: doBind; target: settings; property: "appHeight"; value: height }
28 | Binding { when: doBind; target: settings; property: "appX"; value: x }
29 | Binding { when: doBind; target: settings; property: "appY"; value: y }
30 | }
31 |
--------------------------------------------------------------------------------
/LQtUtilsQuick/.gitignore:
--------------------------------------------------------------------------------
1 | # This file is used to ignore files which are generated
2 | # ----------------------------------------------------------------------------
3 |
4 | *~
5 | *.autosave
6 | *.a
7 | *.core
8 | *.moc
9 | *.o
10 | *.obj
11 | *.orig
12 | *.rej
13 | *.so
14 | *.so.*
15 | *_pch.h.cpp
16 | *_resource.rc
17 | *.qm
18 | .#*
19 | *.*#
20 | core
21 | !core/
22 | tags
23 | .DS_Store
24 | .directory
25 | *.debug
26 | Makefile*
27 | *.prl
28 | *.app
29 | moc_*.cpp
30 | ui_*.h
31 | qrc_*.cpp
32 | Thumbs.db
33 | *.res
34 | *.rc
35 | /.qmake.cache
36 | /.qmake.stash
37 |
38 | # qtcreator generated files
39 | *.pro.user*
40 |
41 | # xemacs temporary files
42 | *.flc
43 |
44 | # Vim temporary files
45 | .*.swp
46 |
47 | # Visual Studio generated files
48 | *.ib_pdb_index
49 | *.idb
50 | *.ilk
51 | *.pdb
52 | *.sln
53 | *.suo
54 | *.vcproj
55 | *vcproj.*.*.user
56 | *.ncb
57 | *.sdf
58 | *.opensdf
59 | *.vcxproj
60 | *vcxproj.*
61 |
62 | # MinGW generated files
63 | *.Debug
64 | *.Release
65 |
66 | # Python byte code
67 | *.pyc
68 |
69 | # Binaries
70 | # --------
71 | *.dll
72 | *.exe
73 |
74 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # This file is used to ignore files which are generated
2 | # ----------------------------------------------------------------------------
3 |
4 | *~
5 | *.autosave
6 | *.a
7 | *.core
8 | *.moc
9 | *.o
10 | *.obj
11 | *.orig
12 | *.rej
13 | *.so
14 | *.so.*
15 | *_pch.h.cpp
16 | *_resource.rc
17 | *.qm
18 | .#*
19 | *.*#
20 | core
21 | !core/
22 | tags
23 | .DS_Store
24 | .directory
25 | *.debug
26 | Makefile*
27 | *.prl
28 | *.app
29 | moc_*.cpp
30 | ui_*.h
31 | qrc_*.cpp
32 | Thumbs.db
33 | *.res
34 | *.rc
35 | /.qmake.cache
36 | /.qmake.stash
37 |
38 | # qtcreator generated files
39 | *.pro.user*
40 |
41 | # xemacs temporary files
42 | *.flc
43 |
44 | # Vim temporary files
45 | .*.swp
46 |
47 | # Visual Studio generated files
48 | *.ib_pdb_index
49 | *.idb
50 | *.ilk
51 | *.pdb
52 | *.sln
53 | *.suo
54 | *.vcproj
55 | *vcproj.*.*.user
56 | *.ncb
57 | *.sdf
58 | *.opensdf
59 | *.vcxproj
60 | *vcxproj.*
61 |
62 | # MinGW generated files
63 | *.Debug
64 | *.Release
65 |
66 | # Python byte code
67 | *.pyc
68 |
69 | # Binaries
70 | # --------
71 | *.dll
72 | *.exe
73 |
74 | build*
75 | CMakeLists.txt.*
76 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Luca Carlon
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lqtutils_qsl.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_QSL_H
26 | #define LQTUTILS_QSL_H
27 |
28 | #ifndef QSL
29 | #define QSL QStringLiteral
30 | #endif // QSL
31 |
32 | #endif // LQTUTILS_QSL_H
33 |
--------------------------------------------------------------------------------
/LQtUtilsQuick/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 |
3 | project(LQtUtilsQuick LANGUAGES CXX)
4 |
5 | set(CMAKE_INCLUDE_CURRENT_DIR ON)
6 |
7 | set(CMAKE_AUTOUIC ON)
8 | set(CMAKE_AUTOMOC ON)
9 | set(CMAKE_AUTORCC ON)
10 |
11 | set(CMAKE_CXX_STANDARD 11)
12 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
13 |
14 | # QtCreator supports the following variables for Android, which are identical to qmake Android variables.
15 | # Check http://doc.qt.io/qt-5/deployment-android.html for more information.
16 | # They need to be set before the find_package(Qt5 ...) call.
17 |
18 | #if(ANDROID)
19 | # set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
20 | # if (ANDROID_ABI STREQUAL "armeabi-v7a")
21 | # set(ANDROID_EXTRA_LIBS
22 | # ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
23 | # ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
24 | # endif()
25 | #endif()
26 |
27 | find_package(Qt5 COMPONENTS Core Quick REQUIRED)
28 |
29 | if(ANDROID)
30 | add_library(LQtUtilsQuick SHARED
31 | main.cpp
32 | qml.qrc
33 | )
34 | else()
35 | add_executable(LQtUtilsQuick
36 | main.cpp
37 | ltestsignals.cpp
38 | lquicksettings.cpp
39 | qml.qrc
40 | )
41 | endif()
42 |
43 | target_compile_definitions(LQtUtilsQuick
44 | PRIVATE $<$,$>:QT_QML_DEBUG>)
45 | target_link_libraries(LQtUtilsQuick
46 | PRIVATE Qt5::Core Qt5::Quick)
47 |
--------------------------------------------------------------------------------
/lqtutils_fa.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_FA_H
26 | #define LQTUTILS_FA_H
27 |
28 | #include
29 |
30 | QT_FORWARD_DECLARE_CLASS(QQmlContext);
31 |
32 | namespace lqt
33 | {
34 |
35 | bool embed_font_awesome(QQmlContext* ctx);
36 |
37 | }
38 |
39 |
40 | #endif // LQTUTILS_FA_H
41 |
--------------------------------------------------------------------------------
/lqtutils_time.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2021 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_TIME_H
26 | #define LQTUTILS_TIME_H
27 |
28 | #include
29 |
30 | namespace lqt {
31 |
32 | inline QDateTime today() {
33 | QDateTime now = QDateTime::currentDateTime();
34 | now.setTime(QTime(0, 0));
35 | return now;
36 | }
37 |
38 | inline QDateTime tomorrow() {
39 | return today().addDays(1);
40 | }
41 |
42 | }
43 |
44 | #endif // LQTUTILS_STRING_H
45 |
--------------------------------------------------------------------------------
/lqtutils.pri:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2020-2021 Luca Carlon
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #
24 |
25 | android {
26 | QT += androidextras
27 | }
28 | SOURCES += \
29 | $$PWD/lqtutils_ui.cpp \
30 | $$PWD/lqtutils_freq.cpp \
31 | $$PWD/lqtutils_fa.cpp
32 | HEADERS += \
33 | $$PWD/lqtutils_ui.h \
34 | $$PWD/lqtutils_freq.h \
35 | $$PWD/lqtutils_fa.h
36 | ios {
37 | SOURCES += $$PWD/lqtutils_ui.mm
38 | }
39 | contains(QT, statemachine) {
40 | SOURCES += $$PWD/lqtutils_fsm.cpp
41 | HEADERS += $$PWD/lqtutils_fsm.h
42 | }
43 | OTHER_FILES += $$PWD/lqtutils_*.h
44 |
--------------------------------------------------------------------------------
/qt5/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2020 Luca Carlon
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #
24 |
25 | cmake_minimum_required(VERSION 3.5)
26 |
27 | project(LQtUtilsTest LANGUAGES CXX)
28 |
29 | find_package(Qt5 COMPONENTS Core Test Gui Qml Quick DBus REQUIRED)
30 |
31 | set(CMAKE_INCLUDE_CURRENT_DIR ON)
32 |
33 | set(CMAKE_AUTOUIC ON)
34 | set(CMAKE_AUTOMOC ON)
35 | set(CMAKE_AUTORCC ON)
36 |
37 | set(CMAKE_CXX_STANDARD 17)
38 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
39 | enable_testing()
40 |
41 | include_directories(../)
42 | include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists_qt5.txt)
43 |
44 | add_executable(LQtUtilsTest ../lqtutils/tst_lqtutils.cpp)
45 | add_test(NAME LQtUtilsTest COMMAND LQtUtilsTest)
46 | target_link_libraries(LQtUtilsTest PRIVATE Qt5::Test Qt5::Gui Qt5::Qml Qt5::Quick Qt5::DBus lqtutils)
47 |
--------------------------------------------------------------------------------
/lqtutils_freq.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_FREQ_H
26 | #define LQTUTILS_FREQ_H
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | #include "lqtutils_prop.h"
35 |
36 | QT_FORWARD_DECLARE_CLASS(QTimer);
37 |
38 | namespace lqt {
39 |
40 | class FreqMeter : public QObject
41 | {
42 | Q_OBJECT
43 | L_RO_PROP_AS(int, freq, 0)
44 | public:
45 | explicit FreqMeter(QObject* parent = nullptr);
46 |
47 | public slots:
48 | void registerSample();
49 | void refresh();
50 |
51 | private:
52 | QMutex m_mutex;
53 | QList m_timestamps;
54 | QTimer* m_refreshTimer;
55 | };
56 |
57 | } // namespace
58 |
59 | #endif // LQTUTILS_FREQ_H
60 |
--------------------------------------------------------------------------------
/lqtutils_autoexec.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_AUTOEXEC_H
26 | #define LQTUTILS_AUTOEXEC_H
27 |
28 | #include
29 |
30 | #include
31 |
32 | namespace lqt {
33 |
34 | class AutoExec
35 | {
36 | public:
37 | AutoExec(std::function func) { reset(func); }
38 | AutoExec() { reset(nullptr); }
39 | ~AutoExec() { if (m_func) m_func(); }
40 | void reset(std::function func) { m_func = func; }
41 | void reset() { reset(nullptr); }
42 | private:
43 | std::function m_func;
44 | };
45 |
46 | class SharedAutoExec
47 | {
48 | public:
49 | SharedAutoExec(std::function func) :
50 | m_exec(new AutoExec(func)) {}
51 | SharedAutoExec() {}
52 |
53 | protected:
54 | QSharedPointer m_exec;
55 | };
56 |
57 | } // namespace
58 |
59 | #endif // LQTUTILS_AUTOEXEC_H
60 |
--------------------------------------------------------------------------------
/lqtutils/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2020 Luca Carlon
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #
24 |
25 | cmake_minimum_required(VERSION 3.14)
26 |
27 | project(LQtUtilsTest LANGUAGES CXX)
28 |
29 | find_package(QT NAMES Qt6 Qt5 COMPONENTS Test Gui Qml Quick REQUIRED)
30 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Test Gui Qml Quick REQUIRED)
31 |
32 | set(CMAKE_INCLUDE_CURRENT_DIR ON)
33 |
34 | set(CMAKE_AUTOUIC ON)
35 | set(CMAKE_AUTOMOC ON)
36 | set(CMAKE_AUTORCC ON)
37 |
38 | set(CMAKE_CXX_STANDARD 17)
39 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
40 | enable_testing()
41 |
42 | include_directories(../)
43 | include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)
44 |
45 |
46 | add_executable(LQtUtilsTest ${lqtutils_src} tst_lqtutils.cpp)
47 | add_test(NAME LQtUtilsTest COMMAND LQtUtilsTest)
48 | target_link_libraries(LQtUtilsTest PRIVATE Qt${QT_VERSION_MAJOR}::Test Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Qml Qt${QT_VERSION_MAJOR}::Quick)
49 |
--------------------------------------------------------------------------------
/lqtutils_misc.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_MISC_H
26 | #define LQTUTILS_MISC_H
27 |
28 | #include
29 |
30 | #if defined Q_OS_BLACKBERRY || defined Q_OS_ANDROID || defined Q_OS_IOS || defined Q_OS_WP
31 | #define L_OS_MOBILE
32 | #else
33 | #define L_OS_DESKTOP
34 | #endif
35 |
36 | inline bool operator!(const QString& str)
37 | {
38 | return str.isEmpty();
39 | }
40 |
41 | namespace lqt {
42 |
43 | ///
44 | /// \brief coalesce is a C++ implementation of the coalesce operator.
45 | /// \param lhs value to be evaluated: if evaluates to true, then it is
46 | /// returned, otherwise rhs is returned.
47 | /// \param rhs is the value to be returned if lhs does not evaluate
48 | /// to true.
49 | /// \return lhs if true, rhs otherwise.
50 | ///
51 | template
52 | T coalesce(T lhs, T rhs)
53 | {
54 | return !lhs ? rhs : lhs;
55 | }
56 |
57 | }
58 |
59 | #endif // LQTUTILS_MISC_H
60 |
--------------------------------------------------------------------------------
/lqtutils_fsm.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_FSM_H
26 | #define LQTUTILS_FSM_H
27 |
28 | #include
29 | #include
30 | #include
31 |
32 | #include "lqtutils_prop.h"
33 |
34 | namespace lqt {
35 |
36 | class LoggedState : public QState
37 | {
38 | Q_OBJECT
39 | L_RW_PROP(QString, stateName, setStateName)
40 | public:
41 | LoggedState(QState::ChildMode childMode, QString name = QString(), QState* parent = nullptr) :
42 | QState(childMode, parent) { m_stateName = name; init(); }
43 | LoggedState(QString name = QString(), QState* parent = nullptr) :
44 | QState(parent) { m_stateName = name; init(); }
45 |
46 | protected:
47 | virtual void init() {
48 | connect(this, &QState::entered, this, [this] {
49 | qDebug() << "Entered state:" << stateName();
50 | });
51 | }
52 | };
53 |
54 | } // namespace
55 |
56 | #endif // LQTUTILS_FSM_H
57 |
--------------------------------------------------------------------------------
/CMakeLists_qt5.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | set(CMAKE_AUTOMOC ON)
3 |
4 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui Qml Quick)
5 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui Qml Quick)
6 | find_package(QT NAMES Qt6 Qt5 OPTIONAL_COMPONENTS DBus)
7 | find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS DBus)
8 | if (Qt6_FOUND)
9 | find_package(Qt6 REQUIRED COMPONENTS StateMachine)
10 | endif()
11 |
12 | add_library(lqtutils STATIC
13 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_ui.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_ui.h
14 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_net.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_net.h
15 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_freq.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_freq.h
16 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fsm.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fsm.h
17 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_autoexec.h
18 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_bqueue.h
19 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_data.h
20 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_enum.h
21 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_logging.h
22 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_math.h
23 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_misc.h
24 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_perf.h
25 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_prop.h
26 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_settings.h
27 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_string.h
28 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_qsl.h
29 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_system.h
30 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_threading.h
31 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_time.h
32 | )
33 | if (IOS)
34 | target_sources(lqtutils PRIVATE ${CMAKE_CURRENT_LIST_DIR}/lqtutils_ui.mm)
35 | endif()
36 |
37 | if (ENABLE_FONT_AWESOME)
38 | add_compile_definitions(LQT_FONT_AWESOME_ENABLED)
39 | target_sources(lqtutils PRIVATE
40 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fa.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fa.h
41 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fa.qrc
42 | )
43 | endif()
44 |
45 | target_include_directories(lqtutils
46 | PUBLIC ${CMAKE_CURRENT_LIST_DIR})
47 |
48 | target_link_libraries(lqtutils PRIVATE
49 | Qt${QT_VERSION_MAJOR}::Core
50 | Qt${QT_VERSION_MAJOR}::Gui
51 | Qt${QT_VERSION_MAJOR}::Qml
52 | Qt${QT_VERSION_MAJOR}::Quick
53 | )
54 | if (Qt5DBus_FOUND)
55 | target_link_libraries(lqtutils PRIVATE Qt5::DBus)
56 | endif()
57 |
--------------------------------------------------------------------------------
/qt6/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2021 Luca Carlon
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #
24 |
25 | cmake_minimum_required(VERSION 3.5)
26 |
27 | project(LQtUtilsTest LANGUAGES CXX)
28 |
29 | find_package(Qt6 COMPONENTS Core Test Gui Qml Quick REQUIRED)
30 | find_package(Qt6 OPTIONAL_COMPONENTS DBus)
31 |
32 | set(CMAKE_INCLUDE_CURRENT_DIR ON)
33 |
34 | set(CMAKE_AUTOUIC ON)
35 | set(CMAKE_AUTOMOC ON)
36 | set(CMAKE_AUTORCC ON)
37 |
38 | set(CMAKE_CXX_STANDARD 17)
39 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
40 | enable_testing()
41 |
42 | # Omitting the argument from the signals seems to be more performant,
43 | # so it may be an interesting choice.
44 | add_compile_definitions(LQTUTILS_OMIT_ARG_FROM_SIGNAL)
45 |
46 | set(ENABLE_FONT_AWESOME true)
47 | include_directories(../)
48 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/.. subproject/lqtutils)
49 |
50 | add_executable(LQtUtilsTest ../lqtutils/tst_lqtutils.cpp)
51 | add_test(NAME LQtUtilsTest COMMAND LQtUtilsTest)
52 | target_link_libraries(LQtUtilsTest PRIVATE Qt6::Test Qt6::Gui Qt6::Qml Qt6::Quick lqtutilsplugin)
53 | if (Qt6DBus_FOUND)
54 | target_link_libraries(LQtUtilsTest PRIVATE Qt6::DBus)
55 | endif()
56 |
57 | if(MSVC)
58 | target_compile_options(LQtUtilsTest PRIVATE /W4 /WX)
59 | else()
60 | target_compile_options(LQtUtilsTest PRIVATE -Wall -Wextra -Wpedantic)
61 | endif()
62 |
--------------------------------------------------------------------------------
/lqtutils_freq.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 |
26 | #include
27 | #include
28 |
29 | #include "lqtutils_freq.h"
30 |
31 | #define AUTO_REFRESH_INTERVAL 1000
32 |
33 | namespace lqt {
34 |
35 | FreqMeter::FreqMeter(QObject* parent) :
36 | QObject(parent)
37 | {
38 | m_refreshTimer = new QTimer(this);
39 | connect(m_refreshTimer, &QTimer::timeout,
40 | this, &FreqMeter::refresh);
41 | m_refreshTimer->setInterval(AUTO_REFRESH_INTERVAL);
42 | m_refreshTimer->setSingleShot(true);
43 | m_refreshTimer->start();
44 | }
45 |
46 | void FreqMeter::registerSample()
47 | {
48 | QMutexLocker locker(&m_mutex);
49 | m_timestamps.append(QDateTime::currentDateTime());
50 | QTimer::singleShot(0, this, &FreqMeter::refresh);
51 | }
52 |
53 | void FreqMeter::refresh()
54 | {
55 | QMutexLocker locker(&m_mutex);
56 | QDateTime now = QDateTime::currentDateTime();
57 | QMutableListIterator it(m_timestamps);
58 | while (it.hasNext()) {
59 | if (it.next().msecsTo(now) > 1000)
60 | it.remove();
61 | else
62 | break;
63 | }
64 | set_freq(m_timestamps.size());
65 | m_refreshTimer->stop();
66 | m_refreshTimer->start();
67 | }
68 |
69 | } // namesapce
70 |
--------------------------------------------------------------------------------
/lqtutils_math.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2021 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_MATH
26 | #define LQTUTILS_MATH
27 |
28 | #include
29 | #include
30 |
31 | namespace lqt {
32 |
33 | /**
34 | * @brief in_range Returns true iif val is in [a, b).
35 | * @param val
36 | * @param a
37 | * @param b
38 | * @return
39 | */
40 | template [[deprecated]] inline bool in_range(const T& val, const T& a, const T& b)
41 | { return val >= a && val < b; }
42 |
43 | /**
44 | * @brief in_range Returns true iif val is in [a, b].
45 | * @param val
46 | * @param a
47 | * @param b
48 | * @return
49 | */
50 | template inline bool is_in(const T& val, const T& a, const T& b)
51 | { return val >= a && val <= b; }
52 |
53 | /**
54 | * @brief nearest_in_range Returns the nearest value in the range.
55 | * @param val
56 | * @param a
57 | * @param b
58 | * @return
59 | */
60 | template inline T nearest_in_range(const T& val, const T& a, const T& b)
61 | { return val < a ? a : (val > b) ? b : val; }
62 |
63 | /**
64 | * Compares two floating point numbers.
65 | *
66 | * @brief lqt_approx_equal
67 | * @param a
68 | * @param b
69 | * @param epsilon
70 | * @return
71 | */
72 | template inline bool approx_equal(const T& a, const T& b, const T& epsilon)
73 | { return std::fabs(a - b) <= epsilon; }
74 |
75 | } // namespace
76 |
77 | #endif // LQTUTILS_MATH
78 |
--------------------------------------------------------------------------------
/lqtutils_ui.mm:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | #include "lqtutils_ui.h"
6 |
7 | namespace lqt {
8 |
9 | ScreenLock::ScreenLock() :
10 | m_isValid(false)
11 | {
12 | [[UIApplication sharedApplication] setIdleTimerDisabled: YES];
13 | }
14 |
15 | ScreenLock::~ScreenLock()
16 | {
17 | [[UIApplication sharedApplication] setIdleTimerDisabled: NO];
18 | }
19 |
20 | double QmlUtils::safeAreaBottomInset()
21 | {
22 | if (@available(iOS 11.0, *)) {
23 | UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
24 | return window.safeAreaInsets.bottom;
25 | }
26 |
27 | return 0;
28 | }
29 |
30 | double QmlUtils::safeAreaTopInset()
31 | {
32 | if (@available(iOS 11.0, *)) {
33 | UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
34 | return window.safeAreaInsets.top;
35 | }
36 |
37 | return 0;
38 | }
39 |
40 | double QmlUtils::safeAreaLeftInset()
41 | {
42 | if (@available(iOS 11.0, *)) {
43 | UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
44 | return window.safeAreaInsets.left;
45 | }
46 |
47 | return 0;
48 | }
49 |
50 | double QmlUtils::safeAreaRightInset()
51 | {
52 | if (@available(iOS 11.0, *)) {
53 | UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
54 | return window.safeAreaInsets.right;
55 | }
56 |
57 | return 0;
58 | }
59 |
60 | bool QmlUtils::shareResource(const QUrl& resUrl, const QString& /* mimeType */, const QString& /* authority */)
61 | {
62 | NSString* nsFilePath = resUrl.toLocalFile().toNSString();
63 | NSURL* url = [NSURL fileURLWithPath:nsFilePath];
64 | if (!url) {
65 | qWarning() << "Invalid file name:" << resUrl.toLocalFile();
66 | return false;
67 | }
68 |
69 | NSArray* dataToShare = @[url];
70 |
71 | UIActivityViewController* activityViewController = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
72 | [activityViewController autorelease];
73 |
74 | UIView* view = [[[[UIApplication sharedApplication] keyWindow] rootViewController] view];
75 | activityViewController.popoverPresentationController.sourceView = view;
76 |
77 | [[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:activityViewController animated:YES completion:nil];
78 |
79 | return true;
80 | }
81 |
82 | QRectF QmlUtils::visibleDisplayFrame()
83 | {
84 | qWarning() << "Not implemented";
85 | return QRectF();
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/lqtutils_models.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_MODELS_H
26 | #define LQTUTILS_MODELS_H
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | namespace lqt {
37 |
38 | template
39 | class QmlSharedPointerList : public QAbstractListModel
40 | {
41 | public:
42 | QmlSharedPointerList(const QList>& list = QList>(), QObject* parent = nullptr) :
43 | QAbstractListModel(parent), m_list(list) {}
44 |
45 | int rowCount(const QModelIndex& parent = QModelIndex()) const override {
46 | Q_UNUSED(parent)
47 | return static_cast(m_list.count());
48 | }
49 |
50 | QVariant data(const QModelIndex& index, int role = Qt::UserRole) const override {
51 | if (role != Qt::UserRole)
52 | return QVariant();
53 | if (index.row() < 0 || index.row() >= m_list.size())
54 | return QVariant();
55 |
56 | return QVariant::fromValue(m_list[index.row()].data());
57 | }
58 |
59 | QHash roleNames() const override {
60 | QHash roles;
61 | roles.insert(Qt::UserRole, "data");
62 | return roles;
63 | }
64 |
65 | void refreshModel(const QList>& list) {
66 | beginResetModel();
67 | m_list = list;
68 | endResetModel();
69 | }
70 |
71 | private:
72 | QList> m_list;
73 | };
74 |
75 | } // namespace
76 |
77 | #endif // LQTUTILS_MODELS_H
78 |
--------------------------------------------------------------------------------
/lqtutils_enum.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020-2021 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_ENUM_H
26 | #define LQTUTILS_ENUM_H
27 |
28 | #include
29 | #include
30 |
31 | #define L_DECLARE_ENUM(enumName, ...) \
32 | namespace enumName \
33 | { \
34 | Q_NAMESPACE \
35 | enum Value { __VA_ARGS__ }; \
36 | Q_ENUM_NS(Value) \
37 | inline int qmlRegister##enumName(const char* uri, int major, int minor) { \
38 | return qmlRegisterUncreatableMetaObject(enumName::staticMetaObject, \
39 | uri, major, minor, #enumName, "Access to enums & flags only"); \
40 | } \
41 | inline int qRegisterMetaType() { \
42 | return ::qRegisterMetaType(#enumName); \
43 | } \
44 | inline void registerEnum(const char* uri, int major, int minor) { \
45 | enumName::qmlRegister##enumName(uri, major, minor); \
46 | enumName::qRegisterMetaType(); \
47 | } \
48 | }
49 |
50 | #endif // LQTUTILS_ENUM_H
51 |
--------------------------------------------------------------------------------
/lqtutils_perf.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_PERF_H
26 | #define LQTUTILS_PERF_H
27 |
28 | #include
29 | #include
30 |
31 | #include
32 | #include
33 |
34 | #ifdef __GNUC__
35 | #define LC_LIKELY(x) \
36 | __builtin_expect((x), 1)
37 | #define LC_UNLIKELY(x) \
38 | __builtin_expect((x), 0)
39 | #else
40 | #define LC_LIKELY(x) (x)
41 | #define LC_UNLIKELY(x) (x)
42 | #endif // __GNUC__
43 |
44 | namespace lqt {
45 |
46 | /**
47 | * @brief measure_time Measures time spent in lambda f.
48 | * @param f The procedure to time.
49 | * @param callback The callback returning the result.
50 | * @return Time taken to compute f.
51 | */
52 | inline void measure_time(std::function f, std::function callback = nullptr, bool disable = false)
53 | {
54 | if (disable)
55 | f();
56 | else {
57 | QElapsedTimer timer;
58 | timer.start();
59 | f();
60 |
61 | qint64 time = timer.elapsed();
62 | if (callback)
63 | callback(time);
64 | }
65 | }
66 |
67 | /**
68 | * @brief measure_time Measures time spent in lambda f.
69 | * @param f The procedure to time.
70 | * @param disable Whether you want to disable the measurement.
71 | * @param callback The callback returning the result.
72 | * @return Time taken to compute f and result of f.
73 | */
74 | template
75 | inline T measure_time(std::function f, std::function callback = nullptr, bool disable = false)
76 | {
77 | if (disable)
78 | return f();
79 | else {
80 | QElapsedTimer timer;
81 | timer.start();
82 | T res = f();
83 |
84 | qint64 time = timer.elapsed();
85 | if (callback)
86 | callback(time);
87 | return res;
88 | }
89 | }
90 |
91 | } // namespace
92 |
93 | #endif // LQTUTILS_PERF_H
94 |
--------------------------------------------------------------------------------
/lqtutils_logging.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_LOGGING_H
26 | #define LQTUTILS_LOGGING_H
27 |
28 | #include
29 |
30 | namespace lqt {
31 |
32 | template
33 | struct ListOutput
34 | {
35 | QList& out;
36 | };
37 |
38 | template
39 | struct SetOutput
40 | {
41 | QSet& out;
42 | };
43 |
44 | template
45 | struct HashOutput
46 | {
47 | QHash& out;
48 | };
49 |
50 |
51 | template
52 | inline QDebug operator<<(QDebug debug, const ListOutput& c)
53 | {
54 | QDebugStateSaver saver(debug);
55 | if (c.out.isEmpty())
56 | return debug << "( )";
57 | QListIterator it(c.out);
58 | debug.noquote().nospace() << "( ";
59 | while (it.hasNext()) {
60 | debug.noquote() << it.next();
61 | if (it.hasNext())
62 | debug.noquote() << ", ";
63 | }
64 | debug.noquote().nospace() << " )";
65 | return debug;
66 | }
67 |
68 | template
69 | inline QDebug operator<<(QDebug debug, const SetOutput& c)
70 | {
71 | QDebugStateSaver saver(debug);
72 | if (c.out.isEmpty())
73 | return debug << "{ }";
74 | QSetIterator it(c.out);
75 | debug.noquote().nospace() << "{ ";
76 | while (it.hasNext()) {
77 | debug.noquote() << it.next();
78 | if (it.hasNext())
79 | debug.noquote() << ", ";
80 | }
81 | debug.noquote().nospace() << " }";
82 | return debug;
83 | }
84 |
85 | template
86 | inline QDebug operator<<(QDebug debug, const HashOutput& c)
87 | {
88 | QDebugStateSaver saver(debug);
89 | if (c.out.isEmpty())
90 | return debug << "{ }";
91 | QHashIterator it(c.out);
92 | debug.noquote().nospace() << "{ ";
93 | while (it.hasNext()) {
94 | const auto& n = it.next();
95 | debug.noquote().nospace() << "{ " << n.key() << ", " << n.value() << " }";
96 | if (it.hasNext())
97 | debug.noquote() << ", ";
98 | }
99 | debug.noquote().nospace() << " }";
100 | return debug;
101 | }
102 |
103 | }
104 |
105 | #endif
106 |
--------------------------------------------------------------------------------
/lqtutils_fa.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #include "lqtutils_fa.h"
31 | #include "lqtutils_qsl.h"
32 |
33 | namespace lqt
34 | {
35 |
36 | bool embed_font_awesome(QQmlContext* ctx)
37 | {
38 | if (QFontDatabase::addApplicationFont(QSL(":/lqtutils/fontawesome/Font Awesome 6 Brands-Regular-400.otf")) == -1) {
39 | qWarning() << "Could not load font awesome brands regular";
40 | return false;
41 | }
42 |
43 | if (QFontDatabase::addApplicationFont(QSL(":/lqtutils/fontawesome/Font Awesome 6 Free-Regular-400.otf")) == -1) {
44 | qWarning() << "Could not load font awesome free regular";
45 | return false;
46 | }
47 |
48 | if (QFontDatabase::addApplicationFont(QSL(":/lqtutils/fontawesome/Font Awesome 6 Free-Solid-900.otf")) == -1) {
49 | qWarning() << "Could not load font awesome free solid";
50 | return false;
51 | }
52 |
53 | if (ctx) {
54 | QQmlEngine* engine = ctx->engine();
55 | if (!engine) {
56 | qWarning() << "Cannot find qml engine";
57 | return false;
58 | }
59 |
60 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
61 | ctx->setContextProperty("fontAwesomeBrandsRegular",
62 | QFontDatabase::font("Font Awesome 6 Brands", "Regular", 9));
63 | ctx->setContextProperty("fontAwesomeFreeRegular",
64 | QFontDatabase::font("Font Awesome 6 Free", "Regular", 9));
65 | ctx->setContextProperty("fontAwesomeFreeSolid",
66 | QFontDatabase::font("Font Awesome 6 Free", "Solid", 9));
67 | #else
68 | QFontDatabase db;
69 | ctx->setContextProperty("fontAwesomeBrandsRegular",
70 | db.font("Font Awesome 6 Brands", "Regular", 9));
71 | ctx->setContextProperty("fontAwesomeFreeRegular",
72 | db.font("Font Awesome 6 Free", "Regular", 9));
73 | ctx->setContextProperty("fontAwesomeFreeSolid",
74 | db.font("Font Awesome 6 Free", "Solid", 9));
75 | #endif
76 | }
77 |
78 | return true;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/lqtutils_net.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_NET
26 | #define LQTUTILS_NET
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #include "lqtutils_prop.h"
36 | #include "lqtutils_enum.h"
37 |
38 | L_DECLARE_ENUM(LQTDownloaderState,
39 | S_IDLE,
40 | S_DOWNLOADING,
41 | S_DONE,
42 | S_NETWORK_FAILURE,
43 | S_IO_FAILURE,
44 | S_ABORTED)
45 |
46 | namespace lqt {
47 |
48 | class DownloaderPriv : public QObject
49 | {
50 | Q_OBJECT
51 | L_RO_PROP_AS(LQTDownloaderState::Value, state, LQTDownloaderState::S_IDLE)
52 | public:
53 | DownloaderPriv(const QUrl& url, QIODevice* io, QObject* parent = nullptr);
54 | ~DownloaderPriv();
55 |
56 | QIODevice* ioDevice() { return m_io; }
57 |
58 | public slots:
59 | void download();
60 | void abort();
61 | void write(const QByteArray& data);
62 |
63 | signals:
64 | void downloadProgress(qint64 progress, qint64 total);
65 |
66 | private:
67 | QNetworkAccessManager* m_manager;
68 | QNetworkReply* m_reply;
69 | QUrl m_url;
70 | QIODevice* m_io;
71 | };
72 |
73 | class Downloader : public QObject
74 | {
75 | Q_OBJECT
76 | Q_PROPERTY(bool state READ state NOTIFY stateChanged)
77 | public:
78 | Downloader(const QUrl& url, const QString& filePath, QObject* parent = nullptr);
79 | Downloader(const QUrl& url, QByteArray* bucket, QObject* parent = nullptr);
80 | Downloader(const QUrl& url, QIODevice* destIo, QObject *parent);
81 | ~Downloader();
82 |
83 | void download();
84 | void abort();
85 |
86 | LQTDownloaderState::Value state() const { return m_threadContext->state(); }
87 |
88 | signals:
89 | #ifdef LQTUTILS_OMIT_ARG_FROM_SIGNAL
90 | void stateChanged();
91 | #else
92 | void stateChanged(LQTDownloaderState::Value state);
93 | #endif
94 | void downloadProgress(qint64 done, qint64 total);
95 |
96 | private:
97 | QThread* m_thread;
98 | DownloaderPriv* m_threadContext;
99 | QUrl m_url;
100 | QIODevice* m_io;
101 | };
102 |
103 | } // namespace
104 |
105 | #endif // LQTUTILS_NET
106 |
--------------------------------------------------------------------------------
/lqtutils_system.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #include
31 |
32 | namespace lqt {
33 |
34 | struct MemData
35 | {
36 | // Total usable memory.
37 | qint64 totalMemBytes;
38 | // Total memory still available. This is not necessarily unused, but can
39 | // be allocated.
40 | qint64 freeMemBytes;
41 | };
42 |
43 | /// @brief Returns RAM info. This does not take swap into account.
44 | /// @return Structure with total and free mem.
45 | inline std::optional read_mem_data()
46 | {
47 | QFile memFile(QStringLiteral("/proc/meminfo"));
48 | if (!memFile.exists()) {
49 | qWarning() << "Meminfo file missing";
50 | return std::nullopt;
51 | }
52 |
53 | if (!memFile.open(QIODevice::ReadOnly)) {
54 | qWarning() << "Cannot read meminfo file";
55 | return std::nullopt;
56 | }
57 |
58 | const QString meminfoContent = memFile.readAll();
59 |
60 | static const QRegularExpression regexMemTotal(QStringLiteral("MemTotal:\\s*(\\d+)"));
61 | static const QRegularExpression regexMemFree(QStringLiteral("MemFree:\\s*(\\d+)"));
62 | static const QRegularExpression regexMemBuff(QStringLiteral("Buffers:\\s*(\\d+)"));
63 | static const QRegularExpression regexMemCache(QStringLiteral("Cached:\\s*(\\d+)"));
64 | static const QRegularExpression regexMemRecl(QStringLiteral("SReclaimable:\\s*(\\d+)"));
65 |
66 | auto readValue = [&meminfoContent] (const QRegularExpression& regex) -> qint64 {
67 | QRegularExpressionMatch match = regex.match(meminfoContent);
68 | if (!match.hasMatch() || match.lastCapturedIndex() != 1) {
69 | qWarning() << "Failed to parse meminfo file";
70 | return -1;
71 | }
72 |
73 | return match.captured(1).toLongLong();
74 | };
75 |
76 | const qint64 memTotal = readValue(regexMemTotal)*1024;
77 | const qint64 memFree = readValue(regexMemFree)*1024;
78 | const qint64 memBuff = readValue(regexMemBuff)*1024;
79 | const qint64 memCache = readValue(regexMemCache)*1024;
80 | const qint64 memRecl = readValue(regexMemRecl)*1024;
81 | if (memTotal < 0 || memFree < 0 || memBuff < 0 || memCache < 0 || memRecl < 0)
82 | return std::nullopt;
83 |
84 | return MemData {
85 | memTotal,
86 | memFree + memBuff + memCache + memRecl
87 | };
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | set(CMAKE_AUTOMOC ON)
3 |
4 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Gui Qml Quick)
5 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui Qml Quick)
6 | if (Qt6_FOUND)
7 | find_package(Qt NAMES Qt6 REQUIRED COMPONENTS StateMachine)
8 | find_package(Qt6 REQUIRED COMPONENTS StateMachine)
9 | endif()
10 | find_package(QT NAMES Qt6 Qt5 OPTIONAL_COMPONENTS DBus)
11 | find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS DBus)
12 | if (APPLE)
13 | find_library(USER_NOTIFICATIONS_FRAMEWORK UserNotifications)
14 | endif()
15 | if (ANDROID)
16 | find_package(QT NAMES Qt6 REQUIRED COMPONENTS CorePrivate)
17 | find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS CorePrivate)
18 | endif()
19 |
20 | qt_add_library(lqtutils STATIC
21 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_ui.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_ui.h
22 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_net.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_net.h
23 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_freq.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_freq.h
24 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fsm.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fsm.h
25 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_autoexec.h
26 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_bqueue.h
27 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_data.h
28 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_enum.h
29 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_logging.h
30 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_math.h
31 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_misc.h
32 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_perf.h
33 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_prop.h
34 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_settings.h
35 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_string.h
36 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_qsl.h
37 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_system.h
38 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_threading.h
39 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_time.h
40 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_models.h
41 | )
42 | if (IOS)
43 | target_sources(lqtutils PRIVATE ${CMAKE_CURRENT_LIST_DIR}/lqtutils_ui.mm)
44 | endif()
45 | if (APPLE)
46 | target_sources(lqtutils PRIVATE ${CMAKE_CURRENT_LIST_DIR}/lqtutils_ui_apple.mm)
47 | endif()
48 |
49 | if (ENABLE_FONT_AWESOME)
50 | qt_add_qml_module(lqtutils
51 | URI lqtutils
52 | VERSION 1.0
53 | QML_FILES
54 | fontawesome/LQTFontAwesomeFreeRegular.qml
55 | fontawesome/LQTFontAwesomeFreeSolid.qml
56 | fontawesome/LQTFontAwesomeBrandsRegular.qml
57 | RESOURCES
58 | "fontawesome/Font Awesome 6 Brands-Regular-400.otf"
59 | "fontawesome/Font Awesome 6 Free-Regular-400.otf"
60 | "fontawesome/Font Awesome 6 Free-Solid-900.otf"
61 | SOURCES
62 | ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fa.cpp ${CMAKE_CURRENT_LIST_DIR}/lqtutils_fa.h
63 | IMPORT_PATH
64 | ${CMAKE_CURRENT_LIST_DIR}/fontawesome
65 | RESOURCE_PREFIX /
66 | IMPORT_PATH "/fontawesome"
67 | )
68 | add_compile_definitions(LQT_FONT_AWESOME_ENABLED)
69 | endif()
70 |
71 | target_include_directories(lqtutils
72 | PUBLIC ${CMAKE_CURRENT_LIST_DIR})
73 |
74 | target_link_libraries(lqtutils PRIVATE
75 | Qt${QT_VERSION_MAJOR}::Core
76 | Qt${QT_VERSION_MAJOR}::Gui
77 | Qt${QT_VERSION_MAJOR}::Qml
78 | Qt${QT_VERSION_MAJOR}::Quick
79 | )
80 | if (Qt6DBus_FOUND)
81 | target_link_libraries(lqtutils PRIVATE Qt${QT_VERSION_MAJOR}::DBus)
82 | endif()
83 | if (Qt6_FOUND)
84 | target_link_libraries(lqtutils PRIVATE Qt6::StateMachine)
85 | endif()
86 | if (APPLE)
87 | target_link_libraries(lqtutils PRIVATE ${USER_NOTIFICATIONS_FRAMEWORK})
88 | endif()
89 | if (ANDROID)
90 | target_link_libraries(lqtutils PRIVATE Qt${QT_VERSION_MAJOR}::CorePrivate)
91 | endif()
92 |
--------------------------------------------------------------------------------
/lqtutils_ui_apple.mm:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2023 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #include "lqtutils_ui.h"
26 |
27 | #import
28 | #import
29 |
30 | @interface NotificationDelegate : NSObject
31 | @end
32 |
33 | @implementation NotificationDelegate
34 |
35 | -(void)userNotificationCenter:(UNUserNotificationCenter*)center
36 | willPresentNotification:(UNNotification*)notification
37 | withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
38 | {
39 | Q_UNUSED(center)
40 | completionHandler(UNNotificationPresentationOptionAlert);
41 | }
42 |
43 | -(void)userNotificationCenter:(UNUserNotificationCenter*)center
44 | didReceiveNotificationResponse:(UNNotificationResponse*)response
45 | withCompletionHandler:(void(^)())completionHandler
46 | {
47 | Q_UNUSED(center)
48 | Q_UNUSED(response)
49 | completionHandler();
50 | }
51 |
52 | @end
53 |
54 | namespace lqt {
55 |
56 | void AppleSystemNotification::send()
57 | {
58 | UNMutableNotificationContent* content = [[[UNMutableNotificationContent alloc] init] autorelease];
59 | content.title = m_title.toNSString();
60 | content.body = m_message.toNSString();
61 |
62 | UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO];
63 | UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"LocalNotification" content:content trigger:trigger];
64 |
65 | UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
66 | if (!center.delegate)
67 | center.delegate = [[NotificationDelegate alloc] init];
68 | [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
69 | if (error) {
70 | qDebug() << "Error adding notification request:" << QString::fromNSString(error.localizedDescription);
71 | }
72 | }];
73 | }
74 |
75 | void AppleSystemNotification::requestPermission(std::function callback)
76 | {
77 | UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
78 | [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionAlert | UNAuthorizationOptionSound)
79 | completionHandler:^(BOOL granted, NSError * _Nullable error) {
80 | if (error) {
81 | qWarning() << "Error occurred requesting authorization:"
82 | << QString::fromNSString([error localizedDescription])
83 | << QString::fromNSString([error localizedFailureReason]);
84 | callback(false);
85 | return;
86 | }
87 |
88 | callback(true);
89 | }];
90 | }
91 |
92 | } // namespace
93 |
--------------------------------------------------------------------------------
/lqtutils_threading.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_THREADING_H
26 | #define LQTUTILS_THREADING_H
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
35 | #include
36 | #endif
37 | #include
38 |
39 | #define INVOKE_AWAIT_ASYNC(obj, ...) { \
40 | auto type = QThread::currentThread() == obj->thread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection; \
41 | QMetaObject::invokeMethod(obj, __VA_ARGS__, type); \
42 | }
43 |
44 | namespace lqt {
45 |
46 | template T run_in_thread_sync(QObject* o, std::function f)
47 | {
48 | QSemaphore sem;
49 | T ret;
50 | QTimer::singleShot(0, o, [&f, &ret, &sem] {
51 | ret = f();
52 | sem.release();
53 | });
54 | sem.acquire();
55 | return ret;
56 | }
57 |
58 | template T run_in_thread_sync(QThread* t, std::function f)
59 | {
60 | QSemaphore sem;
61 | T ret;
62 | QObject* o = new QObject;
63 | o->moveToThread(t);
64 | QTimer::singleShot(0, o, [&f, o, &ret, &sem] {
65 | ret = f();
66 | o->deleteLater();
67 | sem.release();
68 | });
69 | sem.acquire();
70 | return ret;
71 | }
72 |
73 | inline void run_in_thread_sync(QThread* t, std::function f)
74 | {
75 | QSemaphore sem;
76 | QObject* o = new QObject;
77 | o->moveToThread(t);
78 | QTimer::singleShot(0, o, [&f, o, &sem] {
79 | f();
80 | o->deleteLater();
81 | sem.release();
82 | });
83 | sem.acquire();
84 | }
85 |
86 | inline void run_in_thread_sync(QObject* o, std::function f, QSemaphore* sem)
87 | {
88 | QTimer::singleShot(0, o, [&f, &sem] {
89 | f();
90 | sem->release();
91 | });
92 | sem->acquire();
93 | }
94 |
95 | inline void run_in_thread_sync(QObject* o, std::function f)
96 | {
97 | QSemaphore sem;
98 | run_in_thread_sync(o, f, &sem);
99 | }
100 |
101 | inline void run_in_thread(QThread* t, std::function f)
102 | {
103 | QObject* o = new QObject;
104 | o->moveToThread(t);
105 | QTimer::singleShot(0, o, [f, o] {
106 | f();
107 | o->deleteLater();
108 | });
109 | }
110 |
111 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
112 | class RecursiveMutex : public QMutex
113 | {
114 | public:
115 | RecursiveMutex() :
116 | QMutex(QMutex::Recursive) {}
117 | };
118 | #else
119 | typedef QRecursiveMutex RecursiveMutex;
120 | #endif
121 |
122 | } // namespace
123 |
124 | #endif // LQTUTILS_THREADING_H
--------------------------------------------------------------------------------
/lqtutils_net.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "lqtutils_net.h"
5 |
6 | //#define DEBUG_LOGS
7 |
8 | namespace lqt {
9 |
10 | DownloaderPriv::DownloaderPriv(const QUrl& url, QIODevice* io, QObject* parent) :
11 | QObject(parent)
12 | , m_manager(new QNetworkAccessManager(this))
13 | , m_reply(nullptr)
14 | , m_url(url)
15 | , m_io(io) {}
16 |
17 | DownloaderPriv::~DownloaderPriv()
18 | {
19 | #ifdef DEBUG_LOGS
20 | qDebug() << Q_FUNC_INFO;
21 | #endif
22 | }
23 |
24 | void DownloaderPriv::download()
25 | {
26 | set_state(LQTDownloaderState::S_DOWNLOADING);
27 |
28 | m_reply = m_manager->get(QNetworkRequest(m_url));
29 | connect(m_reply, &QNetworkReply::downloadProgress,
30 | this, &DownloaderPriv::downloadProgress);
31 | connect(m_reply, &QNetworkReply::readyRead, this, [this] {
32 | if (m_state != LQTDownloaderState::S_DOWNLOADING)
33 | return;
34 | write(m_reply->readAll());
35 | });
36 | connect(m_reply, &QNetworkReply::finished, this, [this] {
37 | if (m_state != LQTDownloaderState::S_DOWNLOADING)
38 | return;
39 | if (m_reply->error() != QNetworkReply::NoError) {
40 | #ifdef DEBUG_LOGS
41 | qWarning() << "Download error:" << m_reply->error() << m_reply->errorString();
42 | #endif
43 | set_state(LQTDownloaderState::S_NETWORK_FAILURE);
44 | return;
45 | }
46 |
47 | m_io->close();
48 | set_state(LQTDownloaderState::S_DONE);
49 | });
50 | }
51 |
52 | void DownloaderPriv::abort()
53 | {
54 | if (m_reply) {
55 | m_reply->abort();
56 | m_reply->deleteLater();
57 | m_reply = nullptr;
58 | }
59 |
60 | set_state(LQTDownloaderState::S_ABORTED);
61 | }
62 |
63 | void DownloaderPriv::write(const QByteArray& data)
64 | {
65 | if (m_state != LQTDownloaderState::S_DOWNLOADING)
66 | return;
67 |
68 | if (!m_io->isOpen()) {
69 | if (!m_io->open(QIODevice::WriteOnly)) {
70 | set_state(LQTDownloaderState::S_IO_FAILURE);
71 | return;
72 | }
73 | }
74 |
75 | if (m_io->write(data) != data.size())
76 | set_state(LQTDownloaderState::S_IO_FAILURE);
77 | }
78 |
79 | class LQTThread : public QThread
80 | {
81 | #ifdef DEBUG_LOGS
82 | ~LQTThread() {
83 | qDebug() << Q_FUNC_INFO;
84 | }
85 | #endif
86 | };
87 |
88 | Downloader::Downloader(const QUrl& url, const QString& filePath, QObject* parent) :
89 | Downloader(url, new QFile(filePath), parent)
90 | {
91 | connect(m_thread, &QThread::finished,
92 | m_threadContext->ioDevice(), &QIODevice::deleteLater);
93 | }
94 |
95 | Downloader::Downloader(const QUrl &url, QByteArray* bucket, QObject *parent) :
96 | Downloader(url, new QBuffer(bucket), parent)
97 | {
98 | connect(m_thread, &QThread::finished,
99 | m_threadContext->ioDevice(), &QIODevice::deleteLater);
100 | }
101 |
102 | Downloader::Downloader(const QUrl& url, QIODevice* destIo, QObject* parent) :
103 | QObject(parent)
104 | , m_url(url)
105 | , m_io(destIo)
106 | , m_thread(new LQTThread)
107 | , m_threadContext(new DownloaderPriv(url, destIo))
108 | {
109 | LQTDownloaderState::registerEnum("com.luke", 1, 0);
110 |
111 | m_threadContext->moveToThread(m_thread);
112 | m_thread->start();
113 |
114 | connect(m_threadContext, &DownloaderPriv::stateChanged,
115 | this, &Downloader::stateChanged);
116 | connect(m_threadContext, &DownloaderPriv::downloadProgress,
117 | this, &Downloader::downloadProgress);
118 | connect(this, &Downloader::destroyed,
119 | m_threadContext, &QObject::deleteLater);
120 | connect(m_threadContext, &DownloaderPriv::destroyed,
121 | m_thread, &QThread::quit);
122 | connect(m_thread, &QThread::finished,
123 | m_thread, &QThread::deleteLater);
124 | }
125 |
126 | Downloader::~Downloader()
127 | {
128 | #ifdef DEBUG_LOGS
129 | qDebug() << Q_FUNC_INFO;
130 | #endif
131 | if (state() == LQTDownloaderState::S_DOWNLOADING)
132 | abort();
133 | }
134 |
135 | void Downloader::download()
136 | {
137 | if (m_threadContext->state() != LQTDownloaderState::S_IDLE) {
138 | qFatal("Do not re-use the downloader");
139 | return;
140 | }
141 |
142 | QMetaObject::invokeMethod(m_threadContext, "download", Qt::BlockingQueuedConnection);
143 | }
144 |
145 | void Downloader::abort()
146 | {
147 | if (m_threadContext->state() == LQTDownloaderState::S_DOWNLOADING)
148 | QMetaObject::invokeMethod(m_threadContext, "abort", Qt::BlockingQueuedConnection);
149 | }
150 |
151 | } // namespace
152 |
--------------------------------------------------------------------------------
/lqtutils_ui.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2021 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_UI_H
26 | #define LQTUTILS_UI_H
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 |
39 | #include "lqtutils_freq.h"
40 | #include "lqtutils_prop.h"
41 |
42 | QT_FORWARD_DECLARE_CLASS(QQuickWindow);
43 |
44 | namespace lqt {
45 |
46 | class FrameRateMonitor : public FreqMeter
47 | {
48 | Q_OBJECT
49 | public:
50 | FrameRateMonitor(QQuickWindow* w = nullptr, QObject* parent = nullptr);
51 | Q_INVOKABLE void setWindow(QQuickWindow* w);
52 | };
53 |
54 | QMetaObject::Connection enableAutoFrameUpdates(QQuickWindow& w);
55 |
56 | class ScreenLock
57 | {
58 | public:
59 | ScreenLock();
60 | ~ScreenLock();
61 | bool isValid() { return m_isValid; }
62 |
63 | private:
64 | void lockScreen(bool lock);
65 |
66 | private:
67 | bool m_isValid;
68 | };
69 |
70 | class QmlUtils : public QObject
71 | {
72 | Q_OBJECT
73 | public:
74 | QmlUtils(QObject* parent = nullptr) : QObject(parent) {}
75 |
76 | Q_INVOKABLE void singleShot(int msec, QJSValue callback);
77 | Q_INVOKABLE static double safeAreaBottomInset();
78 | Q_INVOKABLE static double safeAreaTopInset();
79 | Q_INVOKABLE static double safeAreaRightInset();
80 | Q_INVOKABLE static double safeAreaLeftInset();
81 | Q_INVOKABLE static QRectF visibleDisplayFrame();
82 | Q_INVOKABLE static bool shareResource(const QUrl& resUrl,
83 | const QString& mimeType,
84 | const QString& authority);
85 | Q_INVOKABLE static bool isMobile();
86 | Q_INVOKABLE static bool setBarColorLight(bool light, bool fullscreen);
87 | Q_INVOKABLE static bool setNavBarColor(const QColor& color);
88 | Q_INVOKABLE static bool setStatusBarColor(const QColor& color);
89 | };
90 |
91 | /**
92 | * @brief The SystemNotification class
93 | *
94 | * NOTE: icon must be 16x16 or 32x32 RGB32 on Windows.
95 | * NOTE: timeout is valid on Windows only for 2000 and XP.
96 | */
97 | class SystemNotification : public QObject
98 | {
99 | Q_OBJECT
100 | L_RW_PROP_AS(QString, appName)
101 | L_RW_PROP_AS(quint32, replacesId, 0)
102 | L_RW_PROP_AS(QImage, icon)
103 | L_RW_PROP_AS(QString, title)
104 | L_RW_PROP_AS(QString, message)
105 | L_RW_PROP_AS(QStringList, actions)
106 | L_RW_PROP_AS(QVariantMap, hints)
107 | L_RW_PROP_AS(qint32, timeout, -1)
108 | L_RW_PROP_AS(bool, openApp, false)
109 | public:
110 | SystemNotification(QObject* parent = nullptr) : QObject(parent) {}
111 |
112 | virtual void send();
113 |
114 | private:
115 | friend class AndroidSystemNotification;
116 | friend class AppleSystemNotification;
117 | };
118 |
119 | #ifdef Q_OS_ANDROID
120 | class AndroidSystemNotification : public SystemNotification
121 | {
122 | Q_OBJECT
123 | L_RW_PROP_AS(QString, activityClass)
124 | public:
125 | AndroidSystemNotification(QObject* parent = nullptr) : SystemNotification(parent) {}
126 |
127 | virtual void send() override;
128 | };
129 | #endif
130 |
131 | #ifdef Q_OS_DARWIN
132 | class AppleSystemNotification : public SystemNotification
133 | {
134 | Q_OBJECT
135 | public:
136 | AppleSystemNotification(QObject* parent = nullptr) : SystemNotification(parent) {}
137 |
138 | virtual void send() override;
139 |
140 | static void requestPermission(std::function callback);
141 | };
142 | #endif
143 |
144 | } // namespace
145 |
146 | #endif // LQTUTILS_UI_H
147 |
--------------------------------------------------------------------------------
/lqtutils_bqueue.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2021 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_BQUEUE
26 | #define LQTUTILS_BQUEUE
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include
34 |
35 | namespace lqt {
36 |
37 | template
38 | class BlockingQueue
39 | {
40 | public:
41 | BlockingQueue(int capacity, const QString& name = QString()) :
42 | m_capacity(capacity), m_disposed(false), m_name(name) {}
43 | bool enqueue(const T& e, qint64 timeout = -1);
44 | bool enqueueDropFirst(const T& e, qint64 timeout = -1);
45 | std::optional waitFirst(bool remove, qint64 timeout = -1);
46 | std::optional dequeue(qint64 timeout = -1);
47 | std::optional peek(qint64 timeout = -1);
48 | int size() const;
49 | int capacity() const { return m_capacity; }
50 | bool isEmpty() const;
51 | bool isDisposed() const;
52 | void requestDispose();
53 | void lockQueue(std::function* queue)> callback);
54 | QString name() { return m_name; }
55 |
56 | private:
57 | int m_capacity;
58 | bool m_disposed;
59 | QString m_name;
60 | mutable QMutex m_mutex;
61 | QWaitCondition m_condFull;
62 | QWaitCondition m_condEmpty;
63 | QList m_queue;
64 | };
65 |
66 | template
67 | bool BlockingQueue::enqueue(const T& e, qint64 timeout)
68 | {
69 | QMutexLocker locker(&m_mutex);
70 | if (m_disposed)
71 | return false;
72 | if (m_queue.size() >= m_capacity) {
73 | if (!m_condFull.wait(&m_mutex, timeout))
74 | return false;
75 | if (m_disposed)
76 | return false;
77 | }
78 |
79 | m_queue.append(e);
80 | m_condEmpty.wakeOne();
81 |
82 | return true;
83 | }
84 |
85 | template
86 | bool BlockingQueue::enqueueDropFirst(const T& e, qint64 timeout)
87 | {
88 | QMutexLocker locker(&m_mutex);
89 | if (m_disposed)
90 | return false;
91 | if (m_queue.size() >= m_capacity) {
92 | if (!m_condFull.wait(&m_mutex, timeout))
93 | if (!m_queue.isEmpty())
94 | m_queue.takeFirst();
95 | if (m_disposed)
96 | return false;
97 | }
98 |
99 | m_queue.append(e);
100 | m_condEmpty.wakeOne();
101 |
102 | return true;
103 | }
104 |
105 | template
106 | std::optional BlockingQueue::waitFirst(bool remove, qint64 timeout)
107 | {
108 | QMutexLocker locker(&m_mutex);
109 | if (m_disposed)
110 | return std::nullopt;
111 | if (m_queue.isEmpty()) {
112 | if (!timeout)
113 | return std::nullopt;
114 | if (!m_condEmpty.wait(&m_mutex, timeout))
115 | return std::nullopt;
116 | if (m_disposed)
117 | return std::nullopt;
118 | }
119 |
120 | std::optional ret = remove ? m_queue.takeFirst() : m_queue.first();
121 | if (remove)
122 | m_condFull.wakeOne();
123 | return ret;
124 | }
125 |
126 | template
127 | std::optional BlockingQueue::dequeue(qint64 timeout)
128 | {
129 | return waitFirst(true, timeout);
130 | }
131 |
132 | template
133 | std::optional BlockingQueue::peek(qint64 timeout)
134 | {
135 | return waitFirst(false, timeout);
136 | }
137 |
138 | template
139 | int BlockingQueue::size() const
140 | {
141 | QMutexLocker locker(&m_mutex);
142 | return m_queue.size();
143 | }
144 |
145 | template
146 | bool BlockingQueue::isEmpty() const
147 | {
148 | QMutexLocker locker(&m_mutex);
149 | return m_queue.isEmpty();
150 | }
151 |
152 | template
153 | bool BlockingQueue::isDisposed() const
154 | {
155 | QMutexLocker locker(&m_mutex);
156 | return m_disposed;
157 | }
158 |
159 | template
160 | void BlockingQueue::requestDispose()
161 | {
162 | QMutexLocker locker(&m_mutex);
163 | m_disposed = true;
164 | m_condFull.wakeAll();
165 | m_condEmpty.wakeAll();
166 | }
167 |
168 | template
169 | void BlockingQueue::lockQueue(std::function*)> callback)
170 | {
171 | QMutexLocker locker(&m_mutex);
172 | callback(&m_queue);
173 | }
174 |
175 | }
176 |
177 | #endif // LQTUTILS_BQUEUE
178 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | GIT_SUBMODULE_STRATEGY: recursive
3 |
4 | stages:
5 | - test_qt5
6 | - test_qt62_jammy
7 | - test_qt64
8 | - test_qt65_android
9 | - test_qt66
10 | - test_qt66_android
11 | - test_qt67
12 | - test_qt67_android
13 | - test_qt68
14 | - test_qt68_android
15 | - test_qt69
16 | - test_qt69_android
17 | - test_qt610
18 | - test_qt610_android
19 |
20 | Test_qt5:
21 | stage: test_qt5
22 | image:
23 | name: "carlonluca/qt-dev:5.15.2"
24 | entrypoint: [""]
25 | script:
26 | - mkdir build
27 | - cd build
28 | - cmake ../qt5
29 | - make
30 | - export QTEST_FUNCTION_TIMEOUT=10000000
31 | - ./LQtUtilsTest
32 | - cd ..
33 | - git clone http://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_FQDN}/qt/Fall.git
34 | - cd Fall
35 | - git submodule update --init --recursive
36 | - mkdir build
37 | - cd build
38 | - /opt/Qt-android-5.15.2/bin/qmake ..
39 | - make
40 |
41 | Test_qt62_jammy:
42 | stage: test_qt62_jammy
43 | image:
44 | name: "carlonluca/qt-dev:6.2.4_jammy"
45 | entrypoint: [""]
46 | script:
47 | - mkdir build
48 | - cd build
49 | - cmake ../qt6
50 | - make
51 | - export QTEST_FUNCTION_TIMEOUT=10000000
52 | - ./LQtUtilsTest
53 |
54 | Test_qt64:
55 | stage: test_qt64
56 | image:
57 | name: "carlonluca/qt-dev:6.4.3"
58 | entrypoint: [""]
59 | script:
60 | - mkdir build
61 | - cd build
62 | - cmake ../qt6
63 | - make
64 | - export QTEST_FUNCTION_TIMEOUT=10000000
65 | - LD_LIBRARY_PATH=/usr/local/lib ./LQtUtilsTest
66 |
67 | Test_qt65_android:
68 | stage: test_qt65_android
69 | image:
70 | name: "carlonluca/qt-dev:6.5.2"
71 | entrypoint: [""]
72 | script:
73 | - mkdir build
74 | - cd build
75 | - /opt/Qt-android-6.5.2/android_arm64_v8a/bin/qt-cmake \
76 | -DCMAKE_BUILD_TYPE=Release \
77 | -DQT_ANDROID_BUILD_ALL_ABIS:BOOL=ON \
78 | -S ../qt6;
79 | - cmake --build .
80 |
81 | Test_qt66:
82 | stage: test_qt66
83 | image:
84 | name: "carlonluca/qt-dev:6.6.1"
85 | entrypoint: [""]
86 | script:
87 | - mkdir build
88 | - cd build
89 | - cmake ../qt6
90 | - make
91 | - export QTEST_FUNCTION_TIMEOUT=10000000
92 | - LD_LIBRARY_PATH=/usr/local/lib ./LQtUtilsTest
93 |
94 | Test_qt66_android:
95 | stage: test_qt66_android
96 | image:
97 | name: "carlonluca/qt-dev:6.6.1"
98 | entrypoint: [""]
99 | script:
100 | - mkdir build
101 | - cd build
102 | - /opt/Qt-android-6.6.1/android_arm64_v8a/bin/qt-cmake \
103 | -DCMAKE_BUILD_TYPE=Release \
104 | -DQT_ANDROID_BUILD_ALL_ABIS:BOOL=ON \
105 | -S ../qt6;
106 | - cmake --build .
107 |
108 | Test_qt67:
109 | stage: test_qt67
110 | image:
111 | name: "carlonluca/qt-dev:6.7.3"
112 | entrypoint: [""]
113 | script:
114 | - mkdir build
115 | - cd build
116 | - cmake ../qt6
117 | - make
118 | - export QTEST_FUNCTION_TIMEOUT=10000000
119 | - LD_LIBRARY_PATH=/usr/local/lib ./LQtUtilsTest
120 |
121 | Test_qt67_android:
122 | stage: test_qt67_android
123 | image:
124 | name: "carlonluca/qt-dev:6.7.3"
125 | entrypoint: [""]
126 | script:
127 | - mkdir build
128 | - cd build
129 | - /opt/Qt-android-6.7.3/android_arm64_v8a/bin/qt-cmake \
130 | -DCMAKE_BUILD_TYPE=Release \
131 | -DQT_ANDROID_BUILD_ALL_ABIS:BOOL=ON \
132 | -S ../qt6;
133 | - cmake --build .
134 |
135 | Test_qt68:
136 | stage: test_qt68
137 | image:
138 | name: "carlonluca/qt-dev:6.8.3"
139 | entrypoint: [""]
140 | script:
141 | - mkdir build
142 | - cd build
143 | - cmake ../qt6
144 | - make
145 | - export QTEST_FUNCTION_TIMEOUT=10000000
146 | - LD_LIBRARY_PATH=/usr/local/lib ./LQtUtilsTest
147 |
148 | Test_qt68_android:
149 | stage: test_qt68_android
150 | image:
151 | name: "carlonluca/qt-dev:6.8.3"
152 | entrypoint: [""]
153 | script:
154 | - mkdir build
155 | - cd build
156 | - /opt/qt/6.8.3/android_arm64_v8a/bin/qt-cmake \
157 | -DCMAKE_BUILD_TYPE=Release \
158 | -DQT_ANDROID_BUILD_ALL_ABIS:BOOL=ON \
159 | -S ../qt6;
160 | - cmake --build .
161 |
162 | Test_qt69:
163 | stage: test_qt69
164 | image:
165 | name: "carlonluca/qt-dev:6.9.1"
166 | entrypoint: [""]
167 | script:
168 | - mkdir build
169 | - cd build
170 | - cmake ../qt6
171 | - make
172 | - export QTEST_FUNCTION_TIMEOUT=10000000
173 | - LD_LIBRARY_PATH=/usr/local/lib ./LQtUtilsTest
174 |
175 | Test_qt69_android:
176 | stage: test_qt69_android
177 | image:
178 | name: "carlonluca/qt-dev:6.9.2"
179 | entrypoint: [""]
180 | script:
181 | - mkdir build
182 | - cd build
183 | - /opt/qt/6.9.2/android_arm64_v8a/bin/qt-cmake \
184 | -DCMAKE_BUILD_TYPE=Release \
185 | -DQT_ANDROID_BUILD_ALL_ABIS:BOOL=ON \
186 | -S ../qt6;
187 | - cmake --build .
188 |
189 | Test_qt610:
190 | stage: test_qt610
191 | image:
192 | name: "carlonluca/qt-dev:6.10.0"
193 | entrypoint: [""]
194 | script:
195 | - mkdir build
196 | - cd build
197 | - cmake ../qt6
198 | - make
199 | - export QTEST_FUNCTION_TIMEOUT=10000000
200 | - LD_LIBRARY_PATH=/usr/local/lib ./LQtUtilsTest
201 |
202 | Test_qt610_android:
203 | stage: test_qt610_android
204 | image:
205 | name: "carlonluca/qt-dev:6.10.1"
206 | entrypoint: [""]
207 | script:
208 | - mkdir build
209 | - cd build
210 | - /opt/qt/6.10.1/android_arm64_v8a/bin/qt-cmake \
211 | -DCMAKE_BUILD_TYPE=Release \
212 | -DQT_ANDROID_BUILD_ALL_ABIS:BOOL=ON \
213 | -S ../qt6;
214 | - cmake --build .
--------------------------------------------------------------------------------
/lqtutils_string.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_STRING_H
26 | #define LQTUTILS_STRING_H
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #ifndef QStringLiteral
34 | #define QStringLiteral(s) s
35 | #endif
36 |
37 | namespace lqt {
38 |
39 | inline QString path_combine(std::initializer_list l)
40 | {
41 | QString ret;
42 | for (size_t i = 0; i < l.size(); i++) {
43 | ret += *(l.begin() + i);
44 | if (Q_LIKELY(i != l.size() - 1))
45 | ret += QDir::separator();
46 | }
47 | return ret;
48 | }
49 |
50 | inline int string_to_int(const QString& s, int def, bool* ok = nullptr)
51 | {
52 | bool _ok;
53 | int ret = QLocale::system().toInt(s, &_ok);
54 | if (ok)
55 | *ok = _ok;
56 | return _ok ? ret : def;
57 | }
58 |
59 | inline qint64 string_to_int64(const QString& s, qint64 def, bool* ok = nullptr)
60 | {
61 | bool _ok;
62 | qint64 ret = QLocale::system().toLongLong(s, &_ok);
63 | if (ok)
64 | *ok = _ok;
65 | return _ok ? ret : def;
66 | }
67 |
68 | inline qint64 string_to_uint64(const QString& s, quint64 def, bool* ok = nullptr)
69 | {
70 | bool _ok;
71 | qint64 ret = QLocale::system().toULongLong(s, &_ok);
72 | if (ok)
73 | *ok = _ok;
74 | return _ok ? ret : def;
75 | }
76 |
77 | inline float string_to_float(const QString& s, float def, bool* ok = nullptr)
78 | {
79 | bool _ok;
80 | float ret = QLocale::system().toFloat(s, &_ok);
81 | if (ok)
82 | *ok = _ok;
83 | return _ok ? ret : def;
84 | }
85 |
86 | inline double string_to_double(const QString& s, double def, bool* ok = nullptr)
87 | {
88 | bool _ok;
89 | double ret = QLocale::system().toDouble(s, &_ok);
90 | if (ok)
91 | *ok = _ok;
92 | return _ok ? ret : def;
93 | }
94 |
95 | inline float string_to_float_en(const QString& s, float def, bool* ok = nullptr)
96 | {
97 | bool _ok;
98 | QLocale locale(QLocale::English, QLocale::UnitedStates);
99 | float ret = locale.toFloat(s, &_ok);
100 | if (ok)
101 | *ok = _ok;
102 | return _ok ? ret : def;
103 | }
104 |
105 | inline QRectF string_to_rect(const QString& s)
106 | {
107 | if (s.isEmpty())
108 | return QRectF();
109 |
110 | QStringList tokens = s.split(',');
111 | if (tokens.size() != 4)
112 | return QRectF();
113 |
114 | bool convOk;
115 | QRectF ret;
116 | QLocale locale(QLocale::English, QLocale::UnitedStates);
117 | ret.setX(locale.toDouble(tokens[0].trimmed(), &convOk));
118 | if (!convOk)
119 | return QRectF();
120 | ret.setY(locale.toDouble(tokens[1].trimmed(), &convOk));
121 | if (!convOk)
122 | return QRectF();
123 | ret.setWidth(locale.toDouble(tokens[2].trimmed(), &convOk));
124 | if (!convOk)
125 | return QRectF();
126 | ret.setHeight(locale.toDouble(tokens[3].trimmed(), &convOk));
127 | if (!convOk)
128 | return QRectF();
129 |
130 | return ret;
131 | }
132 |
133 | inline QString string_from_rect(const QRectF& rect)
134 | {
135 | if (!rect.isValid() || rect.isNull())
136 | return QString();
137 |
138 | QLocale locale(QLocale::English, QLocale::UnitedStates);
139 | return QString(QStringLiteral("%1,%2,%3,%4")).arg(
140 | locale.toString(rect.x())
141 | , locale.toString(rect.y())
142 | , locale.toString(rect.width())
143 | , locale.toString(rect.height()));
144 | }
145 |
146 | inline QPointF string_to_point(const QString& s)
147 | {
148 | if (s.isEmpty())
149 | return QPoint();
150 |
151 | QStringList tokens = s.split(',');
152 | if (tokens.size() != 2)
153 | return QPoint();
154 |
155 | bool convOk;
156 | QPoint ret;
157 | QLocale locale(QLocale::English, QLocale::UnitedStates);
158 | ret.setX(locale.toDouble(tokens[0].trimmed(), &convOk));
159 | if (!convOk)
160 | return QPointF();
161 | ret.setY(locale.toDouble(tokens[1].trimmed(), &convOk));
162 | if (!convOk)
163 | return QPointF();
164 |
165 | return ret;
166 | }
167 |
168 | inline QString string_from_point(const QPointF& point)
169 | {
170 | if (point.isNull())
171 | return QString();
172 |
173 | QLocale locale(QLocale::English, QLocale::UnitedStates);
174 | return QString(QStringLiteral("%1,%2"))
175 | .arg(locale.toString(point.x()), locale.toString(point.y()));
176 | }
177 |
178 | inline QSize string_to_size(const QString& s)
179 | {
180 | if (s.isEmpty())
181 | return QSize();
182 |
183 | QStringList tokens = s.split('x');
184 | if (tokens.size() != 2)
185 | return QSize();
186 |
187 | bool convOk;
188 | int width = string_to_int(tokens[0], 0, &convOk);
189 | if (!convOk)
190 | return QSize();
191 | int height = string_to_int(tokens[1], 0, &convOk);
192 | if (!convOk)
193 | return QSize();
194 |
195 | return QSize(width, height);
196 | }
197 |
198 | inline QString size_to_string(const QSize& size)
199 | {
200 | if (!size.isValid() || size.isNull())
201 | return QString();
202 |
203 | return QString(QStringLiteral("%1x%2"))
204 | .arg(size.width())
205 | .arg(size.height());
206 | }
207 |
208 | } // namespace
209 |
210 | #endif // LQTUTILS_STRING_H
211 |
--------------------------------------------------------------------------------
/lqtutils_settings.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LSETTINGS_H
26 | #define LSETTINGS_H
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | // The EXPAND macro here is only needed for MSVC:
35 | // https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
36 | #define EXPAND( x ) x
37 | #define L_SETTINGS_GET_MACRO(_1, _2, _3, NAME,...) NAME
38 | #define L_DECLARE_SETTINGS(...) \
39 | EXPAND(L_SETTINGS_GET_MACRO(__VA_ARGS__, L_DECLARE_SETTINGS3, L_DECLARE_SETTINGS2, L_DECLARE_SETTINGS1)(__VA_ARGS__))
40 |
41 | // Defines a single value inside the settings class.
42 | #define L_DEFINE_VALUE(type, name, def) \
43 | public: \
44 | type name(bool create = false) const { \
45 | const QString key = m_section + QStringLiteral(#name); \
46 | if (create && !m_settings->contains(key)) \
47 | m_settings->setValue(key, def); \
48 | return m_settings->value(key, def).value(); \
49 | } \
50 | public Q_SLOTS: \
51 | void set_##name(type value) { \
52 | if (name() == value) return; \
53 | m_settings->setValue(m_section + QStringLiteral(#name), QVariant::fromValue(value)); \
54 | if (this != ¬ifier()) emit name##Changed(value); \
55 | emit notifier().name##Changed(value); \
56 | } \
57 | Q_SIGNALS: \
58 | void name##Changed(type name); \
59 | private: \
60 | Q_PROPERTY(type name READ name WRITE set_##name NOTIFY name##Changed)
61 |
62 | // Declares the settings class.
63 | #define L_DECLARE_SETTINGS2(classname, qsettings) \
64 | L_DECLARE_SETTINGS3(classname, qsettings, "")
65 |
66 | #define L_DECLARE_SETTINGS3(classname, qsettings, section) \
67 | class classname : public QObject \
68 | { \
69 | private: \
70 | Q_OBJECT \
71 | public: \
72 | static classname& notifier() { \
73 | static classname _notifier; \
74 | return _notifier; \
75 | } \
76 | public: \
77 | classname(QObject* parent = nullptr) : QObject(parent) { \
78 | m_settings = qsettings; \
79 | m_section = QStringLiteral(section).isEmpty() ? "" : QString("%1/").arg(section); \
80 | } \
81 | ~classname() { delete m_settings; } \
82 | protected: \
83 | QSettings* m_settings; \
84 | QString m_section;
85 |
86 | namespace lqt {
87 |
88 | template
89 | class CacheValue
90 | {
91 | public:
92 | T value(const QString& key, std::function init);
93 | void reset(const QString& key);
94 | void setValue(const QString& key, const T& v);
95 | bool isSet(const QString& key);
96 |
97 | private:
98 | QHash m_cache;
99 | QMutex m_mutex;
100 | };
101 |
102 | template
103 | T CacheValue::value(const QString& key, std::function init)
104 | {
105 | QMutexLocker locker(&m_mutex);
106 | if (m_cache.contains(key))
107 | return m_cache.value(key);
108 | T v = init();
109 | m_cache.insert(key, v);
110 | return v;
111 | }
112 |
113 | template
114 | void CacheValue::reset(const QString& key)
115 | {
116 | QMutexLocker locker(&m_mutex);
117 | m_cache.remove(key);
118 | }
119 |
120 | template
121 | void CacheValue::setValue(const QString& key, const T& v)
122 | {
123 | QMutexLocker locker(&m_mutex);
124 | m_cache.insert(key, v);
125 | }
126 |
127 | template
128 | bool CacheValue::isSet(const QString& key)
129 | {
130 | QMutexLocker locker(&m_mutex);
131 | return m_cache.contains(key);
132 | }
133 |
134 | } // namespace
135 |
136 | #endif
137 |
--------------------------------------------------------------------------------
/lqtutils_data.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2022 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | #include "lqtutils_string.h"
35 |
36 | namespace lqt {
37 |
38 | /**
39 | * Computes the hash of a file.
40 | *
41 | * @brief lqt_hash
42 | * @param fileName
43 | * @param algo
44 | * @return
45 | */
46 | QByteArray hash(const QString &fileName,
47 | QCryptographicHash::Algorithm algo = QCryptographicHash::Md5)
48 | {
49 | QFile f(fileName);
50 | if (!f.open(QFile::ReadOnly))
51 | return QByteArray();
52 |
53 | QCryptographicHash hash(algo);
54 | if (hash.addData(&f))
55 | return hash.result();
56 |
57 | return QByteArray();
58 | }
59 |
60 | /**
61 | * Writes random data to a device.
62 | *
63 | * @brief lqt_random_file
64 | * @param fileName
65 | * @param size
66 | * @return
67 | */
68 | bool random_data(QIODevice* device, qint64 size)
69 | {
70 | const int chunks = size/1024;
71 | for (int i = 0; i < chunks; i++) {
72 | QVector list;
73 | list.resize(1024/4);
74 | QRandomGenerator::global()->fillRange(list.data(), list.size());
75 | const int size = list.size()*sizeof(quint32);
76 | if (device->write(reinterpret_cast(list.data()), size) != size)
77 | return false;
78 | }
79 |
80 | const int tailSize = size - chunks*1024;
81 | for (int i = 0; i < tailSize; i++) {
82 | const quint32 v = QRandomGenerator::global()->generate();
83 | device->write(reinterpret_cast(&v), 1);
84 | }
85 |
86 | return true;
87 | }
88 |
89 | /**
90 | * Creates a random file of a specified size.
91 | *
92 | * @brief lqt_random_file
93 | * @param fileName
94 | * @param size
95 | * @return
96 | */
97 | bool random_file(const QString& fileName, qint64 size)
98 | {
99 | QFile f(fileName);
100 | if (!f.open(QIODevice::WriteOnly))
101 | return false;
102 |
103 | return random_data(&f, size);
104 | }
105 |
106 | /**
107 | * Returns random data in a buffer.
108 | *
109 | * @brief random_data
110 | * @param size
111 | * @return
112 | */
113 | QByteArray random_data(qint64 size)
114 | {
115 | QBuffer buffer;
116 | buffer.open(QIODevice::WriteOnly);
117 | return random_data(&buffer, size) ? buffer.buffer() : QByteArray();
118 | }
119 |
120 | template
121 | inline const T* get_any(const QSet& set)
122 | {
123 | if (set.isEmpty())
124 | return nullptr;
125 | typename QSet::const_iterator it = set.constBegin();
126 | return &(*it);
127 | }
128 |
129 | /**
130 | * Reads an entire file into memory.
131 | *
132 | * @brief readAll
133 | * @param io
134 | * @return
135 | */
136 | inline QByteArray read_all(QIODevice* io)
137 | {
138 | if (!io)
139 | return QByteArray();
140 |
141 | if (!io->isOpen()) {
142 | if (!io->open(QIODevice::ReadOnly)) {
143 | qWarning() << "Failed to open I/O device";
144 | return QByteArray();
145 | }
146 | }
147 | else
148 | io->seek(0);
149 |
150 | return io->readAll();
151 | }
152 |
153 | /**
154 | * Reads all data in a file.
155 | *
156 | * @brief read_all
157 | * @param filePath
158 | * @return
159 | */
160 | inline QByteArray read_all(const QString& filePath)
161 | {
162 | QFile f(filePath);
163 | return read_all(&f);
164 | }
165 |
166 | /**
167 | * Writes data to the device.
168 | *
169 | * @brief write_all
170 | * @param io
171 | * @param data
172 | * @return
173 | */
174 | inline bool write_all(QIODevice* io, const QByteArray& data)
175 | {
176 | if (!io)
177 | return false;
178 |
179 | if (!io->open(QIODevice::WriteOnly)) {
180 | qWarning() << "Failed to open I/O device";
181 | return false;
182 | }
183 |
184 | return io->write(data) == data.size();
185 | }
186 |
187 | /**
188 | * Writes data to the file.
189 | *
190 | * @brief write_all
191 | * @param filePath
192 | * @param data
193 | * @return
194 | */
195 | inline bool write_all(const QString& filePath, const QByteArray& data)
196 | {
197 | QFile f(filePath);
198 | return write_all(&f, data);
199 | }
200 |
201 | #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
202 | /**
203 | * Copies an entire directory to another location.
204 | *
205 | * @brief copy_path
206 | * @param src
207 | * @param dst
208 | * @return
209 | */
210 | bool copy_path(const QString& src, const QString& dst)
211 | {
212 | QDir sourceDir(src);
213 | if (!sourceDir.exists())
214 | return false;
215 |
216 | QDir dstDir(dst);
217 | if (dstDir.exists())
218 | dstDir = QDir(lqt::path_combine({ dst, sourceDir.dirName() }));
219 | if (dstDir.exists()) {
220 | qWarning() << "Destination directory exists";
221 | return false;
222 | }
223 |
224 | if (!dstDir.mkpath(".")) {
225 | qWarning() << "Failed to create dir" << dstDir.absolutePath();
226 | return false;
227 | }
228 |
229 | for (const auto& entry : QDirListing(src, QDirListing::IteratorFlag::Recursive)) {
230 | const QString filePath = entry.absoluteFilePath();
231 | const QString relativePath = sourceDir.relativeFilePath(filePath);
232 | const QString destPath = lqt::path_combine({dstDir.absolutePath(), relativePath});
233 |
234 | if (QFile(destPath).exists()) {
235 | qWarning() << "Destination exists:" << destPath;
236 | continue;
237 | }
238 |
239 | if (entry.isDir()) {
240 | if (!QDir(destPath).mkpath(".")) {
241 | qWarning() << "Failed to create dir:" << destPath;
242 | continue;
243 | }
244 | }
245 | else {
246 | if (!QFile(filePath).copy(destPath)) {
247 | qWarning() << "Failed to copy" << filePath << "->" << destPath;
248 | continue;
249 | }
250 | }
251 | }
252 |
253 | return true;
254 | }
255 | #endif
256 |
257 | } // namespace
258 |
--------------------------------------------------------------------------------
/lqtutils_prop.h:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2020 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #ifndef LQTUTILS_PROP_H
26 | #define LQTUTILS_PROP_H
27 |
28 | #include
29 |
30 | // Define LQTUTILS_OMIT_ARG_FROM_SIGNAL to omit the argument from the change notification
31 | // signals.
32 | #ifdef LQTUTILS_OMIT_ARG_FROM_SIGNAL
33 | #define LQTUTILS_EMIT_SIGNAL(name)
34 | #define LQTUTILS_DECLARE_SIGNAL(type, name)
35 | #else
36 | #define LQTUTILS_EMIT_SIGNAL(name) name
37 | #define LQTUTILS_DECLARE_SIGNAL(type, name) type name
38 | #endif
39 |
40 | // The EXPAND macro here is only needed for MSVC:
41 | // https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
42 | #define EXPAND( x ) x
43 | #define L_PROP_GET_MACRO(_1, _2, _3, _4, NAME,...) NAME
44 |
45 | // QObject
46 | // =======
47 | #define L_RW_PROP(...) \
48 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_PROP4, L_RW_PROP3, L_RW_PROP2)(__VA_ARGS__) )
49 | #define L_RW_PROP_AS(...) \
50 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_PROP4_AS, L_RW_PROP3_AS, L_RW_PROP2_AS, L_RW_PROP1_AS)(__VA_ARGS__) )
51 | #define L_RW_PROP_CS(...) \
52 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_PROP4_CS, L_RW_PROP3_CS, L_RW_PROP2_CS)(__VA_ARGS__) )
53 | #define L_RO_PROP(...) \
54 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_PROP4, L_RO_PROP3, L_RO_PROP2)(__VA_ARGS__) )
55 | #define L_RO_PROP_AS(...) \
56 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_PROP4_AS, L_RO_PROP3_AS, L_RO_PROP2_AS, L_RO_PROP1_AS)(__VA_ARGS__) )
57 | #define L_RO_PROP_CS(...) \
58 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_PROP4_CS, L_RO_PROP3_CS, L_RO_PROP2_CS)(__VA_ARGS__) )
59 | // References
60 | #define L_RW_PROP_REF(...) \
61 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_PROP_REF4, L_RW_PROP_REF3, L_RW_PROP_REF2)(__VA_ARGS__) )
62 | #define L_RW_PROP_REF_AS(...) \
63 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_PROP_REF4_AS, L_RW_PROP_REF3_AS, L_RW_PROP_REF2_AS, L_RW_PROP_REF1_AS)(__VA_ARGS__) )
64 | #define L_RW_PROP_REF_CS(...) \
65 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_PROP_REF4_CS, L_RW_PROP_REF3_CS, L_RW_PROP_REF2_CS)(__VA_ARGS__) )
66 | #define L_RO_PROP_REF(...) \
67 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_PROP_REF4, L_RO_PROP_REF3, L_RO_PROP_REF2)(__VA_ARGS__) )
68 | #define L_RO_PROP_REF_AS(...) \
69 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_PROP_REF4_AS, L_RO_PROP_REF3_AS, L_RO_PROP_REF2_AS, L_RO_PROP_REF1_AS)(__VA_ARGS__) )
70 | #define L_RO_PROP_REF_CS(...) \
71 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_PROP_REF4_CS, L_RO_PROP_REF3_CS, L_RO_PROP_REF2_CS)(__VA_ARGS__) )
72 |
73 | // A read-write prop both in C++ and in QML
74 | // ========================================
75 | #define _INT_DECL_L_RW_PROP(type, name, setter) \
76 | public: \
77 | type name() const { return m_##name ; } \
78 | Q_SIGNALS: \
79 | void name##Changed(LQTUTILS_DECLARE_SIGNAL(type, name)); \
80 | private: \
81 | Q_PROPERTY(type name READ name WRITE setter NOTIFY name##Changed)
82 |
83 | #define L_RW_PROP_(type, name, setter) \
84 | _INT_DECL_L_RW_PROP(type, name, setter) \
85 | public Q_SLOTS: \
86 | void setter(type name) { \
87 | if (m_##name == name) return; \
88 | m_##name = name; \
89 | emit name##Changed(LQTUTILS_EMIT_SIGNAL(name)); \
90 | } \
91 | private:
92 |
93 | #define L_RW_PROP4(type, name, setter, def) \
94 | L_RW_PROP_(type, name, setter) \
95 | type m_##name = def;
96 |
97 | #define L_RW_PROP3(type, name, setter) \
98 | L_RW_PROP_(type, name, setter) \
99 | type m_##name;
100 |
101 | // Autosetter
102 | #define L_RW_PROP_AS_(type, name) L_RW_PROP_(type, name, set_##name)
103 |
104 | #define L_RW_PROP3_AS(type, name, def) \
105 | L_RW_PROP_AS_(type, name) \
106 | type m_##name = def;
107 |
108 | #define L_RW_PROP2_AS(type, name) \
109 | L_RW_PROP_AS_(type, name) \
110 | type m_##name;
111 |
112 | // Custom setter
113 | #define L_RW_PROP_CS_(type, name) \
114 | _INT_DECL_L_RW_PROP(type, name, set_##name)
115 |
116 | #define L_RW_PROP3_CS(type, name, def) \
117 | L_RW_PROP_CS_(type, name) \
118 | type m_##name = def;
119 |
120 | #define L_RW_PROP2_CS(type, name) \
121 | L_RW_PROP_CS_(type, name) \
122 | type m_##name;
123 |
124 | // A read-write prop from C++, but read-only from QML
125 | // ==================================================
126 | #define _INT_DECL_L_RO_PROP(type, name, setter) \
127 | public: \
128 | type name() const { return m_##name ; } \
129 | Q_SIGNALS: \
130 | void name##Changed(LQTUTILS_DECLARE_SIGNAL(type, name)); \
131 | private: \
132 | Q_PROPERTY(type name READ name NOTIFY name##Changed) \
133 |
134 | #define L_RO_PROP_(type, name, setter) \
135 | _INT_DECL_L_RO_PROP(type, name, set_##name) \
136 | public: \
137 | void setter(type name) { \
138 | if (m_##name == name) return; \
139 | m_##name = name; \
140 | emit name##Changed(LQTUTILS_EMIT_SIGNAL(name)); \
141 | } \
142 | private:
143 |
144 | #define L_RO_PROP4(type, name, setter, def) \
145 | L_RO_PROP_(type, name, setter) \
146 | type m_##name = def;
147 |
148 | #define L_RO_PROP3(type, name, setter) \
149 | L_RO_PROP_(type, name, setter) \
150 | type m_##name;
151 |
152 | // Autosetter
153 | #define L_RO_PROP_AS_(type, name) L_RO_PROP_(type, name, set_##name)
154 |
155 | #define L_RO_PROP3_AS(type, name, def) \
156 | L_RO_PROP_AS_(type, name) \
157 | type m_##name = def;
158 |
159 | #define L_RO_PROP2_AS(type, name) \
160 | L_RO_PROP_AS_(type, name) \
161 | type m_##name;
162 |
163 | // Custom setter
164 | #define L_RO_PROP_CS_(type, name) \
165 | _INT_DECL_L_RO_PROP(type, name, set_##name)
166 |
167 | #define L_RO_PROP3_CS(type, name, def) \
168 | L_RO_PROP_CS_(type, name) \
169 | type m_##name = def;
170 |
171 | #define L_RO_PROP2_CS(type, name) \
172 | L_RO_PROP_CS_(type, name) \
173 | type m_##name;
174 |
175 | // For references
176 | // ==============
177 |
178 | // A read-write prop both in C++ and in QML
179 | // ========================================
180 | #define _INT_DECL_L_RW_PROP_REF(type, name, setter) \
181 | public: \
182 | type& name() { return m_##name ; } \
183 | Q_SIGNALS: \
184 | void name##Changed(LQTUTILS_DECLARE_SIGNAL(type, name)); \
185 | private: \
186 | Q_PROPERTY(type name READ name WRITE setter NOTIFY name##Changed)
187 |
188 | #define L_RW_PROP_REF_(type, name, setter) \
189 | _INT_DECL_L_RW_PROP_REF(type, name, setter) \
190 | public Q_SLOTS: \
191 | void setter(type name) { \
192 | if (m_##name == name) return; \
193 | m_##name = name; \
194 | emit name##Changed(LQTUTILS_EMIT_SIGNAL(name)); \
195 | } \
196 | private:
197 |
198 | #define L_RW_PROP_REF4(type, name, setter, def) \
199 | L_RW_PROP_REF_(type, name, setter) \
200 | type m_##name = def;
201 |
202 | #define L_RW_PROP_REF3(type, name, setter) \
203 | L_RW_PROP_REF_(type, name, setter) \
204 | type m_##name;
205 |
206 | // Autosetter
207 | #define L_RW_PROP_REF_AS_(type, name) L_RW_PROP_REF_(type, name, set_##name)
208 |
209 | #define L_RW_PROP_REF3_AS(type, name, def) \
210 | L_RW_PROP_REF_AS_(type, name) \
211 | type m_##name = def;
212 |
213 | #define L_RW_PROP_REF2_AS(type, name) \
214 | L_RW_PROP_REF_AS_(type, name) \
215 | type m_##name;
216 |
217 | // Custom setter
218 | #define L_RW_PROP_REF_CS_(type, name) \
219 | _INT_DECL_L_RW_PROP_REF(type, name, set_##name)
220 |
221 | #define L_RW_PROP_REF3_CS(type, name, def) \
222 | L_RW_PROP_REF_CS_(type, name) \
223 | type m_##name = def;
224 |
225 | #define L_RW_PROP_REF2_CS(type, name) \
226 | L_RW_PROP_REF_CS_(type, name) \
227 | type m_##name;
228 |
229 | // A read-write prop from C++, but read-only from QML
230 | // ==================================================
231 | #define _INT_DECL_L_RO_PROP_REF(type, name, setter) \
232 | public: \
233 | type& name() { return m_##name ; } \
234 | Q_SIGNALS: \
235 | void name##Changed(LQTUTILS_DECLARE_SIGNAL(type, name)); \
236 | private: \
237 | Q_PROPERTY(type name READ name NOTIFY name##Changed)
238 |
239 | #define L_RO_PROP_REF_(type, name, setter) \
240 | _INT_DECL_L_RO_PROP_REF(type, name, setter) \
241 | public Q_SLOTS: \
242 | void setter(type name) { \
243 | if (m_##name == name) return; \
244 | m_##name = name; \
245 | emit name##Changed(LQTUTILS_EMIT_SIGNAL(name)); \
246 | } \
247 | private:
248 |
249 | #define L_RO_PROP_REF4(type, name, setter, def) \
250 | L_RO_PROP_REF_(type, name, setter) \
251 | type m_##name = def;
252 |
253 | #define L_RO_PROP_REF3(type, name, setter) \
254 | L_RO_PROP_REF_(type, name, setter) \
255 | type m_##name;
256 |
257 | // Autosetter
258 | #define L_RO_PROP_REF_AS_(type, name) L_RO_PROP_REF_(type, name, set_##name)
259 |
260 | #define L_RO_PROP_REF3_AS(type, name, def) \
261 | L_RO_PROP_REF_AS_(type, name) \
262 | type m_##name = def;
263 |
264 | #define L_RO_PROP_REF2_AS(type, name) \
265 | L_RO_PROP_REF_AS_(type, name) \
266 | type m_##name;
267 |
268 | // Custom setter
269 | #define L_RO_PROP_REF_CS_(type, name) \
270 | _INT_DECL_L_RO_PROP_REF(type, name, set_##name) \
271 |
272 | #define L_RO_PROP_REF3_CS(type, name, def) \
273 | L_RO_PROP_REF_CS_(type, name) \
274 | type m_##name = def;
275 |
276 | #define L_RO_PROP_REF2_CS(type, name) \
277 | L_RO_PROP_REF_CS_(type, name) \
278 | type m_##name;
279 |
280 | // Convenience macros to speed up a QObject subclass.
281 | #define L_BEGIN_CLASS(name) \
282 | class name : public QObject \
283 | { \
284 | Q_OBJECT \
285 | public: \
286 | Q_INVOKABLE name(QObject* parent = nullptr) : \
287 | QObject(parent) {} \
288 | private:
289 |
290 | #define L_END_CLASS };
291 |
292 | // Gadget
293 | // ======
294 |
295 | #define L_RW_GPROP(...) \
296 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_GPROP4, L_RW_GPROP3, L_RW_GPROP2)(__VA_ARGS__) )
297 | #define L_RW_GPROP_AS(...) \
298 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_GPROP4_AS, L_RW_GPROP3_AS, L_RW_GPROP2_AS, L_RW_GPROP1_AS)(__VA_ARGS__) )
299 | #define L_RW_GPROP_CS(...) \
300 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RW_GPROP4_CS, L_RW_GPROP3_CS, L_RW_GPROP2_CS)(__VA_ARGS__) )
301 | #define L_RO_GPROP(...) \
302 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_GPROP4, L_RO_GPROP3, L_RO_GPROP2)(__VA_ARGS__) )
303 | #define L_RO_GPROP_AS(...) \
304 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_GPROP4_AS, L_RO_GPROP3_AS, L_RO_GPROP2_AS, L_RO_GPROP1_AS)(__VA_ARGS__) )
305 | #define L_RO_GPROP_CS(...) \
306 | EXPAND( L_PROP_GET_MACRO(__VA_ARGS__, L_RO_GPROP4_CS, L_RO_GPROP3_CS, L_RO_GPROP2_CS)(__VA_ARGS__) )
307 |
308 | #define _INT_DECL_GADGET_PROP_GETTER(type, name) \
309 | public: \
310 | type name() const { return m_##name ; }
311 |
312 | // A read-write prop both in C++ and in QML
313 | // ========================================
314 | #define L_RW_GPROP_(type, name, setter) \
315 | _INT_DECL_GADGET_PROP_GETTER(type, name) \
316 | private: \
317 | Q_PROPERTY(type name READ name WRITE setter) \
318 | public: \
319 | void setter(type name) { \
320 | m_##name = name; \
321 | } \
322 | private:
323 |
324 | #define L_RW_GPROP4(type, name, setter, def) \
325 | L_RW_GPROP_(type, name, setter) \
326 | type m_##name = def;
327 |
328 | #define L_RW_GPROP3(type, name, setter) \
329 | L_RW_GPROP_(type, name, setter) \
330 | type m_##name;
331 |
332 | // Autosetter
333 | #define L_RW_GPROP_AS_(type, name) L_RW_GPROP_(type, name, set_##name)
334 |
335 | #define L_RW_GPROP3_AS(type, name, def) \
336 | L_RW_GPROP_AS_(type, name) \
337 | type m_##name = def;
338 |
339 | #define L_RW_GPROP2_AS(type, name) \
340 | L_RW_GPROP_AS_(type, name) \
341 | type m_##name;
342 |
343 | // Custom setter
344 | #define L_RW_GPROP_CS_(type, name) \
345 | _INT_DECL_GADGET_PROP_GETTER(type, name) \
346 | private: \
347 | Q_PROPERTY(type name READ name)
348 |
349 | #define L_RW_GPROP3_CS(type, name, def) \
350 | L_RW_GPROP_CS_(type, name) \
351 | type m_##name = def;
352 |
353 | #define L_RW_GPROP2_CS(type, name) \
354 | L_RW_GPROP_CS_(type, name) \
355 | type m_##name;
356 |
357 | // A read-write prop from C++, but read-only from QML
358 | // ==================================================
359 | #define L_RO_GPROP_(type, name, setter) \
360 | _INT_DECL_GADGET_PROP_GETTER(type, name) \
361 | private: \
362 | Q_PROPERTY(type name READ name) \
363 | public: \
364 | void setter(type name) { \
365 | m_##name = name; \
366 | } \
367 | private:
368 |
369 | #define L_RO_GPROP4(type, name, setter, def) \
370 | L_RO_GPROP_(type, name, setter) \
371 | type m_##name = def;
372 |
373 | #define L_RO_GPROP3(type, name, setter) \
374 | L_RO_GPROP_(type, name, setter) \
375 | type m_##name;
376 |
377 | // Autosetter
378 | #define L_RO_GPROP_AS_(type, name) L_RO_GPROP_(type, name, set_##name)
379 |
380 | #define L_RO_GPROP3_AS(type, name, def) \
381 | L_RO_GPROP_AS_(type, name) \
382 | type m_##name = def;
383 |
384 | #define L_RO_GPROP2_AS(type, name) \
385 | L_RO_GPROP_AS_(type, name) \
386 | type m_##name;
387 |
388 | // Custom setter
389 | #define L_RO_GPROP_CS_(type, name) \
390 | _INT_DECL_GADGET_PROP_GETTER(type, name) \
391 | private: \
392 | Q_PROPERTY(type name READ name)
393 |
394 | #define L_RO_GPROP3_CS(type, name, def) \
395 | L_RO_GPROP_CS_(type, name) \
396 | type m_##name = def;
397 |
398 | #define L_RO_GPROP2_CS(type, name) \
399 | L_RO_GPROP_CS_(type, name) \
400 | type m_##name;
401 |
402 | // Convenience macros to speed up a gadget subclass.
403 | #define L_BEGIN_GADGET(name) \
404 | class name \
405 | { \
406 | Q_GADGET \
407 | public: \
408 | Q_INVOKABLE name() {} \
409 | private:
410 |
411 |
412 | #define L_END_GADGET };
413 |
414 | #endif // LQTUTILS_PROP_H
415 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LQtUtils
2 | This is a module containing a few tools that I typically use in Qt apps. Using this module in your app is simple: add a submodule to your git repo and include the headers. Most of the code is in independent headers, so you don't need to build anything separately.
3 | A couple of headers need the related source file to be compiled explicitly; in that case I typically add this project as a submodule and link to my main project file.
4 |
5 | More articles related to these topics: https://bugfreeblog.duckdns.org/tag/lqtutils.
6 |
7 | ## Index
8 |
9 | - [How to Include](#how-to-include)
10 | - [Synthesize Qt properties in a short way (lqtutils_prop.h)](#synthesize-qt-props)
11 | - [Synthesize Qt enums and quickly expose to QML (lqtutils_enum.h)](#synthesize-qt-enums)
12 | - [Synthesize Qt settings with support for signals (lqtutils_settings.h)](#synthesize-qt-settings)
13 | - [Cache values and init automatically](#cache-values)
14 | - [Threading tools](#threading)
15 | - [Auto execute actions when exiting a scope (lqtutils_autoexec.h)](#autoexec)
16 | - [Measuring rate](#measure-rate)
17 | - [Measuring framerate](#measure-framerate)
18 | - [Showing Local Notifications](#local-notifications)
19 | - [Single shot timer for QML (lqtutils_ui.h)](#singleshot-qml)
20 | - [Getting safe areas on mobile](#safe-areas)
21 | - [Measure Performance (lqtutils_perf.h)](#measure-performance)
22 | - [Blocking Queue for qt (lqtutils_bqueue.h)](#blocking-queue)
23 | - [Download a File with Progress Notifications (lqtutils_net.h)](#download-file)
24 | - [FontAwesome in QML](#fontawesome)
25 | - [Compute total and available RAM (lqtutils_system.h) [Linux only]](#available-ram)
26 |
27 |
28 | ## How to Include
29 |
30 | To include in a qmake app:
31 |
32 | ```
33 | include(lqtutils/lqtutils.pri)
34 | ```
35 |
36 | To include in a cmake app in Qt6:
37 |
38 | ```
39 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/deps/lqtutils)
40 | target_link_libraries(yourproj lqtutilsplugin)
41 | ```
42 |
43 | NOTE: the name of the library to link is `lqtutilsplugin`, not just `lqtutils`.
44 |
45 | To include in a cmake app in Qt5:
46 |
47 | ```
48 | include(${CMAKE_CURRENT_SOURCE_DIR}/deps/lqtutils/CMakeLists_qt5.txt)
49 | target_link_libraries(LQtUtilsTest PRIVATE lqtutils)
50 | ```
51 |
52 |
53 | ## Synthesize Qt properties in a short way (lqtutils_prop.h)
54 | **For more info: https://bugfreeblog.duckdns.org/2020/05/synthesize-qt-properties.html.**
55 |
56 | Contains a few useful macros to synthesize Qt props. For instance:
57 | ```c++
58 | L_BEGIN_CLASS(Fraction)
59 | L_RW_PROP_AS(double, numerator, 5)
60 | L_RW_PROP_AS(double, denominator, 9)
61 | L_END_CLASS
62 | ```
63 | instead of:
64 | ```c++
65 | class Fraction : public QObject
66 | {
67 | Q_OBJECT
68 | Q_PROPERTY(double numerator READ numerator WRITE setNumerator NOTIFY numeratorChanged)
69 | Q_PROPERTY(double denominator READ denominator WRITE setDenominator NOTIFY denominatorChanged)
70 | public:
71 | Fraction(QObject* parent = nullptr) :
72 | QObject(parent),
73 | m_numerator(5),
74 | m_denominator(9)
75 | {}
76 |
77 | double numerator() const {
78 | return m_numerator;
79 | }
80 |
81 | double denominator() const {
82 | return m_denominator;
83 | }
84 |
85 | public slots:
86 | void setNumerator(double numerator) {
87 | if (m_numerator == numerator)
88 | return;
89 | m_numerator = numerator;
90 | emit numeratorChanged(numerator);
91 | }
92 |
93 | void setDenominator(double denominator) {
94 | if (m_denominator == denominator)
95 | return;
96 | m_denominator = denominator;
97 | emit denominatorChanged(denominator);
98 | }
99 |
100 | signals:
101 | void numeratorChanged(double numerator);
102 | void denominatorChanged(double denominator);
103 |
104 | private:
105 | double m_numerator;
106 | double m_denominator;
107 | };
108 | ```
109 | This makes the usage of Qt properties more synthetic and speeds up the development. It is very useful when many properties are needed to expose data to QML. Properties will provide a setter, a getter, notifications through their signal and support binding in QML.
110 |
111 | You can use macros even in a larger class, with a regular syntax:
112 | ```c++
113 | class Fraction : public QObject
114 | {
115 | Q_OBJECT
116 | L_RW_PROP_AS(double, numerator, 5)
117 | L_RW_PROP_AS(double, denominator, 9)
118 | public:
119 | Fraction(QObject* parent = nullptr) : QObject(parent) {}
120 | };
121 | ```
122 |
123 | ### References
124 |
125 | If you need to be able to modify the property itself from C++ instead of resetting it, you can use the *_REF alternatives of L_RW_PROP and L_RO_PROP. In that case, getter methods return a reference to the type in C++.
126 |
127 | ### Signals With or Without Parameters
128 |
129 | By default, signals are generated with the value passed in the argument. If you prefer signals without params, you can define LQTUTILS_OMIT_ARG_FROM_SIGNAL **before** including the header.
130 |
131 | ### Autosetter
132 |
133 | It is also possible to omit the name of the setter in the declaration. This results in the auto-generation of a setter with the name "set_". To obtain this behavior, simply use the variants of the above macros with the suffix "_AS". This should work for all property types: ro, rw, ref and all gadget props.
134 |
135 | ### Custom Setter
136 |
137 | It is possible to generate a property without its setter implementation. The setter con be implemented with a slot explicitly by writing a method named "set_" returning void. An example can be found [here](lqtutils/tst_lqtutils.cpp#L52).
138 |
139 | ### Complete List of Available Macros
140 |
141 | For QObjects:
142 |
143 | L_RW_PROP(type, name, setter)
144 | L_RW_PROP(type, name, setter, default)
145 | L_RW_PROP_AS(type, name)
146 | L_RW_PROP_AS(type, name, default)
147 | L_RW_PROP_CS(type, name)
148 | L_RW_PROP_CS(type, name, default)
149 | L_RW_PROP_REF(type, name, setter)
150 | L_RW_PROP_REF(type, name, setter, default)
151 | L_RW_PROP_REF_AS(type, name)
152 | L_RW_PROP_REF_AS(type, name, default)
153 | L_RW_PROP_REF_CS(type, name)
154 | L_RW_PROP_REF_CS(type, name, default)
155 | L_RO_PROP(type, name, setter)
156 | L_RO_PROP(type, name, setter, default)
157 | L_RO_PROP_AS(type, name)
158 | L_RO_PROP_AS(type, name, default)
159 | L_RO_PROP_CS(type, name)
160 | L_RO_PROP_CS(type, name, default)
161 | L_RO_PROP_REF(type, name, setter)
162 | L_RO_PROP_REF(type, name, setter, default)
163 | L_RO_PROP_REF_AS(type, name)
164 | L_RO_PROP_REF_AS(type, name, default)
165 | L_RO_PROP_REF_CS(type, name)
166 | L_RO_PROP_REF_CS(type, name, default)
167 | L_BEGIN_CLASS(name)
168 | L_END_CLASS
169 |
170 | For gadgets:
171 |
172 | L_RW_GPROP(type, name, setter)
173 | L_RW_GPROP(type, name, setter, default)
174 | L_RW_GPROP_AS(type, name)
175 | L_RW_GPROP_AS(type, name, default)
176 | L_RW_GPROP_CS(type, name)
177 | L_RW_GPROP_CS(type, name, default)
178 | L_RO_GPROP(type, name, setter)
179 | L_RO_GPROP(type, name, setter, default)
180 | L_RO_GPROP_AS(type, name)
181 | L_RO_GPROP_AS(type, name, default)
182 | L_RO_GPROP_CS(type, name)
183 | L_RO_GPROP_CS(type, name, default)
184 | L_BEGIN_GADGET(name)
185 | L_END_GADGET
186 |
187 |
188 | ## Synthesize Qt settings with support for signals (lqtutils_settings.h)
189 | **For more info: https://bugfreeblog.duckdns.org/2023/01/lqtutils-settings.html.**
190 |
191 | Contains a few tools that can be used to speed up writing simple settings to a file. Settings will still use QSettings and are therefore fully compatible. The macros are simply shortcuts to synthetise code. I only used this for creating ini files, but should work for other formats. An example:
192 | ```c++
193 | L_DECLARE_SETTINGS(LSettingsTest, new QSettings("settings.ini", QSettings::IniFormat))
194 | L_DEFINE_VALUE(QString, string1, QString("string1"))
195 | L_DEFINE_VALUE(QSize, size, QSize(100, 100))
196 | L_DEFINE_VALUE(double, temperature, -1)
197 | L_DEFINE_VALUE(QByteArray, image, QByteArray())
198 | L_END_CLASS
199 |
200 | L_DECLARE_SETTINGS(LSettingsTestSec1, new QSettings("settings.ini", QSettings::IniFormat), "SECTION_1")
201 | L_DEFINE_VALUE(QString, string2, QString("string2"))
202 | L_END_CLASS
203 | ```
204 | This will provide an interface to a "strong type" settings file containing a string, a QSize value, a double, a jpg image and another string, in a specific section of the ini file. Each class is reentrant like QSettings and can be instantiated in multiple threads.
205 | Each class also provides a unique notifier: the notifier can be used to receive notifications when any thread in the code changes the settings, and can also be used in bindings in QML code. For an example, refer to LQtUtilsQuick:
206 | ```c++
207 | Window {
208 | visible: true
209 | x: settings.appX
210 | y: settings.appY
211 | width: settings.appWidth
212 | height: settings.appHeight
213 | title: qsTr("Hello World")
214 |
215 | Connections {
216 | target: settings
217 | onAppWidthChanged:
218 | console.log("App width saved:", settings.appWidth)
219 | onAppHeightChanged:
220 | console.log("App width saved:", settings.appHeight)
221 | }
222 |
223 | Binding { target: settings; property: "appWidth"; value: width }
224 | Binding { target: settings; property: "appHeight"; value: height }
225 | Binding { target: settings; property: "appX"; value: x }
226 | Binding { target: settings; property: "appY"; value: y }
227 | }
228 | ```
229 |
230 |
231 | ## synthesize Qt enums and quickly expose to QML (lqtutils_enum.h)
232 | **For more info: https://bugfreeblog.duckdns.org/2020/06/synthesizing-qt-settings.html.**
233 |
234 | Contains a macro to define a enum and register it with the meta-object system. This enum can then be exposed to the QML. To create the enum simply do:
235 | ```c++
236 | L_DECLARE_ENUM(MyEnum,
237 | Value1 = 1,
238 | Value2,
239 | Value3)
240 | ```
241 | This enum is exposed using a namespace without subclassing QObject. Register with the QML engine with:
242 | ```c++
243 | MyEnum::registerEnum("com.luke", 1, 0);
244 | ```
245 |
246 |
247 | ## Cache values and init automatically
248 | ```lqt::CacheValue``` caches values of any type in a hash and calls the provided lambda if the value was never initialized. This is useful when writing settings classes and you want to read only once.
249 |
250 |
251 | ## Threading tools (lqtutils_threading.h)
252 | ```lqt::RecursiveMutex``` is a simple QMutex subclass defaulting to recursive mode.
253 |
254 | ```INVOKE_AWAIT_ASYNC``` is a wrapper around QMetaObject::invokeMethod that allows to execute a slot or lambda in the thread of an obj, synchronously awaiting for the result. E.g.:
255 | ```c++
256 | QThread* t = new QThread;
257 | t->start();
258 | QObject* obj = new QObject;
259 | obj->moveToThread(t);
260 | INVOKE_AWAIT_ASYNC(obj, [&i, currentThread, t] {
261 | i++;
262 | QCOMPARE(t, QThread::currentThread());
263 | QVERIFY(QThread::currentThread() != currentThread);
264 | QCOMPARE(i, 11);
265 | });
266 | QCOMPARE(i, 11);
267 | ```
268 |
269 | ```lqt_run_in_thread``` runs a lambda in a specific QThread asynchronously.
270 |
271 |
272 | ## Auto execute actions when exiting a scope (lqtutils_autoexec.h)
273 | A class that can be used to execute a lambda whenever the current scope ends, e.g.:
274 | ```c++
275 | int i = 9;
276 | {
277 | lqt::AutoExec autoexec([&] {
278 | i++;
279 | });
280 | QCOMPARE(i, 9);
281 | }
282 | QCOMPARE(i, 10);
283 | ```
284 |
285 | ```lqt::SharedAutoExec```: a class that can create copiable autoexec objects. Useful to implement locks with a function being executed when the lock is released.
286 |
287 |
288 | ## Measuring rate (lqtutils_freq.h)
289 |
290 | ```lqt::FreqMeter``` is a class that allows to measure the rate of any sampling activity. For example the refresh rate (see lqtutils_ui.h) or the rate of some kind of processing.
291 |
292 |
293 | ## Measuring frame rate in QML (lqtutils_ui.h)
294 |
295 | **For more info: https://bugfreeblog.duckdns.org/2021/09/measure-framerate-qt.html.**
296 |
297 | ```lqt::FrameRateMonitor``` is a class that can be used to measure the current frame rate of a QQuickWindow. The class monitors the frequency of frame swaps and provides a property with a value reporting the frame rate during the last second.
298 |
299 |
300 | ## Showing Local Notifications
301 |
302 | The `lqt::SystemNotification` and the `lqt::AndroidSystemNotification` objects can be used to show a local notification on Linux, Android, Windows, iOS and MacOS.
303 |
304 | Example:
305 |
306 | ```c++
307 | #ifdef Q_OS_ANDROID
308 | lqt::AndroidSystemNotification notification;
309 | notification.set_icon(QImage(":/qt/qml/FlashbackPrism/assets/icon_96.png"));
310 | notification.set_activityClass(QSL("org.qtproject.qt.android.bindings.QtActivity"));
311 | #else
312 | lqt::SystemNotification notification;
313 | #endif
314 | notification.set_appName(qApp->applicationName());
315 | notification.set_title(tr("Flashbacks available"));
316 | notification.set_message(tr("You have %1 memories taken in %2 years for today. Have a look!").arg(photos).arg(years));
317 | notification.set_openApp(true);
318 | notification.send();
319 | ```
320 |
321 |
322 | ## Single shot timer for QML (lqtutils_ui.h)
323 |
324 | ```c++
325 | lqt::QmlUtils::singleShot(int msec, QJSValue callback)
326 | ```
327 |
328 | Useful to defer an action of a specified amount of milleseconds in QML, without having to create a timer. Example:
329 |
330 | ```QML
331 | lqtUtils.singleShot(5000, () => console.log("Hello!"))
332 | ```
333 |
334 | remember to expose lqt::QmlUtils to QML with:
335 |
336 | ```c++
337 | engine.rootContext()->setContextProperty("lqtUtils", new lqt::QmlUtils(qApp));
338 | ```
339 |
340 |
341 | ## Getting safe areas on mobile (lqtutils_ui.h)
342 |
343 | **For more info: https://bugfreeblog.duckdns.org/2023/01/qt-qml-cutouts.html.**
344 |
345 | Both iOS and Android smartphones may include cutouts and you may want to know where it is safe to draw your QML UI. These four methods are useful to get the safe area both on iOS and Android (on Desktop the methods are still defined and simply return 0).
346 |
347 | ```c++
348 | Q_INVOKABLE static double safeAreaBottomInset();
349 | Q_INVOKABLE static double safeAreaTopInset();
350 | Q_INVOKABLE static double safeAreaRightInset();
351 | Q_INVOKABLE static double safeAreaLeftInset();
352 | ```
353 |
354 | Note that the methods return a value in logical pixels, so device pixel ratio is already taken into account.
355 |
356 | This is an example of a demo app where some elements extends under the cutouts, while the interactive area does not.
357 |
358 |
359 |
360 | ### How to Use
361 |
362 | To use it, simply instantiate it when you need it like this:
363 |
364 | ```c++
365 | QQuickView view;
366 | LQTFrameRateMonitor* monitor = new lqt::FrameRateMonitor(&view);
367 | ```
368 |
369 | expose it to QML if you need it:
370 |
371 | ```c++
372 | view.engine()->rootContext()->setContextProperty("fpsmonitor", monitor);
373 | ```
374 |
375 | and use it in QML (or in C++ if you prefer):
376 |
377 | ```js
378 | Text { text: qsTr("fps: ") + fpsmonitor.freq }
379 | ```
380 |
381 | If there have been no updates to the scene, Qt will not redraw it and you will end up with a measurement of ~1fps. If you want to measure how many frames *can* be drawn per second, you can enable automatic frame update triggers via the helper
382 |
383 | ```c++
384 | lqt::enableAutoFrameUpdates(view);
385 | ```
386 |
387 | which causes the window to request an update on every frame swap (that is on every vsync in most cases).
388 |
389 | ### Details
390 |
391 | The frame rate is provided in a notifiable property of the ```lqt::FrameRateMonitor``` class:
392 |
393 | ```c++
394 | L_RO_PROP_AS(int, freq, 0)
395 | ```
396 |
397 | Note that this property is defined using the prop macros provided by this library. The property is recomputed when each frame is swapped or after a second. The overhead of the component should be minimal.
398 |
399 |
400 | ## Measure Performance (lqtutils_perf.h)
401 |
402 | ```measure_time``` is a shortcut to quickly measure a procedure provided in a lambda for benchmarking it. The macro ```L_MEASURE_TIME``` can be used to be able to enable/disable the measurement through ```L_ENABLE_BENCHMARKS``` at project level reducing overhead to zero.
403 |
404 | ### How to Use
405 |
406 | This is an exmaple:
407 |
408 | ```c++
409 | measure_time([&] {
410 | const uchar* rgba = ...
411 | for (int x = 0; x < width; x++) {
412 | for (int y = 0; y < height; y++) {
413 | [process pixel]
414 | }
415 | }
416 | }, [] (qint64 time) {
417 | qWarning() << "Image processed in:" << time;
418 | });
419 | ```
420 |
421 |
422 | ## Blocking Queue for qt (lqtutils_bqueue.h)
423 |
424 | This header contains a simple blocking queue. It allows blocking/nonblocking insertions with timeout, blocking/nonblocking removal and a safe processing of the queue. This is an example of the producer/consumer pattern:
425 |
426 | ```c++
427 | struct LQTTestProducer : public QThread
428 | {
429 | LQTTestProducer(LQTBlockingQueue* queue) : QThread(), m_queue(queue) {}
430 | void run() override {
431 | static int i = 0;
432 | while (!isInterruptionRequested()) {
433 | QThread::msleep(10);
434 | m_queue->enqueue(i++);
435 | QVERIFY(m_queue->size() <= 10);
436 | }
437 | }
438 | void requestDispose() {
439 | requestInterruption();
440 | m_queue->requestDispose();
441 | }
442 |
443 | private:
444 | LQTBlockingQueue* m_queue;
445 | };
446 |
447 | struct LQTTestConsumer : public QThread
448 | {
449 | LQTTestConsumer(LQTBlockingQueue* queue) : QThread(), m_queue(queue) {}
450 | void run() override {
451 | static int i = 0;
452 | while (!isInterruptionRequested()) {
453 | QThread::msleep(15);
454 | std::optional ret = m_queue->dequeue();
455 | if (!ret)
456 | return;
457 | QVERIFY(*ret == i++);
458 | QVERIFY(lqt_in_range(m_queue->size(), 0, 11));
459 | }
460 | }
461 | void requestDispose() {
462 | requestInterruption();
463 | m_queue->requestDispose();
464 | }
465 |
466 | private:
467 | LQTBlockingQueue* m_queue;
468 | };
469 |
470 | [...]
471 |
472 | lqt::BlockingQueue queue(10, QSL("display_name"));
473 | LQTTestConsumer consumer(&queue);
474 | LQTTestProducer producer(&queue);
475 | consumer.start();
476 | producer.start();
477 |
478 | QEventLoop loop;
479 | QTimer::singleShot(30*1000, this, [&] { loop.quit(); });
480 | loop.exec();
481 |
482 | producer.requestDispose();
483 | producer.wait();
484 | consumer.requestDispose();
485 | consumer.wait();
486 | ```
487 |
488 |
489 | ## Download a File with Progress Notifications (lqtutils_net.h)
490 |
491 | The class ```lqt::Downloader``` can be used to download a URL to a file in a background thread. Example:
492 |
493 | ```c++
494 | QScopedPointer downloader(new lqt::Downloader(url, filePath));
495 | downloader->download();
496 | connect(downloader.data(), &lqt::Downloader::downloadProgress, this, [&downloader] (qint64 progress, qint64 total) {
497 | qDebug() << "Downloading:" << progress << "/" << total << downloader->state();
498 | });
499 | connect(downloader.data(), &lqt::Downloader::stateChanged, this, [&loop, &downloader] {
500 | if (downloader->state() == lqt::DownloaderState::S_DONE)
501 | // Done
502 | });
503 | ```
504 |
505 | ## lqtutils_data.h
506 |
507 | Hash of a file:
508 |
509 | ```c++
510 | QByteArray lqt::hash(const QString &fileName,
511 | QCryptographicHash::Algorithm algo = QCryptographicHash::Md5)
512 | ```
513 |
514 | Writes a random file of the specified size:
515 |
516 | ```c++
517 | bool lqt::random_file(const QString& fileName, qint64 size)
518 | ```
519 |
520 |
521 | ## FontAwesome in QML (lqtutils_fa.h)
522 |
523 | **For more info: https://bugfreeblog.duckdns.org/2023/05/fontawesome-qml-lqtutils.html.**
524 |
525 | This header includes a function to load FontAwesome fonts and QML items to render the fonts in QML. To include FontAwesome in Qt6 add the support to your cmake file when including the project:
526 |
527 | ```cmake
528 | set(ENABLE_FONT_AWESOME true)
529 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lqtutils)
530 | ```
531 |
532 | then init FontAwesome in your main function:
533 |
534 | ```c++
535 | lqt::embed_font_awesome(view.engine()->rootContext());
536 | ```
537 |
538 | Now types and fonts are loaded. To use it in QML:
539 |
540 | ```qml
541 | import "qrc:/lqtutils/fontawesome"
542 |
543 | [...]
544 |
545 | LQTFontAwesomeFreeSolid {
546 | width: 16
547 | height: 16
548 | iconUtf8: "\uf013"
549 | }
550 | ```
551 |
552 | to ensure the plugin is linked, add these two lines to your main.cpp:
553 |
554 | ```c++
555 | #include
556 | Q_IMPORT_QML_PLUGIN(lqtutilsPlugin)
557 | ```
558 |
559 | Note that the size is mandatory. The available types are: `LQTFontAwesomeFreeSolid`, `LQTFontAwesomeFreeRegular` and `LQTFontAwesomeBrandsRegular`. The init function also set the context properties: `fontAwesomeBrandsRegular`, `fontAwesomeFreeRegular` and `fontAwesomeFreeSolid`. These are QFont instances available in QML.
560 |
561 |
562 | ## Compute total and available RAM (lqtutils_system.h) [Linux only]
563 |
564 | **For more info: https://bugfreeblog.duckdns.org/2024/01/computing-total-and-free-ram-in-linux-with-qt.html.**
565 |
566 | This header includes a function to compute the total available RAM and the RAM potentially allocatable.
567 |
568 | ```c++
569 | std::optional mem = lqt::read_mem_data();
570 | if (!mem)
571 | return;
572 | qInfo() << "Total:" << mem->totalMemBytes;
573 | qInfo() << "Free :" << mem->freeMemBytes;
574 | ```
--------------------------------------------------------------------------------
/lqtutils_ui.cpp:
--------------------------------------------------------------------------------
1 | /**
2 | * MIT License
3 | *
4 | * Copyright (c) 2021 Luca Carlon
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | **/
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #ifdef Q_OS_ANDROID
33 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
34 | #include
35 | #include
36 | #else
37 | #include
38 | #include
39 | #include
40 | typedef QAndroidJniObject QJniObject;
41 | #endif
42 | #include
43 | #endif
44 |
45 | #if !defined(QT_NO_DBUS) && defined(Q_OS_LINUX)
46 | #include
47 | #include
48 | #endif
49 |
50 | #if defined(Q_OS_WINDOWS)
51 | #include
52 | #include
53 | #endif
54 |
55 | #include
56 |
57 | #include "lqtutils_ui.h"
58 | #include "lqtutils_qsl.h"
59 | #include "lqtutils_misc.h"
60 |
61 | namespace lqt {
62 |
63 | #ifdef Q_OS_ANDROID
64 | inline QJniObject get_activity()
65 | {
66 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
67 | return QNativeInterface::QAndroidApplication::context();
68 | #else
69 | return QtAndroid::androidActivity();
70 | #endif
71 | }
72 |
73 | inline QJniObject get_window()
74 | {
75 | const QJniObject activity = get_activity();
76 | if (!activity.isValid())
77 | return QJniObject();
78 |
79 | QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
80 | if (!window.isValid()) {
81 | qWarning() << "Cannot get window";
82 | return QJniObject();
83 | }
84 |
85 | return window;
86 | }
87 |
88 | inline void run_activity_thread(std::function f)
89 | {
90 | #ifdef Q_OS_ANDROID
91 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
92 | QNativeInterface::QAndroidApplication::runOnAndroidMainThread(f).waitForFinished();
93 | #else
94 | QtAndroid::runOnAndroidThreadSync(f);
95 | #endif
96 | #endif
97 | }
98 | #endif
99 |
100 | #ifndef Q_OS_IOS
101 | ScreenLock::ScreenLock() :
102 | m_isValid(false)
103 | {
104 | #ifdef Q_OS_ANDROID
105 | run_activity_thread([&] {
106 | lockScreen(true);
107 | });
108 | #endif
109 | }
110 |
111 | ScreenLock::~ScreenLock()
112 | {
113 | #ifdef Q_OS_ANDROID
114 | run_activity_thread([&] {
115 | lockScreen(false);
116 | });
117 | #endif
118 | }
119 |
120 | void ScreenLock::lockScreen(bool lock)
121 | {
122 | #ifdef Q_OS_ANDROID
123 | QJniObject window = get_window();
124 | if (!window.isValid())
125 | return;
126 |
127 | const int FLAG_KEEP_SCREEN_ON = 128;
128 | window.callMethod(lock ? "addFlags" : "clearFlags", "(I)V", FLAG_KEEP_SCREEN_ON);
129 | #else
130 | Q_UNUSED(lock);
131 | #endif
132 | }
133 | #endif // Q_IOS_OS
134 |
135 | FrameRateMonitor::FrameRateMonitor(QQuickWindow* w, QObject* parent) :
136 | FreqMeter(parent)
137 | {
138 | setWindow(w);
139 | }
140 |
141 | void FrameRateMonitor::setWindow(QQuickWindow* w)
142 | {
143 | if (!w)
144 | return;
145 | connect(w, &QQuickWindow::frameSwapped,
146 | this, &FrameRateMonitor::registerSample);
147 | }
148 |
149 | QMetaObject::Connection enableAutoFrameUpdates(QQuickWindow& w)
150 | {
151 | return QObject::connect(&w, &QQuickWindow::frameSwapped,
152 | &w, &QQuickWindow::requestUpdate);
153 | }
154 |
155 |
156 | void QmlUtils::singleShot(int msec, QJSValue callback)
157 | {
158 | QTimer::singleShot(msec, this, [callback] () mutable
159 | {
160 | if (callback.isCallable())
161 | callback.call();
162 | });
163 | }
164 |
165 | #ifndef Q_OS_IOS
166 | #ifdef Q_OS_ANDROID
167 | inline QJniObject get_decor_view()
168 | {
169 | QJniObject activity = get_activity();
170 | if (!activity.isValid()) {
171 | qWarning() << "Could not get android context";
172 | return QJniObject();
173 | }
174 |
175 | QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
176 | if (!window.isValid()) {
177 | qWarning() << "Cannot get window";
178 | return QJniObject();
179 | }
180 |
181 | return window.callObjectMethod("getDecorView", "()Landroid/view/View;");
182 | }
183 |
184 | inline QJniObject get_cutout()
185 | {
186 | QJniObject decoView = get_decor_view();
187 | if (!decoView.isValid()) {
188 | qWarning() << "Cannot get decorator view";
189 | return QJniObject();
190 | }
191 |
192 | QJniObject insets = decoView.callObjectMethod("getRootWindowInsets", "()Landroid/view/WindowInsets;");
193 | if (!insets.isValid()) {
194 | qWarning() << "Cannot get root window insets";
195 | return QJniObject();
196 | }
197 |
198 | return insets.callObjectMethod("getDisplayCutout", "()Landroid/view/DisplayCutout;");
199 | }
200 | #endif
201 |
202 | double QmlUtils::safeAreaTopInset()
203 | {
204 | #ifdef Q_OS_ANDROID
205 | QJniObject cutout = get_cutout();
206 | if (!cutout.isValid())
207 | return 0;
208 |
209 | return cutout.callMethod("getSafeInsetTop", "()I")/qApp->devicePixelRatio();
210 | #else
211 | return 0;
212 | #endif
213 | }
214 |
215 | double QmlUtils::safeAreaRightInset()
216 | {
217 | #ifdef Q_OS_ANDROID
218 | QJniObject cutout = get_cutout();
219 | if (!cutout.isValid())
220 | return 0;
221 |
222 | return cutout.callMethod("getSafeInsetRight", "()I")/qApp->devicePixelRatio();
223 | #else
224 | return 0;
225 | #endif
226 | }
227 |
228 | double QmlUtils::safeAreaLeftInset()
229 | {
230 | #ifdef Q_OS_ANDROID
231 | QJniObject cutout = get_cutout();
232 | if (!cutout.isValid())
233 | return 0;
234 |
235 | return cutout.callMethod("getSafeInsetLeft", "()I")/qApp->devicePixelRatio();
236 | #else
237 | return 0;
238 | #endif
239 | }
240 |
241 | QRectF QmlUtils::visibleDisplayFrame()
242 | {
243 | #ifdef Q_OS_ANDROID
244 | QJniObject decoView = get_decor_view();
245 | if (!decoView.isValid()) {
246 | qWarning() << "Could not get decor view";
247 | return QRectF();
248 | }
249 |
250 | QJniObject rectangle("android/graphics/Rect");
251 | decoView.callMethod("getWindowVisibleDisplayFrame", "(Landroid/graphics/Rect;)V", rectangle.object());
252 |
253 | const jint top = rectangle.getField("top")/qApp->devicePixelRatio();
254 | const jint bottom = rectangle.getField("bottom")/qApp->devicePixelRatio();
255 | const jint left = rectangle.getField("left")/qApp->devicePixelRatio();
256 | const jint right = rectangle.getField("right")/qApp->devicePixelRatio();
257 |
258 | return QRectF(left, top, right - left, bottom - top);
259 | #else
260 | return QRectF();
261 | #endif
262 | }
263 |
264 | double QmlUtils::safeAreaBottomInset()
265 | {
266 | #ifdef Q_OS_ANDROID
267 | QJniObject cutout = get_cutout();
268 | if (!cutout.isValid())
269 | return 0;
270 |
271 | return cutout.callMethod("getSafeInsetBottom", "()I")/qApp->devicePixelRatio();
272 | #else
273 | return 0;
274 | #endif
275 | }
276 |
277 | bool QmlUtils::shareResource(const QUrl& resUrl, const QString& mimeType, const QString& authority)
278 | {
279 | #ifdef Q_OS_ANDROID
280 | #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
281 | const QJniObject jniPath = QJniObject::fromString(resUrl.toLocalFile());
282 | if (!jniPath.isValid()) {
283 | qWarning() << "Could not create jni url";
284 | return false;
285 | }
286 |
287 | const QJniObject jniFile("java/io/File", "(Ljava/lang/String;)V", jniPath.object());
288 | if (!jniFile.isValid()) {
289 | qWarning() << "Could not instantiate file";
290 | return false;
291 | }
292 |
293 | const QJniObject jniUri = QJniObject::callStaticObjectMethod("androidx/core/content/FileProvider",
294 | "getUriForFile",
295 | "(Landroid/content/Context;Ljava/lang/String;Ljava/io/File;)Landroid/net/Uri;",
296 | QNativeInterface::QAndroidApplication::context().object(),
297 | QJniObject::fromString(authority).object(),
298 | jniFile.object());
299 | if (!jniUri.isValid()) {
300 | qWarning() << "Failed to create FilePath uri";
301 | return false;
302 | }
303 |
304 | const QJniObject jniParam = QJniObject::getStaticObjectField("android/content/Intent", "ACTION_SEND");
305 | if(!jniParam.isValid()) {
306 | qWarning() << "Could not get jni intent";
307 | return false;
308 | }
309 |
310 | QJniObject jniIntent("android/content/Intent", "(Ljava/lang/String;)V", jniParam.object());
311 | if (!jniIntent.isValid()) {
312 | qWarning() << "Could not instantiate intent";
313 | return false;
314 | }
315 |
316 | QJniObject jniType = QJniObject::fromString(mimeType);
317 | if (!jniType.isValid()) {
318 | qWarning() << "Could not create jni type";
319 | return false;
320 | }
321 |
322 | QJniObject jniResult = jniIntent.callObjectMethod("setType",
323 | "(Ljava/lang/String;)Landroid/content/Intent;",
324 | jniType.object());
325 | if (!jniResult.isValid()) {
326 | qWarning() << "Cannot set intent type";
327 | return false;
328 | }
329 |
330 | const QJniObject jniExtraStream = QJniObject::getStaticObjectField("android/content/Intent",
331 | "EXTRA_STREAM");
332 | if (!jniExtraStream.isValid()) {
333 | qWarning() << "Cannot read extra stream constant";
334 | return false;
335 | }
336 |
337 | jniResult = jniIntent.callObjectMethod("putExtra",
338 | "(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;",
339 | jniExtraStream.object(),
340 | jniUri.object