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))
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)
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)