From 57fbd2fe0146f3445ebdd4bb9b35d320a55fbce9 Mon Sep 17 00:00:00 2001 From: James Turner <zakalawe@mac.com> Date: Sun, 24 Jun 2018 11:34:28 +0100 Subject: [PATCH] Remote-canvas: QPainter rendering mode --- utils/fgqcanvas/CMakeLists.txt | 2 + utils/fgqcanvas/canvaspainteddisplay.cpp | 130 +++++++++++++++++++++++ utils/fgqcanvas/canvaspainteddisplay.h | 74 +++++++++++++ utils/fgqcanvas/fgcanvaselement.cpp | 5 +- utils/fgqcanvas/fgcanvastext.cpp | 8 +- utils/fgqcanvas/main.cpp | 3 + utils/fgqcanvas/qml/CanvasFrame.qml | 21 +++- 7 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 utils/fgqcanvas/canvaspainteddisplay.cpp create mode 100644 utils/fgqcanvas/canvaspainteddisplay.h diff --git a/utils/fgqcanvas/CMakeLists.txt b/utils/fgqcanvas/CMakeLists.txt index c672c3107..fd8f0277c 100644 --- a/utils/fgqcanvas/CMakeLists.txt +++ b/utils/fgqcanvas/CMakeLists.txt @@ -53,6 +53,8 @@ set(SOURCES applicationcontroller.h canvasdisplay.cpp canvasdisplay.h + canvaspainteddisplay.cpp + canvaspainteddisplay.h ) qt5_add_resources(qrc_sources fgqcanvas_resources.qrc) diff --git a/utils/fgqcanvas/canvaspainteddisplay.cpp b/utils/fgqcanvas/canvaspainteddisplay.cpp new file mode 100644 index 000000000..dd3203b27 --- /dev/null +++ b/utils/fgqcanvas/canvaspainteddisplay.cpp @@ -0,0 +1,130 @@ +// +// Copyright (C) 2018 James Turner <james@flightgear.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "canvaspainteddisplay.h" + +#include <QDebug> + +#include "canvasconnection.h" +#include "fgcanvasgroup.h" +#include "fgcanvaspaintcontext.h" +#include "localprop.h" + +CanvasPaintedDisplay::CanvasPaintedDisplay(QQuickItem* parent) : + QQuickPaintedItem(parent) +{ + setTransformOrigin(QQuickItem::TopLeft); + setAntialiasing(true); +} + +CanvasPaintedDisplay::~CanvasPaintedDisplay() +{ +} + +void CanvasPaintedDisplay::paint(QPainter *painter) +{ + if (!m_rootElement) + return; + + const double xScaleFactor = width() / m_sourceSize.width(); + const double yScaleFactor = height() / m_sourceSize.height(); + const double f = std::min(xScaleFactor, yScaleFactor); + painter->scale(f, f); + + FGCanvasPaintContext context(painter); + m_rootElement->paint(&context); +} + +void CanvasPaintedDisplay::geometryChanged(const QRectF &newGeometry, const QRectF &) +{ + Q_UNUSED(newGeometry); + update(); +} + +void CanvasPaintedDisplay::setCanvas(CanvasConnection *canvas) +{ + if (m_connection == canvas) + return; + + if (m_connection) { + disconnect(m_connection, nullptr, this, nullptr); + m_rootElement.reset(); + } + + m_connection = canvas; + emit canvasChanged(m_connection); + + if (m_connection) { + connect(m_connection, &QObject::destroyed, + this, &CanvasPaintedDisplay::onConnectionDestroyed); + connect(m_connection, &CanvasConnection::statusChanged, + this, &CanvasPaintedDisplay::onConnectionStatusChanged); + connect(m_connection, &CanvasConnection::updated, + this, &CanvasPaintedDisplay::onConnectionUpdated); + + onConnectionStatusChanged(); + } + +} + +void CanvasPaintedDisplay::onConnectionDestroyed() +{ + m_connection = nullptr; + emit canvasChanged(m_connection); + + m_rootElement.reset(); +} + +void CanvasPaintedDisplay::onConnectionStatusChanged() +{ + if ((m_connection->status() == CanvasConnection::Connected) || + (m_connection->status() == CanvasConnection::Snapshot)) + { + m_rootElement.reset(new FGCanvasGroup(nullptr, m_connection->propertyRoot())); + // this is important to elements can discover their connection + // by walking their parent chain + m_rootElement->setParent(m_connection); + + connect(m_rootElement.get(), &FGCanvasGroup::canvasSizeChanged, + this, &CanvasPaintedDisplay::onCanvasSizeChanged); + + onCanvasSizeChanged(); + + if (m_connection->status() == CanvasConnection::Snapshot) { + m_connection->propertyRoot()->recursiveNotifyRestored(); + m_rootElement->polish(); + update(); + } + } +} + +void CanvasPaintedDisplay::onConnectionUpdated() +{ + if (m_rootElement) { + m_rootElement->polish(); + update(); + } +} + +void CanvasPaintedDisplay::onCanvasSizeChanged() +{ + m_sourceSize = QSizeF(m_connection->propertyRoot()->value("size", 256).toDouble(), + m_connection->propertyRoot()->value("size[1]", 256).toDouble()); + setImplicitSize(m_sourceSize.width(), m_sourceSize.height()); + update(); +} + diff --git a/utils/fgqcanvas/canvaspainteddisplay.h b/utils/fgqcanvas/canvaspainteddisplay.h new file mode 100644 index 000000000..feea4ff97 --- /dev/null +++ b/utils/fgqcanvas/canvaspainteddisplay.h @@ -0,0 +1,74 @@ +// +// Copyright (C) 2018 James Turner <james@flightgear.org> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef CANVAS_PAINTED_DISPLAY_H +#define CANVAS_PAINTED_DISPLAY_H + +#include <memory> + +#include <QQuickPaintedItem> + +class CanvasConnection; +class FGCanvasGroup; +class QQuickItem; + +class CanvasPaintedDisplay : public QQuickPaintedItem +{ + Q_OBJECT + + Q_PROPERTY(CanvasConnection* canvas READ canvas WRITE setCanvas NOTIFY canvasChanged) + +public: + CanvasPaintedDisplay(QQuickItem* parent = nullptr); + ~CanvasPaintedDisplay(); + + CanvasConnection* canvas() const + { + return m_connection; + } + + void paint(QPainter *painter) override; +signals: + + void canvasChanged(CanvasConnection* canvas); + +public slots: + + void setCanvas(CanvasConnection* canvas); + +protected: + + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + +private slots: + void onConnectionStatusChanged(); + + void onConnectionUpdated(); + + void onCanvasSizeChanged(); + void onConnectionDestroyed(); + +private: + void recomputeScaling(); + + CanvasConnection* m_connection = nullptr; + std::unique_ptr<FGCanvasGroup> m_rootElement; + // QQuickItem* m_rootItem = nullptr; + QSizeF m_sourceSize; +}; + +#endif // CANVAS_PAINTED_DISPLAY_H diff --git a/utils/fgqcanvas/fgcanvaselement.cpp b/utils/fgqcanvas/fgcanvaselement.cpp index 333962724..133af82cd 100644 --- a/utils/fgqcanvas/fgcanvaselement.cpp +++ b/utils/fgqcanvas/fgcanvaselement.cpp @@ -171,7 +171,10 @@ void FGCanvasElement::paint(FGCanvasPaintContext *context) const if (_hasClip) { // clip is defined in the global coordinate system -#if 0 + if (_clipFrame != ReferenceFrame::GLOBAL) { + qWarning() << Q_FUNC_INFO << "implement support for non-global clips"; + } +#if defined(DEBUG_PAINTING) p->save(); p->setTransform(context->globalCoordinateTransform()); p->setPen(Qt::yellow); diff --git a/utils/fgqcanvas/fgcanvastext.cpp b/utils/fgqcanvas/fgcanvastext.cpp index 102594b98..e32e91968 100644 --- a/utils/fgqcanvas/fgcanvastext.cpp +++ b/utils/fgqcanvas/fgcanvastext.cpp @@ -130,13 +130,13 @@ protected: return QPointF(x,y); } - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override { QQuickItem::geometryChanged(newGeometry, oldGeometry); update(); } - QRectF boundingRect() const + QRectF boundingRect() const override { if ((width() == 0.0) || (height() == 0.0)) { return m_layout.boundingRect(); @@ -229,8 +229,8 @@ void FGCanvasText::doPaint(FGCanvasPaintContext *context) const context->painter()->drawText(rect, _alignment, _text); - context->painter()->setPen(Qt::cyan); - context->painter()->drawRect(rect); + // context->painter()->setPen(Qt::cyan); + // context->painter()->drawRect(rect); } void FGCanvasText::doPolish() diff --git a/utils/fgqcanvas/main.cpp b/utils/fgqcanvas/main.cpp index 3558a1858..041ffa93b 100644 --- a/utils/fgqcanvas/main.cpp +++ b/utils/fgqcanvas/main.cpp @@ -24,6 +24,7 @@ #include "applicationcontroller.h" #include "canvasdisplay.h" #include "canvasconnection.h" +#include "canvaspainteddisplay.h" int main(int argc, char *argv[]) { @@ -38,6 +39,8 @@ int main(int argc, char *argv[]) qmlRegisterType<CanvasItem>("FlightGear", 1, 0, "CanvasItem"); qmlRegisterType<CanvasDisplay>("FlightGear", 1, 0, "CanvasDisplay"); + qmlRegisterType<CanvasPaintedDisplay>("FlightGear", 1, 0, "PaintedCanvasDisplay"); + qmlRegisterUncreatableType<CanvasConnection>("FlightGear", 1, 0, "CanvasConnection", "Don't create me"); qmlRegisterUncreatableType<ApplicationController>("FlightGear", 1, 0, "Application", "Can't create"); diff --git a/utils/fgqcanvas/qml/CanvasFrame.qml b/utils/fgqcanvas/qml/CanvasFrame.qml index 3b7d0887c..67004593e 100644 --- a/utils/fgqcanvas/qml/CanvasFrame.qml +++ b/utils/fgqcanvas/qml/CanvasFrame.qml @@ -4,7 +4,7 @@ import FlightGear 1.0 as FG Item { id: root property bool showDecorations: true - property alias canvas: canvasDisplay.canvas + property alias canvas: paintedDisplay.canvas property bool showUi: true Component.onCompleted: { @@ -27,9 +27,24 @@ Item { anchors.fill: parent clip: true - FG.CanvasDisplay { - id: canvasDisplay +// FG.CanvasDisplay { +// id: canvasDisplay +// anchors.fill: parent + +// onCanvasChanged: { +// if (canvas) { +// root.width = canvas.size.width +// root.height = canvas.size.height +// root.x = canvas.origin.x +// root.y = canvas.origin.y +// } +// } +// } + + FG.PaintedCanvasDisplay { + id: paintedDisplay anchors.fill: parent + // canvas: canvasDisplay.canvas onCanvasChanged: { if (canvas) {