예제 #1
0
class TimelineView(QGraphicsView):
    """
    This class draws a graphical representation of a timeline.

    This is ONLY the bar and colored boxes.

    When you instantiate this class, do NOT forget to call set_init_data to
    set necessary data.
    """

    paused = Signal(bool)
    position_changed = Signal(int)
    redraw = Signal()

    def __init__(self, parent=None):
        """Cannot take args other than parent due to loadUi limitation."""

        super(TimelineView, self).__init__(parent=parent)
        self._timeline_marker = QIcon.fromTheme('system-search')

        self._min = 0
        self._max = 0
        self._xpos_marker = -1

        self._timeline_marker_width = 15
        self._timeline_marker_height = 15
        self._last_marker_at = -1

        self.setUpdatesEnabled(True)
        self._scene = QGraphicsScene(self)
        self.setScene(self._scene)

        self._levels = None

        self.redraw.connect(self._signal_redraw)

    def mouseReleaseEvent(self, event):
        """
        :type event: QMouseEvent
        """
        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        """
        # Pause the timeline
        self.paused.emit(True)

        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        """
        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def pos_from_x(self, x):
        """
        Get the index in the timeline from the mouse click position

        :param x: Position relative to self widget.
        :return: Index
        """
        width = self.size().width()
        # determine value from mouse click
        width_cell = width / float(max(len(self._levels), 1))
        position = int(floor(x / width_cell))
        if position == len(self._levels) - 1:
            return -1
        return position

    @Slot(int)
    def set_marker_pos(self, xpos):
        """
        Set marker position from index

        :param xpos: Marker index
        """
        if self._levels is None:
            rospy.logwarn('Called set_marker_pos before set_levels')
            return

        if xpos == -1:
            # stick to the latest when position is -1
            self._xpos_marker = -1
            # check if we chose latest item
            if self._last_marker_at != self._xpos_marker:
                # update variable to check for change during next round
                self._last_marker_at = self._xpos_marker
                # emit change to all timeline_panes
                self.position_changed.emit(self._xpos_marker)
            self.redraw.emit()
            return

        self._xpos_marker = self._clamp(xpos, self._min, self._max)

        if self._xpos_marker == self._last_marker_at:
            # Clicked the same pos as last time.
            return
        elif self._xpos_marker >= len(self._levels):
            # When clicked out-of-region
            return

        self._last_marker_at = self._xpos_marker

        # Set timeline position. This broadcasts the message at that position
        # to all of the other viewers
        self.position_changed.emit(self._xpos_marker)
        self.redraw.emit()

    def _clamp(self, val, min, max):
        """
        Judge if val is within the range given by min & max.
        If not, return either min or max.

        :type val: any number format
        :type min: any number format
        :type max: any number format
        :rtype: int
        """
        if (val < min):
            return min
        if (val > max):
            return max
        return val

    @Slot(list)
    def set_levels(self, levels):
        self._levels = levels
        self.redraw.emit()

    @Slot()
    def _signal_redraw(self):
        """
        Gets called either when new msg comes in or when marker is moved by
        user.
        """
        if self._levels is None:
            return

        # update the limits
        self._min = 0
        self._max = len(self._levels) - 1

        self._scene.clear()

        qsize = self.size()
        width_tl = qsize.width()

        w = width_tl / float(max(len(self._levels), 1))
        is_enabled = self.isEnabled()

        for i, level in enumerate(self._levels):
            h = self.viewport().height()

            # Figure out each cell's color.
            qcolor = QColor('grey')
            if is_enabled and level is not None:
                if level > DiagnosticStatus.ERROR:
                    # Stale items should be reported as errors unless all stale
                    level = DiagnosticStatus.ERROR
                qcolor = util.level_to_color(level)
#  TODO Use this code for adding gradation to the cell color.
#                end_color = QColor(0.5 * QColor('red').value(),
#                                   0.5 * QColor('green').value(),
#                                   0.5 * QColor('blue').value())

            self._scene.addRect(w * i, 0, w, h, QColor('white'), qcolor)

        # Getting marker index.
        xpos_marker = self._xpos_marker

        # If marker is -1 for latest use (number_of_cells -1)
        if xpos_marker == -1:
            xpos_marker = len(self._levels) - 1

        # Convert get horizontal pixel value of selected cell's center
        xpos_marker_in_pixel = (xpos_marker * w + (w / 2.0) -
                                (self._timeline_marker_width / 2.0))
        pos_marker = QPointF(xpos_marker_in_pixel, 0)

        # Need to instantiate marker everytime since it gets deleted
        # in every loop by scene.clear()
        timeline_marker = self._instantiate_tl_icon()
        timeline_marker.setPos(pos_marker)
        self._scene.addItem(timeline_marker)

    def _instantiate_tl_icon(self):
        timeline_marker_icon = QIcon.fromTheme('system-search')
        timeline_marker_icon_pixmap = timeline_marker_icon.pixmap(
            self._timeline_marker_width, self._timeline_marker_height)
        return QGraphicsPixmapItem(timeline_marker_icon_pixmap)
