Beispiel #1
0
    def __init__(self, label="", defaultValue=0, min=0, max=100, **kwargs):
        QtGui.QWidget.__init__(self)
        ControlBase.__init__(self, label, defaultValue, **kwargs)
        self._max = 100
        self._graphs_prop_win = GraphsProperties(self._time, self)

        # Popup menus that only show when clicking on a TIMELINEDELTA object
        self._deltaLockAction = self.addPopupMenuOption("Lock",
                                                        self.__lockSelected,
                                                        key='L')
        self._deltaColorAction = self.addPopupMenuOption(
            "Pick a color", self.__pickColor)
        self._deltaRemoveAction = self.addPopupMenuOption(
            "Remove", self.__removeSelected, key='Delete')
        self._deltaActions = [
            self._deltaLockAction, self._deltaColorAction,
            self._deltaRemoveAction
        ]
        for action in self._deltaActions:
            action.setVisible(False)

        self.addPopupMenuOption("-")

        # General righ click popup menus
        self.addPopupMenuOption("Set track properties...",
                                self.__setLinePropertiesEvent)
        self.addPopupMenuOption("Set graphs properties",
                                self.show_graphs_properties)
        self.addPopupMenuOption("-")
        self.addPopupSubMenuOption(
            "Clean", {
                'Current line': self.__cleanLine,
                'Everything': self.__clean,
                'Charts': self.__cleanCharts
            })
    def __init__(self, label="", defaultValue=0, min=0, max=100, **kwargs):
        QtGui.QWidget.__init__(self)
        ControlBase.__init__(self, label, defaultValue, **kwargs)
        self._max = 100
        self._graphs_prop_win = GraphsProperties(self._time, self)

        # Popup menus that only show when clicking on a TIMELINEDELTA object
        self._deltaLockAction = self.addPopupMenuOption("Lock", self.__lockSelected, key="L")
        self._deltaColorAction = self.addPopupMenuOption("Pick a color", self.__pickColor)
        self._deltaRemoveAction = self.addPopupMenuOption("Remove", self.__removeSelected, key="Delete")
        self._deltaActions = [self._deltaLockAction, self._deltaColorAction, self._deltaRemoveAction]
        for action in self._deltaActions:
            action.setVisible(False)

        self.addPopupMenuOption("-")

        # General righ click popup menus
        self.addPopupMenuOption("Set track properties...", self.__setLinePropertiesEvent)
        self.addPopupMenuOption("Set graphs properties", self.show_graphs_properties)
        self.addPopupMenuOption("-")
        self.addPopupSubMenuOption(
            "Clean", {"Current line": self.__cleanLine, "Everything": self.__clean, "Charts": self.__cleanCharts}
        )
