diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
commit | 2366667fc97eb6a56203b2dd7dac776ff4164abd (patch) | |
tree | b2acb6cc6bfe475d7e619e4788973b61fff775e0 /src/declarative/canvas | |
parent | 2c762f3b8b284a7c6dc0c499b7052013bad5b707 (diff) | |
download | Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.zip Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.gz Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.bz2 |
Initial import of kinetic-dui branch from the old kinetic
Diffstat (limited to 'src/declarative/canvas')
-rw-r--r-- | src/declarative/canvas/canvas.pri | 19 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvas.cpp | 981 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvas.h | 187 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvas_graphicsview.cpp | 180 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvas_opengl.cpp | 456 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvas_opengl1.cpp | 401 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvas_p.h | 196 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvas_software.cpp | 190 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvasfilter.cpp | 323 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvasfilter.h | 113 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvasfilter_p.h | 70 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvasitem.cpp | 1841 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvasitem.h | 300 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvasitem_p.h | 242 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvasserver.cpp | 107 | ||||
-rw-r--r-- | src/declarative/canvas/qsimplecanvasserver_p.h | 71 |
16 files changed, 5677 insertions, 0 deletions
diff --git a/src/declarative/canvas/canvas.pri b/src/declarative/canvas/canvas.pri new file mode 100644 index 0000000..8abfd99 --- /dev/null +++ b/src/declarative/canvas/canvas.pri @@ -0,0 +1,19 @@ +SOURCES += \ + canvas/qsimplecanvas.cpp \ + canvas/qsimplecanvasitem.cpp \ + canvas/qsimplecanvasfilter.cpp \ + canvas/qsimplecanvasserver.cpp + +HEADERS += \ + canvas/qsimplecanvas.h \ + canvas/qsimplecanvasitem.h \ + canvas/qsimplecanvasfilter.h \ + canvas/qsimplecanvas_p.h \ + canvas/qsimplecanvasitem_p.h \ + canvas/qsimplecanvasfilter_p.h \ + canvas/qsimplecanvasserver_p.h + +contains(QT_CONFIG, opengles2): SOURCES += canvas/qsimplecanvas_opengl.cpp +else:contains(QT_CONFIG, opengles1): SOURCES += canvas/qsimplecanvas_opengl1.cpp +else:SOURCES += canvas/qsimplecanvas_software.cpp +SOURCES += canvas/qsimplecanvas_graphicsview.cpp diff --git a/src/declarative/canvas/qsimplecanvas.cpp b/src/declarative/canvas/qsimplecanvas.cpp new file mode 100644 index 0000000..5eb6c60 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvas.cpp @@ -0,0 +1,981 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwidget.h" +#include "qmutex.h" +#include "qdebug.h" +#include "qcoreapplication.h" +#include "qsimplecanvasitem.h" +#include "qsimplecanvasitem_p.h" +#include "qsimplecanvas_p.h" +#include "qtimer.h" +#include "qdatetime.h" +#include "qgraphicssceneevent.h" +#if defined(QFX_RENDER_OPENGL) +#include <glheaders.h> +#endif +#include "qboxlayout.h" +#include "qsimplecanvasserver_p.h" +#include "qsimplecanvas.h" + + +QT_BEGIN_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(fullUpdate, GFX_CANVAS_FULL_UPDATE); +DEFINE_BOOL_CONFIG_OPTION(continuousUpdate, GFX_CANVAS_CONTINUOUS_UPDATE); +DEFINE_BOOL_CONFIG_OPTION(useGraphicsView, QFX_USE_GRAPHICSVIEW); + +template<class T, int s = 60> +class CircularList +{ +public: + CircularList() + : _first(0), _size(0) {} + + void append(const T &t) + { + int entry = (_first + _size) % s; + _array[entry] = t; + if(_size == s) + _first = (_first + 1) % s; + else + _size++; + } + + int size() const + { + return _size; + } + + T &operator[](int idx) + { + Q_ASSERT(idx < _size); + int entry = (_first + idx) % s; + return _array[entry]; + } + + void clear() + { + _first = 0; + _size = 0; + } +private: + int _first; + int _size; + T _array[s]; +}; + + +class QSimpleCanvasRootLayer : public QSimpleCanvasLayer +{ +public: + QSimpleCanvasRootLayer(QSimpleCanvas *); + virtual void addDirty(QSimpleCanvasItem *); + virtual void remDirty(QSimpleCanvasItem *); + +private: + friend class QSimpleCanvasItem; + QSimpleCanvas *_canvas; +}; + +void QSimpleCanvasRootLayer::addDirty(QSimpleCanvasItem *i) +{ + _canvas->addDirty(i); +} + +void QSimpleCanvasRootLayer::remDirty(QSimpleCanvasItem *i) +{ + _canvas->remDirty(i); +} + +void QSimpleCanvasPrivate::clearFocusPanel(QSimpleCanvasItem *panel) +{ + if(q->activeFocusPanel() == panel) { + focusPanels.pop(); + + switchToFocusPanel(q->activeFocusPanel(), panel, Qt::OtherFocusReason); + panel->activePanelOutEvent(); + } else { + for(int ii = 0; ii < focusPanels.count(); ++ii) + if(focusPanels.at(ii) == panel) { + focusPanels.remove(ii); + break; + } + } +} + +void QSimpleCanvasPrivate::switchToFocusPanel(QSimpleCanvasItem *panel, QSimpleCanvasItem *wasPanel, Qt::FocusReason focusReason) +{ + if(panel) + panel->activePanelInEvent(); + + QSimpleCanvasItem *wasFocusRoot = focusPanelData.value(wasPanel); + if(wasFocusRoot) + clearActiveFocusItem(wasFocusRoot, focusReason); + + QSimpleCanvasItem *newFocusRoot = focusPanelData.value(panel); + if(newFocusRoot) + setFocusItem(newFocusRoot, focusReason); +} + +void QSimpleCanvasPrivate::setActiveFocusPanel(QSimpleCanvasItem *panel, Qt::FocusReason focusReason) +{ + if(q->activeFocusPanel() == panel) + return; + + if(panel) { + for(int ii = 0; ii < focusPanels.count(); ++ii) + if(focusPanels.at(ii) == panel) { + focusPanels.remove(ii); + break; + } + } + QSimpleCanvasItem *old = q->activeFocusPanel(); + if(panel) + focusPanels << panel; + switchToFocusPanel(panel, old, focusReason); + if(old) + old->activePanelOutEvent(); +} + +void QSimpleCanvasPrivate::clearActiveFocusItem(QSimpleCanvasItem *item, + Qt::FocusReason focusReason) +{ + if (!item || !item->d_func()) + return; + + if(!item->d_func()->hasActiveFocus) + return; + + item->d_func()->hasActiveFocus = false; + if(item->options() & QSimpleCanvasItem::IsFocusRealm) { + QSimpleCanvasItem *newItem = focusPanelData.value(item); + if(newItem) { + clearActiveFocusItem(newItem, focusReason); + } else { + focusItem = 0; + QFocusEvent event(QEvent::FocusOut, focusReason); + item->focusOutEvent(&event); + } + } else { + focusItem = 0; + QFocusEvent event(QEvent::FocusOut, focusReason); + item->focusOutEvent(&event); + } + + if(item->options() & QSimpleCanvasItem::AcceptsInputMethods){ + if(q->testAttribute(Qt::WA_InputMethodEnabled)) + q->setAttribute(Qt::WA_InputMethodEnabled,false); + } + item->activeFocusChanged(true); +} + +void QSimpleCanvasPrivate::setActiveFocusItem(QSimpleCanvasItem *item, + Qt::FocusReason focusReason) +{ + while(true) { + item->d_func()->setActiveFocus(true); + item->activeFocusChanged(true); + if(item->options() & QSimpleCanvasItem::IsFocusRealm) { + QSimpleCanvasItem *newItem = focusPanelData.value(item); + if(newItem) + item = newItem; + else + break; + } else { + break; + } + } + + if(item->options() & QSimpleCanvasItem::AcceptsInputMethods){ + if(!q->testAttribute(Qt::WA_InputMethodEnabled)) + q->setAttribute(Qt::WA_InputMethodEnabled,true); + } + focusItem = item; + QFocusEvent event(QEvent::FocusIn, focusReason); + focusItem->focusInEvent(&event); +} + +void QSimpleCanvasPrivate::clearFocusItem(QSimpleCanvasItem *item) +{ + // XXX +#if 0 + while(item->focusProxy()) + item = item->focusProxy(); +#endif + + QSimpleCanvasItem *scope = 0; + QSimpleCanvasItem *citem = item; + while(citem && !scope) { + if(citem->options() & QSimpleCanvasItem::IsFocusPanel) + scope = citem; + else if(citem != item && citem->options() & QSimpleCanvasItem::IsFocusRealm) + scope = citem; + citem = citem->parent(); + } + Q_ASSERT(scope); // At the very least we'll find the canvas root + + bool isActive = false; + + if(scope->options() & QSimpleCanvasItem::IsFocusPanel) + isActive = (scope == q->activeFocusPanel()); + else if(scope->options() & QSimpleCanvasItem::IsFocusRealm) + isActive = scope->hasActiveFocus(); + + if(isActive) clearActiveFocusItem(item, Qt::OtherFocusReason); + item->d_func()->setFocus(false); + item->focusChanged(false); + + focusPanelData.insert(scope, 0); + + if(lastFocusItem == item) + lastFocusItem = 0; + if(focusItem == item) + focusItem = 0; + + if(scope->options() & QSimpleCanvasItem::IsFocusRealm && scope->hasActiveFocus()) { + setActiveFocusItem(scope, Qt::OtherFocusReason); + } else { + QSimpleCanvasItem *item = QSimpleCanvasItem::findNextFocus(scope); + if (item) + item->setFocus(true); + } +} + +void QSimpleCanvasPrivate::setFocusItem(QSimpleCanvasItem *item, + Qt::FocusReason focusReason, + bool overwrite) +{ + Q_ASSERT(item); + + // XXX +#if 0 + while(item->focusProxy()) + item = item->focusProxy(); +#endif + + if(item == focusItem) + return; + + QSimpleCanvasItem *scope = 0; + QSimpleCanvasItem *citem = item; + while(citem && !scope) { + if(citem->options() & QSimpleCanvasItem::IsFocusPanel) + scope = citem; + else if(citem != item && citem->options() & QSimpleCanvasItem::IsFocusRealm) + scope = citem; + citem = citem->parent(); + } + Q_ASSERT(scope); // At the very least we'll find the canvas root + + if(!overwrite && focusPanelData.contains(scope)) { + item->d_func()->setFocus(false); + item->focusChanged(false); + return; + } + + QSimpleCanvasItem *oldFocus = focusPanelData.value(scope); + bool isActive = false; + + if(scope->options() & QSimpleCanvasItem::IsFocusPanel) + isActive = (scope == q->activeFocusPanel()); + else if(scope->options() & QSimpleCanvasItem::IsFocusRealm) + isActive = scope->hasActiveFocus(); + + if(oldFocus) { + if(isActive) clearActiveFocusItem(oldFocus, focusReason); + oldFocus->d_func()->setFocus(false); + oldFocus->focusChanged(false); + } + + focusPanelData.insert(scope, item); + + if(isActive) + lastFocusItem = item; + + if (item) { + item->d_func()->setFocus(true); + item->focusChanged(true); + if(isActive) + setActiveFocusItem(item, focusReason); + } +} + + +bool QSimpleCanvas::eventFilter(QObject *obj, QEvent *event) +{ + Q_UNUSED(obj); + switch (event->type()) { + case QEvent::GraphicsSceneMouseMove: { + QGraphicsSceneMouseEvent *me = (QGraphicsSceneMouseEvent*)event; + if (!me->buttons()) + break; + } + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseRelease: { + //same logic as filter() function + for(int ii = 0; ii < d->mouseFilters.count(); ++ii) { + if(d->mouseFilters.at(ii)->mouseFilter((QGraphicsSceneMouseEvent*)event)) + return true; + } + break; + } + default: + break; + } + return false; +} + +void QSimpleCanvasPrivate::installMouseFilter(QSimpleCanvasItem *item) +{ + mouseFilters << item; +} + +void QSimpleCanvasPrivate::removeMouseFilter(QSimpleCanvasItem *item) +{ + mouseFilters.removeAll(item); +} + +bool QSimpleCanvasPrivate::filter(QMouseEvent *e) +{ + if(mouseFilters.isEmpty()) + return false; + + QGraphicsSceneMouseEvent *me = mouseEventToSceneMouseEvent(e, e->pos()); + for(int ii = 0; ii < mouseFilters.count(); ++ii) { + if(mouseFilters.at(ii)->mouseFilter(me)) { + delete me; + return true; + } + } + delete me; + return false; +} + +QGraphicsSceneMouseEvent *QSimpleCanvasPrivate::mouseEventToSceneMouseEvent(QMouseEvent *e, const QPoint &item) +{ + QEvent::Type t; + switch(e->type()) { + default: + case QEvent::MouseButtonPress: + t = QEvent::GraphicsSceneMousePress; + break; + case QEvent::MouseButtonRelease: + t = QEvent::GraphicsSceneMouseRelease; + break; + case QEvent::MouseMove: + t = QEvent::GraphicsSceneMouseMove; + break; + case QEvent::MouseButtonDblClick: + t = QGraphicsSceneEvent::GraphicsSceneMouseDoubleClick; + break; + } + + QGraphicsSceneMouseEvent *me = new QGraphicsSceneMouseEvent(t); + me->setButton(e->button()); + me->setButtons(e->buttons()); + me->setPos(item); + me->setScreenPos(e->pos()); + me->setScenePos(e->pos()); + return me; +} + +bool QSimpleCanvasPrivate::deliverMousePress(QSimpleCanvasItem *base, QMouseEvent *e) +{ + if(base->clipType()) { + QRectF br = base->boundingRect(); + QPointF pos = base->mapFromScene(e->pos()); + if(!br.contains(pos.toPoint())) + return false; + } + + const QList<QSimpleCanvasItem *> &children = base->d_func()->children; + for(int ii = children.count() - 1; ii >= 0; --ii) { + if(children.at(ii)->visible() != 0.) + if(deliverMousePress(children.at(ii), e)) + return true; + } + + if(base->acceptedMouseButtons() & e->button()) { + QRectF br = base->boundingRect(); + QPoint pos = base->mapFromScene(e->pos()).toPoint(); + + if(br.contains(pos)) { + QGraphicsSceneMouseEvent *me = mouseEventToSceneMouseEvent(e, pos); + if (me->type() == QEvent::GraphicsSceneMousePress) + base->mousePressEvent(me); + else + base->mouseDoubleClickEvent(me); + bool isAccepted = me->isAccepted(); + delete me; + if(isAccepted) { + lastMouseItem = base; + return true; + } + } + } + return false; +} + +QSimpleCanvasRootLayer::QSimpleCanvasRootLayer(QSimpleCanvas *c) +: _canvas(c) +{ + QSimpleCanvasItem::d_func()->canvas = c; + setOptions(IsFocusPanel); + update(); +} + + +struct QSimpleCanvasTiming +{ + QSimpleCanvasTiming() + : time(-1), paintTime(-1), timeBetweenFrames(-1) {} + QSimpleCanvasTiming(const QRegion &_r, int _time, int _paintTime, + int _timeBetweenFrames) + : region(_r), time(_time), paintTime(_paintTime), + timeBetweenFrames(_timeBetweenFrames) {} + QSimpleCanvasTiming(const QSimpleCanvasTiming &other) + : region(other.region), time(other.time), paintTime(other.paintTime), + timeBetweenFrames(other.timeBetweenFrames) {} + QSimpleCanvasTiming &operator=(const QSimpleCanvasTiming &other) { + region = other.region; time = other.time; paintTime = other.paintTime; + timeBetweenFrames = other.timeBetweenFrames; return *this; + } + QRegion region; + int time; + int paintTime; + int timeBetweenFrames; +}; + +// XXX +static CircularList<QSimpleCanvasTiming> gfxCanvasTiming; + +void QSimpleCanvasGraphicsView::paintEvent(QPaintEvent *pe) +{ + QRegion r = pe->region(); + int tbf = canvas->frameTimer.restart(); + + canvas->lrpTimer.start(); + QGraphicsView::paintEvent(pe); + canvas->lrpTime = canvas->lrpTimer.elapsed(); + + int frametimer = canvas->frameTimer.elapsed(); + gfxCanvasTiming.append(QSimpleCanvasTiming(r, frametimer, canvas->lrpTime, tbf)); + canvas->lrpTime = 0; + if(canvas->canvasServer) + canvas->canvasServer->addTiming(canvas->lrpTime, frametimer, tbf); +} + +void QSimpleCanvasGraphicsView::focusInEvent(QFocusEvent *) +{ +} + +/*! + \class QSimpleCanvas + \brief The QSimpleCanvas class implements the canvas used by Qt Declarative + */ + +QSimpleCanvas::QSimpleCanvas(CanvasMode mode, QWidget *parent) +: QWidget(parent), d(new QSimpleCanvasPrivate(this)) +{ + d->init(mode); +} + +QSimpleCanvas::QSimpleCanvas(QWidget *parent) +: QWidget(parent), d(new QSimpleCanvasPrivate(this)) +{ + d->init(useGraphicsView()?GraphicsView:SimpleCanvas); +} + +void QSimpleCanvasPrivate::init(QSimpleCanvas::CanvasMode mode) +{ + this->mode = mode; + + if(mode == QSimpleCanvas::SimpleCanvas) + qWarning("QSimpleCanvas: Using simple canvas"); + else + qWarning("QSimpleCanvas: Using GraphicsView canvas"); + + if(fullUpdate()) + qWarning("QSimpleCanvas: Full update enabled"); + if(continuousUpdate()) + qWarning("QSimpleCanvas: Continuous update enabled"); + + QByteArray env = qgetenv("GFX_CANVAS_SERVER_PORT"); + if(!env.isEmpty()){ + int port = env.toInt(); + if(port >= 1024) + canvasServer = new QSimpleCanvasServer(port, q); + } + + root = new QSimpleCanvasRootLayer(q); + root->setActiveFocusPanel(true); + q->setFocusPolicy(Qt::StrongFocus); + + if(mode == QSimpleCanvas::GraphicsView) { + view = new QSimpleCanvasGraphicsView(this); + QHBoxLayout *layout = new QHBoxLayout(q); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + q->setLayout(layout); + layout->addWidget(view); + view->setOptimizationFlags(QGraphicsView::DontSavePainterState); + view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + view->setFrameStyle(0); + static_cast<QSimpleCanvasItemPrivate*>(root->d_ptr)->convertToGraphicsItem(); + view->scene()->addItem(static_cast<QSimpleCanvasItemPrivate*>(root->d_ptr)->graphicsItem); + + // These seem to give the best performance + view->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + view->scene()->setItemIndexMethod(QGraphicsScene::NoIndex); + view->viewport()->setFocusPolicy(Qt::NoFocus); + } + +#if defined(QFX_RENDER_OPENGL) && defined(Q_WS_X11) + QTimer *t = new QTimer(q); + t->setInterval(200); + QObject::connect(t, SIGNAL(timeout()), &egl, SLOT(updateGL())); + t->start(); +#endif +} + +QSimpleCanvas::~QSimpleCanvas() +{ + delete d->root; + delete d; +} + +void QSimpleCanvasPrivate::paint(QPainter &p) +{ +#if defined(QFX_RENDER_QPAINTER) + if(!isSetup) + root->d_func()->setupPainting(0, q->rect()); + + lrpTimer.start(); + + root->d_func()->paint(p); + + lrpTime = lrpTimer.elapsed(); +#else + Q_UNUSED(p); +#endif +} + +QSimpleCanvas::CanvasMode QSimpleCanvas::canvasMode() const +{ + return d->mode; +} + +QSimpleCanvasItem *QSimpleCanvas::root() +{ + return d->root; +} + +void QSimpleCanvas::keyPressEvent(QKeyEvent *event) +{ + if (d->focusItem) + d->focusItem->keyPressEvent(event); + QWidget::keyPressEvent(event); +} + +void QSimpleCanvas::keyReleaseEvent(QKeyEvent *event) +{ + if (d->focusItem) + d->focusItem->keyReleaseEvent(event); + QWidget::keyReleaseEvent(event); +} + +void QSimpleCanvas::inputMethodEvent(QInputMethodEvent *event) +{ + if(d->focusItem) + d->focusItem->inputMethodEvent(event); + else + QWidget::inputMethodEvent(event); +} + +QVariant QSimpleCanvas::inputMethodQuery(Qt::InputMethodQuery query) const +{ + if(d->focusItem) + return d->focusItem->inputMethodQuery(query); + return QWidget::inputMethodQuery(query); +} + +void QSimpleCanvas::mousePressEvent(QMouseEvent *e) +{ + if(d->isSimpleCanvas() && + (d->filter(e) || d->deliverMousePress(d->root, e))) { + e->accept(); + } else { + QWidget::mousePressEvent(e); + } +} + +void QSimpleCanvas::mouseDoubleClickEvent(QMouseEvent *e) +{ + if(d->isSimpleCanvas() && + (d->filter(e) || d->deliverMousePress(d->root, e))) { + e->accept(); + } else { + QWidget::mouseDoubleClickEvent(e); + } +} + +void QSimpleCanvas::mouseMoveEvent(QMouseEvent *e) +{ + if(d->isSimpleCanvas() && d->filter(e)) { + e->accept(); + } else if(d->isSimpleCanvas() && d->lastMouseItem) { + QPoint p = d->lastMouseItem->mapFromScene(e->pos()).toPoint(); + QGraphicsSceneMouseEvent *me = d->mouseEventToSceneMouseEvent(e, p); + d->lastMouseItem->mouseMoveEvent(me); + e->setAccepted(me->isAccepted()); + delete me; + } else { + QWidget::mouseMoveEvent(e); + } +} + +void QSimpleCanvas::mouseReleaseEvent(QMouseEvent *e) +{ + if(d->isSimpleCanvas() && d->filter(e)) { + e->accept(); + } else if(d->isSimpleCanvas() && d->lastMouseItem) { + QPoint p = d->lastMouseItem->mapFromScene(e->pos()).toPoint(); + QGraphicsSceneMouseEvent *me = d->mouseEventToSceneMouseEvent(e, p); + d->lastMouseItem->mouseReleaseEvent(me); + d->lastMouseItem->mouseUngrabEvent(); + e->setAccepted(me->isAccepted()); + delete me; + d->lastMouseItem = 0; + } else { + QWidget::mouseReleaseEvent(e); + } +} + +void QSimpleCanvas::focusInEvent(QFocusEvent *event) +{ + // XXX +#if 0 + if (d->lastFocusItem && event->reason() == Qt::ActiveWindowFocusReason) { + d->setFocusItem(d->lastFocusItem, event->reason()); + } else { + QSimpleCanvasItem *panel = activeFocusPanel(); + QSimpleCanvasItem *focusItem = 0; + if(panel->isFocusable()) + focusItem = panel; + else + focusItem = QSimpleCanvasItem::findNextFocus(panel); + + if (focusItem) + d->setFocusItem(focusItem, event->reason()); + else + QWidget::focusNextPrevChild(true); + } +#endif + QWidget::focusInEvent(event); +} + +void QSimpleCanvas::focusOutEvent(QFocusEvent *event) +{ + // XXX +#if 0 + if (event->reason() == Qt::ActiveWindowFocusReason) { + d->lastFocusItem = activeFocusPanel(); + d->setActiveFocusPanel(0, Qt::ActiveWindowFocusReason); + } +#endif + QWidget::focusOutEvent(event); +} + +bool QSimpleCanvas::focusNextPrevChild(bool) +{ + // XXX +#if 0 + if (d->focusItem) { + QSimpleCanvasItem *item = next ? QSimpleCanvasItem::findNextFocus(d->focusItem) : QSimpleCanvasItem::findPrevFocus(d->focusItem); + if (item) { + d->setFocusItem(item, + next ? Qt::TabFocusReason : Qt::BacktabFocusReason); + return true; + } + } + + QSimpleCanvasItem *panel = activeFocusPanel(); + QSimpleCanvasItem *item = 0; + if(panel->isFocusable()) + item = panel; + else + item = next ? QSimpleCanvasItem::findNextFocus(panel) : QSimpleCanvasItem::findPrevFocus(panel); + if (item && item != d->focusItem) { + d->setFocusItem(item, + next ? Qt::TabFocusReason : Qt::BacktabFocusReason); + return true; + } + + if (d->focusItem) + d->setActiveFocusPanel(0, next ? Qt::TabFocusReason : Qt::BacktabFocusReason); + +#endif + return false; +} + + +void QSimpleCanvas::showEvent(QShowEvent *e) +{ +#if defined(QFX_RENDER_OPENGL) + d->egl.resize(width(), height()); +#endif + if(d->isGraphicsView()) + d->view->setSceneRect(rect()); + + QWidget::showEvent(e); +} + +void QSimpleCanvas::resizeEvent(QResizeEvent *e) +{ +#if defined(QFX_RENDER_OPENGL) + d->egl.resize(width(), height()); +#endif + if(d->isGraphicsView()) + d->view->setSceneRect(rect()); + QWidget::resizeEvent(e); +} + + +void QSimpleCanvas::remDirty(QSimpleCanvasItem *c) +{ + d->dirtyItems.removeAll(c); +} + +void QSimpleCanvas::queueUpdate() +{ + if(!d->timer) { + QCoreApplication::postEvent(this, new QEvent(QEvent::User)); + d->timer = 1; + } +} + +void QSimpleCanvas::addDirty(QSimpleCanvasItem *c) +{ + queueUpdate(); + if(d->isSimpleCanvas()) { + d->oldDirty |= c->d_func()->data()->lastPaintRect; +#if defined(QFX_RENDER_OPENGL) + // Check for filters + QSimpleCanvasItem *fi = c->parent(); + while(fi) { + if(fi->d_func()->data()->dirty) { + break; + } else if(fi->filter()) { + fi->update(); + break; + } + fi = fi->parent(); + } +#endif + d->dirtyItems.append(c); + } +} + +QRect QSimpleCanvasPrivate::dirtyItemClip() const +{ + QRect rv; + if(isSimpleCanvas()) { +#if defined(QFX_RENDER_OPENGL) + QRectF r; + for(int ii = 0; ii < dirtyItems.count(); ++ii) + r |= dirtyItems.at(ii)->d_func()->data()->lastPaintRect; + rv = egl.map(r); +#else + for(int ii = 0; ii < dirtyItems.count(); ++ii) + rv |= dirtyItems.at(ii)->d_func()->data()->lastPaintRect; +#endif + } + return rv; +} + +QRegion QSimpleCanvasPrivate::resetDirty() +{ + if(isSimpleCanvas()) { +#if defined(QFX_RENDER_OPENGL) + QRect r = egl.map(oldDirty) | dirtyItemClip(); +#else + QRect r = oldDirty | dirtyItemClip(); +#endif + if (!r.isEmpty()) + r.adjust(-1,-1,2,2); //make sure we get everything (since we rounded from floats to ints) + for(int ii = 0; ii < dirtyItems.count(); ++ii) + static_cast<QSimpleCanvasItemPrivate*>(dirtyItems.at(ii)->d_ptr)->data()->dirty = false; + dirtyItems.clear(); + oldDirty = QRect(); + + if(fullUpdate()) + return QRegion(); + else + return QRegion(r); + } else { + return QRegion(); + } +} + +QSimpleCanvasItem *QSimpleCanvas::focusItem() const +{ + return d->focusItem; +} + +QSimpleCanvasItem *QSimpleCanvas::activeFocusPanel() const +{ + if(d->focusPanels.isEmpty()) + return 0; + else + return d->focusPanels.top(); +} + +bool QSimpleCanvas::event(QEvent *e) +{ + if(e->type() == QEvent::User && d->isSimpleCanvas()) { + d->timer = 0; + d->isSetup = true; +#if defined(QFX_RENDER_OPENGL1) + unsigned int zero = 0; + d->root->d_func()->setupPainting(0, rect(), &zero); +#else + d->root->d_func()->setupPainting(0, rect()); +#endif + + QRegion r = d->resetDirty(); + + int tbf = d->frameTimer.restart(); + +#if defined(QFX_RENDER_QPAINTER) + if(r.isEmpty() || fullUpdate()) + repaint(); + else + repaint(r); + emit framePainted(); +#else + QRect br = r.boundingRect(); + QRect nr(br.x(), height() - br.y() - br.height(), br.width(), br.height()); + + if(r.isEmpty() || fullUpdate()) + d->egl.updateGL(); + else + d->egl.updateGL(nr); + emit framePainted(); +#endif + d->isSetup = false; + + int frametimer = d->frameTimer.elapsed(); + gfxCanvasTiming.append(QSimpleCanvasTiming(r, frametimer, d->lrpTime, tbf)); + if(d->canvasServer) + d->canvasServer->addTiming(d->lrpTime, frametimer, tbf); + d->lrpTime = 0; + if(continuousUpdate()) + queueUpdate(); + + return true; + } else { + return QWidget::event(e); + } +} + +void QSimpleCanvas::paintEvent(QPaintEvent *) +{ +#if defined(QFX_RENDER_QPAINTER) + if(d->mode == SimpleCanvas) { + QPainter p(this); + d->paint(p); + } +#endif +} + +void QSimpleCanvas::dumpTiming() +{ + for(int ii = 0; ii < gfxCanvasTiming.size(); ++ii) { + const QSimpleCanvasTiming &t = gfxCanvasTiming[ii]; + + qreal repaintFps = 1000. / qreal(t.time); + qreal paintFps = 1000. / qreal(t.paintTime); + qreal tbfFps = 1000. / qreal(t.timeBetweenFrames); + + qWarning() << "repaint():" << t.time << "ms," << repaintFps << "fps. paint():" << t.paintTime << "ms," << paintFps << "fps. timeSinceLastFrame:" << t.timeBetweenFrames << "ms," << tbfFps << "fps."; + qWarning() << t.region; + } + gfxCanvasTiming.clear(); +} + +void QSimpleCanvas::dumpItems() +{ + int items = d->root->d_func()->dump(0); + qWarning() << "Total:" << items; +} + +void QSimpleCanvas::checkState() +{ + if(d->isSimpleCanvas()) { + QSimpleCanvasItemPrivate::FocusStateCheckRDatas r; + if(d->root->d_func()->checkFocusState(0, &r)) + qWarning() << "State OK"; + } +} + +/*! + Returns canvas as an image. Not a fast operation. +*/ +QImage QSimpleCanvas::asImage() const +{ + if(d->isSimpleCanvas()) { +#if defined(QFX_RENDER_QPAINTER) + QImage img(width(),height(),QImage::Format_RGB32); + QPainter p(&img); + const_cast<QSimpleCanvas*>(this)->d->paint(p); + return img; +#elif defined(QFX_RENDER_OPENGL) + return d->egl.grabFrameBuffer(); +#endif + } else { + QImage img(width(),height(),QImage::Format_RGB32); + QPainter p(&img); + d->view->render(&p); + return img; + } +} +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvas.h b/src/declarative/canvas/qsimplecanvas.h new file mode 100644 index 0000000..3da7251 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvas.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLECANVAS_H +#define QSIMPLECANVAS_H + +#include <qfxglobal.h> + +#ifdef QFX_RENDER_OPENGL +#include <QtGui/qmatrix4x4.h> +#endif + +#include <QTransform> +#include <QPainter> +#include <QDebug> +#include <QWidget> +#include <QImage> +#include <QKeyEvent> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +namespace QSimpleCanvasConfig +{ + enum ImageType { Opaque, Translucent }; + +#ifdef QFX_RENDER_OPENGL + typedef QMatrix4x4 Matrix; + typedef QImage Image; + + inline Matrix transformToMatrix(const QTransform &) + { + return Matrix(); // XXX + } + inline QTransform matrixToTransform(const Matrix &) + { + return QTransform(); // XXX + } + inline bool needConvert(ImageType, const Image &) + { return false; } + inline Image convert(ImageType, const Image &i) + { return i; } + inline Image create(const QSize &s) + { return QImage(s, QImage::Format_ARGB32); } + inline const Image &toImage(const QImage &i) + { return i; } + +#elif defined(QFX_RENDER_QPAINTER) + typedef QTransform Matrix; + typedef QImage Image; + + inline Matrix transformToMatrix(const QTransform &t) + { return t; } + inline QTransform matrixToTransform(const Matrix &t) + { return t; } + inline bool needConvert(ImageType type, const Image &img) { + QImage::Format f = img.format(); + return !((type == Opaque && f == QImage::Format_RGB16) || + (type == Translucent && f == QImage::Format_ARGB32_Premultiplied)); + } + inline Image convert(ImageType type, const Image &img) { + if(type == Opaque) + return img.convertToFormat(QImage::Format_RGB16); + else + return img.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } + inline Image create(const QSize &s) + { return QImage(s, QImage::Format_ARGB32_Premultiplied); } + inline const Image &toImage(const QImage &i) + { return i; } +#endif +} + +class QSimpleCanvas; +class QSimpleCanvasLayer; + +class QGraphicsSceneMouseEvent; +class GLBasicShaders; +class QSimpleCanvasItem; +class QSimpleCanvasPrivate; +class Q_DECLARATIVE_EXPORT QSimpleCanvas : public QWidget +{ +Q_OBJECT +public: + typedef QSimpleCanvasConfig::Matrix Matrix; + + enum CanvasMode { GraphicsView, SimpleCanvas }; + + QSimpleCanvas(QWidget *parent = 0); + QSimpleCanvas(CanvasMode, QWidget *parent = 0); + virtual ~QSimpleCanvas(); + + CanvasMode canvasMode() const; + + QSimpleCanvasItem *root(); + + // Debugging + void dumpTiming(); + void dumpItems(); + void checkState(); + + QSimpleCanvasItem *focusItem() const; + QSimpleCanvasItem *activeFocusPanel() const; + QImage asImage() const; + +Q_SIGNALS: + void framePainted(); + +protected: + virtual bool event(QEvent *); + virtual void paintEvent(QPaintEvent *); + virtual void keyPressEvent(QKeyEvent *); + virtual void keyReleaseEvent(QKeyEvent *); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseDoubleClickEvent(QMouseEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void focusInEvent(QFocusEvent *event); + virtual void focusOutEvent(QFocusEvent *event); + virtual bool focusNextPrevChild(bool next); + virtual bool eventFilter(QObject *obj, QEvent *event); + virtual void inputMethodEvent(QInputMethodEvent *event); + virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; + + virtual void showEvent(QShowEvent *); + virtual void resizeEvent(QResizeEvent *); +private: + + friend class QSimpleCanvasRootLayer; + friend class QSimpleCanvasPrivate; + friend class QSimpleCanvasItem; + friend class QSimpleCanvasItemPrivate; + friend class QSimpleCanvasFilter; + friend class QSimpleGraphicsItem; + + void queueUpdate(); + QSimpleCanvasPrivate *d; + void addDirty(QSimpleCanvasItem *); + void remDirty(QSimpleCanvasItem *); +}; + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/canvas/qsimplecanvas_graphicsview.cpp b/src/declarative/canvas/qsimplecanvas_graphicsview.cpp new file mode 100644 index 0000000..0f80128 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvas_graphicsview.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimplecanvas.h" +#include "qsimplecanvas_p.h" +#include "qsimplecanvasitem.h" +#include "qsimplecanvasitem_p.h" +#include <QGraphicsItem> +#include <QGraphicsSceneMouseEvent> + + +QT_BEGIN_NAMESPACE +static QHash<QGraphicsScene*,QSimpleCanvas*> sceneMap; + +QSimpleCanvasGraphicsView::QSimpleCanvasGraphicsView(QSimpleCanvasPrivate *parent) +: QGraphicsView(parent->q), canvas(parent) +{ + setScene(&_scene); + sceneMap[&_scene] = parent->q; + setFrameShape(QFrame::NoFrame); + viewport()->setAttribute(Qt::WA_OpaquePaintEvent); +} + +QSimpleCanvasGraphicsView::~QSimpleCanvasGraphicsView() +{ + sceneMap.remove(&_scene); +} + +QSimpleGraphicsItem::QSimpleGraphicsItem(QSimpleCanvasItem *canvasItem) +: /*scene(0),*/ owner(canvasItem) +{ + setAcceptedMouseButtons(Qt::NoButton); +} + +QSimpleGraphicsItem::~QSimpleGraphicsItem() +{ + owner->d_func()->graphicsItem = 0; +} + +void QSimpleGraphicsItem::paint(QPainter *painter, + const QStyleOptionGraphicsItem *, QWidget *) +{ + owner->paintContents(*painter); +} + +QRectF QSimpleGraphicsItem::boundingRect() const +{ + return owner->boundingRect(); +} + +void QSimpleGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + owner->mousePressEvent(event); +} + +void QSimpleGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + owner->mouseReleaseEvent(event); +} + +void QSimpleGraphicsItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) +{ + owner->mouseDoubleClickEvent(event); +} + +void QSimpleGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + owner->mouseMoveEvent(event); +} + +bool QSimpleGraphicsItem::sceneEvent(QEvent *event) +{ + bool rv = QGraphicsItem::sceneEvent(event); + if(event->type() == QEvent::UngrabMouse) + owner->mouseUngrabEvent(); + return rv; +} + +QVariant QSimpleGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if(change == ItemSceneHasChanged) { + QSimpleCanvasItemPrivate *owner_d = static_cast<QSimpleCanvasItemPrivate*>(owner->d_ptr); + QSimpleCanvas *oldCanvas = owner_d->canvas; + owner_d->canvas = sceneMap[scene()]; + if (owner_d->canvas){ + if (owner->hasFocus()) + owner->canvas()->d->setFocusItem(owner, Qt::OtherFocusReason); + if (owner->options() & QSimpleCanvasItem::IsFocusPanel) { + if (owner_d->wantsActiveFocusPanelPendingCanvas) { + owner_d->hasBeenActiveFocusPanel = true; + owner->canvas()->d->setActiveFocusPanel(owner); + owner_d->wantsActiveFocusPanelPendingCanvas = false; + } + } + } + if(owner->options() & QSimpleCanvasItem::MouseFilter) + owner_d->gvRemoveMouseFilter(); + + if (oldCanvas != owner_d->canvas) + owner->canvasChanged(); + + if(owner->options() & QSimpleCanvasItem::MouseFilter) + owner_d->gvAddMouseFilter(); + } + + return QGraphicsItem::itemChange(change, value); +} + +void QSimpleGraphicsItem::keyPressEvent(QKeyEvent *event) +{ + owner->keyPressEvent(event); + QGraphicsItem::keyPressEvent(event); +} + +void QSimpleGraphicsItem::keyReleaseEvent(QKeyEvent *event) +{ + owner->keyReleaseEvent(event); + QGraphicsItem::keyReleaseEvent(event); +} + +void QSimpleGraphicsItem::focusInEvent(QFocusEvent *) +{ + if (!owner->hasFocus()) + owner->setFocus(true); +} + +void QSimpleCanvasItemPrivate::gvRemoveMouseFilter() +{ + QGraphicsScene *scene = graphicsItem->scene(); + if(!scene) return; + + scene->removeEventFilter(q_ptr); +} + +void QSimpleCanvasItemPrivate::gvAddMouseFilter() +{ + QGraphicsScene *scene = graphicsItem->scene(); + if(!scene) return; + + scene->installEventFilter(q_ptr); +} +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvas_opengl.cpp b/src/declarative/canvas/qsimplecanvas_opengl.cpp new file mode 100644 index 0000000..f508aea --- /dev/null +++ b/src/declarative/canvas/qsimplecanvas_opengl.cpp @@ -0,0 +1,456 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimplecanvas.h" +#include "qsimplecanvas_p.h" +#include "qsimplecanvasitem_p.h" +#include "qsimplecanvasfilter_p.h" +#include <glsave.h> +#include <QtOpenGL/qglframebufferobject.h> +#include <gltexture.h> +#include <math.h> + + +QT_BEGIN_NAMESPACE +void CanvasEGLWidget::paintGL() +{ + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + _canvas->paintGL(); +} + +void CanvasEGLWidget::updateGL() +{ + _clip = QRect(); + QGLWidget::updateGL(); +} + +void CanvasEGLWidget::updateGL(const QRect &r) +{ + if(r.isEmpty()) + return; + + _clip = r; + QGLWidget::updateGL(); +} + +void CanvasEGLWidget::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); +} + +QRect CanvasEGLWidget::map(const QRectF &f) const +{ + return invDefaultTransform.mapRect(f).toAlignedRect(); +} + +void CanvasEGLWidget::resizeEvent(QResizeEvent *e) +{ + defaultTransform.setIdentity(); + defaultTransform.flipCoordinates(); + defaultTransform.translate(-1, -1, 0); + defaultTransform.scale(2. / width(), 2. / height(), 1. / (1024. * 1024.)); + invDefaultTransform = defaultTransform.inverted(); + _canvas->root->d_func()->data()->transformActive = defaultTransform; + _canvas->root->d_func()->data()->transformValid = true; + + QGLWidget::resizeEvent(e); +} + +void CanvasEGLWidget::initializeGL() +{ + glEnable(GL_BLEND); + glEnable(GL_STENCIL_TEST); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glStencilFunc(GL_EQUAL, 0, 0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); +} + +void QSimpleCanvasPrivate::paintGL() +{ + lrpTimer.start(); + + QSimpleCanvasItemPrivate::GLPaintParameters p; + p.sceneRect = QRect(0, 0, q->width(), q->height()); + p.clipRect = p.sceneRect; + p.stencilValue = 0; + p.opacity = 1; + p.forceParamRefresh = false; + if(!isSetup) + root->d_func()->setupPainting(0, QRect()); + root->d_func()->paint(p); + + lrpTime = lrpTimer.elapsed(); +} + +QGLFramebufferObject *QSimpleCanvasPrivate::acquire(int w, int h) +{ + if(w <= 0 || h <= 0) + return 0; + + int size = qMax(w, h); + for(int ii = 0; ii < frameBuffers.count(); ++ii) { + if(frameBuffers.at(ii)->width() >= size) { + QGLFramebufferObject *rv = frameBuffers.at(ii); + frameBuffers.removeAt(ii); + return rv; + } + } + + // Find power of two + size--; + size |= size >> 1; + size |= size >> 2; + size |= size >> 4; + size |= size >> 8; + size |= size >> 16; + size++; + + QGLFramebufferObject *fbo = new QGLFramebufferObject(size, size); + return fbo; +} + +void QSimpleCanvasPrivate::release(QGLFramebufferObject *buf) +{ + int size = qMax(buf->width(), buf->height()); + for(int ii = 0; ii < frameBuffers.count(); ++ii) { + if(frameBuffers.at(ii)->width() >= size) { + frameBuffers.insert(ii, buf); + return; + } + } + frameBuffers.append(buf); +} + +GLBasicShaders *QSimpleCanvasItemPrivate::basicShaders() const +{ + return canvas->d->basicShaders(); +} + +QSimpleCanvas::Matrix QSimpleCanvasItemPrivate::localTransform() const +{ + Q_Q(const QSimpleCanvasItem); + + QSimpleCanvas::Matrix trans; + trans.translate(q->x(), q->y()); + QPointF to = transformOrigin(); + trans.translate(to.x(), to.y()); + trans.scale(q->scale(), q->scale()); + trans.translate(-to.x(), -to.y()); + if(data()->transformUser) + trans *= *data()->transformUser; + return trans; +} + +void QSimpleCanvasItemPrivate::simplePaintChild(const GLPaintParameters ¶ms, QSimpleCanvasItem *child) +{ + Q_Q(QSimpleCanvasItem); + + GLPaintParameters childParams = params; + if(clip) + ++childParams.stencilValue; + + if(child->d_func()->data()->activeOpacity != 0) { + childParams.boundingRect = child->boundingRect(); + + if(child->filter() && child->filter()->enabled()) { + QSimpleCanvasItem::GLPainter painter(q); + painter.activeTransform = child->d_func()->data()->transformActive; + painter.activeOpacity = child->d_func()->data()->activeOpacity; + painter.sceneClipRect = params.clipRect; + child->filter()->d->doFilterGL(painter, childParams); + } else { + child->d_func()->paint(childParams); + } + } +} + +void QSimpleCanvasItemPrivate::paintChild(const GLPaintParameters ¶ms, + QSimpleCanvasItem *child) +{ + if(params.forceParamRefresh) { + QSimpleCanvas::Matrix t = child->d_func()->data()->transformActive; + qreal o = child->d_func()->data()->activeOpacity; + setupChildState(child); + simplePaintChild(params, child); + child->d_func()->data()->transformActive = t; + child->d_func()->data()->transformValid = true; + child->d_func()->data()->activeOpacity = o; + } else { + simplePaintChild(params, child); + } +} + +void QSimpleCanvasItemPrivate::setupChildState(QSimpleCanvasItem *child) +{ + qreal visible = child->visible(); + child->d_func()->data()->activeOpacity = data()->activeOpacity; + if(visible != 1) + child->d_func()->data()->activeOpacity *= visible; + + if(child->d_func()->data()->activeOpacity != 0) { + // Calculate child's transform + qreal x = child->x(); + qreal y = child->y(); + qreal scale = child->scale(); + QSimpleCanvasItem::Flip flip = child->flip(); + + QSimpleCanvas::Matrix &am = child->d_func()->data()->transformActive; + am = data()->transformActive; + if(x != 0 || y != 0) + am.translate(x, y); + if(scale != 1) { + QPointF to = child->d_func()->transformOrigin(); + if(to.x() != 0. || to.y() != 0.) + am.translate(to.x(), to.y()); + am.scale(scale, scale); + if(to.x() != 0. || to.y() != 0.) + am.translate(-to.x(), -to.y()); + } + if(child->d_func()->data()->transformUser) + am *= *child->d_func()->data()->transformUser; + if(flip) { + QRectF br = child->boundingRect(); + am.translate(br.width() / 2., br.height() / 2); + am.rotate(180, (flip & QSimpleCanvasItem::VerticalFlip)?1:0, (flip & QSimpleCanvasItem::HorizontalFlip)?1:0, 0); + am.translate(-br.width() / 2., -br.height() / 2); + } + child->d_func()->data()->transformValid = true; + } +} + +QRectF QSimpleCanvasItemPrivate::setupPainting(int version, const QRect &bounding) +{ + Q_Q(QSimpleCanvasItem); + + QRectF filteredBoundRect = q->boundingRect(); + if(filter) + filteredBoundRect = filter->itemBoundingRect(filteredBoundRect); + QRectF rv = data()->transformActive.mapRect(filteredBoundRect); + + for(int ii = 0; ii < children.count(); ++ii) { + QSimpleCanvasItem *child = children.at(ii); + setupChildState(child); + + if(child->d_func()->data()->activeOpacity != 0) + rv |= child->d_func()->setupPainting(version, bounding); + } + + data()->lastPaintRect = rv; + return rv; +} + +void QSimpleCanvasItemPrivate::paint(GLPaintParameters &oldParams, QSimpleCanvasFilter::Layer layer) +{ + if(!layer) + return; + + Q_Q(QSimpleCanvasItem); + + GLPaintParameters params = oldParams; + + qreal width = params.boundingRect.width(); + qreal height = params.boundingRect.height(); + + GLfloat vertices[] = { 0, height, + width, height, + 0, 0, + width, 0 }; + + // XXX Handle separate cliping modes + if(clip) { + if(params.stencilValue == 255) + qWarning() + << "OpenGL: Clip recursion greater than 255 not permitted."; + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + glStencilFunc(GL_EQUAL, params.stencilValue, 0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + + ConstantColorShader *shader = basicShaders()->constantColor(); + shader->enable(); + shader->setTransform(data()->transformActive); + + shader->setAttributeArray(ConstantColorShader::Vertices, vertices, 2); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + shader->disableAttributeArray(ConstantColorShader::Vertices); + + glStencilFunc(GL_EQUAL, params.stencilValue + 1, 0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + // XXX Copied from qsimplecanvas_opengl1 scissor based clipping + QRectF r = data()->transformActive.mapRect(params.boundingRect); + r.translate(1, 1); + float xscale = 0.5 * float(params.sceneRect.width()); + float yscale = 0.5 * float(params.sceneRect.height()); + r.moveTo(r.x() * xscale, r.y() * yscale); + r.setSize(QSizeF(r.width() * xscale, r.height() * yscale)); + int sr_x = int(::floorf(r.x())); + int sr_y = int(::floorf(r.y())); + int sr_width = int(::ceilf(r.right())) - sr_x; + int sr_height = int(::ceilf(r.bottom())) - sr_y; + QRect sr(sr_x, sr_y, sr_width, sr_height); + sr.moveTo(sr.x(), params.sceneRect.height() - sr.y() - sr.height()); + sr &= params.clipRect; + params.clipRect = sr; + } + + zOrderChildren(); + + int upto = 0; + for(upto = 0; upto < children.count(); ++upto) { + QSimpleCanvasItem *c = children.at(upto); + if(c->z() < 0) { + if(layer & QSimpleCanvasFilter::ChildrenUnderItem) + paintChild(params, c); + } else { + break; + } + } + + if(layer & QSimpleCanvasFilter::Item && + q->options() & QSimpleCanvasItem::HasContents) { + QSimpleCanvasItem::GLPainter painter(q); + painter.activeTransform = data()->transformActive; + painter.activeOpacity = data()->activeOpacity; + painter.sceneClipRect = params.clipRect; + + q->paintGLContents(painter); + } + + if(layer & QSimpleCanvasFilter::ChildrenAboveItem) { + for(; upto < children.count(); ++upto) { + QSimpleCanvasItem *c = children.at(upto); + paintChild(params, c); + } + } + + if(clip) { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glStencilFunc(GL_EQUAL, params.stencilValue + 1, 0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); + + ConstantColorShader *shader = basicShaders()->constantColor(); + shader->enable(); + shader->setTransform(data()->transformActive); + + shader->setAttributeArray(ConstantColorShader::Vertices, vertices, 2); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + shader->disableAttributeArray(ConstantColorShader::Vertices); + + glStencilFunc(GL_EQUAL, params.stencilValue, 0xFFFFFFFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } +} + +QGLShaderProgram *QSimpleCanvasItem::GLPainter::useTextureShader() +{ + if(activeOpacity == 1.) { + item->basicShaders()->singleTexture()->enable(); + item->basicShaders()->singleTexture()->setTransform(activeTransform); + return item->basicShaders()->singleTexture(); + } else { + item->basicShaders()->singleTextureOpacity()->enable(); + item->basicShaders()->singleTextureOpacity()->setTransform(activeTransform); + item->basicShaders()->singleTextureOpacity()->setOpacity(activeOpacity); + return item->basicShaders()->singleTextureOpacity(); + } + +} + +QGLShaderProgram *QSimpleCanvasItem::GLPainter::useColorShader(const QColor &color) +{ + QColor c = color; + item->basicShaders()->constantColor()->enable(); + if(activeOpacity != 1.) { + c.setAlpha(int(c.alpha() * activeOpacity)); + } + + item->basicShaders()->constantColor()->setColor(c); + item->basicShaders()->constantColor()->setTransform(activeTransform); + + return item->basicShaders()->constantColor(); +} + +void QSimpleCanvasItem::GLPainter::drawImage(const QPointF &point, + const GLTexture &texture) +{ + drawImage(QRectF(point, QSizeF(texture.width(), texture.height())), texture); +} + +void QSimpleCanvasItem::GLPainter::drawImage(const QRectF &rect, + const GLTexture &img) +{ + QGLShaderProgram *shader = useTextureShader(); + + GLfloat vertices[8]; + GLfloat texVertices[8]; + + float widthV = img.width(); + float heightV = img.height(); + + vertices[0] = rect.x(); vertices[1] = rect.y()+heightV; + vertices[2] = rect.x()+widthV; vertices[3] = rect.y()+heightV; + vertices[4] = rect.x(); vertices[5] = rect.y(); + vertices[6] = rect.x()+widthV; vertices[7] = rect.y(); + + texVertices[0] = 0; texVertices[1] = 0; + texVertices[2] = 1; texVertices[3] = 0; + texVertices[4] = 0; texVertices[5] = 1; + texVertices[6] = 1; texVertices[7] = 1; + + shader->setAttributeArray(SingleTextureShader::Vertices, vertices, 2); + shader->setAttributeArray(SingleTextureShader::TextureCoords, texVertices, 2); + + glBindTexture(GL_TEXTURE_2D, img.texture()); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + shader->disableAttributeArray(SingleTextureShader::Vertices); + shader->disableAttributeArray(SingleTextureShader::TextureCoords); +} + +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvas_opengl1.cpp b/src/declarative/canvas/qsimplecanvas_opengl1.cpp new file mode 100644 index 0000000..ad21c77 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvas_opengl1.cpp @@ -0,0 +1,401 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimplecanvas.h" +#include "qsimplecanvas_p.h" +#include "qsimplecanvasitem_p.h" +#include "qsimplecanvasfilter_p.h" +#include <gltexture.h> +#include <glsave.h> +#include <math.h> + + +QT_BEGIN_NAMESPACE +void CanvasEGLWidget::updateGL() +{ + _clip = QRect(); + QGLWidget::updateGL(); +} + +void CanvasEGLWidget::updateGL(const QRect &r) +{ + if(r.isEmpty()) + return; + + _clip = r; + QGLWidget::updateGL(); +} + +void CanvasEGLWidget::paintGL() +{ + if(!_clip.isEmpty()) { + glEnable(GL_SCISSOR_TEST); + glScissor(_clip.x(), _clip.y(), _clip.width(), _clip.height()); + } else { + glDisable(GL_SCISSOR_TEST); + } + + glDepthMask(GL_TRUE); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDepthMask(GL_FALSE); + + _canvas->paintGL(); +} + +QRect CanvasEGLWidget::map(const QRectF &f) +{ + return invDefaultTransform.mapRect(f).toAlignedRect(); +} + +void CanvasEGLWidget::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); +} + +void CanvasEGLWidget::resizeEvent(QResizeEvent *e) +{ + defaultTransform.identity(); + defaultTransform.flipCoordinates(); + defaultTransform.translate(-1, -1, 0); + defaultTransform.scale(2. / width(), 2. / height(), -2. / 65536.); + invDefaultTransform = defaultTransform.inverted(); + _canvas->root->d_func()->transformActive = defaultTransform; + QGLWidget::resizeEvent(e); +} + +void CanvasEGLWidget::initializeGL() +{ + glEnable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthFunc(GL_GREATER); +#ifdef QT_OPENGL_ES + glClearDepthf(0); +#else + glClearDepth(0); +#endif +} + +void QSimpleCanvasPrivate::paintGL() +{ + lrpTimer.start(); + + QSimpleCanvasItemPrivate::GLPaintParameters p; + p.sceneRect = QRect(0, 0, q->width(), q->height()); + p.clipRect = p.sceneRect; + p.opacity = 1; + p.forceParamRefresh = false; + if(!isSetup) { + unsigned int zero = 0; + root->d_func()->setupPainting(0, QRect(), &zero); + } + root->d_func()->paint(p); + + lrpTime = lrpTimer.elapsed(); +} + +QSimpleCanvas::Matrix QSimpleCanvasItemPrivate::localTransform() const +{ + Q_Q(const QSimpleCanvasItem); + + QSimpleCanvas::Matrix trans; + trans.translate(q->x(), q->y()); + QPointF to = transformOrigin(); + trans.translate(to.x(), to.y()); + trans.scale(q->scale().value(), q->scale().value()); + trans.translate(-to.x(), -to.y()); + trans *= transformUser; + return trans; +} + +void QSimpleCanvasItemPrivate::simplePaintChild(const GLPaintParameters ¶ms, QSimpleCanvasItem *child) +{ + GLPaintParameters childParams = params; + + if(child->d_func()->activeOpacity != 0) { + childParams.boundingRect = child->boundingRect(); + child->d_func()->paint(childParams); + } +} + +void QSimpleCanvasItemPrivate::paintChild(const GLPaintParameters ¶ms, + QSimpleCanvasItem *child) +{ + if(params.forceParamRefresh) { + QSimpleCanvas::Matrix t = child->d_func()->transformActive; + qreal o = child->d_func()->activeOpacity; + setupChildState(child); + simplePaintChild(params, child); + child->d_func()->transformActive = t; + child->d_func()->activeOpacity = o; + } else { + simplePaintChild(params, child); + } +} + + +void QSimpleCanvasItemPrivate::setupChildState(QSimpleCanvasItem *child) +{ + qreal visible = child->visible().value(); + child->d_func()->activeOpacity = activeOpacity; + if(visible != 1) + child->d_func()->activeOpacity *= visible; + + if(child->d_func()->activeOpacity != 0) { + // Calculate child's transform + qreal x = child->x(); + qreal y = child->y(); + qreal scale = child->scale().value(); + QSimpleCanvasItem::Flip flip = child->flip(); + + QSimpleCanvas::Matrix &am = child->d_func()->transformActive; + am = transformActive; + if(x != 0 || y != 0) + am.translate(x, y); + if(scale != 1) { + QPointF to = child->d_func()->transformOrigin(); + if(to.x() != 0. || to.y() != 0.) + am.translate(to.x(), to.y()); + am.scale(scale, scale); + if(to.x() != 0. || to.y() != 0.) + am.translate(-to.x(), -to.y()); + } + if(child->d_func()->transformUserSet) + am *= child->d_func()->transformUser; + if(flip) { + QRectF br = child->boundingRect(); + am.translate(br.width() / 2., br.height() / 2); + am.rotate(180, (flip & QSimpleCanvasItem::VerticalFlip)?1:0, (flip & QSimpleCanvasItem::HorizontalFlip)?1:0, 0); + am.translate(-br.width() / 2., -br.height() / 2); + } + } +} + +QRectF QSimpleCanvasItemPrivate::setupPainting(int version, const QRect &bounding, unsigned int *zero) +{ + Q_Q(QSimpleCanvasItem); + + QRectF rv = transformActive.mapRect(q->boundingRect()); + + unsigned int oldZero = *zero; + + for(int ii = 0; ii < children.count(); ++ii) { + QSimpleCanvasItem *child = children.at(ii); + setupChildState(child); + + if(child->d_func()->activeOpacity != 0) + rv |= child->d_func()->setupPainting(version, bounding, zero); + } + + if(clip || oldZero != *zero) + (*zero)++; + transformActive.translate(0, 0, *zero); + + lastPaintRect = rv; + return rv; +} + +void QSimpleCanvasItemPrivate::paintNoClip(GLPaintParameters ¶ms, QSimpleCanvasFilter::Layer layer) +{ + Q_Q(QSimpleCanvasItem); + + zOrderChildren(); + + int upto = 0; + for(upto = 0; upto < children.count(); ++upto) { + QSimpleCanvasItem *c = children.at(upto); + if(c->zValue().value() < 0) { + if(layer & QSimpleCanvasFilter::ChildrenUnderItem) + paintChild(params, c); + } else { + break; + } + } + + if(layer & QSimpleCanvasFilter::Item && + q->options() & QSimpleCanvasItem::HasContents) { + QSimpleCanvasItem::GLPainter painter(q); + painter.activeTransform = transformActive; + painter.activeOpacity = activeOpacity; + painter.sceneClipRect = params.clipRect; + + q->paintGLContents(painter); + } + + if(layer & QSimpleCanvasFilter::ChildrenAboveItem) { + for(; upto < children.count(); ++upto) { + QSimpleCanvasItem *c = children.at(upto); + paintChild(params, c); + } + } +} + +void QSimpleCanvasItemPrivate::paint(GLPaintParameters ¶ms, QSimpleCanvasFilter::Layer layer) +{ + if(!layer) + return; + + // XXX Handle separate cliping modes + if(clip) { + + GLSaveScissor ss; + qreal width = params.boundingRect.width(); + qreal height = params.boundingRect.height(); + float margin = width + height; + + GLfloat clipvertices[] = + { + -margin, -margin, + margin, -margin, + margin, 0, + + -margin, -margin, + -margin, 0, + margin, 0, + + -margin, 0, + -margin, margin, + 0, 0, + + 0, 0, + 0, margin, + -margin, margin, + + 0, height, + 0, margin, + margin, margin, + + margin, margin, + 0, height, + margin, height, + + width, 0, + margin, 0, + margin, height, + + margin, height, + width, height, + width, 0 + }; + + QRectF r = transformActive.mapRect(params.boundingRect); + r.translate(1, 1); + float xscale = 0.5 * float(params.sceneRect.width()); + float yscale = 0.5 * float(params.sceneRect.height()); + r.moveTo(r.x() * xscale, r.y() * yscale); + r.setSize(QSizeF(r.width() * xscale, r.height() * yscale)); + + glEnable(GL_SCISSOR_TEST); + int sr_x = ::floorf(r.x()); + int sr_y = ::floorf(r.y()); + int sr_width = ::ceilf(r.right()) - sr_x; + int sr_height = ::ceilf(r.bottom()) - sr_y; + + QRect sr(sr_x, sr_y, sr_width, sr_height); + if(ss.wasEnabled()) + sr &= ss.rect(); + + glScissor(sr.x(), sr.y(), sr.width(), sr.height()); + + { + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(transformActive.data()); + glDepthMask(GL_TRUE); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, clipvertices); + glDrawArrays(GL_TRIANGLES, 0, 24); + glDisableClientState(GL_VERTEX_ARRAY); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthMask(GL_FALSE); + } + + GLPaintParameters newParams = params; + newParams.clipRect = sr; + newParams.clipRect.moveTo(sr.x(), params.sceneRect.height() - sr.y() - sr.height()); + paintNoClip(newParams, layer); + } else { + paintNoClip(params, layer); + } +} + +QGLShaderProgram *QSimpleCanvasItem::GLPainter::useTextureShader() +{ + qFatal("Cannot call QSimpleCanvasItem::GLPainter::useTextureShader() when using OpenGL ES 1.1"); + return 0; +} + +QGLShaderProgram *QSimpleCanvasItem::GLPainter::useColorShader(const QColor &color) +{ + Q_UNUSED(color); + qFatal("Cannot call QSimpleCanvasItem::GLPainter::useColorShader() when using OpenGL ES 1.1"); + return 0; +} + +GLBasicShaders *QSimpleCanvasItemPrivate::basicShaders() const +{ + qFatal("Cannot call QSimpleCanvasItem::basicShaders() when using OpenGL ES 1.1"); + return 0; +} + +QGLFramebufferObject *QSimpleCanvasPrivate::acquire(int, int) +{ + return 0; +} + +void QSimpleCanvasPrivate::release(QGLFramebufferObject *) +{ +} + +void QSimpleCanvasItem::GLPainter::drawImage(const QPointF &point, + const GLTexture &texture) +{ + drawImage(QRectF(point, QSizeF(texture.width(), texture.height())), texture); +} + +void QSimpleCanvasItem::GLPainter::drawImage(const QRectF &rect, + const GLTexture &img) +{ + qFatal("Cannot call QSimpleCanvasItem::GLPainter::drawImage() when using OpenGL ES 1.1"); +} + +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvas_p.h b/src/declarative/canvas/qsimplecanvas_p.h new file mode 100644 index 0000000..4c8b41e --- /dev/null +++ b/src/declarative/canvas/qsimplecanvas_p.h @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLECANVAS_P_H +#define QSIMPLECANVAS_P_H + +#include "qsimplecanvas.h" +#include <qstack.h> +#include <qdatetime.h> + +#if defined(QFX_RENDER_OPENGL) + +#if defined(QFX_RENDER_OPENGL2) +#include "glbasicshaders.h" +#endif + +#include <QGLWidget> +QT_BEGIN_NAMESPACE + +class CanvasEGLWidget : public QGLWidget +{ +public: + CanvasEGLWidget(QSimpleCanvas *parent, QSimpleCanvasPrivate *canvas) + : + QGLWidget(parent), + _canvas(canvas) + { + } + + virtual void paintGL(); + virtual void resizeGL(int,int); + virtual void resizeEvent(QResizeEvent *e); + virtual void initializeGL(); + + void updateGL(); + void updateGL(const QRect &); + + QRect map(const QRectF &) const; +private: + QRect _clip; + QSimpleCanvasPrivate *_canvas; + QSimpleCanvas::Matrix defaultTransform; + QSimpleCanvas::Matrix invDefaultTransform; +}; +#endif + +#include <QGraphicsView> +#include <QGraphicsScene> + +struct QSimpleCanvasGraphicsView : public QGraphicsView +{ +public: + QSimpleCanvasGraphicsView(QSimpleCanvasPrivate *parent); + ~QSimpleCanvasGraphicsView(); + +protected: + virtual void paintEvent(QPaintEvent *); + virtual void focusInEvent(QFocusEvent *); + +private: + QSimpleCanvasPrivate *canvas; + QGraphicsScene _scene; +}; + +class QGLFramebufferObject; +class QSimpleCanvasServer; +class QSimpleCanvasPrivate +{ +public: + QSimpleCanvasPrivate(QSimpleCanvas *canvas) + : q(canvas), timer(0), root(0), lrpTime(0), canvasServer(0), focusItem(0), + lastFocusItem(0), lastMouseItem(0), isSetup(false), + view(0) +#if defined(QFX_RENDER_OPENGL) + ,egl(q, this), basicShadersInstance(0) +#endif + { + } + + QSimpleCanvas *q; + QSimpleCanvas::CanvasMode mode; + bool isSimpleCanvas() const { return mode == QSimpleCanvas::SimpleCanvas; } + bool isGraphicsView() const { return mode == QSimpleCanvas::GraphicsView; } + +#if defined(QFX_RENDER_OPENGL) + QRectF oldDirty; +#else + QRect oldDirty; +#endif + QRegion resetDirty(); + void paint(QPainter &p); + + + int timer; + + QSimpleCanvasLayer *root; + QList<QSimpleCanvasItem *> dirtyItems; + int lrpTime; + + QTime frameTimer; + QTime lrpTimer; + + QSimpleCanvasServer *canvasServer; + + QStack<QSimpleCanvasItem *> focusPanels; + QHash<QSimpleCanvasItem *, QSimpleCanvasItem *> focusPanelData; + QSimpleCanvasItem *focusItem; + QSimpleCanvasItem *lastFocusItem; + + QRect dirtyItemClip() const; + void clearFocusPanel(QSimpleCanvasItem *); + void setActiveFocusPanel(QSimpleCanvasItem *, Qt::FocusReason focusReason = Qt::OtherFocusReason); + void switchToFocusPanel(QSimpleCanvasItem *, QSimpleCanvasItem *, Qt::FocusReason focusReason); + + void setFocusItem(QSimpleCanvasItem *item, Qt::FocusReason focusReason, + bool overwrite = true); + void clearFocusItem(QSimpleCanvasItem *item); + + void clearActiveFocusItem(QSimpleCanvasItem *, Qt::FocusReason focusReason); + void setActiveFocusItem(QSimpleCanvasItem *, Qt::FocusReason focusReason); + void installMouseFilter(QSimpleCanvasItem *); + void removeMouseFilter(QSimpleCanvasItem *); + QList<QSimpleCanvasItem *> mouseFilters; + bool filter(QMouseEvent *e); + bool deliverMousePress(QSimpleCanvasItem *, QMouseEvent *); + QGraphicsSceneMouseEvent *mouseEventToSceneMouseEvent(QMouseEvent *, const QPoint &); + QSimpleCanvasItem *lastMouseItem; + + bool isSetup; + + void init(QSimpleCanvas::CanvasMode mode); + + QSimpleCanvasGraphicsView *view; + +#if defined(QFX_RENDER_OPENGL) + CanvasEGLWidget egl; + GLBasicShaders *basicShaders() const + { +#if defined(QFX_RENDER_OPENGL2) + if(!basicShadersInstance) + basicShadersInstance = new GLBasicShaders; + return basicShadersInstance; +#else + return 0; +#endif + } + mutable GLBasicShaders *basicShadersInstance; + + QList<QGLFramebufferObject *> frameBuffers; + QGLFramebufferObject *acquire(int, int); + void release(QGLFramebufferObject *); + void paintGL(); +#endif +}; + +#endif + +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvas_software.cpp b/src/declarative/canvas/qsimplecanvas_software.cpp new file mode 100644 index 0000000..06e221e --- /dev/null +++ b/src/declarative/canvas/qsimplecanvas_software.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimplecanvas.h" +#include "qsimplecanvasitem_p.h" + + +QT_BEGIN_NAMESPACE +QRect QSimpleCanvasItemPrivate::setupPainting(int version, const QRect &bounding) +{ + Q_Q(QSimpleCanvasItem); + + QRectF boundingRectActive = q->boundingRect(); + QRect rv = + data()->transformActive.mapRect(boundingRectActive).toAlignedRect() & bounding; + QRect myBounding = bounding; + if(q->clip()) + myBounding &= rv; + + for(int ii = 0; ii < children.count(); ++ii) { + QSimpleCanvasItem *child = children.at(ii); + + qreal visible = child->visible(); + child->d_func()->data()->activeOpacity = data()->activeOpacity; + if(visible != 1) + child->d_func()->data()->activeOpacity *= visible; + + if(child->d_func()->data()->activeOpacity != 0) { + // Calculate child's transform + qreal x = child->x(); + qreal y = child->y(); + qreal scale = child->scale(); + QSimpleCanvasItem::Flip flip = child->flip(); + + QSimpleCanvas::Matrix &am = child->d_func()->data()->transformActive; + am = data()->transformActive; + if(x != 0 || y != 0) + am.translate(x, y); + if(scale != 1) { + QPointF to = child->d_func()->transformOrigin(); + if(to.x() != 0. || to.y() != 0.) + am.translate(to.x(), to.y()); + am.scale(scale, scale); + if(to.x() != 0. || to.y() != 0.) + am.translate(-to.x(), -to.y()); + } + + if(child->d_func()->data()->transformUser) + am = *child->d_func()->data()->transformUser * am; + + if(flip) { + QRectF br = child->boundingRect(); + am.translate(br.width() / 2., br.height() / 2); + am.scale((flip & QSimpleCanvasItem::HorizontalFlip)?-1:1, + (flip & QSimpleCanvasItem::VerticalFlip)?-1:1); + am.translate(-br.width() / 2., -br.height() / 2); + } + child->d_func()->data()->transformValid = true; + rv |= child->d_func()->setupPainting(version, myBounding); + } + } + + data()->lastPaintRect = rv; + return rv; +} + +void QSimpleCanvasItemPrivate::paint(QPainter &p) +{ + Q_Q(QSimpleCanvasItem); + + QRect oldUcr; + if(clip) { + + p.save(); + QRectF boundingRectActive = q->boundingRect(); + + QRect cr; + switch(clip) { + case QSimpleCanvasItem::ClipToHeight: + { + qWarning("QSimpleCanvasItem: ClipToHeight not implemented"); + QRect r = p.clipRegion().boundingRect(); + cr = QRect(r.x(), 0, r.width(), + boundingRectActive.height()); + } + break; + case QSimpleCanvasItem::ClipToWidth: + { + qWarning("QSimpleCanvasItem: ClipToWidth not implemented"); + QRect r = p.clipRegion().boundingRect(); + cr = QRect(0, r.y(), boundingRectActive.width(), + r.height()); + } + break; + case QSimpleCanvasItem::ClipToRect: + cr = boundingRectActive.toAlignedRect(); + break; + default: + break; + } + + p.setWorldTransform(data()->transformActive); + if(p.clipRegion().isEmpty()) { + p.setClipRect(cr); + } else { + p.setClipRect(cr, Qt::IntersectClip); + } + + if(p.clipRegion().isEmpty()) { + p.restore(); + return; + } + } + + zOrderChildren(); + + int upto = 0; + for(upto = 0; upto < children.count(); ++upto) { + QSimpleCanvasItem *c = children.at(upto); + if(c->z() < 0) { + paintChild(p, c); + } else { + break; + } + } + + p.setWorldTransform(data()->transformActive); + q->paintContents(p); + + for(; upto < children.count(); ++upto) { + QSimpleCanvasItem *c = children.at(upto); + paintChild(p, c); + } + + if(clip) + p.restore(); +} + +void QSimpleCanvasItemPrivate::paintChild(QPainter &p, QSimpleCanvasItem *c) +{ + if(c->d_func()->data()->activeOpacity != 0) { + + qreal op = p.opacity(); + p.setOpacity(c->d_func()->data()->activeOpacity); + + c->d_func()->paint(p); + + p.setOpacity(op); + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvasfilter.cpp b/src/declarative/canvas/qsimplecanvasfilter.cpp new file mode 100644 index 0000000..00c88c5 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvasfilter.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimplecanvasfilter.h" +#include "qsimplecanvasfilter_p.h" +#include "qsimplecanvasitem_p.h" +#include "qsimplecanvas.h" +#include "qsimplecanvas_p.h" + +#if defined(QFX_RENDER_OPENGL2) +#include <glsave.h> +#include <QtOpenGL/qglframebufferobject.h> +#endif + +QT_BEGIN_NAMESPACE + +/*! + \qmlclass Filter + \brief A Filter is a graphical filter that can be applied to items. +*/ + +QSimpleCanvasFilter::QSimpleCanvasFilter(QObject *parent) +: QObject(parent), d(new QSimpleCanvasFilterPrivate(this)) +{ +} + +QSimpleCanvasFilter::~QSimpleCanvasFilter() +{ + if(d->item) d->item->setFilter(0); + delete d; d = 0; +} + +bool QSimpleCanvasFilter::enabled() const +{ + return d->enabled; +} + +/*! + \qmlproperty bool Filter::enabled + \brief Controls whether the filter is applied. +*/ + +void QSimpleCanvasFilter::setEnabled(bool e) +{ + if(e == d->enabled) + return; + d->enabled = e; + emit enabledChanged(); + update(); +} + +QGLFramebufferObject *QSimpleCanvasFilter::renderToFBO(float scale, const QRectF &src, const QPoint &offset, Layer) +{ + // XXX - respect src +#if defined(QFX_RENDER_OPENGL2) + Q_UNUSED(src); + Q_UNUSED(offset); + + QSimpleCanvasItem *item = d->item; + QRect br = item->itemBoundingRect(); + if(br.isEmpty()) + return 0; + QGLFramebufferObject *fbo = + item->canvas()->d->acquire(int(br.width() * scale), int(br.height() * scale)); + + GLSaveViewport sv; GLSaveScissor ss; + qreal oldOpacity = item->d_func()->data()->activeOpacity; + item->d_func()->data()->activeOpacity = 1; + + fbo->bind(); + + glClearColor(0,0,0,0); + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, int(br.width() * scale), int(br.height() * scale)); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, int(br.width() * scale), int(br.height() * scale)); + + QMatrix4x4 mat; + mat.flipCoordinates(); + mat.translate(-1, -1, 0); + mat.scale(2. / (br.width()), 2. / (br.height()), 1. / (1024. * 1024.)); + + renderToScreen(mat); + + fbo->release(); + + item->d_func()->data()->activeOpacity = oldOpacity; + return fbo; +#else + Q_UNUSED(src); + Q_UNUSED(offset); + Q_UNUSED(scale); + return 0; +#endif +} + +QGLFramebufferObject *QSimpleCanvasFilter::renderToFBO(const QRectF &src, const QPoint &offset, Layer) +{ + // XXX - respect src +#if defined(QFX_RENDER_OPENGL2) + Q_UNUSED(src); + Q_UNUSED(offset); + + QSimpleCanvasItem *item = d->item; + QRect br = item->itemBoundingRect(); + if(br.isEmpty()) + return 0; + QGLFramebufferObject *fbo = + item->canvas()->d->acquire(br.width(), br.height()); + + GLSaveViewport sv; GLSaveScissor ss; + qreal oldOpacity = item->d_func()->data()->activeOpacity; + item->d_func()->data()->activeOpacity = 1; + + fbo->bind(); + + glClearColor(0,0,0,0); + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, br.width(), br.height()); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, br.width(), br.height()); + + QMatrix4x4 mat; + mat.flipCoordinates(); + mat.translate(-1, -1, 0); + mat.scale(2. / br.width(), 2. / br.height(), 1. / (1024. * 1024.)); + + renderToScreen(mat); + + fbo->release(); + + item->d_func()->data()->activeOpacity = oldOpacity; + return fbo; +#else + Q_UNUSED(src); + Q_UNUSED(offset); + return 0; +#endif +} + +QGLFramebufferObject *QSimpleCanvasFilter::acquireFBO(const QSize &s) +{ +#if defined(QFX_RENDER_OPENGL2) + QSize size; + QSimpleCanvasItem *item = d->item; + if(size.isNull()) { + QRect br = item->itemBoundingRect(); + size = br.size(); + } else { + size = s; + } + + QGLFramebufferObject *fbo = + item->canvas()->d->acquire(s.width(), s.height()); + + return fbo; +#else + Q_UNUSED(s); + return 0; +#endif +} + +void QSimpleCanvasFilter::releaseFBO(QGLFramebufferObject *fbo) +{ +#if defined(QFX_RENDER_OPENGL2) + d->item->d_func()->canvas->d->release(fbo); +#else + Q_UNUSED(fbo); +#endif +} + +void QSimpleCanvasFilter::renderToScreen(const QRectF &src, Layer layer) +{ + // XXX - respect src +#if defined(QFX_RENDER_OPENGL2) + Q_UNUSED(src); + Q_UNUSED(layer); + d->item->d_func()->paint(d->params, layer); +#else + Q_UNUSED(src); + Q_UNUSED(layer); +#endif +} + +void QSimpleCanvasFilter::renderToScreen(const QSimpleCanvas::Matrix &trans, const QRectF &src, Layer layer) +{ + // XXX - respect src +#if defined(QFX_RENDER_OPENGL2) + Q_UNUSED(src); + QSimpleCanvas::Matrix old = d->item->d_func()->data()->transformActive; + d->item->d_func()->data()->transformActive = trans; + QSimpleCanvasItemPrivate::GLPaintParameters params = d->params; + params.forceParamRefresh = true; + d->item->d_func()->paint(params, layer); + d->item->d_func()->data()->transformActive = old; +#else + Q_UNUSED(trans); + Q_UNUSED(src); + Q_UNUSED(layer); +#endif +} + +QSimpleCanvasItem *QSimpleCanvasFilter::item() const +{ + return d->item; +} + +void QSimpleCanvasFilter::setItem(QSimpleCanvasItem *i) +{ + if(d->item == i) + return; + if(d->item) { + d->item->setFilter(0); + d->item = 0; + } + + if(i->filter() != this) { + i->setFilter(this); + } else { + d->item = i; + } +} + +#if defined(QFX_RENDER_OPENGL2) +void QSimpleCanvasFilterPrivate::doFilterGL(QSimpleCanvasItem::GLPainter &p, const QSimpleCanvasItemPrivate::GLPaintParameters &prms) +{ + params = prms; + q->filterGL(p); +} +#endif + +QRectF QSimpleCanvasFilter::itemBoundingRect(const QRectF &r) const +{ + return r; +} + +void QSimpleCanvasFilter::filterGL(QSimpleCanvasItem::GLPainter &p) +{ + Q_UNUSED(p); +} + +void QSimpleCanvasFilter::filter(QPainter &) +{ +} + +void QSimpleCanvasFilter::update() +{ + if(d->item) + d->item->update(); +} + +#if defined(QFX_RENDER_OPENGL2) +bool QSimpleCanvasFilterPrivate::isSimpleItem(QSimpleCanvasItem *item, QSimpleCanvasItem **out, QSimpleCanvas::Matrix *mout) +{ + if(item->options() & QSimpleCanvasItem::SimpleItem && !item->hasChildren()) { + *out = item; + return true; + } else if(!(item->options() & QSimpleCanvasItem::HasContents) && + item->children().count() == 1) { + QSimpleCanvasItem *child = item->children().first(); + if(child->filter() && child->filter()->enabled()) + return false; + bool rv = isSimpleItem(child, out, mout); + if(rv) + *mout *= child->d_func()->localTransform(); + return rv; + } else { + return false; + } +} +#endif + +bool QSimpleCanvasFilter::isSimpleItem(QSimpleCanvasItem **out, QSimpleCanvas::Matrix *mout) +{ +#if defined(QFX_RENDER_OPENGL2) + return d->isSimpleItem(item(), out, mout); +#else + Q_UNUSED(out); + Q_UNUSED(mout); +#endif + + return false; +} + +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvasfilter.h b/src/declarative/canvas/qsimplecanvasfilter.h new file mode 100644 index 0000000..cb75ddf --- /dev/null +++ b/src/declarative/canvas/qsimplecanvasfilter.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLECANVASFILTER_H +#define QSIMPLECANVASFILTER_H + +#include <QtCore/qobject.h> +#include <qfxglobal.h> +#include <qsimplecanvasitem.h> +#include <qsimplecanvas.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QSimpleCanvasFilterPrivate; +class QRectF; +class QPoint; +class QGLFramebufferObject; +class GLShaderProgram; +class Q_DECLARATIVE_EXPORT QSimpleCanvasFilter : public QObject +{ +Q_OBJECT +public: + QSimpleCanvasFilter(QObject *parent); + virtual ~QSimpleCanvasFilter(); + + enum Layer { ChildrenUnderItem = 0x01, + Item = 0x02, + ChildrenAboveItem = 0x04, + All = 0x07 }; + + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged); + bool enabled() const; + void setEnabled(bool); + + QSimpleCanvasItem *item() const; + void setItem(QSimpleCanvasItem *); +Q_SIGNALS: + void enabledChanged(); + +protected: + + virtual QRectF itemBoundingRect(const QRectF &) const; + virtual void filterGL(QSimpleCanvasItem::GLPainter &p); + virtual void filter(QPainter &p); + + QGLFramebufferObject *renderToFBO(const QRectF &src = QRect(), const QPoint &offset = QPoint(), Layer = All); + QGLFramebufferObject *renderToFBO(float scale, const QRectF &src = QRect(), const QPoint &offset = QPoint(), Layer = All); + QGLFramebufferObject *acquireFBO(const QSize & = QSize()); + void releaseFBO(QGLFramebufferObject *); + + void renderToScreen(const QRectF &src = QRect(), Layer = All); + void renderToScreen(const QSimpleCanvas::Matrix &trans, const QRectF &src = QRect(), Layer = All); + + void update(); + + bool isSimpleItem(QSimpleCanvasItem **, QSimpleCanvas::Matrix *); + +private: + friend class QSimpleCanvasFilterPrivate; + friend class QSimpleCanvasItemPrivate; + friend class QSimpleCanvasItem; + + QSimpleCanvasFilterPrivate *d; +}; + + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/canvas/qsimplecanvasfilter_p.h b/src/declarative/canvas/qsimplecanvasfilter_p.h new file mode 100644 index 0000000..1c72993 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvasfilter_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLECANVASFILTER_P_H +#define QSIMPLECANVASFILTER_P_H + +#include "qsimplecanvasitem.h" +#include "qsimplecanvasitem_p.h" + + +QT_BEGIN_NAMESPACE +class QSimpleCanvasFilterPrivate +{ +public: + QSimpleCanvasFilterPrivate(QSimpleCanvasFilter *_q) + : q(_q), item(0), enabled(true) {} + + QSimpleCanvasFilter *q; + + QSimpleCanvasItem *item; + bool enabled; +#if defined(QFX_RENDER_OPENGL) + QSimpleCanvasItemPrivate::GLPaintParameters params; + + void doFilterGL(QSimpleCanvasItem::GLPainter &, const QSimpleCanvasItemPrivate::GLPaintParameters &); + + bool isSimpleItem(QSimpleCanvasItem *item, QSimpleCanvasItem **out, QSimpleCanvas::Matrix *mout); +#endif +}; + +QT_END_NAMESPACE +#endif diff --git a/src/declarative/canvas/qsimplecanvasitem.cpp b/src/declarative/canvas/qsimplecanvasitem.cpp new file mode 100644 index 0000000..3d3bf84 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvasitem.cpp @@ -0,0 +1,1841 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimplecanvasitem.h" +#include "qsimplecanvas.h" +#include "qsimplecanvasitem_p.h" +#include "qsimplecanvas_p.h" +#include <qfxitem.h> +#include <QGraphicsSceneEvent> + + +QT_BEGIN_NAMESPACE +QSimpleCanvasItemData::QSimpleCanvasItemData() +: buttons(Qt::NoButton), flip(QSimpleCanvasItem::NoFlip), + dirty(false), transformValid(true), x(0), y(0), z(0), visible(1), + transformUser(0), activeOpacity(1) +{ +} + +QSimpleCanvasItemData::~QSimpleCanvasItemData() +{ + if(transformUser) + delete transformUser; +} + +/*! + \class QSimpleCanvasItem + \brief The QSimpleCanvasItem class is the base class of canvas items. + */ +QSimpleCanvasLayer::QSimpleCanvasLayer() +{ +} + +QSimpleCanvasLayer::QSimpleCanvasLayer(QSimpleCanvasItem *parent) +: QSimpleCanvasItem(parent) +{ +} + +void QSimpleCanvasLayer::addChild(QSimpleCanvasItem *c) +{ + QSimpleCanvasItem::addChild(c); +} + +void QSimpleCanvasLayer::addDirty(QSimpleCanvasItem *) +{ +} + +void QSimpleCanvasLayer::remDirty(QSimpleCanvasItem *) +{ +} + +QSimpleCanvasLayer *QSimpleCanvasLayer::layer() +{ + return this; +} + +QSimpleCanvasItem::Options QSimpleCanvasItem::options() const +{ + Q_D(const QSimpleCanvasItem); + return (QSimpleCanvasItem::Options)d->options; +} + +bool QSimpleCanvasItem::mouseFilter(QGraphicsSceneMouseEvent *) +{ + return false; +} + +void QSimpleCanvasItem::mousePressEvent(QGraphicsSceneMouseEvent *) +{ +} + +void QSimpleCanvasItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) +{ +} + +void QSimpleCanvasItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) +{ +} + +void QSimpleCanvasItem::mouseMoveEvent(QGraphicsSceneMouseEvent *) +{ +} + +void QSimpleCanvasItem::hoverEnterEvent(QGraphicsSceneHoverEvent *) +{ +} + +void QSimpleCanvasItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) +{ +} + +void QSimpleCanvasItem::mouseUngrabEvent() +{ +} + +void QSimpleCanvasItem::keyPressEvent(QKeyEvent *) +{ +} + +void QSimpleCanvasItem::keyReleaseEvent(QKeyEvent *) +{ +} + +void QSimpleCanvasItem::focusOutEvent(QFocusEvent *) +{ +} + +void QSimpleCanvasItem::focusInEvent(QFocusEvent *) +{ +} + +void QSimpleCanvasItem::activePanelInEvent() +{ +} + +void QSimpleCanvasItem::activePanelOutEvent() +{ +} + +void QSimpleCanvasItem::inputMethodEvent(QInputMethodEvent *) +{ +} + +QVariant QSimpleCanvasItem::inputMethodQuery(Qt::InputMethodQuery) const +{ + return QVariant(); +} + +void QSimpleCanvasItem::childrenChanged() +{ +} + +QRectF QSimpleCanvasItem::boundingRect() const +{ + Q_D(const QSimpleCanvasItem); + return QRectF(0., 0., d->width, d->height); +} + +void QSimpleCanvasItem::paintContents(QPainter &) +{ +} + +void QSimpleCanvasItem::paintGLContents(GLPainter &) +{ +} + +uint QSimpleCanvasItem::glSimpleItemData(float *vertices, float *texVertices, + GLTexture **texture, uint count) +{ + Q_UNUSED(vertices); + Q_UNUSED(texVertices); + Q_UNUSED(texture); + Q_UNUSED(count); + return 0; +} + +void QSimpleCanvasItem::canvasChanged() +{ +} + +void QSimpleCanvasItem::focusChanged(bool) +{ +} + +void QSimpleCanvasItem::activeFocusChanged(bool) +{ +} + +void QSimpleCanvasItem::parentChanged(QSimpleCanvasItem *, QSimpleCanvasItem *) +{ +} + +GLBasicShaders *QSimpleCanvasItem::basicShaders() const +{ +#if defined(QFX_RENDER_OPENGL2) + return canvas()->d->basicShaders(); +#else + return 0; +#endif +} + +/*! + Returns the item's (0, 0) point relative to its parent. + */ +QPointF QSimpleCanvasItem::pos() const +{ + return QPointF(x(),y()); +} + +/*! + Returns the item's (0, 0) point mapped to scene coordinates. + */ +QPointF QSimpleCanvasItem::scenePos() const +{ + return mapToScene(QPointF(0, 0)); +} + +/*! + \enum QSimpleCanvasItem::TransformOrigin + + Controls the point about which simple transforms like scale apply. + + \o TopLeft The top-left corner of the item. + \o TopCenter The center point of the top of the item. + \o TopRight The top-right corner of the item. + \o MiddleLeft The left most point of the vertical middle. + \o Center The center of the item. + \o MiddleRight The right most point of the vertical middle. + \o BottomLeft The bottom-left corner of the item. + \o BottomCenter The center point of the bottom of the item. + \o BottomRight The bottom-right corner of the item. +*/ + +/*! + Returns the current transform origin. +*/ +QSimpleCanvasItem::TransformOrigin QSimpleCanvasItem::transformOrigin() const +{ + Q_D(const QSimpleCanvasItem); + return d->origin; +} + +/*! + Set the transform \a origin. +*/ +void QSimpleCanvasItem::setTransformOrigin(TransformOrigin origin) +{ + Q_D(QSimpleCanvasItem); + if(origin != d->origin) { + d->origin = origin; + update(); + } +} + +QPointF QSimpleCanvasItem::transformOriginPoint() const +{ + Q_D(const QSimpleCanvasItem); + return d->transformOrigin(); +} + +/*! + Returns the canvas the item is on, or 0 if the item is not on a canvas. + */ +QSimpleCanvas *QSimpleCanvasItem::canvas() const +{ + Q_D(const QSimpleCanvasItem); + return d->canvas; +} + +/*! + Returns the parent if the item, or 0 if the item has no parent. + */ +QSimpleCanvasItem *QSimpleCanvasItem::parent() const +{ + Q_D(const QSimpleCanvasItem); + return d->parent; +} + +void QSimpleCanvasItemPrivate::zOrderChildren() +{ + if(!needsZOrder || children.count() <= 1) + return; + + needsZOrder = false; + // This is a bubble sort for a reason - it is the fastest sort for a mostly + // ordered list. We only expect z ordering to change infrequently. + bool swap = true; + int c = 0; + while(swap) { + ++c; + swap = false; + QSimpleCanvasItem *item = children.first(); + qreal z = item->z(); + for(int ii = 1; ii < children.count(); ++ii) { + QSimpleCanvasItem *i2 = children.at(ii); + qreal z2 = i2->z(); + if(z2 < z) { + swap = true; + children[ii] = item; + children[ii - 1] = i2; + } else { + item = i2; + z = z2; + } + } + } +} + +void QSimpleCanvasItemPrivate::canvasChanged(QSimpleCanvas *newCanvas, QSimpleCanvas *oldCanvas) +{ + Q_Q(QSimpleCanvasItem); + canvas = newCanvas; + if(options & QSimpleCanvasItem::MouseFilter) { + if(oldCanvas) oldCanvas->d->removeMouseFilter(q); + if(newCanvas) newCanvas->d->installMouseFilter(q); + } + if(newCanvas) { + if(!oldCanvas && hasFocus) + newCanvas->d->setFocusItem(q, Qt::OtherFocusReason, false); + if(wantsActiveFocusPanelPendingCanvas) { + hasBeenActiveFocusPanel = true; + newCanvas->d->setActiveFocusPanel(q); + wantsActiveFocusPanelPendingCanvas = false; + } + } + + for(int ii = 0; ii < children.count(); ++ii) + children.at(ii)->d_func()->canvasChanged(newCanvas, oldCanvas); + q->canvasChanged(); +} + +void QSimpleCanvasItem::setFocus(bool focus) +{ + Q_D(QSimpleCanvasItem); + if(d->hasFocus == focus) + return; + QSimpleCanvas *c = canvas(); + + if(c) { + if(focus) + c->d->setFocusItem(this, Qt::OtherFocusReason); + else + c->d->clearFocusItem(this); + } else { + d->setFocus(focus); + focusChanged(d->hasFocus); + } +} + +qreal QSimpleCanvasItem::x() const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) + return d->graphicsItem->x(); + else if(d->data_ptr) + return d->data()->x; + else + return 0; +} + +qreal QSimpleCanvasItem::y() const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) + return d->graphicsItem->y(); + else if(d->data_ptr) + return d->data()->y; + else + return 0; +} + +qreal QSimpleCanvasItem::z() const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) + return d->graphicsItem->zValue(); + else if(d->data_ptr) + return d->data()->z; + else + return 0; +} + +void QSimpleCanvasItem::setX(qreal x) +{ + Q_D(QSimpleCanvasItem); + if(x == this->x()) + return; + + qreal oldX = this->x(); + + if(d->graphicsItem) { + d->graphicsItem->setPos(x, y()); + } else { + d->data()->x = x; + update(); + } + + geometryChanged(QRectF(this->x(), y(), width(), height()), + QRectF(oldX, y(), width(), height())); +} + +void QSimpleCanvasItem::setY(qreal y) +{ + Q_D(QSimpleCanvasItem); + if(y == this->y()) + return; + + qreal oldY = this->y(); + + if(d->graphicsItem) { + d->graphicsItem->setPos(x(), y); + } else { + d->data()->y = y; + update(); + } + + geometryChanged(QRectF(x(), this->y(), width(), height()), + QRectF(x(), oldY, width(), height())); +} + +void QSimpleCanvasItem::setZ(qreal z) +{ + Q_D(QSimpleCanvasItem); + if(z == this->z()) + return; + + if(d->graphicsItem) { + d->graphicsItem->setZValue(z); + } else { + if(d->data()->z == z) + return; + + d->data()->z = z; + if(parent()) + static_cast<QSimpleCanvasItemPrivate*>(parent()->d_ptr)->needsZOrder = true; + update(); + } +} + +qreal QSimpleCanvasItem::width() const +{ + Q_D(const QSimpleCanvasItem); + return d->width; +} + +void QSimpleCanvasItem::setWidth(qreal w) +{ + Q_D(QSimpleCanvasItem); + d->widthValid = true; + if(d->width == w) + return; + + qreal oldWidth = d->width; + + d->width = w; + update(); + + geometryChanged(QRectF(x(), y(), width(), height()), + QRectF(x(), y(), oldWidth, height())); +} + +void QSimpleCanvasItem::setImplicitWidth(qreal w) +{ + Q_D(QSimpleCanvasItem); + if(d->width == w || widthValid()) + return; + + qreal oldWidth = d->width; + + d->width = w; + update(); + + geometryChanged(QRectF(x(), y(), width(), height()), + QRectF(x(), y(), oldWidth, height())); +} + +bool QSimpleCanvasItem::widthValid() const +{ + Q_D(const QSimpleCanvasItem); + return d->widthValid; +} + +qreal QSimpleCanvasItem::height() const +{ + Q_D(const QSimpleCanvasItem); + return d->height; +} + +void QSimpleCanvasItem::setHeight(qreal h) +{ + Q_D(QSimpleCanvasItem); + d->heightValid = true; + if(d->height == h) + return; + + qreal oldHeight = d->height; + + d->height = h; + update(); + + geometryChanged(QRectF(x(), y(), width(), height()), + QRectF(x(), y(), width(), oldHeight)); +} + +void QSimpleCanvasItem::setImplicitHeight(qreal h) +{ + Q_D(QSimpleCanvasItem); + if(d->height == h || heightValid()) + return; + + qreal oldHeight = d->height; + + d->height = h; + update(); + + geometryChanged(QRectF(x(), y(), width(), height()), + QRectF(x(), y(), width(), oldHeight)); +} + +bool QSimpleCanvasItem::heightValid() const +{ + Q_D(const QSimpleCanvasItem); + return d->heightValid; +} + +void QSimpleCanvasItem::setPos(const QPointF &point) +{ + Q_D(QSimpleCanvasItem); + qreal oldX = x(); + qreal oldY = y(); + + if(d->graphicsItem) { + d->graphicsItem->setPos(point); + } else { + d->data()->x = point.x(); + d->data()->y = point.y(); + update(); + } + + geometryChanged(QRectF(x(), y(), width(), height()), + QRectF(oldX, oldY, width(), height())); +} + +qreal QSimpleCanvasItem::scale() const +{ + Q_D(const QSimpleCanvasItem); + return d->scale; +} + +void QSimpleCanvasItem::setScale(qreal s) +{ + Q_D(QSimpleCanvasItem); + d->scale = s; + if(d->graphicsItem) { + QTransform t; + QPointF to = transformOriginPoint(); + if(to.x() != 0. || to.y() != 0.) + t.translate(to.x(), to.y()); + t.scale(s, s); + if(to.x() != 0. || to.y() != 0.) + t.translate(-to.x(), -to.y()); + d->graphicsItem->setTransform(t * d->graphicsItem->transform); + } else { + update(); + } +} + +bool QSimpleCanvasItem::isVisible() const +{ + if(visible() <= 0) + return false; + else if(!parent()) + return true; + else + return parent()->isVisible(); +} + +qreal QSimpleCanvasItem::visible() const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) + return d->graphicsItem->opacity(); + else if(d->data_ptr) + return d->data()->visible; + else + return 1; +} + +void QSimpleCanvasItem::setVisible(qreal v) +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) { + d->graphicsItem->setOpacity(v); + } else { + if(v == visible()) + return; + if(v == 0) + update(); + + d->data()->visible = v; + + if(v != 0) + update(); + } +} + +void QSimpleCanvasItem::addChild(QSimpleCanvasItem *c) +{ + Q_D(QSimpleCanvasItem); + d->children.append(c); + if(d->graphicsItem) { + // XXX - GraphicsView does not preserve the stacking order of items + c->setZ(d->children.count()); + } else { + d->needsZOrder = true; + } + childrenChanged(); +} + +void QSimpleCanvasItem::remChild(QSimpleCanvasItem *c) +{ + Q_D(QSimpleCanvasItem); + d->children.removeAll(c); + childrenChanged(); +} + +QSimpleCanvasFilter *QSimpleCanvasItem::filter() const +{ + Q_D(const QSimpleCanvasItem); + return d->filter; +} + +/*! +QSimpleCanvasItem takes ownership of filter. +*/ +void QSimpleCanvasItem::setFilter(QSimpleCanvasFilter *f) +{ + Q_D(QSimpleCanvasItem); + if(!d || f == d->filter) + return; + + d->filter = f; + if(d->filter) + d->filter->setItem(this); + update(); +} + +const QList<QSimpleCanvasItem *> &QSimpleCanvasItem::children() const +{ + Q_D(const QSimpleCanvasItem); + return d->children; +} + +bool QSimpleCanvasItem::hasChildren() const +{ + Q_D(const QSimpleCanvasItem); + return !d->children.isEmpty(); +} + +QSimpleCanvasLayer *QSimpleCanvasItem::layer() +{ + if(parent()) + return parent()->layer(); + else + return 0; +} + +void QSimpleCanvasItem::update() +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) { + d->graphicsItem->update(); + } else { + if(!parent()) + return; + + if(d->data()->dirty || 0. == d->data()->visible) return; + + QSimpleCanvasLayer *l = layer(); + if(l == this && parent()) + l = parent()->layer(); + if(l) { + l->addDirty(this); + d->data()->dirty = true; + d->data()->transformValid = false; + } + } +} + +bool QSimpleCanvasItem::clip() const +{ + Q_D(const QSimpleCanvasItem); + return d->clip; +} + +void QSimpleCanvasItem::setClip(bool c) +{ + Q_D(const QSimpleCanvasItem); + if(bool(d->clip) == c) + return; + + if(c) + setClipType(ClipToRect); + else + setClipType(NoClip); + + update(); +} + +QSimpleCanvasItem::ClipType QSimpleCanvasItem::clipType() const +{ + Q_D(const QSimpleCanvasItem); + return d->clip; +} + +void QSimpleCanvasItem::setClipType(ClipType c) +{ + Q_D(QSimpleCanvasItem); + d->clip = c; + if(d->graphicsItem) + d->graphicsItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape, bool(c)); + else + update(); +} + +Qt::MouseButtons QSimpleCanvasItem::acceptedMouseButtons() const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) + return d->graphicsItem->acceptedMouseButtons(); + else if(d->data_ptr) + return (Qt::MouseButtons)d->data()->buttons; + else + return Qt::NoButton; +} + +void QSimpleCanvasItem::setAcceptedMouseButtons(Qt::MouseButtons buttons) +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) + d->graphicsItem->setAcceptedMouseButtons(buttons); + else + d->data()->buttons = buttons; +} + + +QRect QSimpleCanvasItem::itemBoundingRect() +{ + return boundingRect().toAlignedRect(); +} + +QPointF QSimpleCanvasItemPrivate::adjustFrom(const QPointF &p) const +{ +#if defined(QFX_RENDER_OPENGL) + if(!canvas) + return p; + + QPointF rv(-1. + 2. * p.x() / qreal(canvas->width()), + 1 - 2. * p.y() / qreal(canvas->height())); + + return rv; +#else + return p; +#endif +} + +QRectF QSimpleCanvasItemPrivate::adjustFrom(const QRectF &r) const +{ +#if defined(QFX_RENDER_OPENGL) + if(!canvas) + return r; + + qreal width = r.width() * 2. / qreal(canvas->width()); + qreal height = r.height() * 2. / qreal(canvas->height()); + qreal x = -1. + 2. * r.x() / qreal(canvas->width()); + qreal y = 1. - 2. * r.y() / qreal(canvas->height()) - height; + + return QRectF(x, y, width, height); +#else + return r; +#endif +} + +QPointF QSimpleCanvasItemPrivate::adjustTo(const QPointF &p) const +{ +#if defined(QFX_RENDER_OPENGL) + if(!canvas) + return p; + + QPointF rv(0.5 * (p.x() + 1.) * qreal(canvas->width()), + 0.5 * (1. - p.y()) * qreal(canvas->height())); + + return rv; +#else + return p; +#endif +} + +QRectF QSimpleCanvasItemPrivate::adjustTo(const QRectF &r) const +{ +#if defined(QFX_RENDER_OPENGL) + if(!canvas) + return r; + + qreal width = 0.5 * r.width() * qreal(canvas->width()); + qreal height = 0.5 * r.height() * qreal(canvas->height()); + qreal x = 0.5 * (r.x() + 1.) * qreal(canvas->width()); + qreal y = 0.5 * (1. - r.y()) * qreal(canvas->height()) - height; + + return QRectF(x, y, width, height); +#else + return r; +#endif +} + +QPointF QSimpleCanvasItem::mapFromScene(const QPointF &p) const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) { + return d->graphicsItem->mapFromScene(p); + } else { + QPointF mp = d->adjustFrom(p); + d->freshenTransforms(); +#if defined(QFX_RENDER_OPENGL) + // m20X + m21Y + m22Z + m23 = 1 + // Z = (1 - m23 - m20X - m21Y) / m22 + + QMatrix4x4 inv = d->data()->transformActive.inverted(); + qreal z_s = (1 - inv(2,3) - inv(2,0) * mp.x() - inv(2, 1) * mp.y()) / inv(2, 2); + + QVector3D vec(mp.x(), mp.y(), z_s); + QVector3D r = inv.map(vec); + + return r.toPointF(); +#else + return d->data()->transformActive.inverted().map(mp); +#endif + } +} + +QRectF QSimpleCanvasItem::mapFromScene(const QRectF &r) const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) { + return d->graphicsItem->mapFromScene(r).boundingRect(); + } else { + QRectF mr = d->adjustFrom(r); + d->freshenTransforms(); +#if defined(QFX_RENDER_OPENGL) + // m20X + m21Y + m22Z + m23 = 1 + // Z = (1 - m23 - m20X - m21Y) / m22 + + QMatrix4x4 inv = d->data()->transformActive.inverted(); + qreal tl_z_s = (1 - inv(2,3) - inv(2,0) * mr.topLeft().x() - inv(2, 1) * mr.topLeft().y()) / inv(2, 2); + qreal tr_z_s = (1 - inv(2,3) - inv(2,0) * mr.topRight().x() - inv(2, 1) * mr.topRight().y()) / inv(2, 2); + qreal bl_z_s = (1 - inv(2,3) - inv(2,0) * mr.bottomLeft().x() - inv(2, 1) * mr.bottomLeft().y()) / inv(2, 2); + qreal br_z_s = (1 - inv(2,3) - inv(2,0) * mr.bottomRight().x() - inv(2, 1) * mr.bottomRight().y()) / inv(2, 2); + + QVector3D tl(mr.topLeft().x(), mr.topLeft().y(), tl_z_s); + QVector3D tr(mr.topRight().x(), mr.topRight().y(), tr_z_s); + QVector3D bl(mr.bottomLeft().x(), mr.bottomLeft().y(), bl_z_s); + QVector3D br(mr.bottomRight().x(), mr.bottomRight().y(), br_z_s); + + tl = inv.map(tl); tr = inv.map(tr); bl = inv.map(bl); br = inv.map(br); + + qreal xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x())); + qreal xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x())); + qreal ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y())); + qreal ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y())); + + return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax)); +#else + return d->data()->transformActive.inverted().mapRect(mr); +#endif + } +} + +QPointF QSimpleCanvasItem::mapToScene(const QPointF &p) const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) { + return d->graphicsItem->mapToScene(p); + } else { + d->freshenTransforms(); + QPointF rp = d->data()->transformActive.map(p); + return d->adjustTo(rp); + } +} + +QRectF QSimpleCanvasItem::mapToScene(const QRectF &r) const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) { + return d->graphicsItem->mapToScene(r).boundingRect(); + } else { + d->freshenTransforms(); + QRectF rr = d->data()->transformActive.mapRect(r); + return d->adjustTo(rr); + } +} + +int QSimpleCanvasItemPrivate::nextTransformVersion = 1; + +void QSimpleCanvasItemPrivate::freshenTransforms() const +{ + if(freshenNeeded()) + doFreshenTransforms(); +} + +bool QSimpleCanvasItemPrivate::freshenNeeded() const +{ +#if 0 + return parent && + (data()->transformVersion == -1 || + data()->parentTransformVersion == -1 || + parent->d_func()->data()->transformVersion != data()->parentTransformVersion); +#else + const QSimpleCanvasItemPrivate *me = this; + while(me) { + if(me->data_ptr && !me->data_ptr->transformValid) + return true; + if(me->parent) + me = me->parent->d_func(); + else + me = 0; + } + return false; +#endif +} + +void QSimpleCanvasItemPrivate::doFreshenTransforms() const +{ + Q_Q(const QSimpleCanvasItem); + if(parent) + parent->d_func()->doFreshenTransforms(); + + if(freshenNeeded()) { + if(parent) + data()->transformActive = parent->d_func()->data()->transformActive; + else + data()->transformActive = QSimpleCanvas::Matrix(); + data()->transformActive.translate(q->x(), q->y()); + if(scale != 1.) { + QPointF to = transformOrigin(); + if(to.x() != 0. || to.y() != 0.) + data()->transformActive.translate(to.x(), to.y()); + data()->transformActive.scale(scale, scale); + if(to.x() != 0. || to.y() != 0.) + data()->transformActive.translate(-to.x(), -to.y()); + } + + Q_Q(const QSimpleCanvasItem); +#if defined(QFX_RENDER_OPENGL) + if(q->d_func()->data()->transformUser) + data()->transformActive *= *q->d_func()->data()->transformUser; +#endif + + if(data()->flip) { + QRectF br = q->boundingRect(); + data()->transformActive.translate(br.width() / 2., br.height() / 2); +#if defined(QFX_RENDER_OPENGL) + data()->transformActive.rotate(180, (data()->flip & QSimpleCanvasItem::VerticalFlip)?1:0, (data()->flip & QSimpleCanvasItem::HorizontalFlip)?1:0, 0); +#else + data()->transformActive.scale((data()->flip & QSimpleCanvasItem::HorizontalFlip)?-1:1, + (data()->flip & QSimpleCanvasItem::VerticalFlip)?-1:1); +#endif + data()->transformActive.translate(-br.width() / 2., -br.height() / 2); + } + } +} + +QSimpleCanvas::Matrix QSimpleCanvasItem::transform() const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) + return QSimpleCanvasConfig::transformToMatrix(d->graphicsItem->transform); + else if(d->data()->transformUser) + return *d->data()->transformUser; + else + return QSimpleCanvas::Matrix(); +} + +void QSimpleCanvasItem::setTransform(const QSimpleCanvas::Matrix &m) +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) { + d->graphicsItem->transform = QSimpleCanvasConfig::matrixToTransform(m); + d->graphicsItem->setTransform(QTransform::fromScale(d->scale, d->scale) * d->graphicsItem->transform); + } else { + if(!d->data()->transformUser) + d->data()->transformUser = new QSimpleCanvas::Matrix; + *d->data()->transformUser = m; + update(); + } +} + +QSimpleCanvasItem *QSimpleCanvasItem::mouseGrabberItem() const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) { + QGraphicsScene *s = d->graphicsItem->scene(); + if(s) { + QGraphicsItem *item = s->mouseGrabberItem(); + QSimpleGraphicsItem *dgi = static_cast<QSimpleGraphicsItem *>(item); + return dgi?static_cast<QSimpleCanvasItem*>(dgi->owner):0; + } + } else { + QSimpleCanvas *c = canvas(); + if(c) + return c->d->lastMouseItem; + } + return 0; +} + +void QSimpleCanvasItem::ungrabMouse() +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) { + d->graphicsItem->ungrabMouse(); + } else { + QSimpleCanvas *c = canvas(); + if(c && c->d->lastMouseItem == this) { + c->d->lastMouseItem->mouseUngrabEvent(); + c->d->lastMouseItem = 0; + } + } +} + +void QSimpleCanvasItem::grabMouse() +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) { + d->graphicsItem->grabMouse(); + } else { + QSimpleCanvas *c = canvas(); + if(c) { + if(c->d->lastMouseItem != this) { + if(c->d->lastMouseItem) + c->d->lastMouseItem->mouseUngrabEvent(); + c->d->lastMouseItem = this; + } + } + } +} + +bool QSimpleCanvasItem::isFocusable() const +{ + Q_D(const QSimpleCanvasItem); + return d->focusable; +} + +void QSimpleCanvasItem::setFocusable(bool f) +{ + Q_D(QSimpleCanvasItem); + d->focusable = f; +} + +bool QSimpleCanvasItem::hasFocus() const +{ + Q_D(const QSimpleCanvasItem); + return d->hasFocus; +} + +void QSimpleCanvasItemPrivate::setFocus(bool f) +{ + hasFocus = f; +} + +void QSimpleCanvasItemPrivate::setActiveFocus(bool f) +{ + hasActiveFocus = f; + + if(graphicsItem) { + if (f) { + if (!(graphicsItem->flags() & QGraphicsItem::ItemIsFocusable)) + graphicsItem->setFlag(QGraphicsItem::ItemIsFocusable); + graphicsItem->setFocus(); + } else { + graphicsItem->clearFocus(); + if ((graphicsItem->flags() & QGraphicsItem::ItemIsFocusable) && !focusable) + graphicsItem->setFlag(QGraphicsItem::ItemIsFocusable, false); + } + + } +} + +QSimpleCanvasItem::Flip QSimpleCanvasItem::flip() const +{ + Q_D(const QSimpleCanvasItem); + if(d->graphicsItem) + return NoFlip; + else if(d->data_ptr) + return d->data()->flip; + else + return NoFlip; +} + +void QSimpleCanvasItem::setFlip(Flip f) +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) + return; + + if(d->data()->flip == f) + return; + + d->data()->flip = f; + update(); +} + +/*! + Places the item under \a item in the parent item's stack. + + The item itself and \a item must be siblings, or this method has no effect. + + \sa stackOver(), stackAt() + */ +void QSimpleCanvasItem::stackUnder(QSimpleCanvasItem *item) +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) + return; // XXX + + QSimpleCanvasItem *p = parent(); + if(!p || !item || item == this) return; + + QSimpleCanvasItemPrivate *parent_d_ptr = static_cast<QSimpleCanvasItemPrivate*>(p->d_ptr); + int idx = parent_d_ptr->children.indexOf(item); + if(idx == -1) return; + + parent_d_ptr->children.removeAll(this); + idx = parent_d_ptr->children.indexOf(item); + parent_d_ptr->children.insert(idx + 1, this); + parent_d_ptr->needsZOrder = true; + + p->childrenChanged(); +} + +/*! + Places the item over \a item in the parent item's stack. + + The item itself and \a item must be siblings, or this method has no effect. + + \sa stackUnder(), stackAt() + */ +void QSimpleCanvasItem::stackOver(QSimpleCanvasItem *item) +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) + return; // XXX + + QSimpleCanvasItem *p = parent(); + if(!p || !item || item == this) return; + + QSimpleCanvasItemPrivate *parent_d_ptr = static_cast<QSimpleCanvasItemPrivate*>(p->d_ptr); + int idx = parent_d_ptr->children.indexOf(item); + if(idx == -1) return; + + parent_d_ptr->children.removeAll(this); + idx = parent_d_ptr->children.indexOf(item); + parent_d_ptr->children.insert(idx, this); + parent_d_ptr->needsZOrder = true; + + p->childrenChanged(); +} + +/*! + Places the item at position \a index in the parent item's stack. + + If index is zero or less, the item is placed at the beginning of the + stack. If the index is greater than the number of items in the stack, the + item is placed at the end. + + \sa stackOver(), stackUnder() + */ +void QSimpleCanvasItem::stackAt(int index) +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) + return; // XXX + + QSimpleCanvasItem *p = parent(); + if(!p) return; + + QSimpleCanvasItemPrivate *parent_d_ptr = static_cast<QSimpleCanvasItemPrivate*>(p->d_ptr); + parent_d_ptr->children.removeAll(this); + + if(index < 0) index = 0; + if(index > parent_d_ptr->children.size()) index = parent_d_ptr->children.size(); + + parent_d_ptr->children.insert(index, this); + parent_d_ptr->needsZOrder = true; + p->childrenChanged(); +} + +/*! + Returns the current stacking index for the child \a item. + + If \a item is not a child, -1 is returned. + + \sa stackAt() + */ +int QSimpleCanvasItem::indexForChild(QSimpleCanvasItem *item) +{ + Q_D(QSimpleCanvasItem); + return d->children.indexOf(item); +} + +bool QSimpleCanvasItem::eventFilter(QObject *o, QEvent *e) +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) { + switch(e->type()) { + case QEvent::GraphicsSceneMouseDoubleClick: + case QEvent::GraphicsSceneMouseMove: + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseRelease: + if(mouseFilter(static_cast<QGraphicsSceneMouseEvent *>(e))) + return true; + break; + default: + break; + } + } + + return QObject::eventFilter(o, e); +} + +void QSimpleCanvasItem::setOptions(Options options, bool set) +{ + Q_D(QSimpleCanvasItem); + Options old = (Options)d->options; + + if(options & IsFocusPanel) { + if(!set) { + qWarning("QSimpleCanvasItem::setOptions: Cannot unset IsFocusPanel"); + return; + } else if(hasChildren()) { + qWarning("QSimpleCanvasItem::setOptions: Cannot set IsFocusPanel once item has children"); + return; + } + } + + if(options & IsFocusRealm) { + if(!set) { + qWarning("QSimpleCanvasItem::setOptions: Cannot unset IsFocusRealm"); + return; + } + } + + if(set) + d->options |= options; + else + d->options &= ~options; + + if((d->options & IsFocusPanel) && (d->options & IsFocusRealm)) { + qWarning("QSimpleCanvasItem::setOptions: Cannot set both IsFocusPanel and IsFocusRealm. IsFocusRealm will be unset."); + d->options &= ~IsFocusRealm; + } + + if((old & MouseFilter) != (d->options & MouseFilter)) { + if(d->graphicsItem) { + if(d->options & MouseFilter) + d->gvAddMouseFilter(); + else + d->gvRemoveMouseFilter(); + } else { + QSimpleCanvas *c = canvas(); + if(c) { + if(d->options & MouseFilter) + c->d->installMouseFilter(this); + else + c->d->removeMouseFilter(this); + } + } + } +} + +QSimpleCanvasItem::QSimpleCanvasItem(QSimpleCanvasItemPrivate &dd, QSimpleCanvasItem *parent) +: QObject(dd, parent) +{ +} + +QSimpleCanvasItem::QSimpleCanvasItem(QSimpleCanvasItem *p) +: QObject(*(new QSimpleCanvasItemPrivate), p) +{ +} + +QSimpleCanvasItem::~QSimpleCanvasItem() +{ + Q_D(QSimpleCanvasItem); + if(d->graphicsItem) { + if ((d->options & (IsFocusPanel|IsFocusRealm)) && d->canvas) + d->canvas->d->focusPanelData.remove(this); + if (d->hasFocus && d->canvas) { + QSimpleCanvasItem *prnt = parent(); + while (prnt && !(prnt->options() & (IsFocusPanel|IsFocusRealm))) + prnt = prnt->parent(); + if (prnt && d->canvas->d->focusPanelData.value(prnt) == this) + d->canvas->d->focusPanelData.remove(prnt); + } + if(d->filter) + delete d->filter; + + qDeleteAll(children()); + if(parent()) + parent()->remChild(this); + delete d->graphicsItem; + } else { + setOptions(MouseFilter, false); + + if(d->canvas){ + if(d->canvas->focusItem() == this) + d->canvas->d->focusItem = 0; + if(d->canvas->d->lastFocusItem == this) + d->canvas->d->lastFocusItem = 0; + if(d->hasBeenActiveFocusPanel) + d->canvas->d->clearFocusPanel(this); + if(d->hasFocus) + d->canvas->d->clearFocusItem(this); + } + + while(!d->children.isEmpty()) { + QSimpleCanvasItem *child = d->children.takeFirst(); + delete child; + } + + delete d->filter; + + if (parent() && d->data_ptr && d->data()->dirty) { + QSimpleCanvasLayer *l = parent()->layer(); + if(l) { + l->remDirty(this); + } + } + if (d->parent) + d->parent->remChild(this); + + + if(d->data_ptr) + delete d->data_ptr; + } +} + +QSimpleCanvasItem::operator QGraphicsItem *() +{ + Q_D(QSimpleCanvasItem); + if(!d->graphicsItem) { + if(parent()) { + qWarning("QSimpleCanvasItem: Only the root item can be converted into a QGraphicsItem"); + return 0; + } + d->convertToGraphicsItem(); + } + return d->graphicsItem; +} + +QPointF QSimpleCanvasItemPrivate::transformOrigin() const +{ + Q_Q(const QSimpleCanvasItem); + + QRectF br = q->boundingRect(); + + switch(origin) { + default: + case QSimpleCanvasItem::TopLeft: + return QPointF(0, 0); + case QSimpleCanvasItem::TopCenter: + return QPointF(br.width() / 2., 0); + case QSimpleCanvasItem::TopRight: + return QPointF(br.width(), 0); + case QSimpleCanvasItem::MiddleLeft: + return QPointF(0, br.height() / 2.); + case QSimpleCanvasItem::Center: + return QPointF(br.width() / 2., br.height() / 2.); + case QSimpleCanvasItem::MiddleRight: + return QPointF(br.width(), br.height() / 2.); + case QSimpleCanvasItem::BottomLeft: + return QPointF(0, br.height()); + case QSimpleCanvasItem::BottomCenter: + return QPointF(br.width() / 2., br.height()); + case QSimpleCanvasItem::BottomRight: + return QPointF(br.width(), br.height()); + } +} + +void QSimpleCanvasItemPrivate::setParentInternal(QSimpleCanvasItem *p) +{ + Q_Q(QSimpleCanvasItem); + QSimpleCanvasItem *oldParent = parent; + if(graphicsItem) { + if(oldParent) + oldParent->remChild(q); + + parent = p; + graphicsItem->setParentItem(p->d_func()->graphicsItem); + + if(parent) + p->addChild(q); + + } else { + bool canvasChange = false; + if(p) + canvasChange = (p->d_func()->canvas != canvas); + QSimpleCanvas *old = canvas; + + QSimpleCanvasLayer *o = q->layer(); + if(q->parent()) { + q->update(); + q->parent()->remChild(q); + } + parent = p; + QSimpleCanvasLayer *n = 0; + if(q->parent()) { + q->parent()->addChild(q); + n = q->layer(); + } + + if(o != n) { + data()->dirty = false; + data()->transformValid = false; + if(o) o->remDirty(q); + if(n) n->addDirty(q); + } + + if(canvasChange) + canvasChanged(p->d_func()->canvas, old); + + q->update(); + } +} + +void QSimpleCanvasItemPrivate::convertToGraphicsItem(QGraphicsItem *parent) +{ + Q_Q(QSimpleCanvasItem); + Q_ASSERT(!graphicsItem); + graphicsItem = new QSimpleGraphicsItem(q); + if(parent) + graphicsItem->setParentItem(parent); + + QSimpleCanvasItemData *old = data_ptr; + data_ptr = 0; + + if(old) { + q->QSimpleCanvasItem::setX(old->x); + q->QSimpleCanvasItem::setY(old->y); + q->QSimpleCanvasItem::setZ(old->z); + q->QSimpleCanvasItem::setVisible(old->visible); + if(old->transformUser) + q->QSimpleCanvasItem::setTransform(*old->transformUser); + q->QSimpleCanvasItem::setFlip(old->flip); + q->QSimpleCanvasItem::setAcceptedMouseButtons((Qt::MouseButtons)old->buttons); + delete old; + } + + if(scale != 1) { + qreal s = scale; + scale = 1; + q->QSimpleCanvasItem::setScale(s); + } + + q->setClipType(clip); + + for(int ii = 0; ii < children.count(); ++ii) { + static_cast<QSimpleCanvasItemPrivate*>(children.at(ii)->d_ptr)->convertToGraphicsItem(graphicsItem); + if(children.at(ii)->z() == 0) + children.at(ii)->setZ(ii); + } +} + +/*! + \fn void QSimpleCanvasItem::setParent(QSimpleCanvasItem *parent) + + Sets the parent of the item to \a parent. + */ +void QSimpleCanvasItem::setParent(QSimpleCanvasItem *p) +{ + Q_D(QSimpleCanvasItem); + if(p == parent() || !p) return; + + QObject::setParent(p); + + if(d->graphicsItem && !static_cast<QSimpleCanvasItemPrivate*>(p->d_ptr)->graphicsItem) + qWarning("QSimpleCanvasItem: Cannot reparent a QGraphicsView item to a QSimpleCanvas item"); + + if(static_cast<QSimpleCanvasItemPrivate*>(p->d_ptr)->graphicsItem && !d->graphicsItem) { + d->setParentInternal(0); + d->convertToGraphicsItem(); + } + + QSimpleCanvasItem *oldParent = d->parent; + d->setParentInternal(p); + parentChanged(p, oldParent); +} + +int QSimpleCanvasItemPrivate::dump(int indent) +{ + Q_Q(QSimpleCanvasItem); + QByteArray ba(indent * 2, ' '); + + QByteArray state; + if(options & QSimpleCanvasItem::MouseFilter) + state.append("i"); + else + state.append("-"); + if(options & QSimpleCanvasItem::HoverEvents) + state.append("h"); + else + state.append("-"); + if(options & QSimpleCanvasItem::MouseEvents) + state.append("m"); + else + state.append("-"); + if(options & QSimpleCanvasItem::HasContents) + state.append("c"); + else + state.append("-"); + if(options & QSimpleCanvasItem::SimpleItem) + state.append("s"); + else + state.append("-"); + if(options & QSimpleCanvasItem::IsFocusPanel) { + if(q->activeFocusPanel()) + state.append("P"); + else + state.append("p"); + } else { + state.append("-"); + } + if(options & QSimpleCanvasItem::IsFocusRealm) + state.append("r"); + else + state.append("-"); + if(q->hasFocus()) { + if(q->hasActiveFocus()) + state.append("F"); + else + state.append("f"); + } else { + if(q->hasActiveFocus()) + state.append("X"); + else + state.append("-"); + } + + QByteArray name; + QFxItem *i = qobject_cast<QFxItem *>(q); + if(i) + name = i->id().toLatin1(); + qWarning().nospace() << ba.constData() << state.constData() << " " << children.count() << " " << q << " " << name.constData(); + + int rv = 0; + + for(int ii = 0; ii < children.count(); ++ii) + rv += children.at(ii)->d_func()->dump(indent + 1); + + return rv + 1; +} + +bool QSimpleCanvasItemPrivate::checkFocusState(FocusStateCheckDatas d, + FocusStateCheckRDatas *r) +{ + Q_Q(QSimpleCanvasItem); + + bool rv = true; + bool isRealm = (options & QSimpleCanvasItem::IsFocusPanel || + options & QSimpleCanvasItem::IsFocusRealm); + + if(options & QSimpleCanvasItem::IsFocusPanel) { + + if(q->activeFocusPanel()) { + if(d & InActivePanel) { + qWarning() << "State ERROR: Nested active focus panels"; + rv = false; + } + + d |= InActivePanel; + } else { + d &= ~InActivePanel; + } + + } + + if(q->hasActiveFocus()) { + if(!(d & InActivePanel)) { + qWarning() << "State ERROR: Active focus in non-active panel"; + rv = false; + } + + if(d & InRealm && !(d & InActiveFocusedRealm)) { + qWarning() << "State ERROR: Active focus in non-active-focused realm"; + rv = false; + } + + if(!q->hasFocus()) { + qWarning() << "State ERROR: Active focus on element that does not have focus"; + rv = false; + } + + if(*r & SeenActiveFocus) { + qWarning() << "State ERROR: Two active focused elements in same realm"; + rv = false; + } + + *r |= SeenActiveFocus; + } + + if(q->hasFocus()) { + if(*r & SeenFocus) { + qWarning() << "State ERROR: Two focused elements in same realm"; + rv = false; + } + + *r |= SeenFocus; + } + + if(options & QSimpleCanvasItem::IsFocusRealm) { + d |= InRealm; + + if(q->hasActiveFocus()) + d |= InActiveFocusedRealm; + else + d &= ~InActiveFocusedRealm; + } + + FocusStateCheckRDatas newR = NoCheckRData; + if(isRealm) + r = &newR; + + for(int ii = 0; ii < children.count(); ++ii) + rv &= children.at(ii)->d_func()->checkFocusState(d, r); + + return rv; +} + +bool QSimpleCanvasItem::activeFocusPanel() const +{ + QSimpleCanvas *c = canvas(); + if(!c) { + Q_D(const QSimpleCanvasItem); + return d->wantsActiveFocusPanelPendingCanvas; + } else { + return c->activeFocusPanel() == this; + } +} + +void QSimpleCanvasItem::setActiveFocusPanel(bool b) +{ + if(!(options() & IsFocusPanel)) { + qWarning("QSimpleCanvasItem::setActiveFocusPanel: Item is not a focus panel"); + return; + } + + QSimpleCanvas *c = canvas(); + Q_D(QSimpleCanvasItem); + if(c) { + if(b) { + d->hasBeenActiveFocusPanel = true; + c->d->setActiveFocusPanel(this); + } else if(d->hasBeenActiveFocusPanel) { + d->hasBeenActiveFocusPanel = false; + c->d->clearFocusPanel(this); + } + } else { + d->wantsActiveFocusPanelPendingCanvas = b; + } +} + +bool QSimpleCanvasItem::hasActiveFocus() const +{ + Q_D(const QSimpleCanvasItem); + return d->hasActiveFocus; +} + +QSimpleCanvasItem *QSimpleCanvasItem::findFirstFocusChild() const +{ + Q_D(const QSimpleCanvasItem); + + const QList<QSimpleCanvasItem *> &children = d->children; + + for (int i = 0; i < children.count(); ++i) { + QSimpleCanvasItem *child = children.at(i); + if(child->options() & IsFocusPanel) + continue; + + if (child->isFocusable()) + return child; + + QSimpleCanvasItem *testFocus = child->findFirstFocusChild(); + if (testFocus) + return testFocus; + } + + return 0; +} + +QSimpleCanvasItem *QSimpleCanvasItem::findLastFocusChild() const +{ + Q_D(const QSimpleCanvasItem); + + const QList<QSimpleCanvasItem *> &children = d->children; + + for (int i = children.count()-1; i >= 0; --i) { + QSimpleCanvasItem *child = children.at(i); + if(child->options() & IsFocusPanel) + continue; + + if (child->isFocusable()) + return child; + QSimpleCanvasItem *testFocus = child->findLastFocusChild(); + if (testFocus) + return testFocus; + } + + return 0; +} + +QSimpleCanvasItem *QSimpleCanvasItem::findPrevFocus(QSimpleCanvasItem *item) +{ + QSimpleCanvasItem *focusChild = item->findLastFocusChild(); + if (focusChild) + return focusChild; + + if(item->options() & IsFocusPanel) { + if(item->isFocusable()) + return item; + else + return 0; + } + + QSimpleCanvasItem *parent = item->parent(); + while (parent) { + const QList<QSimpleCanvasItem *> &children = parent->d_func()->children; + + int idx = children.indexOf(item); + QSimpleCanvasItem *testFocus = 0; + if (idx > 0) { + while (--idx >= 0) { + testFocus = children.at(idx); + if(testFocus->options() & IsFocusPanel) + continue; + if (testFocus->isFocusable()) + return testFocus; + testFocus = testFocus->findLastFocusChild(); + if (testFocus) + return testFocus; + } + } + if(parent->options() & IsFocusPanel) { + if(parent->isFocusable()) + return parent; + else + return 0; + } + item = parent; + parent = parent->parent(); + } + + return 0; +} + +QSimpleCanvasItem *QSimpleCanvasItem::findNextFocus(QSimpleCanvasItem *item) +{ + QSimpleCanvasItem *focusChild = item->findFirstFocusChild(); + if (focusChild) + return focusChild; + + if(item->options() & IsFocusPanel) { + if(item->isFocusable()) + return item; + else + return 0; + } + + QSimpleCanvasItem *parent = item->parent(); + while (parent) { + const QList<QSimpleCanvasItem *> &children = parent->d_func()->children; + + int idx = children.indexOf(item); + QSimpleCanvasItem *testFocus = 0; + if (idx >= 0) { + while (++idx < children.count()) { + testFocus = children.at(idx); + if(testFocus->options() & IsFocusPanel) + continue; + if (testFocus->isFocusable()) + return testFocus; + testFocus = testFocus->findFirstFocusChild(); + if (testFocus) + return testFocus; + } + } + if(parent->options() & IsFocusPanel) { + if(parent->isFocusable()) + return parent; + else + return 0; + } + item = parent; + parent = parent->parent(); + } + + return 0; +} + +QImage QSimpleCanvasItem::string(const QString &str, const QColor &c, const QFont &f) +{ + QFontMetrics fm(f); + QSize size(fm.width(str), fm.height()*(str.count(QLatin1Char('\n'))+1)); //fm.boundingRect(str).size(); + QImage img(size, QImage::Format_ARGB32_Premultiplied); + img.fill(0); + QPainter p(&img); + p.setPen(c); + p.setFont(f); + p.drawText(img.rect(), Qt::AlignVCenter, str); + return img; +} + +void QSimpleCanvasItem::geometryChanged(const QRectF &, const QRectF &) +{ +} + +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvasitem.h b/src/declarative/canvas/qsimplecanvasitem.h new file mode 100644 index 0000000..d51f2c8 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvasitem.h @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLECANVASITEM_H +#define QSIMPLECANVASITEM_H + +#include <gfxtimeline.h> +#include <qfxglobal.h> +#include <qsimplecanvas.h> +#include <QObject> +#include <QGraphicsItem> +class QPainter; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QRect; +class QSimpleCanvas; +class QMouseEvent; +class QKeyEvent; +class QSimpleCanvasItemPrivate; +class QSimpleCanvasLayer; +class QPointF; +class QRectF; +class QGraphicsSceneHoverEvent; +class QSimpleCanvasFilter; +class GLTexture; +class QGLShaderProgram; + +class Q_DECLARATIVE_EXPORT QSimpleCanvasItem : public QObject +{ + Q_OBJECT + Q_CAST_INTERFACES(QGraphicsItem) + Q_DECLARE_PRIVATE(QSimpleCanvasItem) + Q_ENUMS(TransformOrigin) + Q_PROPERTY(TransformOrigin transformOrigin READ transformOrigin WRITE setTransformOrigin); + +public: + enum ClipType { NoClip = 0x00, + ClipToHeight = 0x01, + ClipToWidth = 0x02, + ClipToRect = 0x03 }; + enum Option { NoOption = 0x00000000, + MouseFilter = 0x00000001, + HoverEvents = 0x00000002, + MouseEvents = 0x00000004, + HasContents = 0x00000008, + SimpleItem = 0x00000010, + IsFocusPanel = 0x00000020, + IsFocusRealm = 0x00000040, + AcceptsInputMethods = 0x00000080}; + Q_DECLARE_FLAGS(Options, Option); + + QSimpleCanvasItem(QSimpleCanvasItem *parent=0); + virtual ~QSimpleCanvasItem(); + operator QGraphicsItem *(); + + bool clip() const; + void setClip(bool); + ClipType clipType() const; + void setClipType(ClipType); + + Options options() const; + void setOptions(Options, bool set = true); + + Qt::MouseButtons acceptedMouseButtons() const; + void setAcceptedMouseButtons(Qt::MouseButtons buttons); + + qreal x() const; + qreal y() const; + qreal z() const; + QPointF pos() const; + void setX(qreal); + void setY(qreal); + virtual void setZ(qreal); + void setPos(const QPointF &); + + qreal width() const; + void setWidth(qreal); + void setImplicitWidth(qreal); + bool widthValid() const; + qreal height() const; + void setHeight(qreal); + void setImplicitHeight(qreal); + bool heightValid() const; + + QPointF scenePos() const; + + enum TransformOrigin { + TopLeft, TopCenter, TopRight, + MiddleLeft, Center, MiddleRight, + BottomLeft, BottomCenter, BottomRight + }; + TransformOrigin transformOrigin() const; + void setTransformOrigin(TransformOrigin); + QPointF transformOriginPoint() const; + + + qreal scale() const; + virtual void setScale(qreal); + + enum Flip { NoFlip = 0, + VerticalFlip = 0x01, + HorizontalFlip = 0x02, + VerticalAndHorizontalFlip = 0x03 }; + Flip flip() const; + void setFlip(Flip); + + qreal visible() const; + virtual void setVisible(qreal); + bool isVisible() const; + + QSimpleCanvas *canvas() const; + + QSimpleCanvasItem *parent() const; + void setParent(QSimpleCanvasItem *); + void stackUnder(QSimpleCanvasItem *); + void stackOver(QSimpleCanvasItem *); + void stackAt(int idx); + int indexForChild(QSimpleCanvasItem *); + + QRect itemBoundingRect(); + + class GLPainter + { + public: + GLPainter(QSimpleCanvasItem *i) : item(i), activeOpacity(1) {} + QSimpleCanvasItem *item; + QSimpleCanvas::Matrix activeTransform; + qreal activeOpacity; + QRect sceneClipRect; + + QGLShaderProgram *useTextureShader(); + QGLShaderProgram *useColorShader(const QColor &); + void drawImage(const QPointF &, const GLTexture &); + void drawImage(const QRectF &, const GLTexture &); + private: + GLPainter(const GLPainter &); + GLPainter &operator=(const GLPainter &); + }; + + + QRectF boundingRect() const; + virtual void paintContents(QPainter &); + virtual void paintGLContents(GLPainter &); + virtual uint glSimpleItemData(float *vertices, float *texVertices, + GLTexture **texture, uint count); + + void update(); + + virtual QSimpleCanvasLayer *layer(); + + bool hasChildren() const; + const QList<QSimpleCanvasItem *> &children() const; + + QPointF mapFromScene(const QPointF &) const; + QRectF mapFromScene(const QRectF &) const; + QPointF mapToScene(const QPointF &) const; + QRectF mapToScene(const QRectF &) const; + + QSimpleCanvas::Matrix transform() const; + void setTransform(const QSimpleCanvas::Matrix &); + + QSimpleCanvasFilter *filter() const; + void setFilter(QSimpleCanvasFilter *); + + QSimpleCanvasItem *mouseGrabberItem() const; + void ungrabMouse(); + void grabMouse(); + + virtual bool isFocusable() const; + void setFocusable(bool); + virtual bool hasFocus() const; + void setFocus(bool); + bool activeFocusPanel() const; + void setActiveFocusPanel(bool); + + bool hasActiveFocus() const; + + QSimpleCanvasItem *findFirstFocusChild() const; + QSimpleCanvasItem *findLastFocusChild() const; + static QSimpleCanvasItem *findPrevFocus(QSimpleCanvasItem *item); + static QSimpleCanvasItem *findNextFocus(QSimpleCanvasItem *item); + + GLBasicShaders *basicShaders() const; + + static QImage string(const QString &, const QColor & = Qt::black, const QFont & = QFont()); + +protected: + virtual void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry); + virtual void addChild(QSimpleCanvasItem *); + virtual void remChild(QSimpleCanvasItem *); + virtual void canvasChanged(); + virtual void childrenChanged(); + virtual void parentChanged(QSimpleCanvasItem *, QSimpleCanvasItem *); + virtual void focusChanged(bool); + virtual void activeFocusChanged(bool); + virtual bool eventFilter(QObject *, QEvent *); + +public: + // Events + virtual bool mouseFilter(QGraphicsSceneMouseEvent *); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseUngrabEvent(); + virtual void keyPressEvent(QKeyEvent *event); + virtual void keyReleaseEvent(QKeyEvent *event); + virtual void focusOutEvent(QFocusEvent *e); + virtual void focusInEvent(QFocusEvent *e); + virtual void activePanelInEvent(); + virtual void activePanelOutEvent(); + virtual void inputMethodEvent(QInputMethodEvent* event); + virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; + +private: + friend class QSimpleCanvas; + friend class QSimpleCanvasPrivate; + friend class QSimpleCanvasRootLayer; + friend class QSimpleCanvasItem::GLPainter; + friend class QSimpleCanvasFilter; + friend class QGraphicsQSimpleCanvasItem; + friend class QSimpleGraphicsItem; + friend class CanvasEGLWidget; + friend class QSimpleCanvasFilterPrivate; + +public: + QSimpleCanvasItem(QSimpleCanvasItemPrivate &dd, QSimpleCanvasItem *parent); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QSimpleCanvasItem::Options); + +class QSimpleCanvasLayer : public QSimpleCanvasItem +{ +public: + QSimpleCanvasLayer(QSimpleCanvasItem *parent); + + virtual void addChild(QSimpleCanvasItem *); + virtual void addDirty(QSimpleCanvasItem *); + virtual void remDirty(QSimpleCanvasItem *); + virtual QSimpleCanvasLayer *layer(); + +private: + friend class QSimpleCanvas; + friend class QSimpleCanvasRootLayer; + QSimpleCanvasLayer(); +}; + + + +#endif // _GFXCANVASITEM_H_ + + +QT_END_NAMESPACE + +QT_END_HEADER diff --git a/src/declarative/canvas/qsimplecanvasitem_p.h b/src/declarative/canvas/qsimplecanvasitem_p.h new file mode 100644 index 0000000..7f66be5 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvasitem_p.h @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLECANVASITEM_P_H +#define QSIMPLECANVASITEM_P_H + +#include "private/qobject_p.h" +#include "qsimplecanvas.h" +#include "qsimplecanvasitem.h" +#include "qsimplecanvasfilter.h" + +#if defined(QFX_RENDER_OPENGL2) +#include <glbasicshaders.h> +#endif + +#include "qgraphicsitem.h" + + +QT_BEGIN_NAMESPACE +class QSimpleGraphicsItem : public QGraphicsItem +{ +public: + QSimpleGraphicsItem(QSimpleCanvasItem *); + virtual ~QSimpleGraphicsItem(); + + virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + virtual QRectF boundingRect() const; + + QTransform transform; +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + virtual bool sceneEvent(QEvent *); + virtual QVariant itemChange(GraphicsItemChange, const QVariant &); + virtual void keyPressEvent(QKeyEvent *event); + virtual void keyReleaseEvent(QKeyEvent *event); + virtual void focusInEvent(QFocusEvent *event); + +private: + friend class QSimpleCanvasItem; + QSimpleCanvasItem *owner; +}; + +class QSimpleCanvasItemData +{ +public: + QSimpleCanvasItemData(); + ~QSimpleCanvasItemData(); + + // 5 bits is all that's needed to store Qt::MouseButtons + int buttons:5; + QSimpleCanvasItem::Flip flip:2; + bool dirty:1; + bool transformValid:1; + + qreal x; + qreal y; + qreal z; + float visible; + + QSimpleCanvas::Matrix *transformUser; + QSimpleCanvas::Matrix transformActive; + + float activeOpacity; + +#if defined(QFX_RENDER_OPENGL) + QRectF lastPaintRect; +#else + QRect lastPaintRect; +#endif +}; + +class QSimpleCanvasFilter; +class QGraphicsQSimpleCanvasItem; +class QSimpleCanvasItemPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QSimpleCanvasItem); +public: + QSimpleCanvasItemPrivate() + : parent(0), canvas(0), filter(0), clip(QSimpleCanvasItem::NoClip), + origin(QSimpleCanvasItem::TopLeft), options(QSimpleCanvasItem::NoOption), + focusable(false), wantsActiveFocusPanelPendingCanvas(false), + hasBeenActiveFocusPanel(false), + hasFocus(false), hasActiveFocus(false), needsZOrder(false), + widthValid(false), heightValid(false), width(0), height(0), scale(1), + graphicsItem(0), data_ptr(0) + { + } + + virtual ~QSimpleCanvasItemPrivate() {} + + QSimpleCanvasItem *parent; + QSimpleCanvas *canvas; + QList<QSimpleCanvasItem *> children; + + QSimpleCanvasFilter *filter; + + QSimpleCanvasItem::ClipType clip:3; + QSimpleCanvasItem::TransformOrigin origin:4; + int options:8; + bool focusable:1; + bool wantsActiveFocusPanelPendingCanvas:1; + bool hasBeenActiveFocusPanel:1; + bool hasFocus:1; + bool hasActiveFocus:1; + bool needsZOrder:1; + bool widthValid:1; + bool heightValid:1; + + void setFocus(bool f); + void setActiveFocus(bool f); + + qreal width; + qreal height; + qreal scale; + + QSimpleGraphicsItem *graphicsItem; + inline QSimpleCanvasItemData *data() const { + if(!data_ptr) data_ptr = new QSimpleCanvasItemData; + return data_ptr; + } + mutable QSimpleCanvasItemData *data_ptr; + + void gvRemoveMouseFilter(); + void gvAddMouseFilter(); + + void canvasChanged(QSimpleCanvas *newCanvas, QSimpleCanvas *oldCanvas); + + void freshenTransforms() const; + + QPointF adjustFrom(const QPointF &) const; + QRectF adjustFrom(const QRectF &) const; + QPointF adjustTo(const QPointF &) const; + QRectF adjustTo(const QRectF &) const; + + QPointF transformOrigin() const; + + void setParentInternal(QSimpleCanvasItem *); + void convertToGraphicsItem(QGraphicsItem * = 0); + +#if defined(QFX_RENDER_QPAINTER) + void paint(QPainter &); + void paintChild(QPainter &, QSimpleCanvasItem *); + QRect setupPainting(int version, const QRect &bounding); +#else + struct GLPaintParameters + { + QRect sceneRect; + QRectF boundingRect; + QRect clipRect; +#if defined(QFX_RENDER_OPENGL2) + uchar stencilValue; +#endif + float opacity; + bool forceParamRefresh; + }; +#if defined(QFX_RENDER_OPENGL2) + QRectF setupPainting(int version, const QRect &bounding); +#elif defined(QFX_RENDER_OPENGL1) + QRectF setupPainting(int version, const QRect &bounding, unsigned int *zero); +#endif + void setupChildState(QSimpleCanvasItem *); + + void paint(GLPaintParameters &, QSimpleCanvasFilter::Layer = QSimpleCanvasFilter::All); +#if defined(QFX_RENDER_OPENGL1) + void paintNoClip(GLPaintParameters &, QSimpleCanvasFilter::Layer = QSimpleCanvasFilter::All); +#endif + void paintChild(const GLPaintParameters &, QSimpleCanvasItem *); + void simplePaintChild(const GLPaintParameters &, QSimpleCanvasItem *); + + inline GLBasicShaders *basicShaders() const; + + QSimpleCanvas::Matrix localTransform() const; + +#endif + + void zOrderChildren(); + static int nextTransformVersion; + bool freshenNeeded() const; + void doFreshenTransforms() const; + + // Debugging + int dump(int); + enum FocusStateCheckData { NoCheckData = 0x00, + InActivePanel = 0x01, + InRealm = 0x02, + InActiveFocusedRealm = 0x04 + }; + Q_DECLARE_FLAGS(FocusStateCheckDatas, FocusStateCheckData); + enum FocusStateCheckRData { NoCheckRData = 0x00, + SeenFocus = 0x01, + SeenActiveFocus = 0x02 }; + Q_DECLARE_FLAGS(FocusStateCheckRDatas, FocusStateCheckRData); + bool checkFocusState(FocusStateCheckDatas, FocusStateCheckRDatas *); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QSimpleCanvasItemPrivate::FocusStateCheckDatas); +Q_DECLARE_OPERATORS_FOR_FLAGS(QSimpleCanvasItemPrivate::FocusStateCheckRDatas); + +#endif // QSIMPLECANVASITEM_P_H + +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvasserver.cpp b/src/declarative/canvas/qsimplecanvasserver.cpp new file mode 100644 index 0000000..7eebe65 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvasserver.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimplecanvasserver_p.h" +#include "qdebug.h" +#ifndef Q_OS_WIN32 +#include <arpa/inet.h> +#endif + +QT_BEGIN_NAMESPACE + +QSimpleCanvasServer::QSimpleCanvasServer(int port, QObject *parent) +: QObject(parent), _tcpServer(new QTcpServer(this)) +{ + QObject::connect(_tcpServer, SIGNAL(newConnection()), + this, SLOT(newConnection())); + + _time.start(); + + if(!_tcpServer->listen(QHostAddress::Any, port)) { + qWarning() << "QSimpleCanvasServer: Cannot listen on port" << port; + return; + } +} + +void QSimpleCanvasServer::newConnection() +{ + QTcpSocket *socket = _tcpServer->nextPendingConnection(); + QObject::connect(socket, SIGNAL(disconnected()), + this, SLOT(disconnected())); + _tcpClients << socket; +} + +void QSimpleCanvasServer::addTiming(quint32 paint, + quint32 repaint, + quint32 timeBetweenFrames) +{ + /* + quint32 data[3]; + data[0] = ::htonl(paint); + data[1] = ::htonl(repaint); + data[2] = ::htonl(timeBetweenFrames); + */ + + int e = _time.elapsed(); + QString d = QString::number(paint) + QLatin1String(" ") + QString::number(repaint) + QLatin1String(" ") + QString::number(timeBetweenFrames) + QLatin1String(" ") + QString::number(e) + QLatin1String("\n"); + QByteArray ba = d.toLatin1(); + + // XXX + for(int ii = 0; ii < _tcpClients.count(); ++ii) +// _tcpClients.at(ii)->write((const char *)data, 12); + _tcpClients.at(ii)->write(ba.constData(), ba.length()); +} + +void QSimpleCanvasServer::disconnected() +{ + QTcpSocket *socket = static_cast<QTcpSocket *>(sender()); + + for(int ii = 0; ii < _tcpClients.count(); ++ii) { + if(_tcpClients.at(ii) == socket) { + socket->disconnect(); + socket->deleteLater(); + _tcpClients.removeAt(ii); + return; + } + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/canvas/qsimplecanvasserver_p.h b/src/declarative/canvas/qsimplecanvasserver_p.h new file mode 100644 index 0000000..7d53357 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvasserver_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLECANVASSERVER_P_H +#define QSIMPLECANVASSERVER_P_H + +#include "qobject.h" +#include "qtcpserver.h" +#include "qtcpsocket.h" +#include "qdatetime.h" + + +QT_BEGIN_NAMESPACE +class QSimpleCanvasServer : public QObject +{ +Q_OBJECT +public: + QSimpleCanvasServer(int port, QObject *parent); + + void addTiming(quint32, quint32, quint32); + +private Q_SLOTS: + void newConnection(); + void disconnected(); + +private: + QTcpServer *_tcpServer; + QList<QTcpSocket *> _tcpClients; + QTime _time; +}; + +QT_END_NAMESPACE +#endif // GFXCANVASSERVER_P_H |