예제 #2
0
class TimelineView(QGraphicsView):
    """
    This class draws a graphical representation of a timeline.

    This is ONLY the bar and colored boxes.

    When you instantiate this class, do NOT forget to call set_init_data to
    set necessary data.
    """

    redraw = Signal()

    def __init__(self, parent):
        """Cannot take args other than parent due to loadUi limitation."""

        super(TimelineView, self).__init__()
        self._parent = parent
        self._timeline_marker = QIcon.fromTheme('system-search')

        self._min = 0
        self._max = 0
        self._xpos_marker = 5

        self._timeline_marker_width = 15
        self._timeline_marker_height = 15
        self._last_marker_at = 2

        self.redraw.connect(self._slot_redraw)

        self._timeline = None

        self.setUpdatesEnabled(True)
        self._scene = QGraphicsScene(self)
        self.setScene(self._scene)

    def set_timeline(self, timeline, name=None):
        assert(self._timeline is None)
        self._name = name
        self._timeline = timeline
        self._timeline.message_updated.connect(self._updated)

    @Slot()
    def _updated(self):
        """
        Update the widget whenever we receive a new message
        """
        # update the limits
        self._min = 0
        self._max = len(self._timeline)-1

        # update the marker position
        self._xpos_marker = self._timeline.get_position()

        # redraw
        self.redraw.emit()

    def mouseReleaseEvent(self, event):
        """
        :type event: QMouseEvent
        """
        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        """
        assert(self._timeline is not None)
        # Pause the timeline
        self._timeline.set_paused(True)

        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        """
        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def pos_from_x(self, x):
        """
        Get the index in the timeline from the mouse click position

        :param x: Position relative to self widget.
        :return: Index
        """
        width = self.size().width()
        # determine value from mouse click
        width_cell = width / float(len(self._timeline))
        return int(floor(x / width_cell))

    def set_marker_pos(self, xpos):
        """
        Set marker position from index

        :param xpos: Marker index
        """
        assert(self._timeline is not None)
        self._xpos_marker = self._clamp(xpos, self._min, self._max)

        if self._xpos_marker == self._last_marker_at:
            # Clicked the same pos as last time.
            return
        elif self._xpos_marker >= len(self._timeline):
            # When clicked out-of-region
            return

        self._last_marker_at = self._xpos_marker

        # Set timeline position. This broadcasts the message at that position
        # to all of the other viewers
        self._timeline.set_position(self._xpos_marker)

        # redraw
        self.redraw.emit()

    def _clamp(self, val, min, max):
        """
        Judge if val is within the range given by min & max.
        If not, return either min or max.

        :type val: any number format
        :type min: any number format
        :type max: any number format
        :rtype: int
        """
        if (val < min):
            return min
        if (val > max):
            return max
        return val

    @Slot()
    def _slot_redraw(self):
        """
        Gets called either when new msg comes in or when marker is moved by
        user.
        """
        self._scene.clear()

        qsize = self.size()
        width_tl = qsize.width()

        w = width_tl / float(max(len(self._timeline), 1))
        is_enabled = self.isEnabled()

        if self._timeline is not None:
            for i, m in enumerate(self._timeline):
                h = self.viewport().height()

                # Figure out each cell's color.
                qcolor = QColor('grey')
                if is_enabled:
                    qcolor = self._get_color_for_value(m)