class ControlEventTimeline(ControlBase, QtGui.QWidget):
    """
        Timeline events editor
    """

    def __init__(self, label="", defaultValue=0, min=0, max=100, **kwargs):
        QtGui.QWidget.__init__(self)
        ControlBase.__init__(self, label, defaultValue, **kwargs)
        self._max = 100
        self._graphs_properties_win = None

        # Popup menus that only show when clicking on a TIMELINEDELTA object
        self._deltaLockAction = self.addPopupMenuOption("Lock", self.__lockSelected, key='L')
        self._deltaColorAction = self.addPopupMenuOption("Pick a color", self.__pickColor)
        self._deltaRemoveAction = self.addPopupMenuOption("Remove", self.__removeSelected, key='Delete')
        self._deltaActions = [self._deltaLockAction, self._deltaColorAction, self._deltaRemoveAction]
        for action in self._deltaActions:
            action.setVisible(False)

        self.addPopupMenuOption("-")

        # General righ click popup menus
        self.addPopupMenuOption("Set track properties...", self.__setLinePropertiesEvent)
        self.addPopupMenuOption("Set graphs properties", self.__set_graphs_properties)
        self.addPopupMenuOption("-")
        self.addPopupSubMenuOption("Import/Export", {
            'Export to CSV': self.__export,
            'Import to CSV': self.__import
        })
        self.addPopupMenuOption("-")
        self.addPopupSubMenuOption("Clean", {
            'Current line': self.__cleanLine,
            'Everything': self.__clean,
            'Charts': self.__cleanCharts
        })

    def initForm(self):
        # Get the current path of the file
        rootPath = os.path.dirname(__file__)

        vlayout = QtGui.QVBoxLayout()
        hlayout = QtGui.QHBoxLayout()
        # hlayout.setMargin(0)
        vlayout.setMargin(0)
        self.setLayout(vlayout)

        # Add scroll area
        scrollarea = QtGui.QScrollArea()
        scrollarea.setMinimumHeight(140)
        scrollarea.setWidgetResizable(True)
        scrollarea.keyPressEvent = self.__scrollAreaKeyPressEvent
        scrollarea.keyReleaseEvent = self.__scrollAreaKeyReleaseEvent
        vlayout.addWidget(scrollarea)

        # The timeline widget
        widget = TimelineWidget()
        widget._scroll = scrollarea
        # widget.setMinimumHeight(1000)
        scrollarea.setWidget(widget)

        # TODO Options buttons
        # btn_1 = QtGui.QPushButton("?")
        # btn_2 = QtGui.QPushButton("?")
        # vlayout_options = QtGui.QVBoxLayout()
        # vlayout_options.addWidget(btn_1)
        # vlayout_options.addWidget(btn_2)
        # hlayout.addLayout(vlayout_options)
        # hlayout.addWidget(btn_1)
        # hlayout.addWidget(btn_2)

        # Timeline zoom slider
        slider = QtGui.QSlider(QtCore.Qt.Horizontal)
        slider.setFocusPolicy(QtCore.Qt.NoFocus)
        slider.setMinimum(1)
        slider.setMaximum(100)
        slider.setValue(10)
        slider.setPageStep(1)
        slider.setTickPosition(QtGui.QSlider.NoTicks)  # TicksBothSides
        slider.valueChanged.connect(self.__scaleSliderChange)
        slider_icon_zoom_in = QtGui.QPixmap(os.path.join(rootPath, "..", "uipics", "zoom_in.png"))
        slider_icon_zoom_out = QtGui.QPixmap(os.path.join(rootPath, "..", "uipics", "zoom_out.png"))
        slider_label_zoom_in = QtGui.QLabel()
        slider_label_zoom_out = QtGui.QLabel()
        slider_label_zoom_in.setPixmap(slider_icon_zoom_in)
        slider_label_zoom_out.setPixmap(slider_icon_zoom_out)
        # slider_vlayout = QtGui.QVBoxLayout()
        # slider_hlayout = QtGui.QHBoxLayout()
        # slider_hlayout.addWidget(slider_label_zoom_out)
        # slider_hlayout.addStretch()
        # slider_hlayout.addWidget(QtGui.QLabel("Zoom"))
        # slider_hlayout.addStretch()
        # slider_hlayout.addWidget(slider_label_zoom_in)
        # slider_vlayout.addWidget(slider)
        # slider_vlayout.addLayout(slider_hlayout)
        # hlayout.addLayout(slider_vlayout)
        self._zoomLabel = QtGui.QLabel("100%")
        hlayout.addWidget(self._zoomLabel)
        hlayout.addWidget(slider_label_zoom_out)
        hlayout.addWidget(slider)
        hlayout.addWidget(slider_label_zoom_in)

        # Import/Export Buttons
        btn_import = QtGui.QPushButton("Import")
        btn_import_icon = QtGui.QIcon(
            os.path.join(rootPath, "..", "uipics", "page_white_get.png"))
        btn_import.setIcon(btn_import_icon)
        btn_import.clicked.connect(self.__import)
        btn_export = QtGui.QPushButton("Export")
        btn_export_icon = QtGui.QIcon(
            os.path.join(rootPath, "..", "uipics", "page_white_put.png"))
        btn_export.setIcon(btn_export_icon)
        btn_export.clicked.connect(self.__export)
        # importexport_vlayout = QtGui.QVBoxLayout()
        # importexport_vlayout.addWidget(btn_import)
        # importexport_vlayout.addWidget(btn_export)
        # hlayout.addLayout(importexport_vlayout)
        hlayout.addWidget(btn_import)
        hlayout.addWidget(btn_export)

        vlayout.addLayout(hlayout)

        self._time = widget
        self._scrollArea = scrollarea

        

    ##########################################################################
    #### HELPERS/PUBLIC FUNCTIONS ############################################
    ##########################################################################

    def getExportFilename(self):
        return "untitled.csv"

    def addRow(self, values):
        for v in values:
            self.addPeriod(v, track=0)

    def addPeriod(self, value, track=0, color=None):
        self._time.addPeriod(value, track, color)

    ##########################################################################
    #### EVENTS ##############################################################
    ##########################################################################

    def aboutToShowContextMenuEvent(self):
        for action in self._deltaActions:
            action.setVisible(
                True) if self._time._selected is not None else action.setVisible(False)

    def __set_graphs_properties(self):
        if self._graphs_properties_win is None: self._graphs_properties_win = GraphsProperties(self._time)

        self._graphs_properties_win.show()

    def __setLinePropertiesEvent(self):
        """
        This controls makes possible the edition of a track in the
        timeline, based on the position of the mouse.

        Updates:
        - Track label
        - Track default color
        """
        current_track = self.mouseOverLine
        parent = self._time

        # Tracks info dict and index
        i = current_track

        # Save current default color to override with selected track color
        timeline_default_color = parent.color
        try:
            parent.color = self._time._tracks[current_track].color
        except Exception as e:
            error_message = ("You tried to edit an empty track.",
                             "\n",
                             "Initialize it by creating an event first.")
            QtGui.QMessageBox.warning(
                parent, "Attention!", "".join(error_message))
            return e

        # Create dialog
        dialog = TimelinePopupWindow(parent, i)
        dialog.setModal(True)  # to disable main application window

        # If dialog is accepted, update dict info
        if dialog._ui.exec_() == dialog.Accepted:
            # Update label
            if dialog.behavior is not None:
                self._time._tracks[i].title = dialog.behavior

            # Update color
            if self._time._tracks[i].color != dialog.color:
                for delta in self._time._tracks[i].periods:
                    delta.color = dialog.color
                self._time._tracks[i].color = dialog.color
        else:
            pass

        # Restore timeline default color
        parent.color = timeline_default_color

    def __lockSelected(self): self._time.lockSelected()

    def __removeSelected(self): self._time.removeSelected()

    def __import(self):
        """Import annotations from a file."""
        win = ImportWindow(self)
        win.show()

    def import_csv(self, csvfile):
        # If there are annotation in the timeline, show a warning
        if len(self._time._tracks) > 0:  # dict returns True if not empty
            message = ["You are about to import new data. ",
                       "If you proceed, current annotations will be erased. ",
                       "Make sure to export current annotations first to save.",
                       "\n",
                       "Are you sure you want to proceed?"]
            reply = QtGui.QMessageBox.question(self,
                                               "Warning!",
                                               "".join(message),
                                               QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                                               QtGui.QMessageBox.No)

            if reply != QtGui.QMessageBox.Yes:
                return

        self._time.import_csv(csvfile)
        print("Annotations file imported: {:s}".format(filename))

    def __export(self):
        """Export annotations to a file."""

        filename = QtGui.QFileDialog.getSaveFileName(parent=self,
                                                     caption="Export annotations file",
                                                     directory=self.getExportFilename(),
                                                     filter="CSV Files (*.csv)",
                                                     options=QtGui.QFileDialog.DontUseNativeDialog)
        if filename != "":
            with open(filename, 'wb') as csvfile:
                spamwriter = csv.writer(csvfile, dialect='excel')
                self._time.export_csv(spamwriter)

    def __cleanLine(self):
        reply = QtGui.QMessageBox.question(self, 'Confirm',
                                           "Are you sure you want to clean all the events?", QtGui.QMessageBox.Yes |
                                           QtGui.QMessageBox.No, QtGui.QMessageBox.No)
        if reply == QtGui.QMessageBox.Yes:
            self._time.cleanLine()

    def __cleanCharts(self):
        reply = QtGui.QMessageBox.question(self, 'Confirm',
                                           "Are you sure you want to clean all the charts?", QtGui.QMessageBox.Yes |
                                           QtGui.QMessageBox.No, QtGui.QMessageBox.No)
        if reply == QtGui.QMessageBox.Yes:
            self._time.cleanCharts()

    def __clean(self):
        reply = QtGui.QMessageBox.question(self, 'Confirm',
                                           "Are you sure you want to clean all the events?", QtGui.QMessageBox.Yes |
                                           QtGui.QMessageBox.No, QtGui.QMessageBox.No)
        if reply == QtGui.QMessageBox.Yes:
            self._time.clean()

    def __pickColor(self):
        self._time.color = QtGui.QColorDialog.getColor(self._time.color)
        if self._time._selected != None:
            self._time._selected.color = self._time.color
            self._time.repaint()

    def __scaleSliderChange(self, value):
        scale = 0.1 * value
        self._time.setMinimumWidth(scale * self._max)
        self._time.scale = scale
        self._zoomLabel.setText(str(value * 10).zfill(3) + "%")

    def __scrollAreaKeyReleaseEvent(self, event):
        modifiers = int(event.modifiers())
        self._time.keyReleaseEvent(event)
        if  modifiers is not QtCore.Qt.ControlModifier and \
                modifiers is not int(QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier) and \
                modifiers is not QtCore.Qt.ShiftModifier:
            QtGui.QScrollArea.keyReleaseEvent(self._scrollArea, event)

    def __scrollAreaKeyPressEvent(self, event):
        modifiers = int(event.modifiers())
        if  modifiers is not QtCore.Qt.ControlModifier and \
                modifiers is not int(QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier) and \
                modifiers is not QtCore.Qt.ShiftModifier:
            QtGui.QScrollArea.keyPressEvent(self._scrollArea, event)

    ##########################################################################
    #### PROPERTIES ##########################################################
    ##########################################################################

    @property
    def pointerChanged(self):
        return self._time._pointer.moveEvent

    @pointerChanged.setter
    def pointerChanged(self, value):
        self._time._pointer.moveEvent = value

    @property
    def value(self): return self._time.position

    @value.setter
    def value(self, value):
        ControlBase.value.fset(self, value)
        self._time.position = value

    @property
    def max(self): return self._time.minimumWidth()

    @max.setter
    def max(self, value):
        self._max = value
        self._time.setMinimumWidth(value)
        self.repaint()

    @property
    def mouseOverLine(self):
        globalPos = QtGui.QCursor.pos()
        widgetPos = self._time.mapFromGlobal(globalPos)
        return self._time.trackInPosition(widgetPos.x(), widgetPos.y())

    # Video playback properties
    @property
    def playVideoEvent(self):
        return self._time.playVideoEvent

    @playVideoEvent.setter
    def playVideoEvent(self, value):
        self._time.playVideoEvent = value

    @property
    def fpsChanged(self): return self._time.fpsChangeEvent

    @fpsChanged.setter
    def fpsChanged(self, value): self._time.fpsChangeEvent = value

    @property
    def form(self): return self

    @property
    def tracks(self): return self._time.tracks
    def __set_graphs_properties(self):
        if self._graphs_properties_win is None: self._graphs_properties_win = GraphsProperties(self._time)

        self._graphs_properties_win.show()