class FeatureWidget(QWidget):

    def __init__(self, parent, name, valuechange):
        super().__init__(parent)

        self.valuechange = valuechange

        self.layout = QVBoxLayout()
        self.name = name
        self.title = QLabel('{}:'.format(name), self)
        self.title.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)

        self.slider = QSlider(QtCore.Qt.Horizontal, self)

        slider_color = Application.Application.getAccentColor()
        self.slider.setStyleSheet(
            "QSlider::handle:horizontal {background-color: " + slider_color.name() + ";}")

        self.slider.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.slider.setTickPosition(QSlider.TicksBothSides)
        self.slider.setRange(0, 100)
        self.slider.setTickInterval(10)
        self.slider.setPageStep(10)
        self.slider.setSingleStep(1)
        self.slider.valueChanged.connect(self.value_change)

        self.layout.addWidget(self.title)
        self.layout.addWidget(self.slider)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)

        self.setLayout(self.layout)

    def value_change(self):
        value = self.slider.value()
        print('FeatureWidget {} value change {}'.format(self.name, value))
        self.valuechange(value)

    def set_value(self, value):
        print('FeatureWidget {} 1 set value {}'.format(self.name, value))
        self.slider.blockSignals(True)
        self.slider.setValue(value)
        self.slider.blockSignals(False)
        print('FeatureWidget {} 2 set value {}'.format(self.name, value))