#  TODO Use this code for adding gradation to the cell color.
#                end_color = QColor(0.5 * QColor('red').value(),
#                                   0.5 * QColor('green').value(),
#                                   0.5 * QColor('blue').value())

                self._scene.addRect(w * i, 0, w, h, QColor('white'), qcolor)

        # Setting marker.
        xpos_marker = (self._xpos_marker * w +
                       (w / 2.0) - (self._timeline_marker_width / 2.0))
        pos_marker = QPointF(xpos_marker, 0)

        # Need to instantiate marker everytime since it gets deleted
        # in every loop by scene.clear()
        timeline_marker = self._instantiate_tl_icon()
        timeline_marker.setPos(pos_marker)
        self._scene.addItem(timeline_marker)

    def _instantiate_tl_icon(self):
        timeline_marker_icon = QIcon.fromTheme('system-search')
        timeline_marker_icon_pixmap = timeline_marker_icon.pixmap(
                                                self._timeline_marker_width,
                                                self._timeline_marker_height)
        return QGraphicsPixmapItem(timeline_marker_icon_pixmap)

    def _get_color_for_value(self, msg):
        """
        :type msg: DiagnosticArray
        """

        if self._name is not None:
            # look up name in msg; return grey if not found
            status = util.get_status_by_name(msg, self._name)
            if status is not None:
                return util.level_to_color(status.level)
            else:
                return QColor('grey')
        return util.get_color_for_message(msg)
예제 #3
0
class TimelineView(QGraphicsView):
    """
    This class draws a graphical representation of a timeline.

    This is ONLY the bar and colored boxes.

    When you instantiate this class, do NOT forget to call set_init_data to
    set necessary data.
    """

    redraw = Signal()

    def __init__(self, parent):
        """Cannot take args other than parent due to loadUi limitation."""

        super(TimelineView, self).__init__()
        self._parent = parent
        self._timeline_marker = QIcon.fromTheme('system-search')

        self._min = 0
        self._max = 0
        self._xpos_marker = 5

        self._timeline_marker_width = 15
        self._timeline_marker_height = 15
        self._last_marker_at = 2

        self.redraw.connect(self._slot_redraw)

        self._timeline = None

        self.setUpdatesEnabled(True)
        self._scene = QGraphicsScene(self)
        self.setScene(self._scene)

    def set_timeline(self, timeline, name=None):
        assert(self._timeline is None)
        self._name = name
        self._timeline = timeline
        self._timeline.message_updated.connect(self._updated)

    @Slot()
    def _updated(self):
        """
        Update the widget whenever we receive a new message
        """
        # update the limits
        self._min = 0
        self._max = len(self._timeline)-1

        # update the marker position
        self._xpos_marker = self._timeline.get_position()

        # redraw
        self.redraw.emit()

    def mouseReleaseEvent(self, event):
        """
        :type event: QMouseEvent
        """
        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        """
        assert(self._timeline is not None)
        # Pause the timeline
        self._timeline.set_paused(True)

        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        """
        xpos = self.pos_from_x(event.x())
        self.set_marker_pos(xpos)

    def pos_from_x(self, x):
        """
        Get the index in the timeline from the mouse click position

        :param x: Position relative to self widget.
        :return: Index
        """
        width = self.size().width()
        # determine value from mouse click
        width_cell = width / float(max(len(self._timeline), 1))
        return int(floor(x / width_cell))

    def set_marker_pos(self, xpos):
        """
        Set marker position from index

        :param xpos: Marker index
        """
        assert(self._timeline is not None)
        self._xpos_marker = self._clamp(xpos, self._min, self._max)

        if self._xpos_marker == self._last_marker_at:
            # Clicked the same pos as last time.
            return
        elif self._xpos_marker >= len(self._timeline):
            # When clicked out-of-region
            return

        self._last_marker_at = self._xpos_marker

        # Set timeline position. This broadcasts the message at that position
        # to all of the other viewers
        self._timeline.set_position(self._xpos_marker)

        # redraw
        self.redraw.emit()

    def _clamp(self, val, min, max):
        """
        Judge if val is within the range given by min & max.
        If not, return either min or max.

        :type val: any number format
        :type min: any number format
        :type max: any number format
        :rtype: int
        """
        if (val < min):
            return min
        if (val > max):
            return max
        return val

    @Slot()
    def _slot_redraw(self):
        """
        Gets called either when new msg comes in or when marker is moved by
        user.
        """
        self._scene.clear()

        qsize = self.size()
        width_tl = qsize.width()

        w = width_tl / float(max(len(self._timeline), 1))
        is_enabled = self.isEnabled()

        if self._timeline is not None:
            for i, m in enumerate(self._timeline):
                h = self.viewport().height()

                # Figure out each cell's color.
                qcolor = QColor('grey')
                if is_enabled:
                    qcolor = self._get_color_for_value(m)

