diff options
Diffstat (limited to 'src/declarative/canvas/qsimplecanvas.cpp')
-rw-r--r-- | src/declarative/canvas/qsimplecanvas.cpp | 1029 |
1 files changed, 1029 insertions, 0 deletions
diff --git a/src/declarative/canvas/qsimplecanvas.cpp b/src/declarative/canvas/qsimplecanvas.cpp new file mode 100644 index 0000000..e582226 --- /dev/null +++ b/src/declarative/canvas/qsimplecanvas.cpp @@ -0,0 +1,1029 @@ +/**************************************************************************** +** +** 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 "qsimplecanvasdebugplugin_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(useSimpleCanvas, QFX_USE_SIMPLECANVAS); + +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->setModifiers(e->modifiers()); + me->setPos(item); + me->setScreenPos(e->pos()); + me->setScenePos(e->pos()); + return me; +} + +bool QSimpleCanvasPrivate::deliverMousePress(QSimpleCanvasItem *base, QMouseEvent *e, bool seenChildFilter) +{ + 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; + + if (base->options() & QSimpleCanvasItem::ChildMouseFilter) + seenChildFilter = true; + + for (int ii = children.count() - 1; ii >= 0; --ii) { + if (children.at(ii)->visible() != 0.) + if (deliverMousePress(children.at(ii), e, seenChildFilter)) + return true; + } + + if (base->acceptedMouseButtons() & e->button() || base->options() & QSimpleCanvasItem::ChildMouseFilter) { + + QRectF br = base->boundingRect(); + QPoint pos = base->mapFromScene(e->pos()).toPoint(); + + if (br.contains(pos)) { + QGraphicsSceneMouseEvent *me = mouseEventToSceneMouseEvent(e, pos); + + sendMouseEvent(base, me); + bool isAccepted = me->isAccepted(); + delete me; + if (isAccepted) { + lastMouseItem = base; + return true; + } + } + } + return false; +} + +// Delivers e to item +void QSimpleCanvasPrivate::sendMouseEvent(QSimpleCanvasItem *item, QGraphicsSceneMouseEvent *e) +{ + QSimpleCanvasItem *p = item->parent(); + while(p) { + if (p->options() & QSimpleCanvasItem::ChildMouseFilter) { + if (p->mouseFilter(e)) + return; + } + p = p->parent(); + } + switch(e->type()) { + case QEvent::GraphicsSceneMousePress: + item->mousePressEvent(e); + break; + case QEvent::GraphicsSceneMouseRelease: + item->mouseReleaseEvent(e); + break; + case QEvent::GraphicsSceneMouseMove: + item->mouseMoveEvent(e); + break; + case QEvent::GraphicsSceneMouseDoubleClick: + item->mouseDoubleClickEvent(e); + break; + default: + break; + } +} + + +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->debugPlugin) + canvas->debugPlugin->addTiming(canvas->lrpTime, frametimer, tbf); +} + +void QSimpleCanvasGraphicsView::focusInEvent(QFocusEvent *) +{ +} + +/*! + \internal + \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(useSimpleCanvas()?SimpleCanvas:GraphicsView); +} + +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"); + + if (QmlDebugServerPlugin::isDebuggingEnabled()) { + debugPlugin = new QSimpleCanvasDebugPlugin(q); + new QSimpleCanvasSceneDebugPlugin(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) { + ++paintVersion; + 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->sendMouseEvent(d->lastMouseItem, 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->sendMouseEvent(d->lastMouseItem, 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(); +} + +QSimpleCanvasItem *QSimpleCanvas::focusItem(QSimpleCanvasItem *item) const +{ + while (item && d->focusPanelData.contains(item)) + item = d->focusPanelData.value(item); + return item; +} + +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->paintVersion; + 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->debugPlugin) + d->debugPlugin->addTiming(d->lrpTime, frametimer, tbf); + d->lrpTime = 0; + if (continuousUpdate()) + queueUpdate(); + + return true; + } + + if (e->type() == QEvent::ShortcutOverride) { + if (QSimpleCanvasItem *focus = focusItem()) + return focus->event(e); + } + + 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 |