mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-05-01 03:07:46 +02:00
210 lines
6.4 KiB
Python
Executable file
210 lines
6.4 KiB
Python
Executable file
from PySide2.QtCore import Signal, Property, QPointF, Qt, QObject
|
|
from PySide2.QtGui import QPainterPath, QVector2D
|
|
from PySide2.QtQuick import QQuickItem
|
|
|
|
|
|
class MouseEvent(QObject):
|
|
"""
|
|
Simple MouseEvent object, since QQuickMouseEvent is not accessible in the public API
|
|
"""
|
|
def __init__(self, evt):
|
|
super(MouseEvent, self).__init__()
|
|
self._x = evt.x()
|
|
self._y = evt.y()
|
|
self._button = evt.button()
|
|
|
|
x = Property(float, lambda self: self._x, constant=True)
|
|
y = Property(float, lambda self: self._y, constant=True)
|
|
button = Property(Qt.MouseButton, lambda self: self._button, constant=True)
|
|
|
|
|
|
class EdgeMouseArea(QQuickItem):
|
|
"""
|
|
Provides a MouseArea shaped as a cubic spline for mouse interaction with edges.
|
|
|
|
Note: for performance reason, shape is updated only when geometry changes since this is the main use-case with edges.
|
|
TODOs:
|
|
- update when start/end points change too
|
|
- review this when using new QML Shape module
|
|
"""
|
|
def __init__(self, parent=None):
|
|
super(EdgeMouseArea, self).__init__(parent)
|
|
|
|
self._viewScale = 1.0
|
|
self._startX = 0.0
|
|
self._startY = 0.0
|
|
self._endX = 0.0
|
|
self._endY = 0.0
|
|
self._curveScale = 0.7
|
|
self._edgeThickness = 1.0
|
|
self._hullThickness = 2.0
|
|
self._containsMouse = False
|
|
self._path = None # type: QPainterPath
|
|
|
|
self.setAcceptHoverEvents(True)
|
|
self.setAcceptedMouseButtons(Qt.AllButtons)
|
|
|
|
def contains(self, point):
|
|
return self._path.contains(point)
|
|
|
|
def hoverEnterEvent(self, evt):
|
|
self.setContainsMouse(True)
|
|
super(EdgeMouseArea, self).hoverEnterEvent(evt)
|
|
|
|
def hoverLeaveEvent(self, evt):
|
|
self.setContainsMouse(False)
|
|
super(EdgeMouseArea, self).hoverLeaveEvent(evt)
|
|
|
|
def geometryChanged(self, newGeometry, oldGeometry):
|
|
super(EdgeMouseArea, self).geometryChanged(newGeometry, oldGeometry)
|
|
self.updateShape()
|
|
|
|
def mousePressEvent(self, evt):
|
|
if not self.acceptedMouseButtons() & evt.button():
|
|
evt.setAccepted(False)
|
|
return
|
|
e = MouseEvent(evt)
|
|
self.pressed.emit(e)
|
|
e.deleteLater()
|
|
|
|
def mouseReleaseEvent(self, evt):
|
|
e = MouseEvent(evt)
|
|
self.released.emit(e)
|
|
e.deleteLater()
|
|
|
|
def updateShape(self):
|
|
p1 = QPointF(self._startX, self._startY)
|
|
p2 = QPointF(self._endX, self._endY)
|
|
ctrlPt = QPointF(self.ctrlPtDist, 0)
|
|
path = QPainterPath(p1)
|
|
path.cubicTo(p1 + ctrlPt, p2 - ctrlPt, p2)
|
|
|
|
# Compute offset on x and y axis
|
|
hullOffset = self._edgeThickness * self._viewScale + self._hullThickness
|
|
v = QVector2D(p2 - p1).normalized()
|
|
offset = QPointF(hullOffset * -v.y(), hullOffset * v.x())
|
|
|
|
self._path = QPainterPath(path.toReversed())
|
|
self._path.translate(-offset)
|
|
path.translate(offset)
|
|
self._path.connectPath(path)
|
|
|
|
@property
|
|
def thickness(self):
|
|
return self._hullThickness
|
|
|
|
@thickness.setter
|
|
def thickness(self, value):
|
|
if self._hullThickness == value:
|
|
return
|
|
self._hullThickness = value
|
|
self.thicknessChanged.emit()
|
|
|
|
@property
|
|
def edgeThickness(self):
|
|
return self._edgeThickness
|
|
|
|
@edgeThickness.setter
|
|
def edgeThickness(self, value):
|
|
if self._edgeThickness == value:
|
|
return
|
|
self._edgeThickness = value
|
|
self.thicknessChanged.emit()
|
|
|
|
@property
|
|
def viewScale(self):
|
|
return self._viewScale
|
|
|
|
@viewScale.setter
|
|
def viewScale(self, value):
|
|
if self.viewScale == value:
|
|
return
|
|
self._viewScale = value
|
|
self.viewScaleChanged.emit()
|
|
|
|
@property
|
|
def startX(self):
|
|
return self._startX
|
|
|
|
@startX.setter
|
|
def startX(self, value):
|
|
self._startX = value
|
|
self.startXChanged.emit()
|
|
|
|
@property
|
|
def startY(self):
|
|
return self._startY
|
|
|
|
@startY.setter
|
|
def startY(self, value):
|
|
self._startY = value
|
|
self.startYChanged.emit()
|
|
|
|
@property
|
|
def endX(self):
|
|
return self._endX
|
|
|
|
@endX.setter
|
|
def endX(self, value):
|
|
self._endX = value
|
|
self.endXChanged.emit()
|
|
|
|
@property
|
|
def endY(self):
|
|
return self._endY
|
|
|
|
@endY.setter
|
|
def endY(self, value):
|
|
self._endY = value
|
|
self.endYChanged.emit()
|
|
|
|
@property
|
|
def curveScale(self):
|
|
return self._curveScale
|
|
|
|
@curveScale.setter
|
|
def curveScale(self, value):
|
|
self._curveScale = value
|
|
self.curveScaleChanged.emit()
|
|
self.updateShape()
|
|
|
|
@property
|
|
def ctrlPtDist(self):
|
|
return self.width() * self.curveScale * (-1 if self._startX > self._endX else 1)
|
|
|
|
@property
|
|
def containsMouse(self):
|
|
return self._containsMouse
|
|
|
|
def setContainsMouse(self, value):
|
|
if self._containsMouse == value:
|
|
return
|
|
self._containsMouse = value
|
|
self.containsMouseChanged.emit()
|
|
|
|
thicknessChanged = Signal()
|
|
thickness = Property(float, thickness.fget, thickness.fset, notify=thicknessChanged)
|
|
edgeThicknessChanged = Signal()
|
|
edgeThickness = Property(float, edgeThickness.fget, edgeThickness.fset, notify=edgeThicknessChanged)
|
|
viewScaleChanged = Signal()
|
|
viewScale = Property(float, viewScale.fget, viewScale.fset, notify=viewScaleChanged)
|
|
startXChanged = Signal()
|
|
startX = Property(float, startX.fget, startX.fset, notify=startXChanged)
|
|
startYChanged = Signal()
|
|
startY = Property(float, startY.fget, startY.fset, notify=startYChanged)
|
|
endXChanged = Signal()
|
|
endX = Property(float, endX.fget, endX.fset, notify=endXChanged)
|
|
endYChanged = Signal()
|
|
endY = Property(float, endY.fget, endY.fset, notify=endYChanged)
|
|
curveScaleChanged = Signal()
|
|
curveScale = Property(float, curveScale.fget, curveScale.fset, notify=curveScaleChanged)
|
|
ctrlPtDistChanged = Signal()
|
|
ctrlPtDist = Property(float, ctrlPtDist.fget, notify=ctrlPtDist)
|
|
containsMouseChanged = Signal()
|
|
containsMouse = Property(float, containsMouse.fget, notify=containsMouseChanged)
|
|
acceptedButtons = Property(int,
|
|
lambda self: super(EdgeMouseArea, self).acceptedMouseButtons,
|
|
lambda self, value: super(EdgeMouseArea, self).setAcceptedMouseButtons(value))
|
|
|
|
pressed = Signal(MouseEvent)
|
|
released = Signal(MouseEvent)
|