#  TODO Use this code for adding gradation to the cell color.
#                end_color = QColor(0.5 * QColor('red').value(),
#                                   0.5 * QColor('green').value(),
#                                   0.5 * QColor('blue').value())

                self._scene.addRect(w * i, 0, w, h, QColor('white'), qcolor)

        # Setting marker.
        xpos_marker = (self._xpos_marker * w +
                       (w / 2.0) - (self._timeline_marker_width / 2.0))
        pos_marker = QPointF(xpos_marker, 0)

        # Need to instantiate marker everytime since it gets deleted
        # in every loop by scene.clear()
        timeline_marker = self._instantiate_tl_icon()
        timeline_marker.setPos(pos_marker)
        self._scene.addItem(timeline_marker)

    def _instantiate_tl_icon(self):
        timeline_marker_icon = QIcon.fromTheme('system-search')
        timeline_marker_icon_pixmap = timeline_marker_icon.pixmap(
                                                self._timeline_marker_width,
                                                self._timeline_marker_height)
        return QGraphicsPixmapItem(timeline_marker_icon_pixmap)

    def _get_color_for_value(self, msg):
        """
        :type msg: DiagnosticArray
        """

        if self._name is not None:
            # look up name in msg; return grey if not found
            status = util.get_status_by_name(msg, self._name)
            if status is not None:
                return util.level_to_color(status.level)
            else:
                return QColor('grey')
        return util.get_color_for_message(msg)
예제 #4
0
class Widget(QGraphicsView):

    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self.setWindowTitle('U-CTF View')

        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)

        # game cube grass area
        grass_color = QColor(0, 255, 0, 50)
        self._scene.addRect(
            0, 0, CUBE_LENGTH, CUBE_LENGTH,
            QPen(grass_color), QBrush(grass_color))
        # blue team area
        blue_color = QColor(0, 0, 255, 50)
        self._scene.addRect(
            0, -SUPPORT_AREA_DEPTH, CUBE_LENGTH, SUPPORT_AREA_DEPTH,
            QPen(blue_color), QBrush(blue_color))
        # gold team area
        gold_color = QColor(255, 215, 0, 50)
        self._scene.addRect(
            0, CUBE_LENGTH, CUBE_LENGTH, SUPPORT_AREA_DEPTH,
            QPen(gold_color), QBrush(gold_color))
        # penalty area
        orange_color = QColor(0, 200, 0, 50)
        self._scene.addRect(
            CUBE_LENGTH, 0, SUPPORT_AREA_DEPTH, CUBE_LENGTH,
            QPen(orange_color), QBrush(orange_color))

        # rotate view to match the coordinate system of the game cube
        self.rotate(180)
        self.setScene(self._scene)

        # pens and brushes for the vehicles
        self._pens = {
            'blue': QPen(Qt.blue, 2),
            'gold': QPen(QColor(191, 151, 0), 2),
        }
        self._brushes = {
            'blue': QBrush(Qt.blue),
            'gold': QBrush(QColor(191, 151, 0)),
        }

        self._vehicles = {}

    def update_vehicle(self, color, mav_id, vehicle_type, global_pos):
        if mav_id not in self._vehicles:
            item = self._create_vehicle_item(color, mav_id, vehicle_type)
            self._scene.addItem(item)
            self._vehicles[mav_id] = item
        else:
            item = self._vehicles[mav_id]
        cube_pos = global_to_cube(global_pos['lat'], global_pos['lon'])
        item.setPos(*cube_pos)

        # set visible area
        padding = 10
        self.fitInView(
            -SUPPORT_AREA_DEPTH - padding, -SUPPORT_AREA_DEPTH - padding,
            CUBE_LENGTH + 2.0 * (SUPPORT_AREA_DEPTH + 2),
            CUBE_LENGTH + 2.0 * (SUPPORT_AREA_DEPTH + padding),
            Qt.KeepAspectRatio)

    def _create_vehicle_item(self, color, mav_id, vehicle_type):
        if vehicle_type == MAV_TYPE_QUADROTOR:
            # draw cross
            item = QGraphicsPolygonItem(QPolygonF([
                QPointF(0, 0),
                QPointF(-3, -3),
                QPointF(3, 3),
                QPointF(0, 0),
                QPointF(-3, 3),
                QPointF(3, -3),
                QPointF(0, 0),
            ]))
        elif vehicle_type == MAV_TYPE_FIXED_WING:
            # draw circle
            item = QGraphicsEllipseItem(-3, -3, 6, 6)
        else:
            # draw square
            item = QGraphicsRectItem(-3, -3, 6, 6)
        item.setBrush(self._brushes[color])
        item.setPen(self._pens[color])
        item.setToolTip('%s #%d (%s)' % (color, mav_id, vehicle_type))
        return item