Exemple #2
0
class MVCPlaybackControlGUI(PlaybackControlConsole):
    """
    GUI implementation of MVCPlaybackControlBase
    """
    nameFiltersChanged = Signal("QStringList")

    def __init__(self, config):
        assertMainThread()
        super().__init__(config)

        # state
        self.preventSeek = False
        self.beginTime = None
        self.timeRatio = 1.0

        # gui
        srv = Services.getService("MainWindow")
        config.configLoaded.connect(self.restoreState)
        config.configAboutToSave.connect(self.saveState)
        self.config = config
        playbackMenu = srv.menuBar().addMenu("&Playback")

        style = QApplication.style()
        self.actStart = QAction(QIcon.fromTheme("media-playback-start", style.standardIcon(QStyle.SP_MediaPlay)),
                                "Start Playback", self)
        self.actPause = QAction(QIcon.fromTheme("media-playback-pause", style.standardIcon(QStyle.SP_MediaPause)),
                                "Pause Playback", self)
        self.actPause.setEnabled(False)
        self.actStepFwd = QAction(QIcon.fromTheme("media-seek-forward",
                                                  style.standardIcon(QStyle.SP_MediaSeekForward)),
                                  "Step Forward", self)
        self.actStepBwd = QAction(QIcon.fromTheme("media-seek-backward",
                                                  style.standardIcon(QStyle.SP_MediaSeekBackward)),
                                  "Step Backward", self)
        self.actSeekEnd = QAction(QIcon.fromTheme("media-skip-forward",
                                                  style.standardIcon(QStyle.SP_MediaSkipForward)),
                                  "Seek End", self)
        self.actSeekBegin = QAction(QIcon.fromTheme("media-skip-backward",
                                                    style.standardIcon(QStyle.SP_MediaSkipBackward)),
                                    "Seek Begin", self)
        self.actSetTimeFactor = {r : QAction("x 1/%d" % (1/r), self) if r < 1 else QAction("x %d" % r, self)
                                 for r in (1/8, 1/4, 1/2, 1, 2, 4, 8)}

        # pylint: disable=unnecessary-lambda
        # let's stay on the safe side and do not use emit as a slot...
        self.actStart.triggered.connect(lambda: self._startPlayback.emit())
        self.actPause.triggered.connect(lambda: self._pausePlayback.emit())
        self.actStepFwd.triggered.connect(lambda: self._stepForward.emit(self.selectedStream()))
        self.actStepBwd.triggered.connect(lambda: self._stepBackward.emit(self.selectedStream()))
        self.actSeekEnd.triggered.connect(lambda: self._seekEnd.emit())
        self.actSeekBegin.triggered.connect(lambda: self._seekBeginning.emit())
        # pylint: enable=unnecessary-lambda

        def setTimeFactor(newFactor):
            logger.debug("new time factor %f", newFactor)
            self._setTimeFactor.emit(newFactor)

        for r in self.actSetTimeFactor:
            logger.debug("adding action for time factor %f", r)
            self.actSetTimeFactor[r].triggered.connect(functools.partial(setTimeFactor, r))

        self.dockWidget = srv.newDockWidget("PlaybackControl", None, Qt.LeftDockWidgetArea)
        self.dockWidgetContents = QWidget(self.dockWidget)
        self.dockWidget.setWidget(self.dockWidgetContents)
        toolLayout = QBoxLayout(QBoxLayout.TopToBottom, self.dockWidgetContents)
        toolLayout.setContentsMargins(0, 0, 0, 0)
        toolBar = QToolBar()
        toolLayout.addWidget(toolBar)
        toolBar.addAction(self.actSeekBegin)
        toolBar.addAction(self.actStepBwd)
        toolBar.addAction(self.actStart)
        toolBar.addAction(self.actPause)
        toolBar.addAction(self.actStepFwd)
        toolBar.addAction(self.actSeekEnd)
        playbackMenu.addAction(self.actSeekBegin)
        playbackMenu.addAction(self.actStepBwd)
        playbackMenu.addAction(self.actStart)
        playbackMenu.addAction(self.actPause)
        playbackMenu.addAction(self.actStepFwd)
        playbackMenu.addAction(self.actSeekEnd)
        playbackMenu.addSeparator()
        for r in self.actSetTimeFactor:
            playbackMenu.addAction(self.actSetTimeFactor[r])
        self.timeRatioLabel = QLabel("x 1")
        self.timeRatioLabel.addActions(list(self.actSetTimeFactor.values()))
        self.timeRatioLabel.setContextMenuPolicy(Qt.ActionsContextMenu)
        toolBar.addSeparator()
        toolBar.addWidget(self.timeRatioLabel)
        contentsLayout = QGridLayout()
        toolLayout.addLayout(contentsLayout, 10)
        # now we add a position view
        self.positionSlider = QSlider(Qt.Horizontal, self.dockWidgetContents)
        self.beginLabel = QLabel(parent=self.dockWidgetContents)
        self.beginLabel.setAlignment(Qt.AlignLeft|Qt.AlignCenter)
        self.currentLabel = QLabel(parent=self.dockWidgetContents)
        self.currentLabel.setAlignment(Qt.AlignHCenter|Qt.AlignCenter)
        self.endLabel = QLabel(parent=self.dockWidgetContents)
        self.endLabel.setAlignment(Qt.AlignRight|Qt.AlignCenter)
        contentsLayout.addWidget(self.beginLabel, 0, 0, alignment=Qt.AlignLeft)
        contentsLayout.addWidget(self.currentLabel, 0, 1, alignment=Qt.AlignHCenter)
        contentsLayout.addWidget(self.endLabel, 0, 2, alignment=Qt.AlignRight)
        contentsLayout.addWidget(self.positionSlider, 1, 0, 1, 3)
        self.positionSlider.setTracking(False)
        self.positionSlider.valueChanged.connect(self.onSliderValueChanged, Qt.DirectConnection)
        self.positionSlider.sliderMoved.connect(self.displayPosition)

        # file browser
        self.browser = BrowserWidget(self.dockWidget)
        self.nameFiltersChanged.connect(self._onNameFiltersChanged, Qt.QueuedConnection)
        contentsLayout.addWidget(self.browser, 3, 0, 1, 3)
        contentsLayout.setRowStretch(3, 100)
        self.browser.activated.connect(self.browserActivated)

        self.actShowAllFiles = QAction("Show all files")
        self.actShowAllFiles.setCheckable(True)
        self.actShowAllFiles.setChecked(False)
        self.actShowAllFiles.toggled.connect(self._onShowAllFiles)
        playbackMenu.addSeparator()
        playbackMenu.addAction(self.actShowAllFiles)

        self.actGroupStream = QActionGroup(self)
        self.actGroupStream.setExclusionPolicy(QActionGroup.ExclusionPolicy.ExclusiveOptional)
        playbackMenu.addSeparator()
        self.actGroupStreamMenu = playbackMenu.addMenu("Step Stream")
        self._selectedStream = None

        self.recentSeqs = [QAction() for i in range(10)]
        playbackMenu.addSeparator()
        recentMenu = playbackMenu.addMenu("Recent")
        for a in self.recentSeqs:
            a.setVisible(False)
            a.triggered.connect(self.openRecent)
            recentMenu.addAction(a)

        self._supportedFeaturesChanged(set(), set())

    def __del__(self):
        logger.internal("deleting playback control")

    def _onNameFiltersChanged(self, nameFilt):
        self.browser.setFilter(nameFilt)

    def _onShowAllFiles(self, enabled):
        self.fileSystemModel.setNameFilterDisables(enabled)

    def _supportedFeaturesChanged(self, featureset, nameFilters):
        """
        overwritten from MVCPlaybackControlBase. This function is called
        from multiple threads, but not at the same time.

        :param featureset: the current featureset
        :return:
        """
        assertMainThread()
        self.featureset = featureset
        self.actStepFwd.setEnabled("stepForward" in featureset)
        self.actStepBwd.setEnabled("stepBackward" in featureset)
        self.actSeekBegin.setEnabled("seekBeginning" in featureset)
        self.actSeekEnd.setEnabled("seekEnd" in featureset)
        self.positionSlider.setEnabled("seekTime" in featureset)
        self.browser.setEnabled("setSequence" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        for f in self.actSetTimeFactor:
            self.actSetTimeFactor[f].setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        if "startPlayback" not in featureset:
            self.actStart.setEnabled(False)
        if "pausePlayback" not in featureset:
            self.actPause.setEnabled(False)
        logger.debug("current feature set: %s", featureset)
        logger.debug("Setting name filters of browser: %s", list(nameFilters))
        self.nameFiltersChanged.emit(list(nameFilters))
        super()._supportedFeaturesChanged(featureset, nameFilters)

    def scrollToCurrent(self):
        """
        Scrolls to the current item in the browser

        :return:
        """
        assertMainThread()
        c = self.browser.current()
        if c is not None:
            self.browser.scrollTo(c)

    def _sequenceOpened(self, filename, begin, end, streams):
        """
        Notifies about an opened sequence.

        :param filename: the filename which has been opened
        :param begin: timestamp of sequence's first sample
        :param end: timestamp of sequence's last sample
        :param streams: list of streams in the sequence
        :return: None
        """
        assertMainThread()
        self.beginTime = begin
        self.preventSeek = True
        self.positionSlider.setRange(0, end.toMSecsSinceEpoch() - begin.toMSecsSinceEpoch())
        self.preventSeek = False
        self.beginLabel.setText(begin.toString("hh:mm:ss.zzz"))
        self.endLabel.setText(end.toString("hh:mm:ss.zzz"))
        self._currentTimestampChanged(begin)
        try:
            self.browser.blockSignals(True)
            self.browser.setActive(filename)
            self.browser.scrollTo(filename)
        finally:
            self.browser.blockSignals(False)
        self._selectedStream = None
        for a in self.actGroupStream.actions():
            logger.debug("Remove stream group action: %s", a.data())
            self.actGroupStream.removeAction(a)
        for stream in streams:
            act = QAction(stream, self.actGroupStream)
            act.triggered.connect(lambda cstream=stream: self.setSelectedStream(cstream))
            act.setCheckable(True)
            act.setChecked(False)
            logger.debug("Add stream group action: %s", act.data())
            self.actGroupStreamMenu.addAction(act)
        QTimer.singleShot(250, self.scrollToCurrent)
        super()._sequenceOpened(filename, begin, end, streams)

    def _currentTimestampChanged(self, currentTime):
        """
        Notifies about a changed timestamp

        :param currentTime: the new current timestamp
        :return: None
        """
        assertMainThread()
        if self.beginTime is None:
            self.currentLabel.setText("")
        else:
            sliderVal = currentTime.toMSecsSinceEpoch() - self.beginTime.toMSecsSinceEpoch()
            self.preventSeek = True
            self.positionSlider.setValue(sliderVal)
            self.preventSeek = False
            self.positionSlider.blockSignals(False)
            self.currentLabel.setEnabled(True)
            self.currentLabel.setText(currentTime.toString("hh:mm:ss.zzz"))
        super()._currentTimestampChanged(currentTime)

    def onSliderValueChanged(self, value):
        """
        Slot called whenever the slider value is changed.

        :param value: the new slider value
        :return:
        """
        assertMainThread()
        if self.beginTime is None or self.preventSeek:
            return
        if self.actStart.isEnabled():
            ts = QDateTime.fromMSecsSinceEpoch(self.beginTime.toMSecsSinceEpoch() + value, self.beginTime.timeSpec())
            self._seekTime.emit(ts)
        else:
            logger.warning("Can't seek while playing.")

    def displayPosition(self, value):
        """
        Slot called when the slider is moved. Displays the position without actually seeking to it.

        :param value: the new slider value.
        :return:
        """
        assertMainThread()
        if self.beginTime is None:
            return
        if self.positionSlider.isSliderDown():
            ts = QDateTime.fromMSecsSinceEpoch(self.beginTime.toMSecsSinceEpoch() + value, self.beginTime.timeSpec())
            self.currentLabel.setEnabled(False)
            self.currentLabel.setText(ts.toString("hh:mm:ss.zzz"))

    def _playbackStarted(self):
        """
        Notifies about starting playback

        :return: None
        """
        assertMainThread()
        self.actStart.setEnabled(False)
        if "pausePlayback" in self.featureset:
            self.actPause.setEnabled(True)
        super()._playbackStarted()

    def _playbackPaused(self):
        """
        Notifies about pause playback

        :return: None
        """
        assertMainThread()
        logger.debug("playbackPaused received")
        if "startPlayback" in self.featureset:
            self.actStart.setEnabled(True)
        self.actPause.setEnabled(False)
        super()._playbackPaused()

    def openRecent(self):
        """
        Called when the user clicks on a recent sequence.

        :return:
        """
        assertMainThread()
        action = self.sender()
        self.browser.setActive(action.data())

    def browserActivated(self, filename):
        """
        Called when the user activated a file.

        :param filename: the new filename
        :return:
        """
        assertMainThread()
        if filename is not None and Path(filename).is_file():
            foundIdx = None
            for i, a in enumerate(self.recentSeqs):
                if a.data() == filename:
                    foundIdx = i
            if foundIdx is None:
                foundIdx = len(self.recentSeqs)-1
            for i in range(foundIdx, 0, -1):
                self.recentSeqs[i].setText(self.recentSeqs[i-1].text())
                self.recentSeqs[i].setData(self.recentSeqs[i-1].data())
                logger.debug("%d data: %s", i, self.recentSeqs[i-1].data())
                self.recentSeqs[i].setVisible(self.recentSeqs[i-1].data() is not None)
            self.recentSeqs[0].setText(self.compressFileName(filename))
            self.recentSeqs[0].setData(filename)
            self.recentSeqs[0].setVisible(True)
            self._setSequence.emit(filename)

    def _timeRatioChanged(self, newRatio):
        """
        Notifies about a changed playback time ratio,

        :param newRatio the new playback ratio as a float
        :return: None
        """
        assertMainThread()
        self.timeRatio = newRatio
        logger.debug("new timeRatio: %f", newRatio)
        for r in [1/8, 1/4, 1/2, 1, 2, 4, 8]:
            if abs(newRatio / r - 1) < 0.01:
                self.timeRatioLabel.setText(("x 1/%d"%(1/r)) if r < 1 else ("x %d"%r))
                return
        self.timeRatioLabel.setText("%.2f" % newRatio)
        super()._timeRatioChanged(newRatio)

    def selectedStream(self):
        """
        Returns the user-selected stream (for forward/backward stepping)

        :return:
        """
        return self._selectedStream

    def setSelectedStream(self, stream):
        """
        Sets the user-selected stream (for forward/backward stepping)

        :param stream the stream name.
        :return:
        """
        self._selectedStream = stream

    def saveState(self):
        """
        Saves the state of the playback control

        :return:
        """
        assertMainThread()
        propertyCollection = self.config.guiState()
        showAllFiles = self.actShowAllFiles.isChecked()
        folder = self.browser.folder()
        logger.debug("Storing current folder: %s", folder)
        try:
            propertyCollection.setProperty("PlaybackControl_showAllFiles", int(showAllFiles))
            propertyCollection.setProperty("PlaybackControl_folder", folder)
            recentFiles = [a.data() for a in self.recentSeqs if a.data() is not None]
            propertyCollection.setProperty("PlaybackControl_recent", "|".join(recentFiles))
        except PropertyCollectionPropertyNotFound:
            pass

    def restoreState(self):
        """
        Restores the state of the playback control from the given property collection

        :param propertyCollection: a PropertyCollection instance
        :return:
        """
        assertMainThread()
        propertyCollection = self.config.guiState()
        propertyCollection.defineProperty("PlaybackControl_showAllFiles", 0, "show all files setting")
        showAllFiles = propertyCollection.getProperty("PlaybackControl_showAllFiles")
        self.actShowAllFiles.setChecked(bool(showAllFiles))
        propertyCollection.defineProperty("PlaybackControl_folder", "", "current folder name")
        folder = propertyCollection.getProperty("PlaybackControl_folder")
        if Path(folder).is_dir():
            logger.debug("Setting current file: %s", folder)
            self.browser.setFolder(folder)
        propertyCollection.defineProperty("PlaybackControl_recent", "", "recent opened sequences")
        recentFiles = propertyCollection.getProperty("PlaybackControl_recent")
        idx = 0
        for f in recentFiles.split("|"):
            if f != "" and Path(f).is_file():
                self.recentSeqs[idx].setData(f)
                self.recentSeqs[idx].setText(self.compressFileName(f))
                self.recentSeqs[idx].setVisible(True)
                idx += 1
                if idx >= len(self.recentSeqs):
                    break
        for a in self.recentSeqs[idx:]:
            a.setData(None)
            a.setText("")
            a.setVisible(False)

    @staticmethod
    def compressFileName(filename):
        """
        Compresses long path names with an ellipsis (...)

        :param filename: the original path name as a Path or string instance
        :return: the compressed path name as a string instance
        """
        p = Path(filename)
        parts = tuple(p.parts)
        if len(parts) >= 6:
            p = Path(*parts[:2]) / "..." /  Path(*parts[-2:])
        return str(p)
Exemple #3
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)

        self.player = QMediaPlayer()

        self.player.error.connect(self.erroralert)
        self.player.play()

        # Setup the playlist.
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)

        # Add viewer for video playback, separate floating window.
        self.viewer = ViewerWindow(self)
        self.viewer.setWindowFlags(self.viewer.windowFlags()
                                   | Qt.WindowStaysOnTopHint)
        self.viewer.setMinimumSize(QSize(480, 360))

        videoWidget = QVideoWidget()
        self.viewer.setCentralWidget(videoWidget)
        self.player.setVideoOutput(videoWidget)

        # Connect control buttons/slides for media player.
        self.playButton.pressed.connect(self.player.play)
        self.pauseButton.pressed.connect(self.player.pause)
        self.stopButton.pressed.connect(self.player.stop)
        self.volumeSlider.valueChanged.connect(self.player.setVolume)

        self.viewButton.toggled.connect(self.toggle_viewer)
        self.viewer.state.connect(self.viewButton.setChecked)

        self.previousButton.pressed.connect(self.playlist.previous)
        self.nextButton.pressed.connect(self.playlist.next)

        self.model = PlaylistModel(self.playlist)
        self.playlistView.setModel(self.model)
        self.playlist.currentIndexChanged.connect(
            self.playlist_position_changed)
        selection_model = self.playlistView.selectionModel()
        selection_model.selectionChanged.connect(
            self.playlist_selection_changed)

        self.player.durationChanged.connect(self.update_duration)
        self.player.positionChanged.connect(self.update_position)
        self.timeSlider.valueChanged.connect(self.player.setPosition)

        self.open_file_action.triggered.connect(self.open_file)

        self.setAcceptDrops(True)

        self.show()

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(484, 371)
        self.centralWidget = QWidget(MainWindow)
        sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.centralWidget.sizePolicy().hasHeightForWidth())
        self.centralWidget.setSizePolicy(sizePolicy)
        self.centralWidget.setObjectName("centralWidget")
        self.horizontalLayout = QHBoxLayout(self.centralWidget)
        self.horizontalLayout.setContentsMargins(11, 11, 11, 11)
        self.horizontalLayout.setSpacing(6)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(6)
        self.verticalLayout.setObjectName("verticalLayout")
        self.playlistView = QListView(self.centralWidget)
        self.playlistView.setAcceptDrops(True)
        self.playlistView.setProperty("showDropIndicator", True)
        self.playlistView.setDragDropMode(QAbstractItemView.DropOnly)
        self.playlistView.setAlternatingRowColors(True)
        self.playlistView.setUniformItemSizes(True)
        self.playlistView.setObjectName("playlistView")
        self.verticalLayout.addWidget(self.playlistView)
        self.horizontalLayout_4 = QHBoxLayout()
        self.horizontalLayout_4.setSpacing(6)
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.currentTimeLabel = QLabel(self.centralWidget)
        self.currentTimeLabel.setMinimumSize(QSize(80, 0))
        self.currentTimeLabel.setAlignment(Qt.AlignRight | Qt.AlignTrailing
                                           | Qt.AlignVCenter)
        self.currentTimeLabel.setObjectName("currentTimeLabel")
        self.horizontalLayout_4.addWidget(self.currentTimeLabel)
        self.timeSlider = QSlider(self.centralWidget)
        self.timeSlider.setOrientation(Qt.Horizontal)
        self.timeSlider.setObjectName("timeSlider")
        self.horizontalLayout_4.addWidget(self.timeSlider)
        self.totalTimeLabel = QLabel(self.centralWidget)
        self.totalTimeLabel.setMinimumSize(QSize(80, 0))
        self.totalTimeLabel.setAlignment(Qt.AlignLeading | Qt.AlignLeft
                                         | Qt.AlignVCenter)
        self.totalTimeLabel.setObjectName("totalTimeLabel")
        self.horizontalLayout_4.addWidget(self.totalTimeLabel)
        self.verticalLayout.addLayout(self.horizontalLayout_4)
        self.horizontalLayout_5 = QHBoxLayout()
        self.horizontalLayout_5.setSpacing(6)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.previousButton = QPushButton(self.centralWidget)
        self.previousButton.setText("")
        icon = QIcon()
        icon.addPixmap(QPixmap("images/control-skip-180.png"), QIcon.Normal,
                       QIcon.Off)
        self.previousButton.setIcon(icon)
        self.previousButton.setObjectName("previousButton")
        self.horizontalLayout_5.addWidget(self.previousButton)
        self.playButton = QPushButton(self.centralWidget)
        self.playButton.setText("")
        icon1 = QIcon()
        icon1.addPixmap(QPixmap("images/control.png"), QIcon.Normal, QIcon.Off)
        self.playButton.setIcon(icon1)
        self.playButton.setObjectName("playButton")
        self.horizontalLayout_5.addWidget(self.playButton)
        self.pauseButton = QPushButton(self.centralWidget)
        self.pauseButton.setText("")
        icon2 = QIcon()
        icon2.addPixmap(QPixmap("images/control-pause.png"), QIcon.Normal,
                        QIcon.Off)
        self.pauseButton.setIcon(icon2)
        self.pauseButton.setObjectName("pauseButton")
        self.horizontalLayout_5.addWidget(self.pauseButton)
        self.stopButton = QPushButton(self.centralWidget)
        self.stopButton.setText("")
        icon3 = QIcon()
        icon3.addPixmap(QPixmap("images/control-stop-square.png"),
                        QIcon.Normal, QIcon.Off)
        self.stopButton.setIcon(icon3)
        self.stopButton.setObjectName("stopButton")
        self.horizontalLayout_5.addWidget(self.stopButton)
        self.nextButton = QPushButton(self.centralWidget)
        self.nextButton.setText("")
        icon4 = QIcon()
        icon4.addPixmap(QPixmap("images/control-skip.png"), QIcon.Normal,
                        QIcon.Off)
        self.nextButton.setIcon(icon4)
        self.nextButton.setObjectName("nextButton")
        self.horizontalLayout_5.addWidget(self.nextButton)
        self.viewButton = QPushButton(self.centralWidget)
        self.viewButton.setText("")
        icon5 = QIcon()
        icon5.addPixmap(QPixmap("images/application-image.png"), QIcon.Normal,
                        QIcon.Off)
        self.viewButton.setIcon(icon5)
        self.viewButton.setCheckable(True)
        self.viewButton.setObjectName("viewButton")
        self.horizontalLayout_5.addWidget(self.viewButton)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout_5.addItem(spacerItem)
        self.label = QLabel(self.centralWidget)
        self.label.setText("")
        self.label.setPixmap(QPixmap("images/speaker-volume.png"))
        self.label.setObjectName("label")
        self.horizontalLayout_5.addWidget(self.label)
        self.volumeSlider = QSlider(self.centralWidget)
        self.volumeSlider.setMaximum(100)
        self.volumeSlider.setProperty("value", 100)
        self.volumeSlider.setOrientation(Qt.Horizontal)
        self.volumeSlider.setObjectName("volumeSlider")
        self.horizontalLayout_5.addWidget(self.volumeSlider)
        self.verticalLayout.addLayout(self.horizontalLayout_5)
        self.horizontalLayout.addLayout(self.verticalLayout)
        MainWindow.setCentralWidget(self.centralWidget)
        self.menuBar = QMenuBar(MainWindow)
        self.menuBar.setGeometry(QRect(0, 0, 484, 22))
        self.menuBar.setObjectName("menuBar")
        self.menuFIle = QMenu(self.menuBar)
        self.menuFIle.setObjectName("menuFIle")
        MainWindow.setMenuBar(self.menuBar)
        self.statusBar = QStatusBar(MainWindow)
        self.statusBar.setObjectName("statusBar")
        MainWindow.setStatusBar(self.statusBar)
        self.open_file_action = QAction(MainWindow)
        self.open_file_action.setObjectName("open_file_action")
        self.menuFIle.addAction(self.open_file_action)
        self.menuBar.addAction(self.menuFIle.menuAction())

        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Failamp"))
        self.currentTimeLabel.setText(_translate("MainWindow", "0:00"))
        self.totalTimeLabel.setText(_translate("MainWindow", "0:00"))
        self.menuFIle.setTitle(_translate("MainWindow", "FIle"))
        self.open_file_action.setText(_translate("MainWindow", "Open file..."))

    def dragEnterEvent(self, e):
        if e.mimeData().hasUrls():
            e.acceptProposedAction()

    def dropEvent(self, e):
        for url in e.mimeData().urls():
            self.playlist.addMedia(QMediaContent(url))

        self.model.layoutChanged.emit()

        # If not playing, seeking to first of newly added + play.
        if self.player.state() != QMediaPlayer.PlayingState:
            i = self.playlist.mediaCount() - len(e.mimeData().urls())
            self.playlist.setCurrentIndex(i)
            self.player.play()

    def open_file(self):
        path, _ = QFileDialog.getOpenFileName(
            self, "Open file", "",
            "mp3 Audio (*.mp3);mp4 Video (*.mp4);Movie files (*.mov);All files (*.*)"
        )

        if path:
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path)))

        self.model.layoutChanged.emit()

    def update_duration(self, duration):
        print("!", duration)
        print("?", self.player.duration())

        self.timeSlider.setMaximum(duration)

        if duration >= 0:
            self.totalTimeLabel.setText(hhmmss(duration))

    def update_position(self, position):
        if position >= 0:
            self.currentTimeLabel.setText(hhmmss(position))

        # Disable the events to prevent updating triggering a setPosition event (can cause stuttering).
        self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(position)
        self.timeSlider.blockSignals(False)

    def playlist_selection_changed(self, ix):
        # We receive a QItemSelection from selectionChanged.
        i = ix.indexes()[0].row()
        self.playlist.setCurrentIndex(i)

    def playlist_position_changed(self, i):
        if i > -1:
            ix = self.model.index(i)
            self.playlistView.setCurrentIndex(ix)

    def toggle_viewer(self, state):
        if state:
            self.viewer.show()
        else:
            self.viewer.hide()

    def erroralert(self, *args):
        print(args)
