예제 #1
0
class BaseViewWidget(QtOpenGL.QGLWidget):
    def __init__(self, parent: Optional[QtWidgets.QWidget] = None) -> None:
        super(BaseViewWidget, self).__init__(parent)
        if hasattr(QtOpenGL.QGLFormat, 'setVersion'):
            f = QtOpenGL.QGLFormat()
            f.setVersion(3, 2)
            f.setProfile(QtOpenGL.QGLFormat.CoreProfile)
            c = QtOpenGL.QGLContext(f)
            QtOpenGL.QGLWidget.__init__(self, c, parent)
        else:
            QtOpenGL.QGLWidget.__init__(self, parent)

        self.__gl_initialized = False

        self.viewState = ViewPort(self.width(), self.height())
        self.viewState.changed.connect(self.update)

        self.lastPoint = QtCore.QPoint(0, 0)
        # Nav Handling
        self.active_drag = None

        self.mouse_wheel_emu = None

        self.action_log_cb: 'Optional[Callable[[VarArg(Any)], None]]' = None
        self.interactionDelegate = None
        self.setMouseTracking(True)

        # TODO refine type
        self.selectionList: Set[Any] = set()

        self.open_time = time.time()

        # OpenGL shared resources object. Initialized during initializeGL
        self.gls = GLShared()

        #
        self.local_actions_map = {
            (EventID.Mouse_B2_DragStart, Modifier(0)): EVT_START_FIELD_DRAG,
            (EventID.Mouse_B2, Modifier(0)): EVT_STOP_FIELD_DRAG,
        }

        self.id_actions_map = {}
        self.notify_changed_actions = []

    def internal_event(self, action_event: ToolActionEvent) -> None:
        if action_event.code == EVT_START_FIELD_DRAG:
            self.active_drag = MoveDragHandler(self.viewState, action_event.cursor_pos)
        elif action_event.code == EVT_STOP_FIELD_DRAG:
            self.active_drag = None

    def _log_action(self, *args: Any) -> None:
        if self.action_log_cb is not None:
            self.action_log_cb(*args)

    def dispatchActionEvent(self, point: QtCore.QPoint, event_id: int, modifiers: Modifier, amount: int = 1) -> bool:
        key = (event_id, modifiers)

        if key in self.local_actions_map:
            code = self.local_actions_map[key]
            cb = self.internal_event
            self._log_action(key, "local")

        elif key in self.id_actions_map:
            if self.interactionDelegate is None:
                self._log_action(key, "noid")
                return False

            self._log_action(key, "delegate", self.id_actions_map[key].description)
            code = self.id_actions_map[key].event_code
            cb = self.interactionDelegate.tool_event
        else:
            self._log_action(key, "unhandled")
            return False

        pt = QPoint_to_point(point)
        w_pt = self.viewState.tfV2W(pt)

        event = ToolActionEvent(code, pt, w_pt, amount)

        cb(event)
        return True

    def eventFilter(self, target: Any, qevent: QtCore.QEvent) -> bool:
        if self.interactionDelegate is None:
            return False

        if qevent.type() == QtCore.QEvent.KeyPress:
            q_key_event = cast(QtGui.QKeyEvent, qevent)
            event_id = EventID.from_key_event(q_key_event)
            modifiers = Modifier.from_qevent(qevent)

            ate_event = self.dispatchActionEvent(self.lastPoint, event_id, modifiers)
            if ate_event:
                self.update()

            return ate_event

        return False

    def setSelectionList(self, l: Optional[Sequence[Geom]]) -> None:
        old = self.selectionList
        if l is None:
            self.selectionList = set()
        else:
            self.selectionList = set(l)

        if old != self.selectionList:
            self.update()

    def setInteractionDelegate(self, ed: 'BaseToolController') -> None:
        self.selectionList = set()

        if self.interactionDelegate == ed:
            return

        if self.interactionDelegate:
            self.interactionDelegate.finalize()

        # Build a map of internal event IDs to actions on the delegate
        self.id_actions_map = {}
        for action in ed.tool_actions:
            # TODO: customized shortcuts
            for shortcut in action.default_shortcuts:
                self.id_actions_map[(shortcut.evtid, shortcut.modifiers)] = action

        for notify_changed in self.notify_changed_actions:
            notify_changed()

        self.interactionDelegate = ed
        ed.initialize()

        # If we have an overlay, GLinit it only if we've initialized shared state
        # If we haven't, self.initializeGL will be called anyways before render, which will end up calling
        # overlay.initializeGL
        if ed.overlay is not None and self.gls:
            self.makeCurrent()
            ed.overlay.initializeGL(self.gls)

        self.update()

    def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
        self.lastPoint = event.pos()

        event_id = EventID.from_mouse_event(event)
        modifiers = Modifier.from_qevent(event)

        self.dispatchActionEvent(event.pos(), event_id, modifiers)

        self.update()

    def mouseMoveEvent(self, qevent: QtGui.QMouseEvent) -> None:
        self.lastPoint = qevent.pos()

        if self.active_drag:
            self.active_drag.move(QPoint_to_point(qevent.pos()))

        elif self.active_drag is None and not self.mouse_wheel_emu:
            if self.interactionDelegate is not None:

                pos = QPoint_to_point(qevent.pos())

                # TODO - revisit behaviour?
                potential_actions = []
                for (event_id, modifiers), act in self.id_actions_map.items():
                    if event_id.mouse_triggered():
                        potential_actions.append(act)

                event = MoveEvent(
                    pos,
                    self.viewState.tfV2W(pos),
                    potential_actions)

                self.interactionDelegate.mouseMoveEvent(event)

        self.update()

    def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None:
        event_id = EventID.from_mouse_event(event)
        modifiers = Modifier.from_qevent(event)

        self.dispatchActionEvent(event.pos(), event_id, modifiers)

        self.update()

    def zoom(self, step: int, around_point: Point2) -> None:
        sf = 1.1 ** step
        self.viewState.zoom_at(around_point, sf)

    def wheelEvent(self, event: QtGui.QWheelEvent) -> None:
        cpt = QPoint_to_point(event.pos())

        if not event.modifiers():
            step = event.angleDelta().y() / 120.0
            self.zoom(step, cpt)
        else:
            if self.interactionDelegate:
                step = event.angleDelta().y() / 120.0
                if step < 0:
                    step = - step
                    code = EventID.Mouse_WheelDown
                else:
                    code = EventID.Mouse_WheelUp

                w_pt = self.viewState.tfV2W(cpt)

                tool_event = ToolActionEvent(code, cpt, w_pt, step)
                self.interactionDelegate.tool_event(tool_event)


        self.update()

    def initializeGL(self) -> None:
        assert not self.__gl_initialized

        self.__gl_initialized = True

        GL.glClearColor(0, 0, 0, 1)

        self.gls.initializeGL()
        GL.glGetError()

        GL.glEnable(GL.GL_BLEND)

        # Additive Blending
        GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE)

        self.reinit()

        if self.interactionDelegate is not None and self.interactionDelegate.overlay is not None:
            self.interactionDelegate.overlay.initializeGL(self.gls)
            pass

    def reinit(self) -> None:
        pass

    def paintGL(self) -> None:
        if not self.__gl_initialized:
            self.initializeGL()

        GL.glClear(GL.GL_COLOR_BUFFER_BIT, GL.GL_DEPTH_BUFFER_BIT)

        self.render()

    def render_tool(self) -> None:
        if self.interactionDelegate and self.interactionDelegate.overlay:
            self.interactionDelegate.overlay.render(self.viewState, self.compositor)

    def resizeGL(self, width: int, height: int) -> None:
        if width == 0 or height == 0:
            return

        size = max(width, height)

        GL.glViewport((width - size) // 2, (height - size) // 2, size, size)
        self.viewState.resize(width, height)

    def isModified(self) -> bool:
        return self.modified
예제 #2
0
class BaseViewWidget(QtOpenGL.QGLWidget):
    def __init__(self, parent=None):
        if hasattr(QtOpenGL.QGLFormat, 'setVersion'):
            f = QtOpenGL.QGLFormat();
            f.setVersion(3, 2)
            f.setProfile(QtOpenGL.QGLFormat.CoreProfile)
            c = QtOpenGL.QGLContext(f)
            QtOpenGL.QGLWidget.__init__(self, c, parent)
        else:
            QtOpenGL.QGLWidget.__init__(self, parent)

        self.viewState = ViewState(self.width(), self.height())

        self.viewState.changed.connect(self.update)

        # Nav Handling
        self.move_dragging = False
        self.move_dragged = False
        self.mwemu = False
        self.lastPoint = None

        self.interactionDelegate = None
        self.setMouseTracking(True)

        self.selectionList = set()

        self.open_time = time.time()

        # OpenGL shared resources object. Initialized during initializeGL
        self.gls = GLShared()



    def eventFilter(self, target, event):
        if self.interactionDelegate is None:
            return False

        if event.type() == QtCore.QEvent.KeyRelease:
            s = self.interactionDelegate.keyReleaseEvent(event)
            self.update()
            return s

        if event.type() == QtCore.QEvent.KeyPress:
            s = self.interactionDelegate.keyPressEvent(event)
            self.update()
            return s

        return False


    def setSelectionList(self, l):
        old = self.selectionList
        if l is None:
            self.selectionList = set()
        else:
            self.selectionList = set(l)

        if old != self.selectionList:
            self.update()

    def setInteractionDelegate(self, ed):
        """

        :param ed:
        :type ed: pcbre.ui.tools.basetool.BaseToolController
        """
        self.selectionList = set()

        if self.interactionDelegate == ed:
            return

        if self.interactionDelegate:
            self.interactionDelegate.changed.disconnect(self.update)
            self.interactionDelegate.finalize()

        self.interactionDelegate = ed
        ed.changed.connect(self.update)
        ed.initialize()

        # If we have an overlay, GLinit it only if we've initialized shared state
        # If we haven't, self.initializeGL will be called anyways before render, which will end up calling
        # overlay.initializeGL
        if ed.overlay is not None and self.gls:
            self.makeCurrent()
            ed.overlay.initializeGL(self.gls)

        self.update()

    def mousePressEvent(self, event):
        self.lastPoint = event.pos()
        self.move_dragged = False


        if event.button() == MOVE_MOUSE_BUTTON:
            self.move_dragging = True
            return
        elif event.button() == QtCore.Qt.MiddleButton:
            self.mwemu = True
            return
        elif not self.move_dragging and not self.mwemu:
            if self.interactionDelegate is not None:
                self.interactionDelegate.mousePressEvent(event)

        self.update()

    def mouseMoveEvent(self, event):
        if self.lastPoint is None:
            self.lastPoint = event.pos()
            return

        delta_px = event.pos() - self.lastPoint
        lastpoint_real = self.viewState.tfV2P(Point2(self.lastPoint))
        newpoint_real = self.viewState.tfV2P(Point2(event.pos()))
        lx,ly = lastpoint_real
        nx,ny = newpoint_real
        delta = nx-lx, ny-ly

        self.lastPoint = event.pos()

        needs_update = False
        if (event.buttons() & MOVE_MOUSE_BUTTON) and self.move_dragging:
            self.move_dragged = True

            self.viewState.transform = M.translate(*delta).dot(self.viewState.transform)
            needs_update = True

        elif (event.buttons() & QtCore.Qt.MiddleButton):
            delta = -10 * delta_px.y()

            self.wheelEvent(QtGui.QWheelEvent(event.pos(),delta, event.buttons(), event.modifiers()))
            needs_update = True
        elif not self.move_dragging and not self.mwemu:
            if self.interactionDelegate is not None:
                self.interactionDelegate.mouseMoveEvent(event)
                needs_update = True

        if needs_update:
            self.update()

    def mouseReleaseEvent(self, event):
        if event.button() == MOVE_MOUSE_BUTTON and self.move_dragging:
            self.move_dragging = False
            return

        # Middle mouse button events are mapped to mouse wheel
        elif event.button() == QtCore.Qt.MiddleButton:
            self.mwemu = False
            return

        if not self.move_dragged and not self.move_dragging and not self.mwemu:
            if self.interactionDelegate is not None:
                self.interactionDelegate.mouseReleaseEvent(event)

        self.update()


    def wheelEvent(self, event):
        """
        :param event:
        :type event: QtGui.MouseWheelEvent
        :return:
        """
        if not event.modifiers():
            step = event.delta()/120.0

            sf = 1.1 ** step
            fixed_center_dot(self.viewState, M.scale(sf), QPoint_to_pair(event.pos()))
        else:
            if self.interactionDelegate:
                self.interactionDelegate.mouseWheelEvent(event)

    def initializeGL(self):
        GL.glClearColor(0,0,0,1)

        self.gls.initializeGL()
        GL.glGetError()

        GL.glEnable(GL.GL_BLEND)

        # Additive Blending
        GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE)

        self.reinit()

        if self.interactionDelegate is not None and self.interactionDelegate.overlay is not None:
            self.interactionDelegate.overlay.initializeGL(self.gls)

    def reinit(self):
        pass

    def paintGL(self):
        GL.glClear(GL.GL_COLOR_BUFFER_BIT, GL.GL_DEPTH_BUFFER_BIT)

        self.render()



    def render(self):
        if self.interactionDelegate and self.interactionDelegate.overlay:
            self.interactionDelegate.overlay.render(self.viewState)



    def resizeGL(self, width, height):
        if width == 0 or height == 0:
            return

        GL.glViewport(0, 0, width, height)
        self.viewState.resize(self.width(), self.height())

        # Allocate a new image buffer
        #self.image = NPBackedImage(self.width(), self.height())
        #super(BoardViewWidget, self).resizeEvent(event)

    def isModified(self):
        return self.modified
