def __init__(self, signals, def_pixmap=None, parent=None): super().__init__(parent) self.signals = signals self.pre = "CanvasWidget : " self.painter = QtGui.QPainter() self.def_pixmap = def_pixmap self.pixmap = self.def_pixmap self.mouse_click_ctx = MouseClickContext(self.mouseGestureHandler, t_double_click=0) self.initVars()
def __init__(self, parent=None, mouse_gesture_handler=lambda e: None): super().__init__(parent) # self.setStyleSheet("background-color: dark-blue") # self.setStyleSheet("background-color: rgba(0,0,0,0)"); # self.setStyleSheet("border: 1px solid gray; border-radius: 10px; margin: 0px; padding: 0px; background: white;") self.setStyleSheet(style.video_widget) self.setAutoFillBackground(True) self.setAcceptDrops(True) self.signals = VideoContainer.Signals() self.device = None """ pal = QtGui.QPalette() pal.setColor(QtGui.QPalette.Background, QtCore.Qt.black); self.setPalette(pal); """ self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.mouse_click_ctx = MouseClickContext(mouse_gesture_handler)
def __init__(self, parent=None, mouse_gesture_handler=lambda e: None): super().__init__(parent) # qtwidget must have focus to receive keyboard events # however, i don't see code in the other widgets that set focus... why is it needed here? self.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) # self.setStyleSheet("background-color: dark-blue") # self.setStyleSheet("background-color: rgba(0,0,0,0)"); # self.setStyleSheet("border: 1px solid gray; border-radius: 10px; margin: 0px; padding: 0px; background: white;") self.setStyleSheet(style.video_widget) self.setAutoFillBackground(True) self.setAcceptDrops(True) self.signals = VideoContainer.Signals() self.device = None """ pal = QtGui.QPalette() pal.setColor(QtGui.QPalette.Background, QtCore.Qt.black); self.setPalette(pal); """ self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.mouse_click_ctx = MouseClickContext(mouse_gesture_handler)
class VideoWidget(QtWidgets.QFrame): """The video appears here. Must handle drag'n'drop of camera info. Or choosing camera from a pop-up menu. """ def __init__(self, parent=None, mouse_gesture_handler=lambda e: None): super().__init__(parent) # qtwidget must have focus to receive keyboard events # however, i don't see code in the other widgets that set focus... why is it needed here? self.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) # self.setStyleSheet("background-color: dark-blue") # self.setStyleSheet("background-color: rgba(0,0,0,0)"); # self.setStyleSheet("border: 1px solid gray; border-radius: 10px; margin: 0px; padding: 0px; background: white;") self.setStyleSheet(style.video_widget) self.setAutoFillBackground(True) self.setAcceptDrops(True) self.signals = VideoContainer.Signals() self.device = None """ pal = QtGui.QPalette() pal.setColor(QtGui.QPalette.Background, QtCore.Qt.black); self.setPalette(pal); """ self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.mouse_click_ctx = MouseClickContext(mouse_gesture_handler) # TODO: how we communicate, say, a double-click, to the higher-level widget # VideoContainer .. give it a callback that hides/shows all other # widgets .. (stream decoding should be paused as well if needed) def setDevice(self, device): self.device = device def dragEnterEvent(self, e): print("VideoWidget: dragEnterEvent") e.accept() def dropEvent(self, e): print("VideoWidget: dropEvent") # print("VideoWidget: drop event to i,j=",self.row_index,self.column_index) formlist = e.mimeData().formats() if ("application/octet-stream" in formlist): device = pickle.loads( e.mimeData().data("application/octet-stream").data()) print("VideoWidget: got: ", device) # device.RTSPCameraDevice self.signals.drop.emit(device) e.accept() else: e.ignore() # if ptz is enabled, this will stop ptz movement def keyReleaseEvent(self, e): ## TODO: ONVIF: stuff moved into valkka.live.onvif.thread if (e.key() == QtCore.Qt.Key_Left): # print("VideoWidget: left arrow released") ##self.ptz_service.ws_client.Stop(ProfileToken=token) ## ONVIF: TODO: do like this: """ if self.onvif_thread: self.onvif_thread.signals.command.emit(["stop", {}]) """ pass if (e.key() == QtCore.Qt.Key_Right): # print("VideoWidget: right arrow released") pass if (e.key() == QtCore.Qt.Key_Down): # print("VideoWidget: down arrow released") pass if (e.key() == QtCore.Qt.Key_Up): # print("VideoWidget: up arrow released") pass # if ptz is enabled, this will start ptz movement def keyPressEvent(self, e): # this is gross, but hacked in here to get things working # would like to factor this better later ## TODO: ONVIF: stuff moved into valkka.live.onvif.thread if (e.key() == QtCore.Qt.Key_Left): #print("VideoWidget: left arrow pressed") pass if (e.key() == QtCore.Qt.Key_Right): # print("VideoWidget: right arrow pressed") pass if (e.key() == QtCore.Qt.Key_Down): #print("VideoWidget: down arrow pressed") pass if (e.key() == QtCore.Qt.Key_Up): # print("VideoWidget: up arrow pressed") pass def mousePressEvent(self, e): print("VideoWidget: mousePress") self.mouse_click_ctx.atPressEvent(e) super().mousePressEvent(e) def mouseMoveEvent(self, e): if not (e.buttons() & QtCore.Qt.LeftButton): return leni = (e.pos() - self.mouse_click_ctx.info.pos).manhattanLength() if (leni < QtWidgets.QApplication.startDragDistance()): return drag = QtGui.QDrag(self) mimeData = QtCore.QMimeData() mimeData.setData("application/octet-stream", pickle.dumps(self.device) # pickle.dumps(None) ) drag.setMimeData(mimeData) dropAction = drag.exec_(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction) def mouseReleaseEvent(self, e): self.mouse_click_ctx.atReleaseEvent(e) super().mouseReleaseEvent(e)
class VideoWidget(QtWidgets.QFrame): """The video appears here. Must handle drag'n'drop of camera info. Or choosing camera from a pop-up menu. """ def __init__(self, parent=None, mouse_gesture_handler=lambda e: None): super().__init__(parent) # self.setStyleSheet("background-color: dark-blue") # self.setStyleSheet("background-color: rgba(0,0,0,0)"); # self.setStyleSheet("border: 1px solid gray; border-radius: 10px; margin: 0px; padding: 0px; background: white;") self.setStyleSheet(style.video_widget) self.setAutoFillBackground(True) self.setAcceptDrops(True) self.signals = VideoContainer.Signals() self.device = None """ pal = QtGui.QPalette() pal.setColor(QtGui.QPalette.Background, QtCore.Qt.black); self.setPalette(pal); """ self.setSizePolicy( QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.mouse_click_ctx = MouseClickContext(mouse_gesture_handler) # TODO: how we communicate, say, a double-click, to the higher-level widget # VideoContainer .. give it a callback that hides/shows all other # widgets .. (stream decoding should be paused as well if needed) def setDevice(self, device): self.device = device def dragEnterEvent(self, e): print("VideoWidget: dragEnterEvent") e.accept() def dropEvent(self, e): print("VideoWidget: dropEvent") # print("VideoWidget: drop event to i,j=",self.row_index,self.column_index) formlist = e.mimeData().formats() if ("application/octet-stream" in formlist): device = pickle.loads( e.mimeData().data("application/octet-stream").data()) print("VideoWidget: got: ", device) # DataModel.RTSPCameraDevice self.signals.drop.emit(device) e.accept() else: e.ignore() def mousePressEvent(self, e): print("VideoWidget: mousePress") self.mouse_click_ctx.atPressEvent(e) super().mousePressEvent(e) def mouseMoveEvent(self, e): if not (e.buttons() & QtCore.Qt.LeftButton): return leni = ( e.pos() - self.mouse_click_ctx.info.pos ).manhattanLength() if (leni < QtWidgets.QApplication.startDragDistance()): return drag = QtGui.QDrag(self) mimeData = QtCore.QMimeData() mimeData.setData("application/octet-stream", pickle.dumps(self.device) # pickle.dumps(None) ) drag.setMimeData(mimeData) dropAction = drag.exec_(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction) def mouseReleaseEvent(self, e): self.mouse_click_ctx.atReleaseEvent(e) super().mouseReleaseEvent(e)
class CanvasWidget(QtWidgets.QWidget): def __init__(self, signals, def_pixmap=None, parent=None): super().__init__(parent) self.signals = signals self.pre = "CanvasWidget : " self.painter = QtGui.QPainter() self.def_pixmap = def_pixmap self.pixmap = self.def_pixmap self.mouse_click_ctx = MouseClickContext(self.mouseGestureHandler, t_double_click=0) self.initVars() def initVars(self): pass def parametersToMvision(self) -> dict: """Internal parameters of this analyzer widget to something that\ is understood by the associated machine vision process Must use json-seriazable objects """ return {"some": "parameters"} def mvisionToParameters(self, dic: dict): """Inverse of parametersToMVision """ pass def closeEvent(self, e): print("CanvasWidget: close event") self.pixmap = self.def_pixmap e.accept() print("CanvasWidget: close event exit") # pixmap that was sent here through the signal/slot system # gets garbage-collected def paintEvent(self, e): # http://zetcode.com/gui/pyqt5/painting/ self.painter.begin(self) self.drawWidget(self.painter) self.painter.end() e.accept() def drawWidget(self, qp): if self.pixmap is None: # print("no pixmap") return qp.drawPixmap(0, 0, self.width(), self.height(), self.pixmap) def mousePressEvent(self, e): # print("VideoWidget: mousePress") self.mouse_click_ctx.atPressEvent(e) # super().mousePressEvent(e) # why this? e.accept() def mouseMoveEvent(self, e): self.handle_move(e) return """ if not (e.buttons() & QtCore.Qt.LeftButton): return leni = ( e.pos() - self.mouse_click_ctx.info.pos ).manhattanLength() if (leni < QtWidgets.QApplication.startDragDistance()): return """ """ drag = QtGui.QDrag(self) mimeData = QtCore.QMimeData() mimeData.setData("application/octet-stream", pickle.dumps(self.device) # pickle.dumps(None) ) drag.setMimeData(mimeData) dropAction = drag.exec_(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction) """ def mouseReleaseEvent(self, e): self.mouse_click_ctx.atReleaseEvent(e) # super().mouseReleaseEvent(e) e.accept() def mouseGestureHandler(self, info): """This is the callback for MouseClickContext. Passed to VideoWidget as a parameter """ verbose = False if verbose: print(self.pre, ": mouseGestureHandler: ") # *** single click events *** if (info.fsingle): if verbose: print(self.pre, ": mouseGestureHandler: single click") if (info.button == QtCore.Qt.LeftButton): if verbose: print(self.pre, ": mouseGestureHandler: Left button clicked") self.handle_left_single_click(info) elif (info.button == QtCore.Qt.RightButton): if verbose: print(self.pre, ": mouseGestureHandler: Right button clicked") self.handle_right_single_click(info) # *** double click events *** elif (info.fdouble): if (info.button == QtCore.Qt.LeftButton): if verbose: print(self.pre, ": mouseGestureHandler: Left button double-clicked") self.handle_left_double_click(info) elif (info.button == QtCore.Qt.RightButton): if verbose: print( self.pre, ": mouseGestureHandler: Right button double-clicked") self.handle_right_double_click(info) def setTracking(self): self.setMouseTracking(True) def unSetTracking(self): self.setMouseTracking(False) def handle_move(self, info): # print("handle_move") pass def handle_left_single_click(self, info): pass def handle_right_single_click(self, info): pass def handle_left_double_click(self, info): pass def handle_right_double_click(self, info): pass # *** slots *** def set_pixmap_slot(self, pixmap): self.pixmap = pixmap self.repaint() def set_image_slot(self, img): self.pixmap = numpy2QPixmap( img) # THIS WILL CREATE A REFLEAK IN PYSIDE2 # self.pixmap = None self.repaint()
class SimpleVideoWidget(QtWidgets.QWidget): """Receives QPixMaps to a slot & draws them TODO: mouse gestures, draw lines, boxes, etc. """ class Signals(QtCore.QObject): update_analyzer_parameters = QtCore.Signal(object) def __init__(self, def_pixmap=None, parent=None): super().__init__(parent) self.signals = self.Signals() self.pre = "SimpleVideoWidget : " self.painter = QtGui.QPainter() self.pixmap = def_pixmap self.mouse_click_ctx = MouseClickContext(self.mouseGestureHandler, t_double_click=0) self.initVars() def initVars(self): pass def parametersToMvision(self) -> dict: """Internal parameters of this analyzer widget to something that\ is understood by the associated machine vision process Must use json-seriazable objects """ return {"some": "parameters"} def mvisionToParameters(self, dic: dict): """Inverse of parametersToMVision """ pass def paintEvent(self, e): # http://zetcode.com/gui/pyqt5/painting/ self.painter.begin(self) self.drawWidget(self.painter) self.painter.end() def drawWidget(self, qp): if self.pixmap is None: # print("no pixmap") return qp.drawPixmap(0, 0, self.width(), self.height(), self.pixmap) def mousePressEvent(self, e): print("VideoWidget: mousePress") self.mouse_click_ctx.atPressEvent(e) super().mousePressEvent(e) def mouseMoveEvent(self, e): self.handle_move(e) return """ if not (e.buttons() & QtCore.Qt.LeftButton): return leni = ( e.pos() - self.mouse_click_ctx.info.pos ).manhattanLength() if (leni < QtWidgets.QApplication.startDragDistance()): return """ """ drag = QtGui.QDrag(self) mimeData = QtCore.QMimeData() mimeData.setData("application/octet-stream", pickle.dumps(self.device) # pickle.dumps(None) ) drag.setMimeData(mimeData) dropAction = drag.exec_(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction) """ def mouseReleaseEvent(self, e): self.mouse_click_ctx.atReleaseEvent(e) super().mouseReleaseEvent(e) def mouseGestureHandler(self, info): """This is the callback for MouseClickContext. Passed to VideoWidget as a parameter """ print(self.pre, ": mouseGestureHandler: ") # *** single click events *** if (info.fsingle): print(self.pre, ": mouseGestureHandler: single click") if (info.button == QtCore.Qt.LeftButton): print(self.pre, ": mouseGestureHandler: Left button clicked") self.handle_left_single_click(info) elif (info.button == QtCore.Qt.RightButton): print(self.pre, ": mouseGestureHandler: Right button clicked") self.handle_right_single_click(info) # *** double click events *** elif (info.fdouble): if (info.button == QtCore.Qt.LeftButton): print(self.pre, ": mouseGestureHandler: Left button double-clicked") self.handle_left_double_click(info) elif (info.button == QtCore.Qt.RightButton): print(self.pre, ": mouseGestureHandler: Right button double-clicked") self.handle_right_double_click(info) def setTracking(self): self.setMouseTracking(True) def unSetTracking(self): self.setMouseTracking(False) def handle_move(self, info): print("handle_move") def handle_left_single_click(self, info): pass def handle_right_single_click(self, info): pass def handle_left_double_click(self, info): pass def handle_right_double_click(self, info): pass # *** slots *** def set_pixmap_slot(self, pixmap): self.pixmap = pixmap self.repaint()