diff --git a/qt/pe/details_dialog.py b/qt/pe/details_dialog.py index 43793bfb..d96dba17 100644 --- a/qt/pe/details_dialog.py +++ b/qt/pe/details_dialog.py @@ -4,10 +4,10 @@ # which should be included with this package. The terms are also available at # http://www.gnu.org/licenses/gpl-3.0.html -from PyQt5.QtCore import Qt, QSize +from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import ( QAbstractItemView, QSizePolicy, QGridLayout, QSplitter, QFrame) - +from PyQt5.QtGui import QResizeEvent from hscommon.trans import trget from hscommon.plat import ISWINDOWS from ..details_dialog import DetailsDialog as DetailsDialogBase @@ -27,7 +27,7 @@ class DetailsDialog(DetailsDialogBase): self.resize(502, 502) self.setMinimumSize(QSize(250, 250)) self.splitter = QSplitter(Qt.Vertical) - self.topFrame = QFrame() + self.topFrame = EmittingFrame() self.topFrame.setFrameShape(QFrame.StyledPanel) self.horizontalLayout = QGridLayout() # Minimum width for the toolbar in the middle: @@ -76,6 +76,8 @@ class DetailsDialog(DetailsDialogBase): # self.setCentralWidget(self.splitter) # only as QMainWindow self.setWidget(self.splitter) # only as QDockWidget + self.topFrame.resized.connect(self.resizeEvent) + def _update(self): if self.vController is None: # Not yet constructed! return @@ -90,6 +92,7 @@ class DetailsDialog(DetailsDialogBase): self.vController.updateView(ref, dupe, group) # --- Override + @pyqtSlot(QResizeEvent) def resizeEvent(self, event): self.ensure_same_sizes() if self.vController is None or not self.vController.bestFit: @@ -136,3 +139,11 @@ class DetailsDialog(DetailsDialogBase): DetailsDialogBase.refresh(self) if self.isVisible(): self._update() + + +class EmittingFrame(QFrame): + """Emits a signal whenever is resized""" + resized = pyqtSignal(QResizeEvent) + + def resizeEvent(self, event): + self.resized.emit(event) diff --git a/qt/pe/image_viewer.py b/qt/pe/image_viewer.py index 1c4d38c0..08a70db8 100644 --- a/qt/pe/image_viewer.py +++ b/qt/pe/image_viewer.py @@ -149,6 +149,7 @@ class BaseController(QObject): self.bestFit = True self.parent = parent # To change buttons' states self.cached_group = None + self.same_dimensions = True def setupViewers(self, selectedViewer, referenceViewer): self.selectedViewer = selectedViewer @@ -163,6 +164,8 @@ class BaseController(QObject): def updateView(self, ref, dupe, group): # To keep current scale accross dupes from the same group + previous_same_dimensions = self.same_dimensions + self.same_dimensions = True same_group = True if group != self.cached_group: same_group = False @@ -171,6 +174,7 @@ class BaseController(QObject): self.selectedPixmap = QPixmap(str(dupe.path)) if ref is dupe: # currently selected file is the actual reference file + # self.same_dimensions = False self.referencePixmap = QPixmap() self.scaledReferencePixmap = QPixmap() self.parent.verticalToolBar.buttonImgSwap.setEnabled(False) @@ -179,9 +183,9 @@ class BaseController(QObject): self.referencePixmap = QPixmap(str(ref.path)) self.parent.verticalToolBar.buttonImgSwap.setEnabled(True) if ref.dimensions != dupe.dimensions: - self.parent.verticalToolBar.buttonNormalSize.setEnabled(False) - else: - self.parent.verticalToolBar.buttonNormalSize.setEnabled(True) + self.same_dimensions = False + self.parent.verticalToolBar.buttonNormalSize.setEnabled(True) + self.updateButtonsAsPerDimensions(previous_same_dimensions) self.updateBothImages(same_group) self.centerViews(same_group and self.referencePixmap.isNull()) @@ -217,11 +221,11 @@ class BaseController(QObject): # zoomed in state, expand # only if not same_group, we need full update scaledpixmap = pixmap.scaled( - target_size, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation) + target_size, Qt.KeepAspectRatioByExpanding, Qt.FastTransformation) else: # best fit, keep ratio always scaledpixmap = pixmap.scaled( - target_size, Qt.KeepAspectRatio, Qt.SmoothTransformation) + target_size, Qt.KeepAspectRatio, Qt.FastTransformation) viewer.setImage(scaledpixmap) return target_size @@ -304,6 +308,22 @@ class BaseController(QObject): self.parent.verticalToolBar.buttonNormalSize.setEnabled(round(self.current_scale, 1) != 1.0) self.parent.verticalToolBar.buttonBestFit.setEnabled(self.bestFit is False) + def updateButtonsAsPerDimensions(self, previous_same_dimensions): + if not self.same_dimensions: + self.parent.verticalToolBar.buttonZoomIn.setEnabled(False) + self.parent.verticalToolBar.buttonZoomOut.setEnabled(False) + if not self.bestFit: + self.zoomBestFit() + self.parent.verticalToolBar.buttonNormalSize.setEnabled(True) + if not self.referencePixmap.isNull(): + self.parent.verticalToolBar.buttonImgSwap.setEnabled(True) + return + if not self.bestFit and not previous_same_dimensions: + self.zoomBestFit() + self.parent.verticalToolBar.buttonNormalSize.setEnabled(True) + if self.referencePixmap.isNull(): + self.parent.verticalToolBar.buttonImgSwap.setEnabled(False) + @pyqtSlot() def zoomBestFit(self): """Setup before scaling to bestfit""" @@ -330,6 +350,7 @@ class BaseController(QObject): self.parent.verticalToolBar.buttonZoomOut.setEnabled(False) self.parent.verticalToolBar.buttonNormalSize.setEnabled(True) self.parent.verticalToolBar.buttonBestFit.setEnabled(False) + self.parent.verticalToolBar.buttonImgSwap.setEnabled(True) def setBestFit(self, value): self.bestFit = value @@ -349,8 +370,12 @@ class BaseController(QObject): self.selectedViewer.scaleToNormalSize() self.referenceViewer.scaleToNormalSize() - self.parent.verticalToolBar.buttonZoomIn.setEnabled(True) - self.parent.verticalToolBar.buttonZoomOut.setEnabled(True) + if self.same_dimensions: + self.parent.verticalToolBar.buttonZoomIn.setEnabled(True) + self.parent.verticalToolBar.buttonZoomOut.setEnabled(True) + else: + # we can't allow swapping pixmaps of different dimensions + self.parent.verticalToolBar.buttonImgSwap.setEnabled(False) self.parent.verticalToolBar.buttonNormalSize.setEnabled(False) self.parent.verticalToolBar.buttonBestFit.setEnabled(True) @@ -371,8 +396,16 @@ class QWidgetController(BaseController): def __init__(self, parent): super().__init__(parent) + def _updateImage(self, *args): + ret = super()._updateImage(*args) + # Fix alignment when resizing window + self.centerViews() + return ret + @pyqtSlot(QPointF) def onDraggedMouse(self, delta): + if not self.same_dimensions: + return if self.sender() is self.referenceViewer: self.selectedViewer.onDraggedMouse(delta) else: @@ -410,8 +443,14 @@ class ScrollAreaController(BaseController): self.selectedViewer.ignore_signal = True self.referenceViewer.ignore_signal = True - self.selectedViewer.onDraggedMouse(delta) - self.referenceViewer.onDraggedMouse(delta) + if self.same_dimensions: + self.selectedViewer.onDraggedMouse(delta) + self.referenceViewer.onDraggedMouse(delta) + else: + if self.sender() is self.selectedViewer: + self.selectedViewer.onDraggedMouse(delta) + else: + self.referenceViewer.onDraggedMouse(delta) self.selectedViewer.ignore_signal = False self.referenceViewer.ignore_signal = False @@ -432,6 +471,8 @@ class ScrollAreaController(BaseController): @pyqtSlot(int) def onVScrollBarChanged(self, value): + if not self.same_dimensions: + return if self.sender() is self.referenceViewer._verticalScrollBar: if not self.selectedViewer.ignore_signal: self.selectedViewer._verticalScrollBar.setValue(value) @@ -441,6 +482,8 @@ class ScrollAreaController(BaseController): @pyqtSlot(int) def onHScrollBarChanged(self, value): + if not self.same_dimensions: + return if self.sender() is self.referenceViewer._horizontalScrollBar: if not self.selectedViewer.ignore_signal: self.selectedViewer._horizontalScrollBar.setValue(value) @@ -458,6 +501,8 @@ class ScrollAreaController(BaseController): def zoomBestFit(self): # Disable scrollbars to avoid GridLayout size rounding glitch super().zoomBestFit() + if self.referencePixmap.isNull(): + self.parent.verticalToolBar.buttonImgSwap.setEnabled(False) self.selectedViewer.toggleScrollBars() self.referenceViewer.toggleScrollBars() @@ -494,6 +539,8 @@ class GraphicsViewController(BaseController): @pyqtSlot(int) def onVScrollBarChanged(self, value): + if not self.same_dimensions: + return if self.sender() is self.referenceViewer._verticalScrollBar: if not self.selectedViewer.ignore_signal: self.selectedViewer._verticalScrollBar.setValue(value) @@ -503,6 +550,8 @@ class GraphicsViewController(BaseController): @pyqtSlot(int) def onHScrollBarChanged(self, value): + if not self.same_dimensions: + return if self.sender() is self.referenceViewer._horizontalScrollBar: if not self.selectedViewer.ignore_signal: self.selectedViewer._horizontalScrollBar.setValue(value) @@ -528,9 +577,16 @@ class GraphicsViewController(BaseController): self.parent.verticalToolBar.buttonZoomOut.setEnabled(False) self.parent.verticalToolBar.buttonZoomIn.setEnabled(False) self.parent.verticalToolBar.buttonNormalSize.setEnabled(True) + if not self.referencePixmap.isNull(): + self.parent.verticalToolBar.buttonImgSwap.setEnabled(True) + # else: + # self.referenceViewer.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + # self.referenceViewer.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) def updateView(self, ref, dupe, group): # Keep current scale accross dupes from the same group + previous_same_dimensions = self.same_dimensions + self.same_dimensions = True same_group = True if group != self.cached_group: same_group = False @@ -539,16 +595,19 @@ class GraphicsViewController(BaseController): self.selectedPixmap = QPixmap(str(dupe.path)) if ref is dupe: # currently selected file is the actual reference file + self.same_dimensions = False self.referencePixmap = QPixmap() self.parent.verticalToolBar.buttonImgSwap.setEnabled(False) self.parent.verticalToolBar.buttonNormalSize.setEnabled(True) else: self.referencePixmap = QPixmap(str(ref.path)) self.parent.verticalToolBar.buttonImgSwap.setEnabled(True) + if ref.dimensions != dupe.dimensions: + self.same_dimensions = False self.parent.verticalToolBar.buttonNormalSize.setEnabled(True) - - self.selectedViewer.setImage(self.selectedPixmap) - self.referenceViewer.setImage(self.referencePixmap) + # self.selectedViewer.setImage(self.selectedPixmap) + # self.referenceViewer.setImage(self.referencePixmap) + self.updateButtonsAsPerDimensions(previous_same_dimensions) self.updateBothImages(same_group) def updateBothImages(self, same_group=False): @@ -567,7 +626,9 @@ class GraphicsViewController(BaseController): def _updateFitImage(self, pixmap, viewer): # If not same_group, we need full update""" + viewer.setImage(pixmap) if pixmap.isNull(): + # viewer._item = None return if viewer.bestFit: viewer.fitScale() @@ -727,7 +788,7 @@ class QWidgetImageViewer(QWidget): self.setMouseTracking(False) def wheelEvent(self, event): - if self.bestFit or not self.isEnabled(): + if self.bestFit or not self.controller.same_dimensions or not self.isEnabled(): event.ignore() return @@ -920,7 +981,7 @@ class ScrollAreaImageViewer(QScrollArea): super().mouseReleaseEvent(event) def wheelEvent(self, event): - if self.bestFit: + if self.bestFit or not self.controller.same_dimensions: event.ignore() return oldScale = self.current_scale @@ -1044,7 +1105,7 @@ class ScrollAreaImageViewer(QScrollArea): class GraphicsViewViewer(QGraphicsView): - """Re-Implementation using a more full fledged class.""" + """Re-Implementation a full-fledged GraphicsView but is a bit buggy.""" mouseDragged = pyqtSignal() mouseWheeled = pyqtSignal(float, QPointF) @@ -1173,7 +1234,7 @@ class GraphicsViewViewer(QGraphicsView): self._centerPoint = self.mapToScene(self.rect().center()) def wheelEvent(self, event): - if self.bestFit or MIN_SCALE > self.current_scale > MAX_SCALE: + if self.bestFit or MIN_SCALE > self.current_scale > MAX_SCALE or not self.controller.same_dimensions: event.ignore() return pointBeforeScale = QPointF(self.mapToScene(self.mapFromGlobal(QCursor.pos()))) @@ -1196,6 +1257,10 @@ class GraphicsViewViewer(QGraphicsView): self.other_viewer.ignore_signal = False def setImage(self, pixmap): + if pixmap.isNull(): + self.ignore_signal = True + elif self.ignore_signal: + self.ignore_signal = False self._pixmap = pixmap self._item.setPixmap(pixmap) self.translate(1, 1) @@ -1251,7 +1316,7 @@ class GraphicsViewViewer(QGraphicsView): """Called when the pixmap is set back to original size.""" self.bestFit = False self.scaleAt(1.0) - self.toggleScrollBars() + self.toggleScrollBars(True) self.update() def adjustScrollBarsScaled(self, delta):