class FeatureSetupWidget(QWidget):

    def __init__(self, app, parent):
        super().__init__(parent)

        self.app = app
        self.parent = parent
        self.features = FeaturesSetup()

        self.layout = QVBoxLayout()

        self.title = QLabel("Brightness", self)
        myFont = self.title.font()
        myFont.setBold(True)
        self.title.setFont(myFont)
        self.title.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter)
        self.title.setAlignment(QtCore.Qt.AlignCenter)

        self.leftButton = QPushButton(u"\U00002190 Info", self)
        self.leftButton.setFlat(True)
        self.leftButton.setStyleSheet("QPushButton { text-align: left; }")
        self.leftButton.clicked.connect(self.previous)
        self.title_layout = QHBoxLayout()
        self.title_layout.addWidget(self.leftButton, 1)
        self.rightButton = QPushButton(u"Contrast \U00002192", self)
        self.rightButton.setFlat(True)
        self.rightButton.setStyleSheet("QPushButton { text-align: right; }")
        self.rightButton.clicked.connect(self.next)
        self.title_layout.addWidget(
            self.title, 1, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter)
        self.title_layout.addWidget(self.rightButton, 1)
        self.title_layout.setContentsMargins(0, 0, 0, 0)
        self.title_layout.setSpacing(0)

        self.info_frame = QtWidgets.QFrame(self)
        self.info_layout = QVBoxLayout()
        self.info_layout.setContentsMargins(0, 0, 0, 0)
        self.info_layout.setSpacing(0)
        self.info_frame.setLayout(self.info_layout)

        # Initialize tab screen
        self.infos = QTabWidget(self.info_frame)
        self.info_layout.addWidget(self.infos, 1)

        self.setup_frame = QtWidgets.QFrame(self)
        self.setup_layout = QVBoxLayout()
        self.setup_layout.setContentsMargins(0, 0, 0, 0)
        self.setup_layout.setSpacing(0)
        self.setup_frame.setLayout(self.setup_layout)

        self.slider = QSlider(QtCore.Qt.Horizontal, self)

        slider_color = Application.Application.getAccentColor()
        self.slider.setStyleSheet(
            "QSlider::handle:horizontal {background-color: " + slider_color.name() + ";}")

        self.slider.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.slider.setTickPosition(QSlider.TicksBothSides)
        self.slider.setRange(0, 100)
        self.slider.setTickInterval(10)
        self.slider.setPageStep(10)
        self.slider.setSingleStep(1)
        self.slider.valueChanged.connect(self.value_change)

        self.calibration = QLabel('{}:'.format("  Calibration"), self)
        self.title.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)

        # Initialize tab screen
        self.calibrations = QTabWidget(self.setup_frame)
        self.calibration1 = QWidget(self.calibrations)
        self.calibration2 = QWidget(self.calibrations)

        # Add calibrations
        self.calibrations.addTab(self.calibration1, "1: CMN")
        self.calibrations.addTab(self.calibration2, "2: HPN")

        self.tab_style_options = QtWidgets.QStyleOptionTabWidgetFrame()
        # self.calibrations.initStyleOption(self.tab_style_options)
        self.tab_style_options.initFrom(self.calibrations)
        print("TabColor Window        {}".format(
            self.tab_style_options.palette.color(QtGui.QPalette.Window).name()))
        print("TabColor Base          {}".format(
            self.tab_style_options.palette.color(QtGui.QPalette.Base).name()))
        print("TabColor AlternateBase {}".format(
            self.tab_style_options.palette.color(QtGui.QPalette.AlternateBase).name()))
        print("TabColor Button        {}".format(
            self.tab_style_options.palette.color(QtGui.QPalette.Button).name()))
        print("TabColor Mid           {}".format(
            self.tab_style_options.palette.color(QtGui.QPalette.Mid).name()))
        print("TabColor Midlight      {}".format(
            self.tab_style_options.palette.color(QtGui.QPalette.Midlight).name()))
        print("TabColor Light         {}".format(
            self.tab_style_options.palette.color(QtGui.QPalette.Light).name()))
        print("TabColor Highlight     {}".format(
            self.tab_style_options.palette.color(QtGui.QPalette.Highlight).name()))

        self.tabbar_style_options = QtWidgets.QStyleOptionTab()
        # self.calibrations.tabBar().initStyleOption(self.tabbar_style_options, 0)
        self.tabbar_style_options.initFrom(self.calibrations.tabBar())
        print("TabbarColor Window        {}".format(
            self.tabbar_style_options.palette.color(QtGui.QPalette.Window).name()))
        print("TabbarColor Base          {}".format(
            self.tabbar_style_options.palette.color(QtGui.QPalette.Base).name()))
        print("TabbarColor AlternateBase {}".format(
            self.tabbar_style_options.palette.color(QtGui.QPalette.AlternateBase).name()))
        print("TabbarColor Button        {}".format(
            self.tabbar_style_options.palette.color(QtGui.QPalette.Button).name()))
        print("TabbarColor Mid           {}".format(
            self.tabbar_style_options.palette.color(QtGui.QPalette.Mid).name()))
        print("TabbarColor Midlight      {}".format(
            self.tabbar_style_options.palette.color(QtGui.QPalette.Midlight).name()))
        print("TabbarColor Light         {}".format(
            self.tabbar_style_options.palette.color(QtGui.QPalette.Light).name()))
        print("TabbarColor Highlight     {}".format(
            self.tabbar_style_options.palette.color(QtGui.QPalette.Highlight).name()))

        groupbox = QtWidgets.QGroupBox()
        self.groupbox_style_options = QtWidgets.QStyleOptionGroupBox()
        groupbox.initStyleOption(self.groupbox_style_options)
        # self.groupbox_style_options.initFrom(groupbox)
        print("GroupBox Window        {}".format(
            self.groupbox_style_options.palette.color(QtGui.QPalette.Window).name()))
        print("GroupBox Base          {}".format(
            self.groupbox_style_options.palette.color(QtGui.QPalette.Base).name()))
        print("GroupBox AlternateBase {}".format(
            self.groupbox_style_options.palette.color(QtGui.QPalette.AlternateBase).name()))
        print("GroupBox Button        {}".format(
            self.groupbox_style_options.palette.color(QtGui.QPalette.Button).name()))
        print("GroupBox Mid           {}".format(
            self.groupbox_style_options.palette.color(QtGui.QPalette.Mid).name()))
        print("GroupBox Midlight      {}".format(
            self.groupbox_style_options.palette.color(QtGui.QPalette.Midlight).name()))
        print("GroupBox Light         {}".format(
            self.groupbox_style_options.palette.color(QtGui.QPalette.Light).name()))
        print("GroupBox Highlight     {}".format(
            self.groupbox_style_options.palette.color(QtGui.QPalette.Highlight).name()))

        r = float(self.groupbox_style_options.palette.color(
            QtGui.QPalette.Button).redF())
        print("tab_base_color        r  {}".format(r))

        r += (0.5 * float(self.groupbox_style_options.palette.color(QtGui.QPalette.Base).redF()))
        g = float(self.groupbox_style_options.palette.color(
            QtGui.QPalette.Button).greenF())
        g += (0.5 * float(self.groupbox_style_options.palette.color(QtGui.QPalette.Base).greenF()))
        b = float(self.groupbox_style_options.palette.color(
            QtGui.QPalette.Button).blueF())
        b += (0.5 * float(self.groupbox_style_options.palette.color(QtGui.QPalette.Base).blueF()))

        print("tab_base_color        rgb {} {} {}".format(r, g, b))
        self.tab_base_color = QtGui.QColor(r*255, g*255, b*255)
        print("tab_base_color          {}".format(
            self.tab_base_color.name()))
        # sys.exit()

        # Create first tab
        self.calibration1.layout = QVBoxLayout()
        self.pushButton1 = QPushButton("PySide2 button", self)
        self.calibration1.layout.addWidget(self.pushButton1)
        self.calibration1.setLayout(self.calibration1.layout)

        # Add calibrations to widget
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.addLayout(self.title_layout)
        self.layout.addWidget(self.info_frame, 1)
        self.layout.addWidget(self.setup_frame, 1)

        self.setup_layout.addWidget(self.slider)
        self.setup_layout.addWidget(self.calibration)
        self.setup_layout.addWidget(self.calibrations)

        self.info_frame.hide()

        self.setLayout(self.layout)

        self.init()

    def init(self):
        self.feature = self.features.get_next(None)
        self.set_feature(self.feature)

    def clear(self):
        while(self.infos.count() > 0):
            self.infos.removeTab(0)

    def value_change(self):
        value = self.slider.value()
        print('FeatureSetupWidget {} value change {}'.format(
            self.feature.name, value))
        if (self.feature.name == "Contrast"):
            self.app.contrast(value)
        if (self.feature.name == "Brightness"):
            self.app.brightness(value)

    def set_contrast(self, value):
        # to gui
        if (self.feature.name == "Contrast"):
            self.slider.blockSignals(True)
            self.slider.setValue(value)
            self.slider.blockSignals(False)

    def set_brightness(self, value):
        # to gui
        if (self.feature.name == "Brightness"):
            self.slider.blockSignals(True)
            self.slider.setValue(value)
            self.slider.blockSignals(False)

    def set_feature(self, feature_setup):
        self.info_frame.setVisible(
            self.features.get_next(None) == feature_setup)
        self.setup_frame.setVisible(
            self.features.get_next(None) != feature_setup)

        self.title.setText(feature_setup.name)
        self.leftButton.setText(u"\U00002190 {}".format(feature_setup.next))
        self.rightButton.setText(
            u"{} \U00002192".format(feature_setup.previous))

        value = None
        if (self.feature.name == "Contrast"):
            self.set_contrast_tabs()
            value = self.app.monitors.get_contrast()
        if (self.feature.name == "Brightness"):
            self.set_brightness_tabs()
            value = self.app.monitors.get_brightness()
        print('FeatureSetupWidget {} value set {}'.format(
            self.feature.name, value))
        if (value is not None):
            self.slider.blockSignals(True)
            self.slider.setValue(value)
            self.slider.blockSignals(False)

    def next(self):
        self.feature = self.features.get_next(self.feature)
        self.set_feature(self.feature)

    def previous(self):
        self.feature = self.features.get_previous(self.feature)
        self.set_feature(self.feature)

    # @ pyqtSlot()
    # def on_click(self):
    #    print("\n")
    #    for currentQTableWidgetItem in self.tableWidget.selectedItems():
    #        print(currentQTableWidgetItem.row(),
    #              currentQTableWidgetItem.column(), currentQTableWidgetItem.text())

    def set_infos(self, monitors):
        self.monitors = monitors

        while(self.infos.count() > 0):
            self.infos.removeTab(0)

        index = 0
        monitor = self.monitors.get_monitor(index)
        while (monitor is not None):

            info_widget = QWidget(self.infos)

            info_layout = QVBoxLayout()
            info_grid = QGridLayout()
            info_grid.setColumnStretch(0, 1)
            info_grid.setColumnStretch(1, 3)
            row = 0
            for key, value in monitor._monitor.info.items():
                variableLabel = QLabel(key)
                valueLabel = QLabel(value)

                info_grid.addWidget(variableLabel, row, 0)
                info_grid.addWidget(valueLabel, row, 1)

                row += 1

            info_layout.addLayout(info_grid)
            info_layout.addStretch(1)

            info_widget.setLayout(info_layout)

            self.infos.addTab(
                info_widget, tab_name(index, monitor._monitor.info))

            index += 1
            monitor = self.monitors.get_monitor(index)

    def update_cal_data(self, datas, values):
        print("-> update_cal_data {} : {}".format(datas, values))
        id = datas[0]
        monitor = self.monitors.get_monitor_by_id(id)
        type = datas[1]
        x_values = values[0]
        y_values = values[1]

        calibration = monitor._calibration.get(type)
        if (calibration is not None):
            calibration._set(values)

    def set_brightness_tabs(self):
        while(self.calibrations.count() > 0):
            self.calibrations.removeTab(0)

        index = 0
        monitor = self.monitors.get_monitor(index)
        while (monitor is not None):
            if (monitor._monitor.brightness is not None):

                type = Display.Display.BRIGHTNESS
                calibration_scaler = monitor._calibration.get(type)
                if (calibration_scaler is not None):

                    back_color = self.calibrations.palette().color(QtGui.QPalette.Base)
                    text_color = self.calibrations.palette().color(QtGui.QPalette.WindowText)
                    line_color = Application.Application.getAccentColor()

                    calibration_widget = CalibrationWidget.CalibrationWidget(self,
                                                                             calibration_scaler._scaling, self.update_cal_data,
                                                                             [monitor._monitor._device_name, type],
                                                                             self.tab_base_color, text_color, line_color)

                    self.calibrations.addTab(
                        calibration_widget, tab_name(index, monitor._monitor.info))

            index += 1
            monitor = self.monitors.get_monitor(index)

    def set_contrast_tabs(self):
        while(self.calibrations.count() > 0):
            self.calibrations.removeTab(0)

        index = 0
        monitor = self.monitors.get_monitor(index)
        while (monitor is not None):
            if (monitor._monitor.contrast is not None):

                type = Display.Display.CONTRAST
                calibration_scaler = monitor._calibration.get(type)

                if (calibration_scaler is not None):

                    back_color = self.calibrations.palette().color(QtGui.QPalette.Base)
                    text_color = self.calibrations.palette().color(QtGui.QPalette.WindowText)
                    line_color = Application.Application.getAccentColor()

                    calibration_widget = CalibrationWidget.CalibrationWidget(self,
                                                                             calibration_scaler._scaling, self.update_cal_data,
                                                                             [monitor._monitor._device_name, type],
                                                                             self.tab_base_color, text_color, line_color)

                    self.calibrations.addTab(
                        calibration_widget, tab_name(index, monitor._monitor.info))

            index += 1
            monitor = self.monitors.get_monitor(index)