[gegl-qt] NodeViewDeclarativeItem: Use a child QGraphicsItem



commit 614857dbfca1954a6ec7f2cbbf98cb260c83ecdc
Author: Jon Nordby <jononor gmail com>
Date:   Sat Sep 24 18:16:38 2011 +0200

    NodeViewDeclarativeItem: Use a child QGraphicsItem
    
    This allows us to make use of the graphicscene for transformations,
    which makes it easier to not do unecessary redraws when only
    the scale or translation changed (but not the content).

 gegl-qt/gegl-qt.pro                         |    9 +++-
 gegl-qt/internal/nodeviewchilditem.cpp      |   65 +++++++++++++++++++++++++++
 gegl-qt/internal/nodeviewchilditem.h        |   48 ++++++++++++++++++++
 gegl-qt/internal/nodeviewimplementation.cpp |   32 +++++++++----
 gegl-qt/internal/nodeviewimplementation.h   |   12 +++++-
 gegl-qt/nodeviewdeclarativeitem.cpp         |   57 ++++++++++++++++++++++--
 gegl-qt/nodeviewdeclarativeitem.h           |    5 ++
 7 files changed, 210 insertions(+), 18 deletions(-)
---
diff --git a/gegl-qt/gegl-qt.pro b/gegl-qt/gegl-qt.pro
index 4e2204d..cda2b3b 100644
--- a/gegl-qt/gegl-qt.pro
+++ b/gegl-qt/gegl-qt.pro
@@ -39,12 +39,15 @@ contains(HAVE_QT_DECLARATIVE, yes) {
 
 PRIVATE_HEADERS = \
     internal/nodeviewimplementation.h \
+    internal/nodeviewchilditem.h \
 
-SOURCES += $$PUBLIC_SOURCES \
+PRIVATE_SOURCES = \
     internal/nodeviewimplementation.cpp \
+    internal/nodeviewchilditem.cpp \
 
-HEADERS += $$PUBLIC_HEADERS \
-    $$PRIVATE_HEADERS \
+SOURCES += $$PUBLIC_SOURCES $$PRIVATE_SOURCES
+
+HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
 
 INCLUDEPATH += .. # Public includes have gegl-qt/ prefix
 
diff --git a/gegl-qt/internal/nodeviewchilditem.cpp b/gegl-qt/internal/nodeviewchilditem.cpp
new file mode 100644
index 0000000..a119170
--- /dev/null
+++ b/gegl-qt/internal/nodeviewchilditem.cpp
@@ -0,0 +1,65 @@
+/* This file is part of GEGL-QT
+ *
+ * GEGL-QT is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-QT 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-QT; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2011 Jon Nordby <jononor gmail com>
+ */
+
+#include "nodeviewchilditem.h"
+#include "internal/nodeviewimplementation.h"
+
+#include <QtDebug> // TEMP
+
+using namespace GeglQt;
+
+NodeViewChildItem::NodeViewChildItem(NodeViewImplementation *helper, QGraphicsItem *parent=0)
+    : QGraphicsObject()
+    , mHelper(helper)
+    , mItemSize(0.0, 0.0)
+{
+    Q_UNUSED(parent);
+}
+
+NodeViewChildItem::~NodeViewChildItem()
+{
+}
+
+void
+NodeViewChildItem::updateSize(QSizeF newSize)
+{
+    if (!newSize.isValid()) {
+        return;
+    }
+
+    // Must be called before changing the return value of boundingRect()
+    prepareGeometryChange();
+    mItemSize = newSize;
+}
+
+QRectF
+NodeViewChildItem::boundingRect() const
+{
+    return QRectF(0.0, 0.0, mItemSize.width(), mItemSize.height());
+}
+
+void
+NodeViewChildItem::paint(QPainter *painter,
+                             const QStyleOptionGraphicsItem *option,
+                             QWidget *widget)
+{
+    Q_UNUSED(widget);
+
+    mHelper->paint(painter, option->exposedRect);
+}
+
diff --git a/gegl-qt/internal/nodeviewchilditem.h b/gegl-qt/internal/nodeviewchilditem.h
new file mode 100644
index 0000000..5341c3e
--- /dev/null
+++ b/gegl-qt/internal/nodeviewchilditem.h
@@ -0,0 +1,48 @@
+#ifndef NODEVIEWCHILDITEM_H
+#define NODEVIEWCHILDITEM_H
+
+/* This file is part of GEGL-QT
+ *
+ * GEGL-QT is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-QT 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-QT; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2011 Jon Nordby <jononor gmail com>
+ */
+
+#include <QGraphicsItem>
+
+namespace GeglQt {
+
+class NodeViewImplementation;
+
+class NodeViewChildItem : public QGraphicsObject
+{
+public:
+    NodeViewChildItem(NodeViewImplementation *helper, QGraphicsItem *parent);
+    ~NodeViewChildItem();
+
+    //! reimpl
+    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+    QRectF boundingRect() const;
+    //! reimpl end
+
+    void updateSize(QSizeF size);
+
+private:
+    NodeViewImplementation *mHelper;
+    QSizeF mItemSize;
+};
+
+}
+
+#endif // NODEVIEWCHILDITEM_H
diff --git a/gegl-qt/internal/nodeviewimplementation.cpp b/gegl-qt/internal/nodeviewimplementation.cpp
index c87dfda..881d24c 100644
--- a/gegl-qt/internal/nodeviewimplementation.cpp
+++ b/gegl-qt/internal/nodeviewimplementation.cpp
@@ -42,16 +42,15 @@ namespace {
     }
 
     /* TODO: handle the clipping caused by the viewport size */
-    QRectF viewAreaFromModelArea(const QRectF & modelArea, NodeViewOptions *viewOptions)
+    QRectF viewAreaFromModelArea(const QRectF & modelArea, QTransform transform)
     {
-        QTransform transform = viewOptions->transformation();
         return transform.mapRect(modelArea);
     }
 
-    QRectF modelAreaFromViewArea(const QRectF & viewArea, NodeViewOptions *viewOptions)
+    QRectF modelAreaFromViewArea(const QRectF & viewArea, QTransform transform)
     {
-        Q_ASSERT(viewOptions->transformation().isInvertible());
-        QTransform transform = viewOptions->transformation().inverted();
+        Q_ASSERT(transform.isInvertible());
+        transform = transform.inverted();
         return transform.mapRect(viewArea);
     }
 }
