|
|
|
@@ -1,326 +0,0 @@ |
|
|
|
#!/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, QPointF, QRectF, QSize |
|
|
|
from PyQt5.QtGui import QPainter |
|
|
|
from PyQt5.QtOpenGL import QGLFramebufferObject, QGLFramebufferObjectFormat |
|
|
|
from PyQt5.QtWidgets import QApplication, QEvent, QGraphicsItem, QGraphicsScene |
|
|
|
else: |
|
|
|
from PyQt4.QtCore import pyqtSignal, pyqtSlot, qRound, Qt, QEvent, QObject, QPoint, QPointF, QRectF, QSize |
|
|
|
from PyQt4.QtOpenGL import QGLFramebufferObject, QGLFramebufferObjectFormat |
|
|
|
from PyQt4.QtGui import QApplication, QPainter, QGraphicsItem, 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 |
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------------------------------------ |
|
|
|
# PatchScene compatible class |
|
|
|
|
|
|
|
# object types |
|
|
|
CanvasBoxType = QGraphicsItem.UserType + 1 |
|
|
|
CanvasIconType = QGraphicsItem.UserType + 2 |
|
|
|
CanvasPortType = QGraphicsItem.UserType + 3 |
|
|
|
CanvasLineType = QGraphicsItem.UserType + 4 |
|
|
|
CanvasBezierLineType = QGraphicsItem.UserType + 5 |
|
|
|
CanvasLineMovType = QGraphicsItem.UserType + 6 |
|
|
|
CanvasBezierLineMovType = QGraphicsItem.UserType + 7 |
|
|
|
|
|
|
|
class PatchScene3D(QGraphicsEmbedScene): |
|
|
|
scaleChanged = pyqtSignal(float) |
|
|
|
sceneGroupMoved = pyqtSignal(int, int, QPointF) |
|
|
|
pluginSelected = pyqtSignal(list) |
|
|
|
|
|
|
|
def __init__(self, parent, view): |
|
|
|
QGraphicsEmbedScene.__init__(self, parent) |
|
|
|
|
|
|
|
self.m_ctrl_down = False |
|
|
|
self.m_mouse_down_init = False |
|
|
|
self.m_mouse_rubberband = False |
|
|
|
|
|
|
|
self.addRubberBand() |
|
|
|
|
|
|
|
self.m_view = view |
|
|
|
#if not self.m_view: |
|
|
|
#qFatal("PatchCanvas::PatchScene() - invalid view") |
|
|
|
|
|
|
|
self.selectionChanged.connect(self.slot_selectionChanged) |
|
|
|
|
|
|
|
def addRubberBand(self): |
|
|
|
self.m_rubberband = self.addRect(QRectF(0, 0, 0, 0)) |
|
|
|
self.m_rubberband.setZValue(-1) |
|
|
|
self.m_rubberband.hide() |
|
|
|
self.m_rubberband_selection = False |
|
|
|
self.m_rubberband_orig_point = QPointF(0, 0) |
|
|
|
|
|
|
|
def clear(self): |
|
|
|
QGraphicsEmbedScene.clear(self) |
|
|
|
|
|
|
|
# Re-add rubberband, that just got deleted |
|
|
|
self.addRubberBand() |
|
|
|
|
|
|
|
def fixScaleFactor(self): |
|
|
|
pass |
|
|
|
|
|
|
|
def updateTheme(self): |
|
|
|
pass |
|
|
|
|
|
|
|
def zoom_fit(self): |
|
|
|
pass |
|
|
|
|
|
|
|
def zoom_in(self): |
|
|
|
pass |
|
|
|
|
|
|
|
def zoom_out(self): |
|
|
|
pass |
|
|
|
|
|
|
|
def zoom_reset(self): |
|
|
|
pass |
|
|
|
|
|
|
|
@pyqtSlot() |
|
|
|
def slot_selectionChanged(self): |
|
|
|
items_list = self.selectedItems() |
|
|
|
|
|
|
|
if len(items_list) == 0: |
|
|
|
self.pluginSelected.emit([]) |
|
|
|
return |
|
|
|
|
|
|
|
plugin_list = [] |
|
|
|
|
|
|
|
for item in items_list: |
|
|
|
if item and item.isVisible(): |
|
|
|
group_item = None |
|
|
|
|
|
|
|
if item.type() == CanvasBoxType: |
|
|
|
group_item = item |
|
|
|
elif item.type() == CanvasPortType: |
|
|
|
group_item = item.parentItem() |
|
|
|
#elif item.type() in (CanvasLineType, CanvasBezierLineType, CanvasLineMovType, CanvasBezierLineMovType): |
|
|
|
#plugin_list = [] |
|
|
|
#break |
|
|
|
|
|
|
|
if group_item is not None and group_item.m_plugin_id >= 0: |
|
|
|
plugin_list.append(group_item.m_plugin_id) |
|
|
|
|
|
|
|
self.pluginSelected.emit(plugin_list) |