diff --git a/images/exchange.icns b/images/exchange.icns
new file mode 100644
index 00000000..f93828b4
Binary files /dev/null and b/images/exchange.icns differ
diff --git a/images/exchange.ico b/images/exchange.ico
new file mode 100644
index 00000000..cf5226c9
Binary files /dev/null and b/images/exchange.ico differ
diff --git a/images/exchange.png b/images/exchange.png
new file mode 100644
index 00000000..6ed902b7
Binary files /dev/null and b/images/exchange.png differ
diff --git a/images/exchange_purple.png b/images/exchange_purple.png
new file mode 100644
index 00000000..21a6296a
Binary files /dev/null and b/images/exchange_purple.png differ
diff --git a/images/exchange_purple_upscaled.png b/images/exchange_purple_upscaled.png
new file mode 100644
index 00000000..1f31231c
Binary files /dev/null and b/images/exchange_purple_upscaled.png differ
diff --git a/images/exchange_purple_waifu_s4_tta8.png b/images/exchange_purple_waifu_s4_tta8.png
new file mode 100644
index 00000000..21bbcf53
Binary files /dev/null and b/images/exchange_purple_waifu_s4_tta8.png differ
diff --git a/images/exchange_purple_waifu_s4_tta8.xcf b/images/exchange_purple_waifu_s4_tta8.xcf
new file mode 100644
index 00000000..f3c922cb
Binary files /dev/null and b/images/exchange_purple_waifu_s4_tta8.xcf differ
diff --git a/images/exchange_waifu_s4_tta8.png b/images/exchange_waifu_s4_tta8.png
new file mode 100644
index 00000000..2f7a1cd9
Binary files /dev/null and b/images/exchange_waifu_s4_tta8.png differ
diff --git a/images/old_zoom_best_fit.png b/images/old_zoom_best_fit.png
new file mode 100644
index 00000000..444d4dcf
Binary files /dev/null and b/images/old_zoom_best_fit.png differ
diff --git a/images/old_zoom_in.png b/images/old_zoom_in.png
new file mode 100644
index 00000000..fbcbe2c1
Binary files /dev/null and b/images/old_zoom_in.png differ
diff --git a/images/old_zoom_original.png b/images/old_zoom_original.png
new file mode 100644
index 00000000..0bb910d6
Binary files /dev/null and b/images/old_zoom_original.png differ
diff --git a/images/old_zoom_out.png b/images/old_zoom_out.png
new file mode 100644
index 00000000..f7e84c98
Binary files /dev/null and b/images/old_zoom_out.png differ
diff --git a/qt/app.py b/qt/app.py
index ac59dd0a..7a5b60f6 100644
--- a/qt/app.py
+++ b/qt/app.py
@@ -7,7 +7,7 @@
import sys
import os.path as op
-from PyQt5.QtCore import QTimer, QObject, QUrl, pyqtSignal
+from PyQt5.QtCore import QTimer, QObject, QUrl, pyqtSignal, Qt
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QApplication, QFileDialog, QDialog, QMessageBox
@@ -54,11 +54,11 @@ class DupeGuru(QObject):
def _setup(self):
core.pe.photo.PLAT_SPECIFIC_PHOTO_CLASS = PlatSpecificPhoto
self._setupActions()
+ self.details_dialog = None
self._update_options()
self.recentResults = Recent(self, "recentResults")
self.recentResults.mustOpenItem.connect(self.model.load_from)
self.resultWindow = None
- self.details_dialog = None
self.directories_dialog = DirectoriesDialog(self)
self.progress_window = ProgressWindow(
self.directories_dialog, self.model.progress_window
@@ -152,6 +152,9 @@ class DupeGuru(QObject):
self.model.options["match_scaled"] = self.prefs.match_scaled
self.model.options["picture_cache_type"] = self.prefs.picture_cache_type
+ if self.details_dialog:
+ self.details_dialog.update_options()
+
# --- Private
def _get_details_dialog_class(self):
if self.model.app_mode == AppMode.Picture:
@@ -284,6 +287,8 @@ class DupeGuru(QObject):
self.resultWindow.setParent(None)
self.resultWindow = ResultWindow(self.directories_dialog, self)
self.details_dialog = self._get_details_dialog_class()(self.resultWindow, self)
+ self.resultWindow.addDockWidget(
+ Qt.BottomDockWidgetArea, self.details_dialog)
def show_results_window(self):
self.showResultsWindow()
diff --git a/qt/details_dialog.py b/qt/details_dialog.py
index 57cc650b..7b3f07d5 100644
--- a/qt/details_dialog.py
+++ b/qt/details_dialog.py
@@ -7,16 +7,19 @@
# http://www.gnu.org/licenses/gpl-3.0.html
from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import QMainWindow
+from PyQt5.QtWidgets import QDockWidget, QWidget
from .details_table import DetailsModel
+from hscommon.plat import ISLINUX
-class DetailsDialog(QMainWindow):
+class DetailsDialog(QDockWidget):
def __init__(self, parent, app, **kwargs):
super().__init__(parent, Qt.Tool, **kwargs)
+ self.parent = parent
self.app = app
self.model = app.model.details_panel
+ self.setAllowedAreas(Qt.AllDockWidgetAreas)
self._setupUi()
# To avoid saving uninitialized geometry on appWillSavePrefs, we track whether our dialog
# has been shown. If it has, we know that our geometry should be saved.
@@ -35,10 +38,31 @@ class DetailsDialog(QMainWindow):
def show(self):
self._shown_once = True
super().show()
+ self.update_options()
+
+ def update_options(self):
+ # This disables the title bar (if we had not set one before already)
+ # essentially making it a simple floating window, not dockable anymore
+ if not self.app.prefs.details_dialog_titlebar_enabled \
+ and not self.titleBarWidget():
+ self.setTitleBarWidget(QWidget())
+ # Windows (and MacOS?) users cannot move a floating window which
+ # has not native decoration so we force it to dock for now
+ if not ISLINUX:
+ self.setFloating(False)
+ elif self.titleBarWidget() is not None:
+ # resets to the default title bar
+ self.setTitleBarWidget(None)
+
+ features = self.features()
+ if self.app.prefs.details_dialog_vertical_titlebar:
+ self.setFeatures(features | QDockWidget.DockWidgetVerticalTitleBar)
+ elif features & QDockWidget.DockWidgetVerticalTitleBar:
+ self.setFeatures(features ^ QDockWidget.DockWidgetVerticalTitleBar)
# --- Events
def appWillSavePrefs(self):
- if self._shown_once:
+ if self._shown_once and self.isFloating():
self.app.prefs.saveGeometry("DetailsWindowRect", self)
# --- model --> view
diff --git a/qt/dg.qrc b/qt/dg.qrc
index 545a9806..760f2a85 100644
--- a/qt/dg.qrc
+++ b/qt/dg.qrc
@@ -5,5 +5,10 @@
../images/plus_8.png
../images/minus_8.png
../qtlib/images/search_clear_13.png
+ ../images/exchange_purple_upscaled.png
+ ../images/old_zoom_in.png
+ ../images/old_zoom_out.png
+ ../images/old_zoom_original.png
+ ../images/old_zoom_best_fit.png
diff --git a/qt/me/details_dialog.py b/qt/me/details_dialog.py
index 935a34c6..ecb947d0 100644
--- a/qt/me/details_dialog.py
+++ b/qt/me/details_dialog.py
@@ -5,7 +5,7 @@
# http://www.gnu.org/licenses/gpl-3.0.html
from PyQt5.QtCore import QSize
-from PyQt5.QtWidgets import QVBoxLayout, QAbstractItemView
+from PyQt5.QtWidgets import QVBoxLayout, QAbstractItemView, QWidget
from hscommon.trans import trget
from ..details_dialog import DetailsDialog as DetailsDialogBase
@@ -27,3 +27,6 @@ class DetailsDialog(DetailsDialogBase):
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
self.tableView.setShowGrid(False)
self.verticalLayout.addWidget(self.tableView)
+ self.centralWidget = QWidget()
+ self.centralWidget.setLayout(self.verticalLayout)
+ self.setWidget(self.centralWidget)
diff --git a/qt/pe/details_dialog.py b/qt/pe/details_dialog.py
index 07ecdfcb..d96dba17 100644
--- a/qt/pe/details_dialog.py
+++ b/qt/pe/details_dialog.py
@@ -4,11 +4,12 @@
# 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
from ..details_table import DetailsTable
from .image_viewer import (
@@ -25,9 +26,8 @@ class DetailsDialog(DetailsDialogBase):
self.setWindowTitle(tr("Details"))
self.resize(502, 502)
self.setMinimumSize(QSize(250, 250))
- self.splitter = QSplitter(Qt.Vertical, self)
- self.setCentralWidget(self.splitter)
- self.topFrame = QFrame()
+ self.splitter = QSplitter(Qt.Vertical)
+ self.topFrame = EmittingFrame()
self.topFrame.setFrameShape(QFrame.StyledPanel)
self.horizontalLayout = QGridLayout()
# Minimum width for the toolbar in the middle:
@@ -73,6 +73,10 @@ class DetailsDialog(DetailsDialogBase):
# Late population needed here for connections to the toolbar
self.vController.setupViewers(
self.selectedImageViewer, self.referenceImageViewer)
+ # 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!
@@ -88,24 +92,9 @@ class DetailsDialog(DetailsDialogBase):
self.vController.updateView(ref, dupe, group)
# --- Override
+ @pyqtSlot(QResizeEvent)
def resizeEvent(self, event):
- # HACK referenceViewer might be 1 pixel shorter in width
- # due to the toolbar in the middle keeping the same width,
- # so resizing in the GridLayout's engine leads to not enough space
- # left for the panel on the right.
- # This ensures same size while shrinking at least:
- self.horizontalLayout.setColumnMinimumWidth(
- 0, self.selectedImageViewer.size().width())
- self.horizontalLayout.setColumnMinimumWidth(
- 2, self.selectedImageViewer.size().width())
- # This works when expanding but it's ugly:
- if self.selectedImageViewer.size().width() > self.referenceImageViewer.size().width():
- # print(f"""Before selected size: {self.selectedImageViewer.size()}\n""",
- # f"""Before reference size: {self.referenceImageViewer.size()}""")
- self.selectedImageViewer.resize(self.referenceImageViewer.size())
- # print(f"""After selected size: {self.selectedImageViewer.size()}\n""",
- # f"""After reference size: {self.referenceImageViewer.size()}""")
-
+ self.ensure_same_sizes()
if self.vController is None or not self.vController.bestFit:
return
# Only update the scaled down pixmaps
@@ -117,12 +106,44 @@ class DetailsDialog(DetailsDialogBase):
self.tableView.setMaximumHeight(
self.tableView.rowHeight(1)
* self.tableModel.model.row_count()
- + self.tableView.verticalHeader().sectionSize(0))
+ + self.tableView.verticalHeader().sectionSize(0)
+ # Windows seems to add a few pixels more to the table somehow
+ + (5 if ISWINDOWS else 0))
DetailsDialogBase.show(self)
+ self.ensure_same_sizes()
self._update()
+ def ensure_same_sizes(self):
+ # HACK This ensures same size while shrinking.
+ # ReferenceViewer might be 1 pixel shorter in width
+ # due to the toolbar in the middle keeping the same width,
+ # so resizing in the GridLayout's engine leads to not enough space
+ # left for the panel on the right.
+ # This work as a QMainWindow, but doesn't work as a QDockWidget:
+ # resize can only grow. Might need some custom sizeHint somewhere...
+ # self.horizontalLayout.setColumnMinimumWidth(
+ # 0, self.selectedImageViewer.size().width())
+ # self.horizontalLayout.setColumnMinimumWidth(
+ # 2, self.selectedImageViewer.size().width())
+
+ # This works when expanding but it's ugly:
+ if self.selectedImageViewer.size().width() > self.referenceImageViewer.size().width():
+ # print(f"""Before selected size: {self.selectedImageViewer.size()}\n""",
+ # f"""Before reference size: {self.referenceImageViewer.size()}""")
+ self.selectedImageViewer.resize(self.referenceImageViewer.size())
+ # print(f"""After selected size: {self.selectedImageViewer.size()}\n""",
+ # f"""After reference size: {self.referenceImageViewer.size()}""")
+
# model --> view
def refresh(self):
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 54366e98..08a70db8 100644
--- a/qt/pe/image_viewer.py
+++ b/qt/pe/image_viewer.py
@@ -10,6 +10,7 @@ from PyQt5.QtWidgets import (
QToolBar, QToolButton, QAction, QWidget, QScrollArea,
QApplication, QAbstractScrollArea, QStyle)
from hscommon.trans import trget
+from hscommon.plat import ISLINUX
tr = trget("ui")
MAX_SCALE = 12.0
@@ -21,7 +22,7 @@ def createActions(actions, target):
for name, shortcut, icon, desc, func in actions:
action = QAction(target)
if icon:
- action.setIcon(QIcon.fromTheme(icon))
+ action.setIcon(icon)
if shortcut:
action.setShortcut(shortcut)
action.setText(desc)
@@ -48,28 +49,32 @@ class ViewerToolBar(QToolBar):
(
"actionZoomIn",
QKeySequence.ZoomIn,
- "zoom-in",
+ QIcon.fromTheme("zoom-in") if ISLINUX
+ else QIcon(QPixmap(":/" + "zoom_in")),
tr("Increase zoom"),
controller.zoomIn,
),
(
"actionZoomOut",
QKeySequence.ZoomOut,
- "zoom-out",
+ QIcon.fromTheme("zoom-out") if ISLINUX
+ else QIcon(QPixmap(":/" + "zoom_out")),
tr("Decrease zoom"),
controller.zoomOut,
),
(
"actionNormalSize",
tr("Ctrl+/"),
- "zoom-original",
+ QIcon.fromTheme("zoom-original") if ISLINUX
+ else QIcon(QPixmap(":/" + "zoom_original")),
tr("Normal size"),
controller.zoomNormalSize,
),
(
"actionBestFit",
tr("Ctrl+*"),
- "zoom-best-fit",
+ QIcon.fromTheme("zoom-best-fit") if ISLINUX
+ else QIcon(QPixmap(":/" + "zoom_best_fit")),
tr("Best fit"),
controller.zoomBestFit,
)
@@ -83,7 +88,9 @@ class ViewerToolBar(QToolBar):
self.buttonImgSwap.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.buttonImgSwap.setIcon(
QIcon.fromTheme('view-refresh',
- self.style().standardIcon(QStyle.SP_BrowserReload)))
+ self.style().standardIcon(QStyle.SP_BrowserReload))
+ if ISLINUX
+ else QIcon(QPixmap(":/" + "exchange")))
self.buttonImgSwap.setText('Swap images')
self.buttonImgSwap.setToolTip('Swap images')
self.buttonImgSwap.pressed.connect(self.controller.swapImages)
@@ -142,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
@@ -156,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
@@ -164,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)
@@ -171,7 +182,10 @@ class BaseController(QObject):
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.updateButtonsAsPerDimensions(previous_same_dimensions)
self.updateBothImages(same_group)
self.centerViews(same_group and self.referencePixmap.isNull())
@@ -207,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
@@ -294,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"""
@@ -320,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
@@ -339,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)
@@ -361,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:
@@ -400,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
@@ -422,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)
@@ -431,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)
@@ -448,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()
@@ -484,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)
@@ -493,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)
@@ -518,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
@@ -529,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):
@@ -557,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()
@@ -717,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
@@ -910,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
@@ -1034,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)
@@ -1163,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())))
@@ -1186,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)
@@ -1241,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):
diff --git a/qt/preferences.py b/qt/preferences.py
index c9691cca..39e55b1e 100644
--- a/qt/preferences.py
+++ b/qt/preferences.py
@@ -31,6 +31,8 @@ class Preferences(PreferencesBase):
self.tableFontSize = get("TableFontSize", self.tableFontSize)
self.reference_bold_font = get('ReferenceBoldFont', self.reference_bold_font)
+ self.details_dialog_titlebar_enabled = get('DetailsDialogTitleBarEnabled', self.details_dialog_titlebar_enabled)
+ self.details_dialog_vertical_titlebar = get('DetailsDialogVerticalTitleBar', self.details_dialog_vertical_titlebar)
self.resultWindowIsMaximized = get(
"ResultWindowIsMaximized", self.resultWindowIsMaximized
)
@@ -67,6 +69,8 @@ class Preferences(PreferencesBase):
self.tableFontSize = QApplication.font().pointSize()
self.reference_bold_font = True
+ self.details_dialog_titlebar_enabled = True
+ self.details_dialog_vertical_titlebar = True
self.resultWindowIsMaximized = False
self.resultWindowRect = None
self.directoriesWindowRect = None
@@ -100,6 +104,8 @@ class Preferences(PreferencesBase):
set_("TableFontSize", self.tableFontSize)
set_('ReferenceBoldFont', self.reference_bold_font)
+ set_('DetailsDialogTitleBarEnabled', self.details_dialog_titlebar_enabled)
+ set_('DetailsDialogVerticalTitleBar', self.details_dialog_vertical_titlebar)
set_("ResultWindowIsMaximized", self.resultWindowIsMaximized)
self.set_rect("ResultWindowRect", self.resultWindowRect)
self.set_rect("DirectoriesWindowRect", self.directoriesWindowRect)
diff --git a/qt/preferences_dialog.py b/qt/preferences_dialog.py
index eb3462e3..95eb1b67 100644
--- a/qt/preferences_dialog.py
+++ b/qt/preferences_dialog.py
@@ -117,8 +117,21 @@ class PreferencesDialogBase(QDialog):
self.widgetsVLayout.addLayout(
horizontalWrap([self.fontSizeLabel, self.fontSizeSpinBox, None])
)
- self._setupAddCheckbox("reference_bold_font", tr("Bold font for reference."))
+ self._setupAddCheckbox("reference_bold_font",
+ tr("Bold font for reference"))
self.widgetsVLayout.addWidget(self.reference_bold_font)
+
+ self._setupAddCheckbox("details_dialog_titlebar_enabled",
+ tr("Details dialog displays a title bar and is dockable"))
+ self.widgetsVLayout.addWidget(self.details_dialog_titlebar_enabled)
+ self._setupAddCheckbox("details_dialog_vertical_titlebar",
+ tr("Details dialog displays a vertical title bar (Linux only)"))
+ self.widgetsVLayout.addWidget(self.details_dialog_vertical_titlebar)
+ self.details_dialog_vertical_titlebar.setEnabled(
+ self.details_dialog_titlebar_enabled.isChecked())
+ self.details_dialog_titlebar_enabled.stateChanged.connect(
+ self.details_dialog_vertical_titlebar.setEnabled)
+
self.languageLabel = QLabel(tr("Language:"), self)
self.languageComboBox = QComboBox(self)
for lang in self.supportedLanguages:
@@ -190,6 +203,8 @@ class PreferencesDialogBase(QDialog):
setchecked(self.ignoreHardlinkMatches, prefs.ignore_hardlink_matches)
setchecked(self.debugModeBox, prefs.debug_mode)
setchecked(self.reference_bold_font, prefs.reference_bold_font)
+ setchecked(self.details_dialog_titlebar_enabled , prefs.details_dialog_titlebar_enabled)
+ setchecked(self.details_dialog_vertical_titlebar, prefs.details_dialog_vertical_titlebar)
self.copyMoveDestinationComboBox.setCurrentIndex(prefs.destination_type)
self.customCommandEdit.setText(prefs.custom_command)
self.fontSizeSpinBox.setValue(prefs.tableFontSize)
@@ -210,6 +225,8 @@ class PreferencesDialogBase(QDialog):
prefs.ignore_hardlink_matches = ischecked(self.ignoreHardlinkMatches)
prefs.debug_mode = ischecked(self.debugModeBox)
prefs.reference_bold_font = ischecked(self.reference_bold_font)
+ prefs.details_dialog_titlebar_enabled = ischecked(self.details_dialog_titlebar_enabled)
+ prefs.details_dialog_vertical_titlebar = ischecked(self.details_dialog_vertical_titlebar)
prefs.destination_type = self.copyMoveDestinationComboBox.currentIndex()
prefs.custom_command = str(self.customCommandEdit.text())
prefs.tableFontSize = self.fontSizeSpinBox.value()
diff --git a/qt/se/details_dialog.py b/qt/se/details_dialog.py
index 812c649f..0f922dc4 100644
--- a/qt/se/details_dialog.py
+++ b/qt/se/details_dialog.py
@@ -5,7 +5,7 @@
# http://www.gnu.org/licenses/gpl-3.0.html
from PyQt5.QtCore import QSize
-from PyQt5.QtWidgets import QVBoxLayout, QAbstractItemView
+from PyQt5.QtWidgets import QVBoxLayout, QAbstractItemView, QWidget
from hscommon.trans import trget
from ..details_dialog import DetailsDialog as DetailsDialogBase
@@ -27,3 +27,6 @@ class DetailsDialog(DetailsDialogBase):
self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
self.tableView.setShowGrid(False)
self.verticalLayout.addWidget(self.tableView)
+ self.centralWidget = QWidget()
+ self.centralWidget.setLayout(self.verticalLayout)
+ self.setWidget(self.centralWidget)
diff --git a/qtlib/about_box.py b/qtlib/about_box.py
index 88512666..99c3a059 100644
--- a/qtlib/about_box.py
+++ b/qtlib/about_box.py
@@ -42,7 +42,7 @@ class AboutBox(QDialog):
self.setWindowTitle(
tr("About {}").format(QCoreApplication.instance().applicationName())
)
- self.resize(400, 190)
+ self.resize(400, 290)
sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -69,6 +69,21 @@ class AboutBox(QDialog):
self.verticalLayout.addWidget(self.label_3)
self.label_3.setText(tr("Licensed under GPLv3"))
self.label = QLabel(self)
+ self.label_4 = QLabel(self)
+ self.label_4.setWordWrap(True)
+ self.label_4.setTextFormat(Qt.RichText)
+ self.label_4.setOpenExternalLinks(True)
+ self.label_4.setText(tr(
+ """ icon
+ made by Jason Cho (used with permission).
+
+
+
+
+
+ icons made by schollidesign
+ (licensed under GPL)."""))
+ self.verticalLayout.addWidget(self.label_4)
font = QFont()
font.setWeight(75)
font.setBold(True)