Fix UI glitches in external window with HiDPI screens

This commit is contained in:
Alex Spataru 2021-10-01 04:12:04 -05:00
parent 5144695aaf
commit 92b0a0193e
7 changed files with 99 additions and 225 deletions

View File

@ -174,7 +174,6 @@ HEADERS += \
src/Widgets/Common/AnalogGauge.h \ src/Widgets/Common/AnalogGauge.h \
src/Widgets/Common/AttitudeIndicator.h \ src/Widgets/Common/AttitudeIndicator.h \
src/Widgets/Common/BaseWidget.h \ src/Widgets/Common/BaseWidget.h \
src/Widgets/Common/ExternalWindow.h \
src/Widgets/Compass.h \ src/Widgets/Compass.h \
src/Widgets/DataGroup.h \ src/Widgets/DataGroup.h \
src/Widgets/Gauge.h \ src/Widgets/Gauge.h \
@ -213,7 +212,6 @@ SOURCES += \
src/Widgets/Common/AnalogGauge.cpp \ src/Widgets/Common/AnalogGauge.cpp \
src/Widgets/Common/AttitudeIndicator.cpp \ src/Widgets/Common/AttitudeIndicator.cpp \
src/Widgets/Common/BaseWidget.cpp \ src/Widgets/Common/BaseWidget.cpp \
src/Widgets/Common/ExternalWindow.cpp \
src/Widgets/Compass.cpp \ src/Widgets/Compass.cpp \
src/Widgets/DataGroup.cpp \ src/Widgets/DataGroup.cpp \
src/Widgets/Gauge.cpp \ src/Widgets/Gauge.cpp \

View File

