def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QVBoxLayout() self.setLayout(layout) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.attachTree = QAttachmentTree(self) self.attachTree.setMinimumHeight(240) hlayout.addWidget(self.attachTree) self.previewWidget = QImageView(self) self.previewWidget.setMinimumWidth(240) self.previewWidget.setMaximumWidth(360) self.previewWidget.hide() hlayout.addWidget(self.previewWidget) btnlayout = QHBoxLayout() layout.addLayout(btnlayout) self.add1Btn = QPushButton("&Add attachment(s) from file(s)...", self) self.add2Btn = QPushButton( "&Import existing attachment(s) from input...", self) self.removeBtn = QPushButton("&Remove selected attachment(s)", self) self.add1Btn.clicked.connect(self.attachTree.addFromFile) self.add2Btn.clicked.connect(self.attachTree.addFromInput) self.removeBtn.clicked.connect(self.attachTree.askDeleteSelected) btnlayout.addWidget(self.add1Btn) btnlayout.addWidget(self.add2Btn) btnlayout.addWidget(self.removeBtn) btnlayout.addStretch()
class QVideoPreview(QWidget): frameChanged = pyqtSignal(int, QTime) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.imageView = QImageView(self) self.frameSelection = QFrameSelect(self) self.frameSelection.frameSelectionChanged.connect(self.updateImage) layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(self.imageView) layout.addWidget(self.frameSelection) def setSource(self, source): self._source = source self.frameSelection.setPtsTimeArray(source.pts_time) self.setFrameIndex(0) s, ms = divmod(int(1000 * source.pts_time[0]), 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) self.updateImage(0, QTime(h, m, s, ms)) def setFrameIndex(self, value): self.frameSelection.slider.setValue(value) def updateImage(self, n, t): try: frame = next(self._source.iterFrames(n, whence="framenumber")) except Exception: return self.imageView.setFrame(frame.to_image().convert("RGBA").toqpixmap()) self.frameChanged.emit(n, t)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QVBoxLayout() self.setLayout(layout) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.selectionTree = AvailableAttachmentsTree(self) self.selectionTree.setMinimumHeight(240) self.previewWidget = QImageView(self) self.previewWidget.setMinimumWidth(240) self.previewWidget.setMaximumWidth(360) self.previewWidget.hide() hlayout.addWidget(self.selectionTree) hlayout.addWidget(self.previewWidget) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.okayBtn = QPushButton("&OK", self) self.cancelBtn = QPushButton("&Cancel", self) hlayout.addStretch() hlayout.addWidget(self.okayBtn) hlayout.addWidget(self.cancelBtn) self.okayBtn.clicked.connect(self.applyAndClose) self.cancelBtn.clicked.connect(self.close) self.selectedAttachments = None
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.imageView = QImageView(self) self.frameSelection = QFrameSelect(self) self.frameSelection.frameSelectionChanged.connect(self.updateImage) layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(self.imageView) layout.addWidget(self.frameSelection)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QGridLayout() self.setLayout(layout) self.cropTop = QSpinBox(self) self.cropLeft = QSpinBox(self) self.cropRight = QSpinBox(self) self.cropBottom = QSpinBox(self) self.cropTop.setSingleStep(2) self.cropTop.setMinimum(0) self.cropTop.valueChanged.connect(self.setCropTop) self.cropBottom.setSingleStep(2) self.cropBottom.setMinimum(0) self.cropBottom.valueChanged.connect(self.setCropBottom) self.cropLeft.setSingleStep(2) self.cropLeft.setMinimum(0) self.cropLeft.valueChanged.connect(self.setCropLeft) self.cropRight.setSingleStep(2) self.cropRight.setMinimum(0) self.cropRight.valueChanged.connect(self.setCropRight) self.scrollArea = QScrollArea(self) self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.imageView = QImageView(self) self.scrollArea.setWidget(self.imageView) self.imageView.setPaintHook(self._paintHook) tlayout = QHBoxLayout() tlayout.addStretch() tlayout.addWidget(self.cropTop) tlayout.addStretch() layout.addLayout(tlayout, 0, 1) layout.addWidget(self.cropLeft, 1, 0) layout.addWidget(self.scrollArea, 1, 1) layout.addWidget(self.cropRight, 1, 2) blayout = QHBoxLayout() blayout.addStretch() blayout.addWidget(self.cropBottom) blayout.addStretch() layout.addLayout(blayout, 2, 1) self.setFrameWidth(1920) self.setFrameHeight(720)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setMaximumWidth(960) layout = QVBoxLayout() layout.setContentsMargins(4, 4, 4, 4) layout.setSpacing(4) self.setLayout(layout) self.imageView = QImageView(self) layout.addWidget(self.imageView) self.slider = Slider(self) self.slider.setOrientation(Qt.Horizontal) self.slider.valueChanged.connect(self.handleSliderChange) self.slider.setTickInterval(1) layout.addWidget(self.slider) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.prevLabel = QLabel(self) self.currentIndex = QSpinBox(self) self.currentIndex.valueChanged.connect(self.handleIndexChange) self.currentTime = QTimeEdit(self) self.currentTime.setDisplayFormat("H:mm:ss.zzz") self.currentTime.timeChanged.connect(self.handleTimeChange) self.nextLabel = QLabel(self) hlayout.addWidget(self.prevLabel) hlayout.addStretch() hlayout.addWidget(QLabel("Frame index:", self)) hlayout.addWidget(self.currentIndex) hlayout.addWidget(QLabel("Timestamp:", self)) hlayout.addWidget(self.currentTime) hlayout.addStretch() hlayout.addWidget(self.nextLabel) hlayout = QHBoxLayout() hlayout.setContentsMargins(0, 0, 0, 0) hlayout.setSpacing(4) layout.addLayout(hlayout) self.okayBtn = QPushButton("&OK", self) self.cancelBtn = QPushButton("&Cancel", self) hlayout.addStretch() hlayout.addWidget(self.okayBtn) hlayout.addWidget(self.cancelBtn) self.setFrameSource(None, None)
def _createControls(self): self.setWindowTitle("Configure Crossfade") layout = QVBoxLayout(self) self.setLayout(layout) self.sourceWidget = QWidget(self) self.source1Selection = self.createSourceControl(self.sourceWidget) self.source1Selection.setSelectFunc(self.isValidSource1) self.source1Selection.currentDataChanged.connect(self.setFilterSource1) self.source1Fade = QCheckBox("Fade Out", self) self.source1Fade.stateChanged.connect(self.setSource1Fade) self.source2Selection = self.createSourceControl(self.sourceWidget) self.source2Selection.setSelectFunc(self.isValidSource2) self.source2Selection.currentDataChanged.connect(self.setFilterSource2) self.source2Fade = QCheckBox("Fade In", self) self.source2Fade.stateChanged.connect(self.setSource2Fade) srclayout = QVBoxLayout() src1layout = QHBoxLayout() src2layout = QHBoxLayout() srclayout.addLayout(src1layout) srclayout.addLayout(src2layout) src1layout.addWidget(QLabel("Source 1: ", self.sourceWidget)) src1layout.addWidget(self.source1Selection) src1layout.addWidget(self.source1Fade) src2layout.addWidget(QLabel("Source 2: ", self.sourceWidget)) src2layout.addWidget(self.source2Selection) src2layout.addWidget(self.source2Fade) self.sourceWidget.setLayout(srclayout) layout.addWidget(self.sourceWidget) self.imageView = QImageView(self) self.frameSelect = QFrameSelect(self) self.frameSelect.frameSelectionChanged.connect( self.handleFrameSelectionChange) layout.addWidget(self.imageView) layout.addWidget(self.frameSelect) self._prepareDlgButtons()
def _createControls(self): self.setWindowTitle("Configure Slice") layout = QVBoxLayout(self) self.setLayout(layout) self.sourceWidget = QWidget(self) self.sourceSelection = self.createSourceControl(self.sourceWidget) self.sourceSelection.currentDataChanged.connect(self.setFilterSource) srclayout = QHBoxLayout() srclayout.addWidget(QLabel("Source: ", self.sourceWidget)) srclayout.addWidget(self.sourceSelection) self.sourceWidget.setLayout(srclayout) layout.addWidget(self.sourceWidget) hlayout = QHBoxLayout() layout.addLayout(hlayout) vlayout = QVBoxLayout() hlayout.addLayout(vlayout) self.startImageView = QImageView(self) self.startSlider = QTimeSlider(self) self.startSlider.timeSelectionChanged.connect(self.setStart) vlayout.addWidget(self.startImageView) vlayout.addWidget(self.startSlider) vlayout = QVBoxLayout() hlayout.addLayout(vlayout) self.endImageView = QImageView(self) self.endSlider = QTimeSlider(self) self.endSlider.timeSelectionChanged.connect(self.setEnd) vlayout.addWidget(self.endImageView) vlayout.addWidget(self.endSlider) self._prepareDlgButtons()
def _createControls(self): self.setWindowTitle("Configure Hue/Saturation/Luminosity") layout = QVBoxLayout(self) self.setLayout(layout) self.sourceWidget = QWidget(self) self.sourceSelection = self.createSourceControl(self.sourceWidget) self.sourceSelection.currentDataChanged.connect(self.setFilterSource) srclayout = QHBoxLayout() srclayout.addWidget(QLabel("Source: ", self.sourceWidget)) srclayout.addWidget(self.sourceSelection) self.sourceWidget.setLayout(srclayout) layout.addWidget(self.sourceWidget) self.imageView = QImageView(self) layout.addWidget(self.imageView) self.slider = QFrameSelect(self) self.slider.frameSelectionChanged.connect(self.loadFrame) layout.addWidget(self.slider) hueLabel = QLabel("Hue adjustment:", self) self.hueSpinBox = QSpinBox(self) self.hueSpinBox.setMinimum(-179) self.hueSpinBox.setMaximum(180) self.hueSpinBox.valueChanged.connect( self._handleHueSpinBoxValueChanged) satLabel = QLabel("Saturation factor:", self) self.satSpinBox = QDoubleSpinBox(self) self.satSpinBox.setDecimals(2) self.satSpinBox.setSingleStep(0.1) self.satSpinBox.setMinimum(0) self.satSpinBox.setMaximum(10) self.satSpinBox.valueChanged.connect( self._handleSatSpinBoxValueChanged) lumLabel = QLabel("Luminosity factor:", self) self.lumSpinBox = QDoubleSpinBox(self) self.lumSpinBox.setDecimals(2) self.lumSpinBox.setMinimum(0) self.lumSpinBox.setMaximum(10) self.lumSpinBox.valueChanged.connect( self._handleLumSpinBoxValueChanged) hlayout = QHBoxLayout() hlayout.addStretch() hlayout.addWidget(hueLabel) hlayout.addWidget(self.hueSpinBox) hlayout.addStretch() hlayout.addWidget(satLabel) hlayout.addWidget(self.satSpinBox) hlayout.addStretch() hlayout.addWidget(lumLabel) hlayout.addWidget(self.lumSpinBox) hlayout.addStretch() layout.addLayout(hlayout) self._prepareDlgButtons()
class QHSLAdjDlg(QFilterConfig): allowedtypes = ("video",) def _createControls(self): self.setWindowTitle("Configure Hue/Saturation/Luminosity") layout = QVBoxLayout(self) self.setLayout(layout) self.sourceWidget = QWidget(self) self.sourceSelection = self.createSourceControl(self.sourceWidget) self.sourceSelection.currentDataChanged.connect(self.setFilterSource) srclayout = QHBoxLayout() srclayout.addWidget(QLabel("Source: ", self.sourceWidget)) srclayout.addWidget(self.sourceSelection) self.sourceWidget.setLayout(srclayout) layout.addWidget(self.sourceWidget) self.imageView = QImageView(self) layout.addWidget(self.imageView) self.slider = QFrameSelect(self) self.slider.frameSelectionChanged.connect(self.loadFrame) layout.addWidget(self.slider) hueLabel = QLabel("Hue adjustment:", self) self.hueSpinBox = QSpinBox(self) self.hueSpinBox.setMinimum(-179) self.hueSpinBox.setMaximum(180) self.hueSpinBox.valueChanged.connect( self._handleHueSpinBoxValueChanged) satLabel = QLabel("Saturation factor:", self) self.satSpinBox = QDoubleSpinBox(self) self.satSpinBox.setDecimals(2) self.satSpinBox.setSingleStep(0.1) self.satSpinBox.setMinimum(0) self.satSpinBox.setMaximum(10) self.satSpinBox.valueChanged.connect( self._handleSatSpinBoxValueChanged) lumLabel = QLabel("Luminosity factor:", self) self.lumSpinBox = QDoubleSpinBox(self) self.lumSpinBox.setDecimals(2) self.lumSpinBox.setMinimum(0) self.lumSpinBox.setMaximum(10) self.lumSpinBox.valueChanged.connect( self._handleLumSpinBoxValueChanged) hlayout = QHBoxLayout() hlayout.addStretch() hlayout.addWidget(hueLabel) hlayout.addWidget(self.hueSpinBox) hlayout.addStretch() hlayout.addWidget(satLabel) hlayout.addWidget(self.satSpinBox) hlayout.addStretch() hlayout.addWidget(lumLabel) hlayout.addWidget(self.lumSpinBox) hlayout.addStretch() layout.addLayout(hlayout) self._prepareDlgButtons() def createNewFilterInstance(self): return HSLAdjust() def _resetControls(self): self.hueSpinBox.blockSignals(True) self.hueSpinBox.setValue(self.filtercopy.dh) self.hueSpinBox.blockSignals(False) self.satSpinBox.blockSignals(True) self.satSpinBox.setValue(self.filtercopy.sfactor) self.satSpinBox.blockSignals(False) self.lumSpinBox.blockSignals(True) self.lumSpinBox.setValue(self.filtercopy.lgamma) self.lumSpinBox.blockSignals(False) if self.filtercopy.prev is not None: self.slider.setPtsTimeArray(self.filtercopy.prev.pts_time) self.loadFrame(self.slider.slider.value(), QTime()) def _handleHueSpinBoxValueChanged(self, value): self.filtercopy.dh = value self.isModified() self.loadFrame(self.slider.slider.value(), None) def _handleSatSpinBoxValueChanged(self, value): self.filtercopy.sfactor = value self.isModified() self.loadFrame(self.slider.slider.value(), None) def _handleLumSpinBoxValueChanged(self, value): self.filtercopy.sfactor = value self.isModified() self.loadFrame(self.slider.slider.value(), None) @pyqtSlot(int, QTime) def loadFrame(self, n, t): if self.filtercopy.prev is not None: frame = next(self.filtercopy.iterFrames(n, whence="framenumber")) im = frame.to_image() pixmap = im.convert("RGBA").toqpixmap() self.imageView.setFrame(pixmap) def _prevChanged(self, source): self.slider.setPtsTimeArray(source.pts_time) self.loadFrame(self.slider.slider.value(), self.slider.currentTime.time())
class FrameSelectWidget(QWidget): frameSelectionChanged = pyqtSignal(int, QTime) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setMaximumWidth(960) layout = QVBoxLayout() layout.setContentsMargins(4, 4, 4, 4) layout.setSpacing(4) self.setLayout(layout) self.imageView = QImageView(self) layout.addWidget(self.imageView) self.slider = Slider(self) self.slider.setOrientation(Qt.Horizontal) self.slider.valueChanged.connect(self.handleSliderChange) self.slider.setTickInterval(1) layout.addWidget(self.slider) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.prevLabel = QLabel(self) self.currentIndex = QSpinBox(self) self.currentIndex.valueChanged.connect(self.handleIndexChange) self.currentTime = QTimeEdit(self) self.currentTime.setDisplayFormat("H:mm:ss.zzz") self.currentTime.timeChanged.connect(self.handleTimeChange) self.nextLabel = QLabel(self) hlayout.addWidget(self.prevLabel) hlayout.addStretch() hlayout.addWidget(QLabel("Frame index:", self)) hlayout.addWidget(self.currentIndex) hlayout.addWidget(QLabel("Timestamp:", self)) hlayout.addWidget(self.currentTime) hlayout.addStretch() hlayout.addWidget(self.nextLabel) hlayout = QHBoxLayout() hlayout.setContentsMargins(0, 0, 0, 0) hlayout.setSpacing(4) layout.addLayout(hlayout) self.okayBtn = QPushButton("&OK", self) self.cancelBtn = QPushButton("&Cancel", self) hlayout.addStretch() hlayout.addWidget(self.okayBtn) hlayout.addWidget(self.cancelBtn) self.setFrameSource(None, None) def sizeHint(self): widgetHeights = ( self.slider.height() + max([self.okayBtn.height(), self.cancelBtn.height()]) + max([self.currentIndex.height(), self.currentTime.height()]) ) if isinstance(self.filters, BaseFilter): w, h = self.filters.width, self.filters.height sar = self.filters.sar elif isinstance(self.source, (Track, BaseFilter)): w, h = self.source.width, self.source.height sar = self.source.sar else: return super().sizeHint() dar = w*sar/h W, H = min([ max([(w, h/sar), (w*sar, h)]), (960 - 8, (960 - 8)/dar), ((720 - 20 - widgetHeights)*dar, 720 - 20 - widgetHeights) ]) return QSize(int(W + 8), int(H + 20 + widgetHeights)) def setFrameSource(self, source, filters=None): self.source = source if source is not None: self.slider.setMaximum(self.source.framecount - 1) self.currentIndex.setMaximum(self.source.framecount - 1) self.filters = filters if self.filters is not None: lastpts = self.filters.pts_time[-1] self.slider.setSnapValues(self.filters.keyframes) else: lastpts = self.source.pts_time[-1] if isinstance(self.source, BaseFilter): self.slider.setSnapValues(self.source.keyframes) else: self.slider.setSnapValues(None) ms = int(lastpts*1000 + 0.5) s, ms = divmod(ms, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) self.currentTime.setMaximumTime(QTime(h, m, s, ms)) self.slider.setValue(0) self._frameChange(0) else: self.slider.setSnapValues(None) self.update() def handleIndexChange(self, n): self._frameChange(n) self.slider.blockSignals(True) self.slider.setValue(n) self.slider.blockSignals(False) def handleSliderChange(self, n): self._frameChange(n) self.currentIndex.blockSignals(True) self.currentIndex.setValue(n) self.currentIndex.blockSignals(False) def _frameChange(self, n): if self.source is not None: if self.filters is not None: nn = n m = -1 while m < 0 and nn < len(self.filters.indexMap): m = self.filters.indexMap[nn] nn += 1 try: pts = self.filters.pts_time[m] except Exception: pts = None try: frame = next(self.filters.iterFrames( m, whence="framenumber")) except StopIteration: frame = None sar = self.filters.sar else: try: pts = self.source.pts_time[n] except IndexError: pts = None try: frame = next(self.source.iterFrames( n, whence="framenumber")) except StopIteration: frame = None sar = self.source.sar if frame is not None: im = frame.to_image() self.imageView.setFrame(im.toqpixmap()) self.imageView.setSar(sar) if pts is not None: ms = int(pts*1000+0.5) s, ms = divmod(ms, 1000) m, s = divmod(s, 60) h, m = divmod(m, 60) self.currentTime.blockSignals(True) self.currentTime.setTime(QTime(h, m, s, ms)) self.currentTime.blockSignals(False) self.frameSelectionChanged.emit(n, self.currentTime.time()) def handleTimeChange(self, t): if self.source is not None: if self.filters is not None: pts = t.msecsSinceStartOfDay()/1000 n = self.filters.frameIndexFromPtsTime(pts, dir="-") else: pts = t.msecsSinceStartOfDay()/1000 n = self.source.frameIndexFromPtsTime(pts, dir="-") self.slider.blockSignals(True) self.slider.setValue(n) self.slider.blockSignals(False) self.currentIndex.blockSignals(True) self.currentIndex.setValue(n) self.currentIndex.blockSignals(False) self._frameChange(n)
class QCrossFade(QFilterConfig): allowedtypes = ("video", "audio") def _createControls(self): self.setWindowTitle("Configure Crossfade") layout = QVBoxLayout(self) self.setLayout(layout) self.sourceWidget = QWidget(self) self.source1Selection = self.createSourceControl(self.sourceWidget) self.source1Selection.setSelectFunc(self.isValidSource1) self.source1Selection.currentDataChanged.connect(self.setFilterSource1) self.source1Fade = QCheckBox("Fade Out", self) self.source1Fade.stateChanged.connect(self.setSource1Fade) self.source2Selection = self.createSourceControl(self.sourceWidget) self.source2Selection.setSelectFunc(self.isValidSource2) self.source2Selection.currentDataChanged.connect(self.setFilterSource2) self.source2Fade = QCheckBox("Fade In", self) self.source2Fade.stateChanged.connect(self.setSource2Fade) srclayout = QVBoxLayout() src1layout = QHBoxLayout() src2layout = QHBoxLayout() srclayout.addLayout(src1layout) srclayout.addLayout(src2layout) src1layout.addWidget(QLabel("Source 1: ", self.sourceWidget)) src1layout.addWidget(self.source1Selection) src1layout.addWidget(self.source1Fade) src2layout.addWidget(QLabel("Source 2: ", self.sourceWidget)) src2layout.addWidget(self.source2Selection) src2layout.addWidget(self.source2Fade) self.sourceWidget.setLayout(srclayout) layout.addWidget(self.sourceWidget) self.imageView = QImageView(self) self.frameSelect = QFrameSelect(self) self.frameSelect.frameSelectionChanged.connect( self.handleFrameSelectionChange) layout.addWidget(self.imageView) layout.addWidget(self.frameSelect) self._prepareDlgButtons() def _resetSourceModels(self): self._resetSourceModel(self.source1Selection) self._resetSourceModel(self.source2Selection) @pyqtSlot(int, QTime) def handleFrameSelectionChange(self, n, t): self.setFrame(n) def setSource1Fade(self, value): if value: self.filtercopy.flags &= ~1 else: self.filtercopy.flags |= 1 if (self.filtercopy.prev is not None and self.filtercopy.prev.type == "video"): self.setFrame(self.frameSelect.slider.value()) self.isModified() def setSource2Fade(self, value): if value: self.filtercopy.flags &= ~2 else: self.filtercopy.flags |= 2 if (self.filtercopy.prev is not None and self.filtercopy.prev.type == "video"): self.setFrame(self.frameSelect.slider.value()) self.isModified() def setFrame(self, n): try: frame = next(self.filtercopy.iterFrames(n, whence="framenumber")) except StopIteration: self.imageView.setFrame( QPixmap(self.filtercopy.width, self.filtercopy.height)) return im = frame.to_image() pixmap = im.convert("RGBA").toqpixmap() self.imageView.setFrame(pixmap) def createNewFilterInstance(self): return CrossFade() def _resetSourceControls(self): self._showSourceControls(self.inputFiles or self.availableFilters) self._setSourceSelection(self.source1Selection, self.filtercopy.source1) self._setSourceSelection(self.source2Selection, self.filtercopy.source2) def _resetControls(self): if self.filtercopy is not None: self.source1Fade.blockSignals(True) self.source1Fade.setCheckState(0 if ( 1 & self.filtercopy.flags) else 2) self.source1Fade.blockSignals(False) self.source2Fade.blockSignals(True) self.source2Fade.setCheckState(0 if ( 2 & self.filtercopy.flags) else 2) self.source2Fade.blockSignals(False) self.frameSelect.setVisible(self.filtercopy.type == "video") self.imageView.setVisible(self.filtercopy.type == "video") if self.filtercopy.type == "video": self.frameSelect.setPtsTimeArray(self.filtercopy.pts_time) self.setFrame(0) self.setEnabled(True) else: self.source1Fade.blockSignals(True) self.source1Fade.setCheckState(2) self.source1Fade.blockSignals(False) self.source2Fade.blockSignals(True) self.source2Fade.setCheckState(2) self.source2Fade.blockSignals(False) self.frameSelect.setVisible(False) self.imageView.setVisible(False) self.setEnabled(False) def setFilterSource1(self, source): self.imageView.setVisible(source is not None and source.type == "video") self.filtercopy.source1 = source self.isModified() if (source is not None and self.filtercopy.source2 is not None and source.type == "video"): self.frameSelect.setPtsTimeArray(source.pts_time) self.setFrame(self.frameSelect.slider.value()) def setFilterSource2(self, source): self.imageView.setVisible(source is not None and source.type == "video") self.filtercopy.source2 = source self.isModified() if (source is not None and self.filtercopy.source1 is not None and source.type == "video"): self.frameSelect.setPtsTimeArray(source.pts_time) self.setFrame(self.frameSelect.slider.value()) def isValidSource1(self, other): if other is self.filter: return False if (isinstance(other, BaseFilter) and self.filter in other.dependencies): return False if self.filtercopy.source2 is None: return other.type in ("video", "audio") if other.type is None: return True elif self.filtercopy.source2.type == "video": return (self.filtercopy.source2.framecount == other.framecount and self.filtercopy.source2.width == other.width and self.filtercopy.source2.height == other.height and (abs(self.filtercopy.source2.pts_time - other.pts_time) < 0.008).all()) elif self.filtercopy.source2.type == "audio": return (self.filtercopy.source2.channels == other.channels and abs(self.filtercopy.source2.duration - other.duration) < 0.00001) def isValidSource2(self, other): if other is self.filter: return False if isinstance(other, BaseFilter) and self.filter in other.dependencies: return False if other.type is None: return True if self.filtercopy.source1 is None: return other.type in ("video", "audio") elif self.filtercopy.source1.type == "video": return (self.filtercopy.source1.framecount == other.framecount and self.filtercopy.source1.width == other.width and self.filtercopy.source1.height == other.height and (abs(self.filtercopy.source1.pts_time - other.pts_time) < 0.008).all()) elif self.filtercopy.source1.type == "audio": return (self.filtercopy.source1.channels == other.channels and abs(self.filtercopy.source1.duration - other.duration) < 0.00001)
class QCrop(QWidget): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QGridLayout() self.setLayout(layout) self.cropTop = QSpinBox(self) self.cropLeft = QSpinBox(self) self.cropRight = QSpinBox(self) self.cropBottom = QSpinBox(self) self.cropTop.setSingleStep(2) self.cropTop.setMinimum(0) self.cropTop.valueChanged.connect(self.setCropTop) self.cropBottom.setSingleStep(2) self.cropBottom.setMinimum(0) self.cropBottom.valueChanged.connect(self.setCropBottom) self.cropLeft.setSingleStep(2) self.cropLeft.setMinimum(0) self.cropLeft.valueChanged.connect(self.setCropLeft) self.cropRight.setSingleStep(2) self.cropRight.setMinimum(0) self.cropRight.valueChanged.connect(self.setCropRight) self.scrollArea = QScrollArea(self) self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.imageView = QImageView(self) self.scrollArea.setWidget(self.imageView) self.imageView.setPaintHook(self._paintHook) tlayout = QHBoxLayout() tlayout.addStretch() tlayout.addWidget(self.cropTop) tlayout.addStretch() layout.addLayout(tlayout, 0, 1) layout.addWidget(self.cropLeft, 1, 0) layout.addWidget(self.scrollArea, 1, 1) layout.addWidget(self.cropRight, 1, 2) blayout = QHBoxLayout() blayout.addStretch() blayout.addWidget(self.cropBottom) blayout.addStretch() layout.addLayout(blayout, 2, 1) self.setFrameWidth(1920) self.setFrameHeight(720) def setFrameWidth(self, width): self._width = width self.cropRight.setMaximum(width - self.cropLeft.value() - 2) self.cropLeft.setMaximum(width - self.cropRight.value() - 2) def setFrameHeight(self, height): self._height = height self.cropTop.setMaximum(height - self.cropBottom.value() - 2) self.cropBottom.setMaximum(height - self.cropTop.value() - 2) def frameWidth(self): return self._width def frameHeight(self): return self._height @pyqtSlot(int) def setCropTop(self, croptop): self.cropBottom.setMaximum(self.frameHeight() - croptop - 2) self.imageView.update() @pyqtSlot(int) def setCropBottom(self, cropbottom): self.cropTop.setMaximum(self.frameHeight() - cropbottom - 2) self.imageView.update() @pyqtSlot(int) def setCropLeft(self, cropleft): self.cropRight.setMaximum(self.frameWidth() - cropleft - 2) self.imageView.update() @pyqtSlot(int) def setCropRight(self, cropright): self.cropLeft.setMaximum(self.frameWidth() - cropright - 2) self.imageView.update() def setFrame(self, frame): self.setFrameWidth(max(2, frame.width())) self.setFrameHeight(max(2, frame.height())) self.imageView.setFrame(frame) self.imageView.resize(frame.width(), frame.height()) def _paintHook(self, widget, event, painter): w, h = widget.pixmap().width(), widget.pixmap().height() dar = w/h W = widget.width() H = widget.height() WW, HH = min([(W, W/dar), (H*dar, H)]) if WW < W: x0, y0 = ((W - WW)/2, 0) else: x0, y0 = (0, (H - HH)/2) zoom = WW/w if widget.pixmap() is not None: if zoom >= 8: pen = QPen(Qt.gray, 1) painter.setPen(pen) for j in range(0, w + 1): J = j*zoom painter.drawLine(x0 + J, y0, x0 + J, y0 + H) for j in range(0, h + 1): J = j*zoom painter.drawLine(x0, y0 + J, x0 + W, y0 + J) pen = QPen(Qt.red, 1) painter.setPen(pen) j = k = int(zoom < 8) painter.drawLine(x0 + self.cropLeft.value()*zoom - j, y0, x0 + self.cropLeft.value()*zoom - j, y0 + H) painter.drawLine(x0 + W - self.cropRight.value()*zoom, y0, x0 + W - self.cropRight.value()*zoom, y0 + H) painter.drawLine(x0, y0 + self.cropTop.value()*zoom - k, x0 + W, y0 + self.cropTop.value()*zoom - k) painter.drawLine(x0, y0 + H - self.cropBottom.value() * zoom, x0 + W, y0 + H - self.cropBottom.value()*zoom)
class QSlice(QFilterConfig): allowedtypes = ("video", "audio", "subtitle") def _createControls(self): self.setWindowTitle("Configure Slice") layout = QVBoxLayout(self) self.setLayout(layout) self.sourceWidget = QWidget(self) self.sourceSelection = self.createSourceControl(self.sourceWidget) self.sourceSelection.currentDataChanged.connect(self.setFilterSource) srclayout = QHBoxLayout() srclayout.addWidget(QLabel("Source: ", self.sourceWidget)) srclayout.addWidget(self.sourceSelection) self.sourceWidget.setLayout(srclayout) layout.addWidget(self.sourceWidget) hlayout = QHBoxLayout() layout.addLayout(hlayout) vlayout = QVBoxLayout() hlayout.addLayout(vlayout) self.startImageView = QImageView(self) self.startSlider = QTimeSlider(self) self.startSlider.timeSelectionChanged.connect(self.setStart) vlayout.addWidget(self.startImageView) vlayout.addWidget(self.startSlider) vlayout = QVBoxLayout() hlayout.addLayout(vlayout) self.endImageView = QImageView(self) self.endSlider = QTimeSlider(self) self.endSlider.timeSelectionChanged.connect(self.setEnd) vlayout.addWidget(self.endImageView) vlayout.addWidget(self.endSlider) self._prepareDlgButtons() @pyqtSlot(int, float) def setStart(self, n, t): self.filtercopy.startpts = t self.updateStartImage() self.isModified() @pyqtSlot(int, float) def setEnd(self, n, t): if self.filtercopy.prev is not None: if abs(t - self.filtercopy.prev.duration) < 10**-9: self.filtercopy.endpts = None else: self.filtercopy.endpts = t else: self.filtercopy.endpts = t self.updateEndImage() self.isModified() def updateStartImage(self): if (self.filtercopy.prev is not None and self.filtercopy.prev.type == "video"): n = search(self.filtercopy.prev.pts_time, self.filtercopy.startpts + 0.0005, "-") try: frame = next(self.filtercopy.prev.iterFrames( n, whence="framenumber")) except StopIteration: self.startImageView.setFrame( QPixmap(self.filtercopy.prev.width, self.filtercopy.prev.height)) return im = frame.to_image() pixmap = im.convert("RGBA").toqpixmap() self.startImageView.setFrame(pixmap) def updateEndImage(self): if (self.filtercopy.prev is not None and self.filtercopy.prev.type == "video"): if self.filtercopy.endpts is not None: n = search(self.filtercopy.prev.pts_time, self.filtercopy.endpts + 0.0005, "-") try: frame = next(self.filtercopy.prev.iterFrames( n, whence="framenumber")) except StopIteration: self.endImageView.setFrame( QPixmap(self.filtercopy.prev.width, self.filtercopy.prev.height)) return im = frame.to_image() pixmap = im.convert("RGBA").toqpixmap() self.endImageView.setFrame(pixmap) else: self.endImageView.setFrame( QPixmap(self.filtercopy.prev.width, self.filtercopy.prev.height)) def createNewFilterInstance(self): return Slice() def _prevChanged(self, source): self._resetControlMaximums() self.startSlider.spinBox.setVisible(source.type == "video") self.startSlider.slider.setVisible(source.type == "video") self.startImageView.setVisible(source.type == "video") self.endSlider.spinBox.setVisible(source.type == "video") self.endSlider.slider.setVisible(source.type == "video") self.endImageView.setVisible(source.type == "video") def _resetControlMaximums(self): if self.filtercopy.prev is not None: pts_time = concatenate( (self.filtercopy.prev.pts_time, [float(self.filtercopy.prev.duration)])) self.startSlider.blockSignals(True) self.startSlider.setPtsTimeArray(pts_time) self.startSlider.blockSignals(False) self.endSlider.blockSignals(True) self.endSlider.setPtsTimeArray(pts_time) self.endSlider.blockSignals(False) if self.filtercopy.prev.type == "subtitle": self.startSlider.timeSelect.setMinimum(0) self.endSlider.timeSelect.setMinimum(0) self.startSlider.timeSelect.setMaximum(24*3600) self.endSlider.timeSelect.setMaximum(24*3600) def _resetControls(self): if self.filtercopy is not None: self._resetControlMaximums() self.startSlider.blockSignals(True) self.startSlider.timeSelect.setValue(self.filtercopy.startpts) self.startSlider.blockSignals(False) self.endSlider.blockSignals(True) if self.filtercopy.endpts is not None: self.endSlider.timeSelect.setValue(self.filtercopy.endpts) elif self.filtercopy.prev is not None: if self.filtercopy.prev.type in ("video", "audio"): self.endSlider.timeSelect.setValue( float(self.filtercopy.prev.duration)) else: self.endSlider.timeSelect.setValue(24*3600) self.endSlider.blockSignals(False) self.updateStartImage() self.updateEndImage() else: self.startSlider.setPtsTimeArray(numpy.array([0])) self.endSlider.setPtsTimeArray(numpy.array([0]))
class QAttachmentsWidget(QWidget): contentsModified = pyqtSignal() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QVBoxLayout() self.setLayout(layout) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.attachTree = QAttachmentTree(self) self.attachTree.setMinimumHeight(240) hlayout.addWidget(self.attachTree) self.previewWidget = QImageView(self) self.previewWidget.setMinimumWidth(240) self.previewWidget.setMaximumWidth(360) self.previewWidget.hide() hlayout.addWidget(self.previewWidget) btnlayout = QHBoxLayout() layout.addLayout(btnlayout) self.add1Btn = QPushButton("&Add attachment(s) from file(s)...", self) self.add2Btn = QPushButton( "&Import existing attachment(s) from input...", self) self.removeBtn = QPushButton("&Remove selected attachment(s)", self) self.add1Btn.clicked.connect(self.attachTree.addFromFile) self.add2Btn.clicked.connect(self.attachTree.addFromInput) self.removeBtn.clicked.connect(self.attachTree.askDeleteSelected) btnlayout.addWidget(self.add1Btn) btnlayout.addWidget(self.add2Btn) btnlayout.addWidget(self.removeBtn) btnlayout.addStretch() def setData(self, tags, attachments): self.attachTree.setData(tags, attachments) if attachments is not None: self.attachTree.model().dataChanged.connect(self.contentsModified) self.attachTree.model().rowsInserted.connect(self.contentsModified) self.attachTree.model().rowsRemoved.connect(self.contentsModified) self.attachTree.model().rowsMoved.connect(self.contentsModified) self.attachTree.selectionModel().selectionChanged.connect( self.handleSelectionChanged) self.handleSelectionChanged() def handleSelectionChanged(self): self.removeBtn.setEnabled( len(self.attachTree.selectionModel().selectedRows()) > 0) selected = self.attachTree.currentIndex().data(Qt.UserRole) if (isinstance(selected, AttachedFile) and selected.mimeType in ("image/jpeg", "image/png")): try: if isinstance(selected.source, AttachmentRef): with io.BytesIO() as b: b.write(b"".join(selected.source.attachment.fileData)) b.seek(0) im = Image.open(b).convert("RGBA") else: im = Image.open(selected.source).convert("RGBA") except Exception: self.previewWidget.hide() return self.previewWidget.setFrame(im.toqpixmap()) self.previewWidget.show() else: self.previewWidget.hide()
class AvailableAttachmentsSelection(QDialog): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) layout = QVBoxLayout() self.setLayout(layout) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.selectionTree = AvailableAttachmentsTree(self) self.selectionTree.setMinimumHeight(240) self.previewWidget = QImageView(self) self.previewWidget.setMinimumWidth(240) self.previewWidget.setMaximumWidth(360) self.previewWidget.hide() hlayout.addWidget(self.selectionTree) hlayout.addWidget(self.previewWidget) hlayout = QHBoxLayout() layout.addLayout(hlayout) self.okayBtn = QPushButton("&OK", self) self.cancelBtn = QPushButton("&Cancel", self) hlayout.addStretch() hlayout.addWidget(self.okayBtn) hlayout.addWidget(self.cancelBtn) self.okayBtn.clicked.connect(self.applyAndClose) self.cancelBtn.clicked.connect(self.close) self.selectedAttachments = None def handleSelectionChanged(self): self.okayBtn.setEnabled( len(self.selectionTree.selectionModel().selectedRows()) > 0) selected = self.selectionTree.currentIndex().data(Qt.UserRole) if selected.mimeType in ("image/jpeg", "image/png"): try: with io.BytesIO() as b: b.write(b"".join(selected.fileData)) b.seek(0) im = Image.open(b).convert("RGBA") except Exception: self.previewWidget.hide() return self.previewWidget.setFrame(im.toqpixmap()) self.previewWidget.show() else: self.previewWidget.hide() def applyAndClose(self): self.selectedAttachments = [ (index.parent().data(Qt.UserRole), index.data(Qt.UserRole)) for index in self.selectionTree.selectionModel().selectedRows() ] self.done(1) self.close() def setInputFiles(self, input_files): self.selectionTree.setInputFiles(input_files) self.selectionTree.selectionModel().selectionChanged.connect( self.handleSelectionChanged) self.okayBtn.setEnabled(len(self.selectionTree.selectedIndexes()) > 0)