Add generic widget loader item

This commit is contained in:
Alex Spataru 2021-09-25 03:52:03 -05:00
parent 230e8809f0
commit 33fecc9ed5
12 changed files with 787 additions and 59 deletions

View File

@ -156,10 +156,12 @@ HEADERS += \
src/Widgets/Gyroscope.h \
src/Widgets/Plot.h \
src/Widgets/Terminal.h \
src/Widgets/Thermometer.h
src/Widgets/Thermometer.h \
src/Widgets/WidgetLoader.h
SOURCES += \
src/UI/Dashboard.cpp \
src/Widgets/WidgetLoader.cpp \
src/main.cpp \
src/CSV/Export.cpp \
src/CSV/Player.cpp \

View File

@ -145,9 +145,9 @@ Page {
Layout.alignment: Qt.AlignVCenter
Layout.maximumHeight: parent.height
Layout.minimumHeight: parent.height
icon.source: "qrc:/icons/widget.svg"
Layout.minimumWidth: root.headerHeight
Layout.maximumWidth: root.headerHeight
icon.source: "qrc:/icons/equalizer.svg"
icon.width: root.headerHeight * 24 / 32
icon.height: root.headerHeight * 24 / 32
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
* Copyright (c) 2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -38,7 +38,6 @@ Item {
// Main layout
//
ColumnLayout {
x: 2 * app.spacing
anchors.fill: parent
spacing: app.spacing * 2
anchors.margins: app.spacing * 1.5
@ -75,6 +74,15 @@ Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumWidth: 240
WidgetGrid {
id: widgetGrid
anchors.fill: parent
}
Widgets.Shadow {
source: widgetGrid
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
* Copyright (c) 2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
* Copyright (c) 2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import QtQuick 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import SerialStudio 1.0
import "../Widgets" as Widgets
Widgets.Window {
id: root
//
// Window properties
//
gradient: true
title: qsTr("Data")
headerDoubleClickEnabled: false
icon.source: "qrc:/icons/dataset.svg"
backgroundColor: Cpp_ThemeManager.embeddedWindowBackground
// Hacks for calculating cell width
readonly property int columns: Math.floor(grid.width / cWidth)
readonly property int cWidth: Math.min(Math.max(356, grid.width / Math.min(3, grid.count)), 480)
//
// Put all items inside a grid view (the column layout in combination with the "clip" property
// of the grid is used to inhibit the generated widgets from escaping the window)
//
ColumnLayout {
spacing: 0
anchors {
fill: parent
margins: 0
leftMargin: app.spacing
rightMargin: app.spacing
}
GridView {
id: grid
clip: true
contentWidth: -1
Layout.fillWidth: true
Layout.fillHeight: true
// Calculate cell size so that cells fill the grid space and heigth < width
cellHeight: cellWidth * (2/3)
cellWidth: cWidth + (grid.width - cWidth * columns) / columns
// Model + delegate
model: Cpp_UI_Dashboard.totalWidgetCount
delegate: Item {
width: grid.cellWidth
height: grid.cellHeight
visible: opacity > 0
opacity: loader.widgetVisible ? 1 : 0
Behavior on opacity {NumberAnimation{}}
Widgets.Window {
id: window
title: loader.widgetTitle
icon.source: loader.widgetIcon
onHeaderDoubleClicked: loader.displayWindow()
borderColor: Cpp_ThemeManager.datasetWindowBorder
anchors {
fill: parent
margins: app.spacing
bottomMargin: app.spacing
topMargin: 2 * app.spacing
}
WidgetLoader {
id: loader
widgetIndex: index
anchors.fill: parent
anchors.margins: app.spacing
}
}
Widgets.Shadow {
source: window
}
}
}
Item {
Layout.fillWidth: true
height: root.borderWidth
}
}
}

View File

@ -28,5 +28,6 @@
<file>JSONDropArea.qml</file>
<file>Windows/ViewOptions.qml</file>
<file>Windows/DashboardTitle.qml</file>
<file>Windows/WidgetGrid.qml</file>
</qresource>
</RCC>

View File

@ -50,15 +50,8 @@
#include <Plugins/Bridge.h>
#include <UI/Dashboard.h>
#include <Widgets/Bar.h>
#include <Widgets/Plot.h>
#include <Widgets/Gauge.h>
#include <Widgets/Compass.h>
#include <Widgets/Terminal.h>
#include <Widgets/DataGroup.h>
#include <Widgets/Gyroscope.h>
#include <Widgets/Thermometer.h>
#include <Widgets/Accelerometer.h>
#include <Widgets/WidgetLoader.h>
#include <QSimpleUpdater.h>
@ -126,6 +119,7 @@ void ModuleManager::registerQmlTypes()
qmlRegisterType<JSON::Group>("SerialStudio", 1, 0, "Group");
qmlRegisterType<JSON::Dataset>("SerialStudio", 1, 0, "Dataset");
qmlRegisterType<Widgets::Terminal>("SerialStudio", 1, 0, "Terminal");
qmlRegisterType<Widgets::WidgetLoader>("SerialStudio", 1, 0, "WidgetLoader");
}
/**

View File

@ -90,6 +90,12 @@ bool Dashboard::frameValid() const
// Widget count functions
//--------------------------------------------------------------------------------------------------
int Dashboard::totalWidgetCount()
{
return mapCount() + barCount() + plotCount() + gaugeCount() + groupCount()
+ compassCount() + gyroscopeCount() + thermometerCount() + accelerometerCount();
}
int Dashboard::mapCount()
{
return m_mapWidgets.count();
@ -220,6 +226,23 @@ QStringList Dashboard::accelerometerTitles()
return list;
}
QStringList Dashboard::widgetTitles()
{
// Warning: maintain same order as the view option repeaters in ViewOptions.qml!
// clang-format off
return groupTitles() +
plotTitles() +
barTitles() +
gaugeTitles() +
thermometerTitles() +
compassTitles() +
gyroscopeTitles() +
accelerometerTitles() +
mapTitles();
// clang-format on
}
//--------------------------------------------------------------------------------------------------
// Widget visibility access functions
//--------------------------------------------------------------------------------------------------
@ -304,11 +327,8 @@ void Dashboard::setBarVisible(const int index, const bool visible)
{
if (index < m_barVisibility.count())
{
if (barVisible(index) != visible)
{
m_barVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_barVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}
@ -316,11 +336,8 @@ void Dashboard::setMapVisible(const int index, const bool visible)
{
if (index < m_mapVisibility.count())
{
if (mapVisible(index) != visible)
{
m_mapVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_mapVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}
@ -328,11 +345,8 @@ void Dashboard::setPlotVisible(const int index, const bool visible)
{
if (index < m_plotVisibility.count())
{
if (plotVisible(index) != visible)
{
m_plotVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_plotVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}
@ -340,11 +354,8 @@ void Dashboard::setGroupVisible(const int index, const bool visible)
{
if (index < m_groupVisibility.count())
{
if (groupVisible(index) != visible)
{
m_groupVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_groupVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}
@ -352,11 +363,8 @@ void Dashboard::setGaugeVisible(const int index, const bool visible)
{
if (index < m_gaugeVisibility.count())
{
if (gaugeVisible(index) != visible)
{
m_gaugeVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_gaugeVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}
@ -364,11 +372,8 @@ void Dashboard::setCompassVisible(const int index, const bool visible)
{
if (index < m_compassVisibility.count())
{
if (compassVisible(index) != visible)
{
m_compassVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_compassVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}
@ -376,11 +381,8 @@ void Dashboard::setGyroscopeVisible(const int index, const bool visible)
{
if (index < m_gyroscopeVisibility.count())
{
if (gyroscopeVisible(index) != visible)
{
m_gyroscopeVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_gyroscopeVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}
@ -388,11 +390,8 @@ void Dashboard::setThermometerVisible(const int index, const bool visible)
{
if (index < m_thermometerVisibility.count())
{
if (thermometerVisible(index) != visible)
{
m_thermometerVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_thermometerVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}
@ -400,11 +399,8 @@ void Dashboard::setAccelerometerVisible(const int index, const bool visible)
{
if (index < m_accelerometerVisibility.count())
{
if (accelerometerVisible(index) != visible)
{
m_accelerometerVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
m_accelerometerVisibility.replace(index, visible);
emit widgetVisibilityChanged();
}
}

View File

@ -39,6 +39,9 @@ class Dashboard : public QObject
Q_PROPERTY(bool available
READ available
NOTIFY widgetCountChanged)
Q_PROPERTY(int totalWidgetCount
READ totalWidgetCount
NOTIFY widgetCountChanged)
Q_PROPERTY(int mapCount
READ mapCount
NOTIFY widgetCountChanged)
@ -81,6 +84,8 @@ public:
QString title();
bool available();
int totalWidgetCount();
int mapCount();
int barCount();
int plotCount();
@ -100,6 +105,7 @@ public:
Q_INVOKABLE QStringList gyroscopeTitles();
Q_INVOKABLE QStringList thermometerTitles();
Q_INVOKABLE QStringList accelerometerTitles();
Q_INVOKABLE QStringList widgetTitles();
Q_INVOKABLE bool barVisible(const int index);
Q_INVOKABLE bool mapVisible(const int index);

View File

@ -0,0 +1,495 @@
/*
* Copyright (c) 2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "WidgetLoader.h"
#include <QPushButton>
#include <QApplication>
#include <UI/Dashboard.h>
using namespace UI;
using namespace Widgets;
/**
* Constructor function
*/
WidgetLoader::WidgetLoader(QQuickItem *parent)
: QQuickPaintedItem(parent)
, m_index(-1)
, m_widget(nullptr)
, m_widgetVisible(true)
{
// Set item flags
setFlag(ItemHasContents, true);
setFlag(ItemAcceptsInputMethod, true);
setFlag(ItemIsFocusScope, true);
setAcceptedMouseButtons(Qt::AllButtons);
// Resize widget to fit QML item size
connect(this, &QQuickPaintedItem::widthChanged, this,
&WidgetLoader::updateWidgetSize);
connect(this, &QQuickPaintedItem::heightChanged, this,
&WidgetLoader::updateWidgetSize);
// Automatically update the widget's visibility
connect(Dashboard::getInstance(), &Dashboard::widgetVisibilityChanged, this,
&WidgetLoader::updateWidgetVisible);
}
/**
* Delete widget on class destruction
*/
WidgetLoader::~WidgetLoader()
{
if (m_widget)
m_widget->deleteLater();
}
/**
* Handle application events manually
*/
bool WidgetLoader::event(QEvent *event)
{
if (!m_widget)
return false;
switch (event->type())
{
case QEvent::FocusIn:
forceActiveFocus();
return QQuickPaintedItem::event(event);
break;
case QEvent::Wheel:
processWheelEvents(static_cast<QWheelEvent *>(event));
return true;
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
processMouseEvents(static_cast<QMouseEvent *>(event));
return true;
break;
default:
break;
}
return QApplication::sendEvent(m_widget, event);
}
/**
* Render the widget on the given @a painter
*/
void WidgetLoader::paint(QPainter *painter)
{
if (m_widget && painter)
m_widget->render(painter);
}
/**
* Custom event filter to manage redraw requests
*/
bool WidgetLoader::eventFilter(QObject *watched, QEvent *event)
{
if (!m_widget)
return false;
if (watched == m_widget)
{
switch (event->type())
{
case QEvent::Paint:
case QEvent::UpdateRequest:
update();
break;
default:
break;
}
}
return QQuickPaintedItem::eventFilter(watched, event);
}
int WidgetLoader::widgetIndex() const
{
return m_index;
}
int WidgetLoader::relativeIndex() const
{
//
// Warning: relative widget index should be calculated using the same order as defined
// by the
// UI::Dashboard::widgetTitles() function.
//
// Get pointer to dashboard module
auto dash = Dashboard::getInstance();
// Check if we should return group widget
int index = widgetIndex();
if (index < dash->groupCount())
return index;
// Check if we should return plot widget
index -= dash->groupCount();
if (index < dash->plotCount())
return index;
// Check if we should return bar widget
index -= dash->plotCount();
if (index < dash->barCount())
return index;
// Check if we should return gauge widget
index -= dash->barCount();
if (index < dash->gaugeCount())
return index;
// Check if we should return thermometer widget
index -= dash->gaugeCount();
if (index < dash->thermometerCount())
return index;
// Check if we should return compass widget
index -= dash->thermometerCount();
if (index < dash->compassCount())
return index;
// Check if we should return gyro widget
index -= dash->compassCount();
if (index < dash->gyroscopeCount())
return index;
// Check if we should return accelerometer widget
index -= dash->gyroscopeCount();
if (index < dash->accelerometerCount())
return index;
// Check if we should return map widget
index -= dash->accelerometerCount();
if (index < dash->mapCount())
return index;
// Return unknown widget
return -1;
}
bool WidgetLoader::widgetVisible() const
{
return m_widgetVisible;
}
QString WidgetLoader::widgetIcon() const
{
switch (widgetType())
{
case WidgetType::Group:
return "qrc:/icons/group.svg";
break;
case WidgetType::Plot:
return "qrc:/icons/plot.svg";
break;
case WidgetType::Bar:
return "qrc:/icons/bar.svg";
break;
case WidgetType::Gauge:
return "qrc:/icons/gauge.svg";
break;
case WidgetType::Thermometer:
return "qrc:/icons/thermometer.svg";
break;
case WidgetType::Compass:
return "qrc:/icons/compass.svg";
break;
case WidgetType::Gyroscope:
return "qrc:/icons/gyroscope.svg";
break;
case WidgetType::Accelerometer:
return "qrc:/icons/accelerometer.svg";
break;
case WidgetType::Map:
return "qrc:/icons/map.svg";
break;
default:
return "qrc:/icons/close.svg";
break;
}
}
/**
* Returns the appropiate window title for the given widget
*/
QString WidgetLoader::widgetTitle() const
{
return UI::Dashboard::getInstance()->widgetTitles().at(widgetIndex());
}
WidgetLoader::WidgetType WidgetLoader::widgetType() const
{
//
// Warning: relative widget index should be calculated using the same order as defined
// by the
// UI::Dashboard::widgetTitles() function.
//
// Unitialized widget loader class
if (widgetIndex() < 0)
return WidgetType::Unknown;
// Get pointer to dashboard module
auto dash = UI::Dashboard::getInstance();
// Check if we should return group widget
int index = widgetIndex();
if (index < dash->groupCount())
return WidgetType::Group;
// Check if we should return plot widget
index -= dash->groupCount();
if (index < dash->plotCount())
return WidgetType::Plot;
// Check if we should return bar widget
index -= dash->plotCount();
if (index < dash->barCount())
return WidgetType::Bar;
// Check if we should return gauge widget
index -= dash->barCount();
if (index < dash->gaugeCount())
return WidgetType::Gauge;
// Check if we should return thermometer widget
index -= dash->gaugeCount();
if (index < dash->thermometerCount())
return WidgetType::Thermometer;
// Check if we should return compass widget
index -= dash->thermometerCount();
if (index < dash->compassCount())
return WidgetType::Compass;
// Check if we should return gyro widget
index -= dash->compassCount();
if (index < dash->gyroscopeCount())
return WidgetType::Gyroscope;
// Check if we should return accelerometer widget
index -= dash->gyroscopeCount();
if (index < dash->accelerometerCount())
return WidgetType::Accelerometer;
// Check if we should return map widget
index -= dash->accelerometerCount();
if (index < dash->mapCount())
return WidgetType::Map;
// Return unknown widget
return WidgetType::Unknown;
}
/**
* Shows a window with the current widget
*/
void WidgetLoader::displayWindow()
{
if (m_widget)
m_widget->showNormal();
}
/**
* Selects & configures the appropiate widget for the given @a index
*/
void WidgetLoader::setWidgetIndex(const int index)
{
if (m_index != index && index < Dashboard::getInstance()->totalWidgetCount()
&& index >= 0)
{
// Update widget index
m_index = index;
// Delete previous widget
if (m_widget)
{
m_widget->deleteLater();
m_widget = nullptr;
}
// Construct new widget
switch (widgetType())
{
case WidgetType::Group:
m_widget = new QPushButton("Group");
break;
case WidgetType::Plot:
m_widget = new QPushButton("Plot");
break;
case WidgetType::Bar:
m_widget = new QPushButton("Bar");
break;
case WidgetType::Gauge:
m_widget = new QPushButton("Gauge");
break;
case WidgetType::Thermometer:
m_widget = new QPushButton("Thermometer");
break;
case WidgetType::Compass:
m_widget = new QPushButton("Compass");
break;
case WidgetType::Gyroscope:
m_widget = new QPushButton("Gyroscope");
break;
case WidgetType::Accelerometer:
m_widget = new QPushButton("Accelerometer");
break;
case WidgetType::Map:
m_widget = new QPushButton("Map");
break;
default:
break;
}
// Allow widget to receive events from the QML interface
if (m_widget)
{
m_widget->installEventFilter(this);
updateWidgetVisible();
}
// Update UI
emit widgetIndexChanged();
}
}
/**
* Resizes the widget to fit inside the QML item.
*/
void WidgetLoader::updateWidgetSize()
{
if (m_widget && width() > 0 && height() > 0)
{
m_widget->setFixedSize(width(), height());
update();
}
}
void WidgetLoader::updateWidgetVisible()
{
bool visible = false;
auto index = relativeIndex();
auto dash = Dashboard::getInstance();
switch (widgetType())
{
case WidgetType::Group:
visible = dash->groupVisible(index);
break;
case WidgetType::Plot:
visible = dash->plotVisible(index);
break;
case WidgetType::Bar:
visible = dash->barVisible(index);
break;
case WidgetType::Gauge:
visible = dash->gaugeVisible(index);
break;
case WidgetType::Thermometer:
visible = dash->thermometerVisible(index);
break;
case WidgetType::Compass:
visible = dash->compassVisible(index);
break;
case WidgetType::Gyroscope:
visible = dash->gyroscopeVisible(index);
break;
case WidgetType::Accelerometer:
visible = dash->accelerometerVisible(index);
break;
case WidgetType::Map:
visible = dash->mapVisible(index);
break;
default:
visible = false;
break;
}
if (widgetVisible() != visible)
{
m_widgetVisible = visible;
emit widgetVisibleChanged();
}
}
/**
* Hack: calls the appropiate protected mouse event handler function of the widget item
*/
void WidgetLoader::processMouseEvents(QMouseEvent *event)
{
if (!m_widget)
return;
class Hack : public QWidget
{
public:
using QWidget::mouseDoubleClickEvent;
using QWidget::mouseMoveEvent;
using QWidget::mousePressEvent;
using QWidget::mouseReleaseEvent;
};
auto hack = static_cast<Hack *>(m_widget);
switch (event->type())
{
case QEvent::MouseButtonPress:
hack->mousePressEvent(event);
break;
case QEvent::MouseMove:
hack->mouseMoveEvent(event);
break;
case QEvent::MouseButtonRelease:
hack->mouseReleaseEvent(event);
break;
case QEvent::MouseButtonDblClick:
hack->mouseDoubleClickEvent(event);
break;
default:
break;
}
}
/**
* Hack: calls the appropiate protected wheel event handler function of the widget item
*/
void WidgetLoader::processWheelEvents(QWheelEvent *event)
{
if (!m_widget)
return;
class Hack : public QWidget
{
public:
using QWidget::wheelEvent;
};
static_cast<Hack *>(m_widget)->wheelEvent(event);
}

112
src/Widgets/WidgetLoader.h Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 2021 Alex Spataru <https://github.com/alex-spataru>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef WIDGETS_LOADER_H
#define WIDGETS_LOADER_H
#include <QWidget>
#include <QObject>
#include <QPainter>
#include <QQuickPaintedItem>
namespace Widgets
{
class WidgetLoader : public QQuickPaintedItem
{
// clang-format off
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(int widgetIndex
READ widgetIndex
WRITE setWidgetIndex
NOTIFY widgetIndexChanged)
Q_PROPERTY(int relativeIndex
READ relativeIndex
NOTIFY widgetIndexChanged)
Q_PROPERTY(WidgetType widgetType
READ widgetType
NOTIFY widgetIndexChanged)
Q_PROPERTY(QString widgetIcon
READ widgetIcon
NOTIFY widgetIndexChanged)
Q_PROPERTY(QString widgetTitle
READ widgetTitle
NOTIFY widgetIndexChanged)
Q_PROPERTY(bool widgetVisible
READ widgetVisible
NOTIFY widgetVisibleChanged)
// clang-format on
signals:
void widgetIndexChanged();
void widgetVisibleChanged();
public:
enum class WidgetType
{
Group,
Plot,
Bar,
Gauge,
Thermometer,
Compass,
Gyroscope,
Accelerometer,
Map,
Unknown
};
Q_ENUM(WidgetType)
WidgetLoader(QQuickItem *parent = 0);
~WidgetLoader();
virtual bool event(QEvent *event) override;
virtual void paint(QPainter *painter) override;
virtual bool eventFilter(QObject *watched, QEvent *event) override;
int widgetIndex() const;
int relativeIndex() const;
bool widgetVisible() const;
QString widgetIcon() const;
QString widgetTitle() const;
WidgetType widgetType() const;
public slots:
void displayWindow();
void setWidgetIndex(const int index);
private slots:
void updateWidgetSize();
void updateWidgetVisible();
protected:
void processMouseEvents(QMouseEvent *event);
void processWheelEvents(QWheelEvent *event);
private:
int m_index;
QWidget *m_widget;
bool m_widgetVisible;
};
}
#endif