@@ -84,13 +83,14 @@ computed_event(GeglNode *node, GeglRectangle *rect, NodeViewImplementation *impl
 * - emitting 'invalidated' on the input node, observing that the 'computed' signal is emitted correctly
 * - emitting 'computed' on the input node, observing that the 'viewAreaChanged' signal is emitted correctly
 */
-NodeViewImplementation::NodeViewImplementation(QObject *parent)
+NodeViewImplementation::NodeViewImplementation(DrawTransform drawTransform, QObject *parent)
     : QObject(parent)
     , mInputNode(0)
     , processor(0)
     , timer(new QTimer())
     , mOptions(0)
     , mViewportSize(-1.0, -1.0)
+    , mDrawTransform(drawTransform)
 {
     setOptions(0); // default
 
@@ -106,6 +106,18 @@ NodeViewImplementation::~NodeViewImplementation()
     delete mOptions;
 }
 
+QTransform
+NodeViewImplementation::drawTransformation()
+{
+    return mDrawTransform == DrawTransformInternal ? options()->transformation() : QTransform();
+}
+
+float
+NodeViewImplementation::drawScale()
+{
+    return mDrawTransform == DrawTransformInternal ? options()->scale() : 1.0;
+}
+
 void
 NodeViewImplementation::setInputNode(GeglNode *node)
 {
@@ -274,7 +286,7 @@ NodeViewImplementation::nodeComputed(GeglRectangle *rect)
 
     QRect modelRect;
     qrect_set_from_gegl_rectangle(modelRect, rect);
-    QRectF viewArea = viewAreaFromModelArea(QRectF(modelRect), options());
+    QRectF viewArea = viewAreaFromModelArea(QRectF(modelRect), drawTransformation());
     Q_EMIT viewAreaChanged(viewArea);
 }
 
@@ -292,8 +304,8 @@ NodeViewImplementation::paint(QPainter *painter, const QRectF & viewRect)
         return;
     }
 
