From e50015c25cf60480903e7af67ff0e18d9743d8cf Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Sat, 24 Feb 2024 13:11:28 +0200
Subject: [PATCH] WrapperSettings: Improve widget structure
* Remove the annoying stacked widget, instead create a double layout in
the container and place a label in that to hold the placeholder message.
* Implement the scroll area as a custom widget. This custom widget installs
an event filter on the container to adjust the scrollarea size when the
container size changes.
---
.../tabs/settings/widgets/wrappers.py | 153 ++++++++++--------
1 file changed, 86 insertions(+), 67 deletions(-)
diff --git a/rare/components/tabs/settings/widgets/wrappers.py b/rare/components/tabs/settings/widgets/wrappers.py
index b508bf33..a4f70eb1 100644
--- a/rare/components/tabs/settings/widgets/wrappers.py
+++ b/rare/components/tabs/settings/widgets/wrappers.py
@@ -4,8 +4,17 @@ import shutil
from logging import getLogger
from typing import Optional, Tuple, Iterable
-from PyQt5.QtCore import pyqtSignal, QSize, Qt, QMimeData, pyqtSlot
-from PyQt5.QtGui import QDrag, QDropEvent, QDragEnterEvent, QDragMoveEvent, QFont, QMouseEvent, QShowEvent
+from PyQt5.QtCore import pyqtSignal, QSize, Qt, QMimeData, pyqtSlot, QObject, QEvent
+from PyQt5.QtGui import (
+ QDrag,
+ QDropEvent,
+ QDragEnterEvent,
+ QDragMoveEvent,
+ QFont,
+ QMouseEvent,
+ QShowEvent,
+ QResizeEvent,
+)
from PyQt5.QtWidgets import (
QHBoxLayout,
QLabel,
@@ -15,7 +24,11 @@ from PyQt5.QtWidgets import (
QWidget,
QScrollArea,
QAction,
- QMenu, QStackedWidget, QPushButton, QLineEdit, QVBoxLayout, QComboBox,
+ QMenu,
+ QPushButton,
+ QLineEdit,
+ QVBoxLayout,
+ QComboBox,
)
from rare.models.wrapper import Wrapper
@@ -172,46 +185,75 @@ class WrapperWidget(QFrame):
drag.exec_(Qt.MoveAction)
+class WrapperSettingsScroll(QScrollArea):
+ def __init__(self, parent=None):
+ super(WrapperSettingsScroll, self).__init__(parent=parent)
+ self.setFrameShape(QFrame.StyledPanel)
+ self.setSizeAdjustPolicy(QScrollArea.AdjustToContents)
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ self.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
+ self.setWidgetResizable(True)
+ self.setProperty("no_kinetic_scroll", True)
+
+ self.setObjectName(type(self).__name__)
+ self.horizontalScrollBar().setObjectName(f"{self.objectName()}Bar")
+ self.verticalScrollBar().setObjectName(f"{self.objectName()}Bar")
+
+ def setWidget(self, w):
+ super().setWidget(w)
+ w.installEventFilter(self)
+
+ def eventFilter(self, a0: QObject, a1: QEvent) -> bool:
+ if a0 is self.widget() and a1.type() == QEvent.Resize:
+ self.__resize(a0)
+ return a0.event(a1)
+ return False
+
+ def __resize(self, e: QResizeEvent):
+ minh = self.horizontalScrollBar().minimum()
+ maxh = self.horizontalScrollBar().maximum()
+ # lk: when the scrollbar is not visible, min and max are 0
+ if maxh > minh:
+ height = (
+ e.size().height()
+ + self.rect().height() // 2
+ - self.contentsRect().height() // 2
+ + self.widget().layout().spacing()
+ + self.horizontalScrollBar().sizeHint().height()
+ )
+ else:
+ height = e.size().height() + self.rect().height() - self.contentsRect().height()
+ self.setMaximumHeight(max(height, self.minimumHeight()))
+
+
class WrapperSettings(QWidget):
def __init__(self, parent=None):
super(WrapperSettings, self).__init__(parent=parent)
- self.widget_stack = QStackedWidget(self)
- self.wrapper_scroll = QScrollArea(self.widget_stack)
- self.wrapper_scroll.setSizeAdjustPolicy(QScrollArea.AdjustToContents)
- self.wrapper_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- self.wrapper_scroll.setWidgetResizable(True)
- self.wrapper_scroll.setProperty("no_kinetic_scroll", True)
- self.wrapper_container = WrapperContainer(parent=self.wrapper_scroll)
- self.wrapper_container.orderChanged.connect(self.__on_order_changed)
- self.wrapper_scroll.setWidget(self.wrapper_container)
-
- self.no_wrapper_label = QLabel(self.tr("No wrappers defined"), self.widget_stack)
-
- self.widget_stack.addWidget(self.wrapper_scroll)
- self.widget_stack.addWidget(self.no_wrapper_label)
+ self.wrapper_label = QLabel(self.tr("No wrappers defined"), self)
+ self.wrapper_label.setFrameStyle(QLabel.StyledPanel | QLabel.Plain)
+ self.wrapper_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.add_button = QPushButton(self.tr("Add wrapper"), self)
self.add_button.clicked.connect(self.__on_add)
- self.wrapper_scroll.horizontalScrollBar().rangeChanged.connect(self.adjust_scrollarea)
+ self.wrapper_scroll = WrapperSettingsScroll(self)
+ self.wrapper_scroll.setMinimumHeight(self.add_button.minimumSizeHint().height())
+
+ self.wrapper_container = WrapperContainer(self.wrapper_label, self.wrapper_scroll)
+ self.wrapper_container.orderChanged.connect(self.__on_order_changed)
+ self.wrapper_scroll.setWidget(self.wrapper_container)
# lk: set object names for the stylesheet
self.setObjectName("WrapperSettings")
- self.no_wrapper_label.setObjectName(f"{self.objectName()}Label")
- self.wrapper_scroll.setObjectName(f"{self.objectName()}Scroll")
- self.wrapper_scroll.horizontalScrollBar().setObjectName(
- f"{self.wrapper_scroll.objectName()}Bar")
- self.wrapper_scroll.verticalScrollBar().setObjectName(
- f"{self.wrapper_scroll.objectName()}Bar")
+ self.wrapper_label.setObjectName(f"{self.objectName()}Label")
main_layout = QHBoxLayout(self)
- main_layout.addWidget(self.widget_stack)
- main_layout.addWidget(self.add_button, alignment=Qt.AlignTop)
main_layout.setContentsMargins(0, 0, 0, 0)
- main_layout.setAlignment(Qt.AlignTop)
+ main_layout.addWidget(self.wrapper_scroll, alignment=Qt.AlignTop)
+ main_layout.addWidget(self.add_button, alignment=Qt.AlignTop)
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+ self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.app_name: str = "default"
self.core = RareCore.instance().core()
@@ -223,27 +265,6 @@ class WrapperSettings(QWidget):
self.update_state()
return super().showEvent(a0)
- @pyqtSlot(int, int)
- def adjust_scrollarea(self, minh: int, maxh: int):
- wrapper_widget = self.wrapper_container.findChild(WrapperWidget)
- if not wrapper_widget:
- return
- # lk: when the scrollbar is not visible, min and max are 0
- if maxh > minh:
- self.wrapper_scroll.setMaximumHeight(
- wrapper_widget.sizeHint().height()
- + self.wrapper_scroll.rect().height() // 2
- - self.wrapper_scroll.contentsRect().height() // 2
- + self.wrapper_container.layout().spacing()
- + self.wrapper_scroll.horizontalScrollBar().sizeHint().height()
- )
- else:
- self.wrapper_scroll.setMaximumHeight(
- wrapper_widget.sizeHint().height()
- + self.wrapper_scroll.rect().height()
- - self.wrapper_scroll.contentsRect().height()
- )
-
@pyqtSlot(QWidget, int)
def __on_order_changed(self, widget: WrapperWidget, new_index: int):
wrapper = widget.data()
@@ -266,16 +287,12 @@ class WrapperSettings(QWidget):
self.add_user_wrapper(wrapper)
def __add_wrapper(self, wrapper: Wrapper, position: int = -1):
- self.widget_stack.setCurrentWidget(self.wrapper_scroll)
+ self.wrapper_label.setVisible(False)
widget = WrapperWidget(wrapper, self.wrapper_container)
if position < 0:
self.wrapper_container.addWidget(widget)
else:
self.wrapper_container.insertWidget(position, widget)
- self.adjust_scrollarea(
- self.wrapper_scroll.horizontalScrollBar().minimum(),
- self.wrapper_scroll.horizontalScrollBar().maximum(),
- )
widget.update_wrapper.connect(self.__update_wrapper)
widget.delete_wrapper.connect(self.__delete_wrapper)
@@ -304,7 +321,9 @@ class WrapperSettings(QWidget):
if wrapper.checksum in self.wrappers.get_game_md5sum_list(self.app_name):
QMessageBox.warning(
- self, self.tr("Warning"), self.tr("Wrapper {0} is already in the list").format(wrapper.as_str)
+ self,
+ self.tr("Warning"),
+ self.tr("Wrapper {0} is already in the list").format(wrapper.as_str),
)
return
@@ -314,7 +333,7 @@ class WrapperSettings(QWidget):
self.tr("Warning"),
self.tr("Wrapper {0} is not in $PATH. Add it anyway?").format(wrapper.executable),
QMessageBox.Yes | QMessageBox.No,
- QMessageBox.No
+ QMessageBox.No,
)
if ans == QMessageBox.No:
return
@@ -327,8 +346,7 @@ class WrapperSettings(QWidget):
wrappers.remove(wrapper)
self.wrappers.set_game_wrapper_list(self.app_name, wrappers)
if not wrappers:
- self.wrapper_scroll.setMaximumHeight(self.no_wrapper_label.sizeHint().height())
- self.widget_stack.setCurrentWidget(self.no_wrapper_label)
+ self.wrapper_label.setVisible(True)
@pyqtSlot(object, object)
def __update_wrapper(self, old: Wrapper, new: Wrapper):
@@ -345,10 +363,7 @@ class WrapperSettings(QWidget):
w.deleteLater()
wrappers = self.wrappers.get_game_wrapper_list(self.app_name)
if not wrappers:
- self.wrapper_scroll.setMaximumHeight(self.no_wrapper_label.sizeHint().height())
- self.widget_stack.setCurrentWidget(self.no_wrapper_label)
- else:
- self.widget_stack.setCurrentWidget(self.wrapper_scroll)
+ self.wrapper_label.setVisible(True)
for wrapper in wrappers:
self.__add_wrapper(wrapper)
@@ -357,15 +372,19 @@ class WrapperContainer(QWidget):
# QWidget: moving widget, int: new index
orderChanged: pyqtSignal = pyqtSignal(QWidget, int)
- def __init__(self, parent=None):
+ def __init__(self, label: QLabel, parent=None):
super(WrapperContainer, self).__init__(parent=parent)
self.setAcceptDrops(True)
- self.__layout = QHBoxLayout(self)
- self.__layout.setContentsMargins(0, 0, 0, 0)
- self.__layout.setAlignment(Qt.AlignLeft | Qt.AlignTop)
-
+ self.__layout = QHBoxLayout()
self.__drag_widget: Optional[QWidget] = None
+ main_layout = QHBoxLayout(self)
+ main_layout.addWidget(label)
+ main_layout.addLayout(self.__layout)
+ main_layout.setContentsMargins(0, 0, 0, 0)
+ main_layout.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
+ main_layout.setSizeConstraint(QHBoxLayout.SetFixedSize)
+
# lk: set object names for the stylesheet
self.setObjectName(type(self).__name__)