예제 #3
0
class BaseViewWidget(QtOpenGL.QGLWidget):
    def __init__(self, parent=None):
        if hasattr(QtOpenGL.QGLFormat, 'setVersion'):
            f = QtOpenGL.QGLFormat();
            f.setVersion(3, 2)
            f.setProfile(QtOpenGL.QGLFormat.CoreProfile)
            c = QtOpenGL.QGLContext(f)
            QtOpenGL.QGLWidget.__init__(self, c, parent)
        else:
            QtOpenGL.QGLWidget.__init__(self, parent)

        self.viewState = ViewState(self.width(), self.height())

        self.viewState.changed.connect(self.update)

        # Nav Handling
        self.move_dragging = False
        self.move_dragged = False
        self.mwemu = False
        self.lastPoint = None

        self.interactionDelegate = None
        self.setMouseTracking(True)

        self.selectionList = set()

        self.open_time = time.time()

        # OpenGL shared resources object. Initialized during initializeGL
        self.gls = GLShared()



    def eventFilter(self, target, event):
        if self.interactionDelegate is None:
            return False

        if event.type() == QtCore.QEvent.KeyRelease:
            s = self.interactionDelegate.keyReleaseEvent(event)
            self.update()
            return s

        if event.type() == QtCore.QEvent.KeyPress:
            s = self.interactionDelegate.keyPressEvent(event)
            self.update()
            return s

        return False


    def setSelectionList(self, l):
        old = self.selectionList
        if l is None:
            self.selectionList = set()
        else:
            self.selectionList = set(l)

        if old != self.selectionList:
            self.update()

    def setInteractionDelegate(self, ed):
        """

        :param ed:
        :type ed: pcbre.ui.tools.basetool.BaseToolController
        """
        self.selectionList = set()

        if self.interactionDelegate == ed:
            return

        if self.interactionDelegate:
            self.interactionDelegate.changed.disconnect(self.update)
            self.interactionDelegate.finalize()

        self.interactionDelegate = ed
        ed.changed.connect(self.update)
        ed.initialize()

        # If we have an overlay, GLinit it only if we've initialized shared state
        # If we haven't, self.initializeGL will be called anyways before render, which will end up calling
        # overlay.initializeGL
        if ed.overlay is not None and self.gls:
            self.makeCurrent()
            ed.overlay.initializeGL(self.gls)

        self.update()

    def mousePressEvent(self, event):
        self.lastPoint = event.pos()
        self.move_dragged = False


        if event.button() == MOVE_MOUSE_BUTTON:
            self.move_dragging = True
            return
        elif event.button() == QtCore.Qt.MiddleButton:
            self.mwemu = True
            return
        elif not self.move_dragging and not self.mwemu:
            if self.interactionDelegate is not None:
                self.interactionDelegate.mousePressEvent(event)

        self.update()

    def mouseMoveEvent(self, event):
        if self.lastPoint is None:
            self.lastPoint = event.pos()
            return

        delta_px = event.pos() - self.lastPoint
        lastpoint_real = self.viewState.tfV2P(Point2(self.lastPoint))
        newpoint_real = self.viewState.tfV2P(Point2(event.pos()))
        lx,ly = lastpoint_real
        nx,ny = newpoint_real
        delta = nx-lx, ny-ly

        self.lastPoint = event.pos()

        needs_update = False
        if (event.buttons() & MOVE_MOUSE_BUTTON) and self.move_dragging:
            self.move_dragged = True

            self.viewState.transform = M.translate(*delta).dot(self.viewState.transform)
            needs_update = True

        elif (event.buttons() & QtCore.Qt.MiddleButton):
            delta = -10 * delta_px.y()

            self.wheelEvent(QtGui.QWheelEvent(event.pos(),delta, event.buttons(), event.modifiers()))
            needs_update = True
        elif not self.move_dragging and not self.mwemu:
            if self.interactionDelegate is not None:
                self.interactionDelegate.mouseMoveEvent(event)
                needs_update = True

        if needs_update:
            self.update()

    def mouseReleaseEvent(self, event):
        if event.button() == MOVE_MOUSE_BUTTON and self.move_dragging:
            self.move_dragging = False
            return

        # Middle mouse button events are mapped to mouse wheel
        elif event.button() == QtCore.Qt.MiddleButton:
            self.mwemu = False
            return

        if not self.move_dragged and not self.move_dragging and not self.mwemu:
            if self.interactionDelegate is not None:
                self.interactionDelegate.mouseReleaseEvent(event)

        self.update()


    def wheelEvent(self, event):
        """
        :param event:
        :type event: QtGui.MouseWheelEvent
        :return:
        """
        if not event.modifiers():
            step = event.delta()/120.0

            sf = 1.1 ** step
            fixed_center_dot(self.viewState, M.scale(sf), QPoint_to_pair(event.pos()))
        else:
            if self.interactionDelegate:
                self.interactionDelegate.mouseWheelEvent(event)

    def initializeGL(self):
        GL.glClearColor(0,0,0,1)

        self.gls.initializeGL()
        GL.glGetError()

        GL.glEnable(GL.GL_BLEND)

        # Additive Blending
        GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE)

        self.reinit()

        if self.interactionDelegate is not None and self.interactionDelegate.overlay is not None:
            self.interactionDelegate.overlay.initializeGL(self.gls)

    def reinit(self):
        pass

    def paintGL(self):
        GL.glClear(GL.GL_COLOR_BUFFER_BIT, GL.GL_DEPTH_BUFFER_BIT)

        self.render()



    def render(self):
        if self.interactionDelegate and self.interactionDelegate.overlay:
            self.interactionDelegate.overlay.render(self.viewState)



    def resizeGL(self, width, height):
        if width == 0 or height == 0:
            return

        GL.glViewport(0, 0, width, height)
        self.viewState.resize(self.width(), self.height())

        # Allocate a new image buffer
        #self.image = NPBackedImage(self.width(), self.height())
        #super(BoardViewWidget, self).resizeEvent(event)

    def isModified(self):
        return self.modified