-    QRect modelRect = modelAreaFromViewArea(viewRect, options()).toRect();
-    gegl_rectangle_set_from_qrect(&roi, modelRect);
+    QRectF modelRect = modelAreaFromViewArea(viewRect, drawTransformation());
+    gegl_rectangle_set_from_qrect(&roi, modelRect.toRect());
 
     if (!inputNode() || roi.width <= 0 || roi.height <= 0) {
         return;
@@ -308,7 +320,7 @@ NodeViewImplementation::paint(QPainter *painter, const QRectF & viewRect)
     QImage image(buffer, roi.width, roi.height, roi.width*4,
                  QImage::QImage::Format_ARGB32_Premultiplied);
 
-    painter->scale(options()->scale(), options()->scale());
+    painter->scale(drawScale(), drawScale());
     painter->drawImage(QPointF(), image);
 
     g_free(buffer);
diff --git a/gegl-qt/internal/nodeviewimplementation.h b/gegl-qt/internal/nodeviewimplementation.h
index 3698246..12bbc0f 100644
--- a/gegl-qt/internal/nodeviewimplementation.h
+++ b/gegl-qt/internal/nodeviewimplementation.h
@@ -29,8 +29,15 @@ namespace GeglQt {
 class NodeViewImplementation : public QObject
 {
     Q_OBJECT
+
+public:
+    enum DrawTransform {
+        DrawTransformInternal,
+        DrawTransformExternal
+    };
+
 public:
-    explicit NodeViewImplementation(QObject *parent = 0);
+    explicit NodeViewImplementation(DrawTransform drawTransform = DrawTransformInternal, QObject *parent = 0);
     ~NodeViewImplementation();
 
     void setInputNode(GeglNode *node);
@@ -59,6 +66,8 @@ private Q_SLOTS:
 
 private:
     void modelAreaChanged();
+    QTransform drawTransformation();
+    float drawScale();
 
 private:
     GeglNode *mInputNode; // The node the widget displays.
@@ -66,6 +75,7 @@ private:
     QTimer *timer; // Used to defer operations to the mainloop.
     GeglQt::NodeViewOptions *mOptions;
     QSizeF mViewportSize;
+    DrawTransform mDrawTransform;
 };
 
 }
diff --git a/gegl-qt/nodeviewdeclarativeitem.cpp b/gegl-qt/nodeviewdeclarativeitem.cpp
index 9ab6d4d..d8f12e7 100644
--- a/gegl-qt/nodeviewdeclarativeitem.cpp
+++ b/gegl-qt/nodeviewdeclarativeitem.cpp
@@ -18,23 +18,34 @@
 
 #include "nodeviewdeclarativeitem.h"
 #include "internal/nodeviewimplementation.h"
+#include "internal/nodeviewchilditem.h"
 
 using namespace GeglQt;
 
 NodeViewDeclarativeItem::NodeViewDeclarativeItem(QDeclarativeItem *parent)
     : QDeclarativeItem(parent)
-    , priv(new NodeViewImplementation())
+    , priv(new NodeViewImplementation(NodeViewImplementation::DrawTransformExternal))
+    , childItem(new NodeViewChildItem(priv, 0))
 {
     setFlag(QGraphicsItem::ItemHasNoContents, false);
 
+    childItem->setParentItem(static_cast<QGraphicsItem *>(this));
+
     connect(priv, SIGNAL(viewAreaChanged(QRectF)),
             this, SLOT(invalidate(QRectF)));
     connect(priv, SIGNAL(viewportSizeRequest(QSizeF)),
             this, SLOT(viewportSizeChangeRequested(QSizeF)));
+
+    connect(this, SIGNAL(optionsChanged()),
+            this, SLOT(handleOptionsChanged()));
+
+    // Initial signal is emitted before the connection, call handler manually
+    handleOptionsChanged();
 }
 
 NodeViewDeclarativeItem::~NodeViewDeclarativeItem()
 {
+    delete childItem;
     delete priv;
 }
 
@@ -87,9 +98,9 @@ void
 NodeViewDeclarativeItem::invalidate(QRectF rect)
 {
     if (rect.isValid()) {
-        update(rect);
+        childItem->update(rect);
     } else {
-        update(boundingRect());
+        childItem->update(childItem->boundingRect());
     }
 }
 
@@ -106,8 +117,10 @@ NodeViewDeclarativeItem::paint(QPainter *painter,
                              const QStyleOptionGraphicsItem *option,
                              QWidget *widget)
 {
+    // Handled by child item
+    Q_UNUSED(widget);
+    Q_UNUSED(option);
     Q_UNUSED(widget);
-    priv->paint(painter, option->exposedRect);
 }
 
 void
@@ -115,5 +128,41 @@ NodeViewDeclarativeItem::geometryChanged(const QRectF & newGeometry,
                                        const QRectF & oldGeometry)
 {
     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
+
+    childItem->updateSize(newGeometry.size());
     priv->viewportSizeChanged(newGeometry.size());
 }
+
+void
+NodeViewDeclarativeItem::handleScaleChanged()
+{
+    float newScale = options()->scale();
+
+    if (childItem->scale() == newScale) {
+        return;
+    }
+
+    childItem->setScale(newScale);
+}
+
+void
+NodeViewDeclarativeItem::handleTranslationChanged()
+{
+    float newX = options()->translationX();
+    float newY = options()->translationY();
+
+    if (childItem->x() == newX || childItem->y() == newY) {
+        return;
+    }
+
+    childItem->setPos(newX, newY);
+}
+
+void
+NodeViewDeclarativeItem::handleOptionsChanged()
+{
+    connect(options(), SIGNAL(scaleChanged()),
+            this, SLOT(handleScaleChanged()));
+    connect(options(), SIGNAL(translationChanged()),
+            this, SLOT(handleTranslationChanged()));
+}
diff --git a/gegl-qt/nodeviewdeclarativeitem.h b/gegl-qt/nodeviewdeclarativeitem.h
index a844643..58a3fc4 100644
--- a/gegl-qt/nodeviewdeclarativeitem.h
+++ b/gegl-qt/nodeviewdeclarativeitem.h
@@ -30,6 +30,7 @@ typedef GeglNode * GeglNodePtr;
 namespace GeglQt {
 
 class NodeViewImplementation;
+class NodeViewChildItem; // FIXME: should be handled internally
 
 class NodeViewDeclarativeItem : public QDeclarativeItem
 {
@@ -64,10 +65,14 @@ Q_SIGNALS:
 private Q_SLOTS:
     void invalidate(QRectF rect);
     void viewportSizeChangeRequested(QSizeF);
+    void handleScaleChanged();
+    void handleTranslationChanged();
+    void handleOptionsChanged();
 
 private:
     Q_DISABLE_COPY(NodeViewDeclarativeItem)
     NodeViewImplementation *priv;
+    NodeViewChildItem *childItem; //FIXME: need to go into priv
 };
 
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]