@ -21,6 +21,7 @@
*/ */
import QtQuick import QtQuick
import QtQuick.Window
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls import QtQuick.Controls
@ -37,7 +38,7 @@ Item {
anchors.fill: parent anchors.fill: parent
title: loader.widgetTitle title: loader.widgetTitle
icon.source: loader.widgetIcon icon.source: loader.widgetIcon
onHeaderDoubleClicked: loader.displayWindow() onHeaderDoubleClicked: externalWindow.visible = true
borderColor: Cpp_ThemeManager.datasetWindowBorder borderColor: Cpp_ThemeManager.datasetWindowBorder
WidgetLoader { WidgetLoader {
@ -56,4 +57,22 @@ Item {
source: window source: window
anchors.fill: window anchors.fill: window
} }
Window {
id: externalWindow
minimumWidth: 640
minimumHeight: 480
title: externalLoader.widgetTitle
palette.base: Cpp_ThemeManager.datasetWindowBackground
palette.window: Cpp_ThemeManager.datasetWindowBackground
flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
WidgetLoader {
id: externalLoader
widgetIndex: index
anchors.fill: parent
isExternalWindow: true
widgetVisible: externalWindow.visible
}
}
} }

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) 2020-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 "ExternalWindow.h"
#include <QShowEvent>
#include <QHideEvent>
using namespace Widgets;
ExternalWindow::ExternalWindow()
: m_widget(nullptr)
{
setLayout(&m_layout);
}
QWidget *ExternalWindow::widget()
{
return m_widget;
}
void ExternalWindow::setWidget(QWidget *widget)
{
Q_ASSERT(widget);
if (m_widget)
m_layout.removeWidget(m_widget);
m_layout.addWidget(widget);
}
void ExternalWindow::showEvent(QShowEvent *event)
{
event->accept();
emit visibleChanged();
}
void ExternalWindow::hideEvent(QHideEvent *event)
{
event->accept();
emit visibleChanged();
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (c) 2020-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_COMMON_EXTERNAL_WINDOW_H
#define WIDGETS_COMMON_EXTERNAL_WINDOW_H
#include <QDialog>
#include <QHBoxLayout>
namespace Widgets
{
class ExternalWindow : public QDialog
{
Q_OBJECT
signals:
void visibleChanged();
public:
ExternalWindow();
QWidget *widget();
void setWidget(QWidget *widget);
protected:
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
private:
QWidget *m_widget;
QHBoxLayout m_layout;
};
}
#endif

View File

@ -46,6 +46,7 @@ WidgetLoader::WidgetLoader(QQuickItem *parent)
, m_index(-1) , m_index(-1)
, m_widget(nullptr) , m_widget(nullptr)
, m_widgetVisible(false) , m_widgetVisible(false)
, m_isExternalWindow(false)
{ {
// Set item flags // Set item flags
setFlag(ItemHasContents, true); setFlag(ItemHasContents, true);
@ -53,17 +54,6 @@ WidgetLoader::WidgetLoader(QQuickItem *parent)
setFlag(ItemAcceptsInputMethod, true); setFlag(ItemAcceptsInputMethod, true);
setAcceptedMouseButtons(Qt::AllButtons); setAcceptedMouseButtons(Qt::AllButtons);
// Configure main window
m_window.setMinimumWidth(640);
m_window.setMinimumHeight(480);
// Set window palette
QPalette palette;
auto theme = Misc::ThemeManager::getInstance();
palette.setColor(QPalette::Base, theme->datasetWindowBackground());
palette.setColor(QPalette::Window, theme->datasetWindowBackground());
m_window.setPalette(palette);
// Resize widget to fit QML item size // Resize widget to fit QML item size
connect(this, &QQuickPaintedItem::widthChanged, this, connect(this, &QQuickPaintedItem::widthChanged, this,
&WidgetLoader::updateWidgetSize); &WidgetLoader::updateWidgetSize);
@ -73,9 +63,6 @@ WidgetLoader::WidgetLoader(QQuickItem *parent)
// Automatically update the widget's visibility // Automatically update the widget's visibility
connect(UI::Dashboard::getInstance(), &UI::Dashboard::widgetVisibilityChanged, this, connect(UI::Dashboard::getInstance(), &UI::Dashboard::widgetVisibilityChanged, this,
&WidgetLoader::updateWidgetVisible); &WidgetLoader::updateWidgetVisible);
// Enable/disable the window widget automatically
connect(&m_window, SIGNAL(visibleChanged()), this, SLOT(updateWidgetWindow()));
} }
/** /**
@ -198,6 +185,11 @@ QString WidgetLoader::widgetTitle() const
return tr("Invalid"); return tr("Invalid");
} }
bool WidgetLoader::isExternalWindow() const
{
return m_isExternalWindow;
}
/** /**
* Returns the type of the current widget (e.g. group, plot, bar, gauge, etc...) * Returns the type of the current widget (e.g. group, plot, bar, gauge, etc...)
*/ */
@ -206,12 +198,10 @@ UI::Dashboard::WidgetType WidgetLoader::widgetType() const
return UI::Dashboard::getInstance()->widgetType(widgetIndex()); return UI::Dashboard::getInstance()->widgetType(widgetIndex());
} }
/** void WidgetLoader::setVisible(const bool visible)
* Shows a window with the current widget
*/
void WidgetLoader::displayWindow()
{ {
m_window.showNormal(); if (m_widget)
m_widget->setEnabled(visible);
} }
/** /**
@ -231,20 +221,11 @@ void WidgetLoader::setWidgetIndex(const int index)
m_widget = nullptr; m_widget = nullptr;
} }
// Delete central widget of window
if (m_window.widget())
delete m_window.widget();
// Hide widget window
if (m_window.isVisible())
m_window.hide();
// Construct new widget // Construct new widget
switch (widgetType()) switch (widgetType())
{ {
case UI::Dashboard::WidgetType::Group: case UI::Dashboard::WidgetType::Group:
m_widget = new DataGroup(relativeIndex()); m_widget = new DataGroup(relativeIndex());
m_window.setWidget(new DataGroup(relativeIndex()));
break; break;
case UI::Dashboard::WidgetType::MultiPlot: case UI::Dashboard::WidgetType::MultiPlot:
m_widget = new QPushButton("Multi-Plot"); m_widget = new QPushButton("Multi-Plot");
@ -254,26 +235,21 @@ void WidgetLoader::setWidgetIndex(const int index)
break; break;
case UI::Dashboard::WidgetType::Bar: case UI::Dashboard::WidgetType::Bar:
m_widget = new Bar(relativeIndex()); m_widget = new Bar(relativeIndex());
m_window.setWidget(new Bar(relativeIndex()));
break; break;
case UI::Dashboard::WidgetType::Gauge: case UI::Dashboard::WidgetType::Gauge:
m_widget = new Gauge(relativeIndex()); m_widget = new Gauge(relativeIndex());
m_window.setWidget(new Gauge(relativeIndex()));
break; break;
case UI::Dashboard::WidgetType::Thermometer: case UI::Dashboard::WidgetType::Thermometer:
m_widget = new QPushButton("Thermometer"); m_widget = new QPushButton("Thermometer");
break; break;
case UI::Dashboard::WidgetType::Compass: case UI::Dashboard::WidgetType::Compass:
m_widget = new Compass(relativeIndex()); m_widget = new Compass(relativeIndex());
m_window.setWidget(new Compass(relativeIndex()));
break; break;
case UI::Dashboard::WidgetType::Gyroscope: case UI::Dashboard::WidgetType::Gyroscope:
m_widget = new Gyroscope(relativeIndex()); m_widget = new Gyroscope(relativeIndex());
m_window.setWidget(new Gyroscope(relativeIndex()));
break; break;
case UI::Dashboard::WidgetType::Accelerometer: case UI::Dashboard::WidgetType::Accelerometer:
m_widget = new Accelerometer(relativeIndex()); m_widget = new Accelerometer(relativeIndex());
m_window.setWidget(new Accelerometer(relativeIndex()));
break; break;
case UI::Dashboard::WidgetType::Map: case UI::Dashboard::WidgetType::Map:
m_widget = new QPushButton("Map"); m_widget = new QPushButton("Map");
@ -282,11 +258,6 @@ void WidgetLoader::setWidgetIndex(const int index)
break; break;
} }
// Update window title
m_window.setWindowTitle(widgetTitle());
if (m_window.widget())
m_window.widget()->setEnabled(false);
// Allow widget to receive events from the QML interface // Allow widget to receive events from the QML interface
if (m_widget) if (m_widget)
{ {
@ -298,6 +269,12 @@ void WidgetLoader::setWidgetIndex(const int index)
} }
} }
void WidgetLoader::setIsExternalWindow(const bool isWindow)
{
m_isExternalWindow = isWindow;
emit isExternalWindowChanged();
}
/** /**
* Resizes the widget to fit inside the QML item. * Resizes the widget to fit inside the QML item.
*/ */
@ -310,16 +287,6 @@ void WidgetLoader::updateWidgetSize()
} }
} }
/**
* Enables/disables the widget updates of the external window when the window
* is shown or hidden.
*/
void WidgetLoader::updateWidgetWindow()
{
if (m_window.widget())
m_window.widget()->setEnabled(m_window.isVisible());
}
/** /**
* Updates the visibility status of the current widget (this function is called * Updates the visibility status of the current widget (this function is called
* automatically by the UI::Dashboard class via signals/slots). * automatically by the UI::Dashboard class via signals/slots).
@ -328,16 +295,13 @@ void WidgetLoader::updateWidgetVisible()
{ {
bool visible = UI::Dashboard::getInstance()->widgetVisible(widgetIndex()); bool visible = UI::Dashboard::getInstance()->widgetVisible(widgetIndex());
if (widgetVisible() != visible) if (widgetVisible() != visible && !isExternalWindow())
{ {
m_widgetVisible = visible; m_widgetVisible = visible;
if (m_widget) if (m_widget)
m_widget->setEnabled(visible); m_widget->setEnabled(visible);
if (m_window.widget())
m_window.widget()->setEnabled(visible);
emit widgetVisibleChanged(); emit widgetVisibleChanged();
} }
} }

View File

@ -30,8 +30,6 @@
#include <UI/Dashboard.h> #include <UI/Dashboard.h>
#include "Common/ExternalWindow.h"
namespace Widgets namespace Widgets
{ {
class WidgetLoader : public QQuickPaintedItem class WidgetLoader : public QQuickPaintedItem
@ -55,11 +53,20 @@ class WidgetLoader : public QQuickPaintedItem
Q_PROPERTY(bool widgetVisible Q_PROPERTY(bool widgetVisible
READ widgetVisible READ widgetVisible
NOTIFY widgetVisibleChanged) NOTIFY widgetVisibleChanged)
Q_PROPERTY(bool isExternalWindow
READ isExternalWindow
WRITE setIsExternalWindow
NOTIFY isExternalWindowChanged)
Q_PROPERTY(bool widgetVisible
READ widgetVisible
WRITE setVisible
NOTIFY widgetVisibleChanged)
// clang-format on // clang-format on
signals: signals:
void widgetIndexChanged(); void widgetIndexChanged();
void widgetVisibleChanged(); void widgetVisibleChanged();
void isExternalWindowChanged();
public: public:
WidgetLoader(QQuickItem *parent = 0); WidgetLoader(QQuickItem *parent = 0);
@ -74,15 +81,16 @@ public:
bool widgetVisible() const; bool widgetVisible() const;
QString widgetIcon() const; QString widgetIcon() const;
QString widgetTitle() const; QString widgetTitle() const;
bool isExternalWindow() const;
UI::Dashboard::WidgetType widgetType() const; UI::Dashboard::WidgetType widgetType() const;
public slots: public slots:
void displayWindow(); void setVisible(const bool visible);
void setWidgetIndex(const int index); void setWidgetIndex(const int index);
void setIsExternalWindow(const bool isWindow);
private slots: private slots:
void updateWidgetSize(); void updateWidgetSize();
void updateWidgetWindow();
void updateWidgetVisible(); void updateWidgetVisible();
protected: protected:
@ -92,8 +100,8 @@ protected:
private: private:
int m_index; int m_index;
QWidget *m_widget; QWidget *m_widget;
ExternalWindow m_window;
bool m_widgetVisible; bool m_widgetVisible;
bool m_isExternalWindow;
}; };
} }