Fix resize of top frame not updating scaled pixmap

* Also limit viewing features such as zoom levels when files have different dimensions
* GraphicsViewImageViewer is still a bit buggy: the scrollbars are toggled on when the pixmap is null in the reference viewer (we do not use that class right anyway)
This commit is contained in:
glubsy 2020-07-16 22:21:24 +02:00
parent 733b3b0ed4
commit ac941037ff
2 changed files with 96 additions and 20 deletions

View File

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

View File

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