Browse Source

Add qgraphicsembedscene.py file based on Qt C++ code

tags/1.9.4
falkTX 11 years ago
parent
commit
46d9f47ef5
2 changed files with 238 additions and 1 deletions
  1. +2
    -1
      Makefile
  2. +236
    -0
      source/widgets/qgraphicsembedscene.py

+ 2
- 1
Makefile View File

@@ -145,7 +145,8 @@ WIDGETS = \
source/paramspinbox.py \
source/pixmapbutton.py \
source/pixmapdial.py \
source/pixmapkeyboard.py
source/pixmapkeyboard.py \
source/qgraphicsembedscene.py

WIDGETS: $(WIDGETS)



+ 236
- 0
source/widgets/qgraphicsembedscene.py View File

@@ -0,0 +1,236 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# QGraphicsEmbedScene class, based on Qt3D C++ code
# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
# Copyright (C) 2014 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

# ------------------------------------------------------------------------------------------------------------
# Imports (Config)

from carla_config import *

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

if config_UseQt5:
from PyQt5.QtCore import pyqtSignal, pyqtSlot, qRound, Qt, QPoint, QSize
from PyQt5.QtGui import QEvent, QPainter
from PyQt5.QtOpenGL import QGLFramebufferObject, QGLFramebufferObjectFormat
from PyQt5.QtWidgets import QApplication, QGraphicsScene
else:
from PyQt4.QtCore import pyqtSignal, pyqtSlot, qRound, Qt, QPoint, QSize
from PyQt4.QtOpenGL import QGLFramebufferObject, QGLFramebufferObjectFormat
from PyQt4.QtGui import QApplication, QEvent, QObject, QPainter, QGraphicsScene

# ------------------------------------------------------------------------------------------------------------

# Returns the next power of two that is greater than or
# equal to @a value. The @a value must be positive or the
# result is undefined.
#
# This is a convenience function for use with GL texture
# handling code.

def nextPowerOfTwo(value):
value -= 1
value |= value >> 1
value |= value >> 2
value |= value >> 4
value |= value >> 8
value |= value >> 16
value += 1
return value

# ------------------------------------------------------------------------------------------------------------
# Widget Class

class QGraphicsEmbedScene(QGraphicsScene):
def __init__(self, parent):
QGraphicsScene.__init__(self, parent)

self.dirty = True
self.fbo = None

self.format = QGLFramebufferObjectFormat()
self.format.setAttachment(QGLFramebufferObject.CombinedDepthStencil)

self.pressedPos = QPoint()

self.changed.connect(self.slot_update)
self.sceneRectChanged.connect(self.slot_update)

def format(self):
return self.format

def setFormat(self, format):
self.format = format

def renderToTexture(self, levelOfDetail = 1.0):
# Determine the fbo size we will need.
size = (self.sceneRect().size() * levelOfDetail).toSize()
fboSize = nextPowerOfTwo(size)
if fboSize.isEmpty():
fboSize = QSize(16, 16)

# Create or re-create the fbo.
if self.fbo is None or self.fbo.size() != fboSize:
#del self.fbo
self.fbo = QGLFramebufferObject(fboSize, self.format)
if not self.fbo.isValid():
#del self.fbo
self.fbo = None
return 0
self.dirty = True

# Return the previous texture contents if the scene hasn't changed.
if self.fbo is not None and not self.dirty:
return self.fbo.texture()

# Render the scene into the fbo, scaling the QPainter's view
# transform up to the power-of-two fbo size.
painter = QPainter(self.fbo)
painter.setWindow(0, 0, size.width(), size.height());
painter.setViewport(0, 0, fboSize.width(), fboSize.height());
self.render(painter)
painter.end()
self.dirty = False
return self.fbo.texture();

def deliverEvent(self, event, texCoord):
# Map the texture co-ordinate into "screen" co-ordinates.
# Mouse move and release events can extend beyond the boundaries
# of the scene, for "click and drag off-screen" operations.
# Mouse press and double-click events need to be constrained.
bounds = self.sceneRect()
screenX = qRound(texCoord.x() * bounds.width())
screenY = qRound((1.0 - texCoord.y()) * bounds.height())
if event.type() in (QEvent.GraphicsSceneMousePress,
QEvent.GraphicsSceneMouseDoubleClick,
QEvent.MouseButtonPress,
QEvent.MouseButtonDblClick):
if screenX < 0:
screenX = 0
elif screenX >= bounds.width():
screenX = qRound(bounds.width() - 1)
if screenY < 0:
screenY = 0
elif screenY >= bounds.height():
screenY = qRound(bounds.height() - 1)
self.pressedPos = QPoint(screenX, screenY)

# Convert the event and deliver it to the scene.
eventType = event.type()

if eventType in (QEvent.GraphicsSceneMouseMove,
QEvent.GraphicsSceneMousePress,
QEvent.GraphicsSceneMouseRelease,
QEvent.GraphicsSceneMouseDoubleClick):
pass
#QGraphicsSceneMouseEvent *ev =
#static_cast<QGraphicsSceneMouseEvent *>(event);
#QGraphicsSceneMouseEvent e(ev->type());
#e.setPos(QPointF(screenX, screenY));
#e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()));
#e.setScreenPos(QPoint(screenX, screenY));
#e.setButtonDownScreenPos(ev->button(), d->pressedPos);
#e.setButtonDownScenePos
#(ev->button(), QPointF(d->pressedPos.x() + bounds.x(),
#d->pressedPos.y() + bounds.y()));
#e.setButtons(ev->buttons());
#e.setButton(ev->button());
#e.setModifiers(ev->modifiers());
#e.setAccepted(false);
#QApplication::sendEvent(this, &e);

elif eventType == QEvent.GraphicsSceneWheel:
pass
#QGraphicsSceneWheelEvent *ev =
#static_cast<QGraphicsSceneWheelEvent *>(event);
#QGraphicsSceneWheelEvent e(QEvent::GraphicsSceneWheel);
#e.setPos(QPointF(screenX, screenY));
#e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()));
#e.setScreenPos(QPoint(screenX, screenY));
#e.setButtons(ev->buttons());
#e.setModifiers(ev->modifiers());
#e.setDelta(ev->delta());
#e.setOrientation(ev->orientation());
#e.setAccepted(false);
#QApplication::sendEvent(this, &e);

elif eventType in (QEvent.MouseButtonPress,
QEvent.MouseButtonRelease,
QEvent.MouseButtonDblClick,
QEvent.MouseMove):
pass
#QMouseEvent *ev = static_cast<QMouseEvent *>(event);
#QEvent::Type type;
#if (ev->type() == QEvent::MouseButtonPress)
#type = QEvent::GraphicsSceneMousePress;
#else if (ev->type() == QEvent::MouseButtonRelease)
#type = QEvent::GraphicsSceneMouseRelease;
#else if (ev->type() == QEvent::MouseButtonDblClick)
#type = QEvent::GraphicsSceneMouseDoubleClick;
#else
#type = QEvent::GraphicsSceneMouseMove;
#QGraphicsSceneMouseEvent e(type);
#e.setPos(QPointF(screenX, screenY));
#e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()));
#e.setScreenPos(QPoint(screenX, screenY));
#e.setButtonDownScreenPos(ev->button(), d->pressedPos);
#e.setButtonDownScenePos
#(ev->button(), QPointF(d->pressedPos.x() + bounds.x(),
#d->pressedPos.y() + bounds.y()));
#e.setButtons(ev->buttons());
#e.setButton(ev->button());
#e.setModifiers(ev->modifiers());
#e.setAccepted(false);
#QApplication::sendEvent(this, &e);

elif eventType == QEvent.Wheel:
pass
#QWheelEvent *ev = static_cast<QWheelEvent *>(event);
#QGraphicsSceneWheelEvent e(QEvent::GraphicsSceneWheel);
#e.setPos(QPointF(screenX, screenY));
#e.setScenePos(QPointF(screenX + bounds.x(), screenY + bounds.y()));
#e.setScreenPos(QPoint(screenX, screenY));
#e.setButtons(ev->buttons());
#e.setModifiers(ev->modifiers());
#e.setDelta(ev->delta());
#e.setOrientation(ev->orientation());
#e.setAccepted(false);
#QApplication::sendEvent(this, &e);

#else:
# Send the event directly without any conversion.
# Typically used for keyboard, focus, and enter/leave events.
#QApplication.sendEvent(self, event)

QApplication.sendEvent(self, event)

def drawBackground(self, painter, rect):
if self.backgroundBrush().style() == Qt.NoBrush:
# Fill the fbo with the transparent color as there won't
# be a window or graphics item drawing a previous background.
painter.save()
painter.setCompositionMode(QPainter.CompositionMode_Source)
painter.fillRect(rect, Qt.transparent)
painter.restore()
else:
QGraphicsScene.drawBackground(painter, rect)

@pyqtSlot()
def slot_update(self):
self.dirty = True

Loading…
Cancel
Save