1
0
Fork 0
mirror of synced 2024-06-02 10:44:40 +12:00

InstallDialog: Update the collapsible widget to take a widget instead of a layout

This change makes it more inline with how QScrollArea operates on a central widget.
Other changes include using a QFrame instead of a QWidget as a base and
adding a QLabel for the title instead of the horizontal line.

The advanced options were split into their own separate widget. Right now
their class operates only as a container with the logic remaining in the
InstallDialog.
This commit is contained in:
loathingKernel 2022-10-31 16:54:40 +02:00
parent ae43fd7ea3
commit 435d560b5c
6 changed files with 289 additions and 492 deletions

View file

@ -5,7 +5,7 @@ from typing import Tuple, List, Union, Optional
from PyQt5.QtCore import Qt, QObject, QRunnable, QThreadPool, pyqtSignal, pyqtSlot, QSettings
from PyQt5.QtGui import QCloseEvent, QKeyEvent
from PyQt5.QtWidgets import QDialog, QFileDialog, QCheckBox, QLayout
from PyQt5.QtWidgets import QDialog, QFileDialog, QCheckBox, QLayout, QWidget, QVBoxLayout, QApplication
from legendary.models.downloading import ConditionCheckResult
from legendary.models.game import Game
from legendary.utils.selective_dl import get_sdl_appname
@ -18,10 +18,20 @@ from rare.lgndr.glue.monkeys import LgndrIndirectStatus
from rare.models.install import InstallDownloadModel, InstallQueueItemModel
from rare.shared import LegendaryCoreSingleton, ApiResultsSingleton, ArgumentsSingleton
from rare.ui.components.dialogs.install_dialog import Ui_InstallDialog
from rare.ui.components.dialogs.install_dialog_advanced import Ui_InstallDialogAdvanced
from rare.utils import config_helper
from rare.utils.extra_widgets import PathEdit
from rare.utils.misc import get_size
from rare.widgets.collapsible_widget import CollapsibleWidget
from rare.widgets.collapsible_widget import CollapsibleFrame
class InstallDialogAdvanced(CollapsibleFrame):
def __init__(self, parent=None):
widget = QWidget()
title = widget.tr("Advanced Options")
self.ui = Ui_InstallDialogAdvanced()
self.ui.setupUi(widget)
super(InstallDialogAdvanced, self).__init__(widget=widget, title=title, parent=parent)
class InstallDialog(QDialog):
@ -43,11 +53,12 @@ class InstallDialog(QDialog):
if not self.dl_item.options.overlay
else Game(app_name=self.app_name, app_title="Epic Overlay")
)
self.ui.advanced_layout.setParent(None)
self.advanced_widget = CollapsibleWidget(
child_layout=self.ui.advanced_layout, title=self.tr("Advanced options"), parent=self
)
self.ui.collapsible_layout.addWidget(self.advanced_widget)
self.advanced = InstallDialogAdvanced(parent=self)
self.ui.advanced_layout.addWidget(self.advanced)
self.selectable = CollapsibleFrame(widget=None, title=self.tr("Optional downloads"), parent=self)
self.ui.selectable_layout.addWidget(self.selectable)
self.game_path = self.game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value", "")
@ -64,7 +75,7 @@ class InstallDialog(QDialog):
header = self.tr("Update") if update else self.tr("Install")
self.ui.install_dialog_label.setText(f'<h3>{header} "{self.game.app_title}"</h3>')
self.setWindowTitle(f'{self.windowTitle()} - {header} "{self.game.app_title}"')
self.setWindowTitle(f'{QApplication.instance().applicationName()} - {header} "{self.game.app_title}"')
if not self.dl_item.options.base_path:
self.dl_item.options.base_path = self.core.lgd.config.get(
@ -112,19 +123,23 @@ class InstallDialog(QDialog):
if pf.system() == "Darwin" and "Mac" in platforms:
self.ui.platform_combo.setCurrentIndex(platforms.index("Mac"))
self.ui.max_workers_spin.setValue(self.core.lgd.config.getint("Legendary", "max_workers", fallback=0))
self.ui.max_workers_spin.valueChanged.connect(self.option_changed)
self.advanced.ui.max_workers_spin.setValue(self.core.lgd.config.getint("Legendary", "max_workers", fallback=0))
self.advanced.ui.max_workers_spin.valueChanged.connect(self.option_changed)
self.ui.max_memory_spin.setValue(self.core.lgd.config.getint("Legendary", "max_memory", fallback=0))
self.ui.max_memory_spin.valueChanged.connect(self.option_changed)
self.advanced.ui.max_memory_spin.setValue(self.core.lgd.config.getint("Legendary", "max_memory", fallback=0))
self.advanced.ui.max_memory_spin.valueChanged.connect(self.option_changed)
self.ui.dl_optimizations_check.stateChanged.connect(self.option_changed)
self.ui.force_download_check.stateChanged.connect(self.option_changed)
self.ui.ignore_space_check.stateChanged.connect(self.option_changed)
self.ui.download_only_check.stateChanged.connect(lambda: self.non_reload_option_changed("download_only"))
self.ui.shortcut_check.stateChanged.connect(lambda: self.non_reload_option_changed("shortcut"))
self.advanced.ui.dl_optimizations_check.stateChanged.connect(self.option_changed)
self.advanced.ui.force_download_check.stateChanged.connect(self.option_changed)
self.advanced.ui.ignore_space_check.stateChanged.connect(self.option_changed)
self.advanced.ui.download_only_check.stateChanged.connect(
lambda: self.non_reload_option_changed("download_only")
)
self.ui.shortcut_check.stateChanged.connect(
lambda: self.non_reload_option_changed("shortcut")
)
self.sdl_list_cbs: List[TagCheckBox] = []
self.selectable_checks: List[TagCheckBox] = []
self.config_tags: Optional[List[str]] = None
self.setup_sdl_list("Mac" if pf.system() == "Darwin" and "Mac" in platforms else "Windows")
@ -133,23 +148,24 @@ class InstallDialog(QDialog):
if self.dl_item.options.overlay:
self.ui.platform_label.setVisible(False)
self.ui.platform_combo.setVisible(False)
self.ui.ignore_space_label.setVisible(False)
self.ui.ignore_space_check.setVisible(False)
self.ui.download_only_label.setVisible(False)
self.ui.download_only_check.setVisible(False)
self.advanced.ui.ignore_space_label.setVisible(False)
self.advanced.ui.ignore_space_check.setVisible(False)
self.advanced.ui.download_only_label.setVisible(False)
self.advanced.ui.download_only_check.setVisible(False)
self.ui.shortcut_label.setVisible(False)
self.ui.shortcut_check.setVisible(False)
self.ui.sdl_list_label.setVisible(False)
self.ui.sdl_list_frame.setVisible(False)
self.selectable.setVisible(False)
if pf.system() == "Darwin":
self.ui.shortcut_check.setDisabled(True)
self.ui.shortcut_check.setChecked(False)
self.ui.shortcut_check.setToolTip(self.tr("Creating a shortcut is not supported on MacOS"))
self.ui.install_prereqs_label.setEnabled(False)
self.ui.install_prereqs_check.setEnabled(False)
self.ui.install_prereqs_check.stateChanged.connect(lambda: self.non_reload_option_changed("install_prereqs"))
self.advanced.ui.install_prereqs_label.setEnabled(False)
self.advanced.ui.install_prereqs_check.setEnabled(False)
self.advanced.ui.install_prereqs_check.stateChanged.connect(
lambda: self.non_reload_option_changed("install_prereqs")
)
self.non_reload_option_changed("shortcut")
@ -157,7 +173,7 @@ class InstallDialog(QDialog):
self.ui.verify_button.clicked.connect(self.verify_clicked)
self.ui.install_button.clicked.connect(self.install_clicked)
self.ui.install_prereqs_check.setChecked(self.dl_item.options.install_prereqs)
self.advanced.ui.install_prereqs_check.setChecked(self.dl_item.options.install_prereqs)
self.ui.install_dialog_layout.setSizeConstraint(QLayout.SetFixedSize)
@ -171,20 +187,22 @@ class InstallDialog(QDialog):
@pyqtSlot(str)
def setup_sdl_list(self, platform="Windows"):
for cb in self.sdl_list_cbs:
for cb in self.selectable_checks:
cb.disconnect()
cb.deleteLater()
self.sdl_list_cbs.clear()
self.selectable_checks.clear()
if config_tags := self.core.lgd.config.get(self.game.app_name, 'install_tags', fallback=None):
self.config_tags = config_tags.split(",")
config_disable_sdl = self.core.lgd.config.getboolean(self.game.app_name, 'disable_sdl', fallback=False)
sdl_name = get_sdl_appname(self.game.app_name)
if not config_disable_sdl and sdl_name is not None:
self.ui.sdl_list_text.hide()
# FIXME: this should be updated whenever platform changes
sdl_data = self.core.get_sdl_data(sdl_name, platform=platform)
if sdl_data:
widget = QWidget(self.selectable)
layout = QVBoxLayout(widget)
layout.setSpacing(0)
for tag, info in sdl_data.items():
cb = TagCheckBox(info["name"], info["tags"])
if tag == "__required":
@ -193,30 +211,29 @@ class InstallDialog(QDialog):
if self.config_tags is not None:
if all(elem in self.config_tags for elem in info["tags"]):
cb.setChecked(True)
self.ui.sdl_list_layout.addWidget(cb)
self.sdl_list_cbs.append(cb)
for cb in self.sdl_list_cbs:
layout.addWidget(cb)
self.selectable_checks.append(cb)
for cb in self.selectable_checks:
cb.stateChanged.connect(self.option_changed)
self.selectable.setWidget(widget)
else:
self.ui.sdl_list_text.show()
self.ui.sdl_list_label.setEnabled(False)
self.ui.sdl_list_frame.setEnabled(False)
self.selectable.setDisabled(True)
def get_options(self):
self.dl_item.options.base_path = self.install_dir_edit.text() if not self.update else None
self.dl_item.options.max_workers = self.ui.max_workers_spin.value()
self.dl_item.options.shared_memory = self.ui.max_memory_spin.value()
self.dl_item.options.order_opt = self.ui.dl_optimizations_check.isChecked()
self.dl_item.options.force = self.ui.force_download_check.isChecked()
self.dl_item.options.ignore_space = self.ui.ignore_space_check.isChecked()
self.dl_item.options.no_install = self.ui.download_only_check.isChecked()
self.dl_item.options.max_workers = self.advanced.ui.max_workers_spin.value()
self.dl_item.options.shared_memory = self.advanced.ui.max_memory_spin.value()
self.dl_item.options.order_opt = self.advanced.ui.dl_optimizations_check.isChecked()
self.dl_item.options.force = self.advanced.ui.force_download_check.isChecked()
self.dl_item.options.ignore_space = self.advanced.ui.ignore_space_check.isChecked()
self.dl_item.options.no_install = self.advanced.ui.download_only_check.isChecked()
self.dl_item.options.platform = self.ui.platform_combo.currentText()
self.dl_item.options.install_prereqs = self.ui.install_prereqs_check.isChecked()
self.dl_item.options.install_prereqs = self.advanced.ui.install_prereqs_check.isChecked()
self.dl_item.options.create_shortcut = self.ui.shortcut_check.isChecked()
if self.sdl_list_cbs:
if self.selectable_checks:
self.dl_item.options.install_tag = [""]
for cb in self.sdl_list_cbs:
for cb in self.selectable_checks:
if data := cb.isChecked():
# noinspection PyTypeChecker
self.dl_item.options.install_tag.extend(data)
@ -253,12 +270,12 @@ class InstallDialog(QDialog):
def non_reload_option_changed(self, option: str):
if option == "download_only":
self.dl_item.options.no_install = self.ui.download_only_check.isChecked()
self.dl_item.options.no_install = self.advanced.ui.download_only_check.isChecked()
elif option == "shortcut":
QSettings().setValue("create_shortcut", self.ui.shortcut_check.isChecked())
self.dl_item.options.create_shortcut = self.ui.shortcut_check.isChecked()
elif option == "install_prereqs":
self.dl_item.options.install_prereqs = self.ui.install_prereqs_check.isChecked()
self.dl_item.options.install_prereqs = self.advanced.ui.install_prereqs_check.isChecked()
def cancel_clicked(self):
if self.config_tags:
@ -292,13 +309,13 @@ class InstallDialog(QDialog):
self.ui.cancel_button.setEnabled(True)
if pf.system() == "Windows" or ArgumentsSingleton().debug:
if dl_item.igame.prereq_info and not dl_item.igame.prereq_info.get("installed", False):
self.ui.install_prereqs_check.setEnabled(True)
self.ui.install_prereqs_label.setEnabled(True)
self.ui.install_prereqs_check.setChecked(True)
self.advanced.ui.install_prereqs_check.setEnabled(True)
self.advanced.ui.install_prereqs_label.setEnabled(True)
self.advanced.ui.install_prereqs_check.setChecked(True)
prereq_name = dl_item.igame.prereq_info.get("name", "")
prereq_path = os.path.split(dl_item.igame.prereq_info.get("path", ""))[-1]
prereq_desc = prereq_name if prereq_name else prereq_path
self.ui.install_prereqs_check.setText(
self.advanced.ui.install_prereqs_check.setText(
self.tr("Also install: {}").format(prereq_desc)
)
if self.silent:
@ -333,7 +350,7 @@ class InstallDialog(QDialog):
self.threadpool.clear()
self.threadpool.waitForDone()
self.result_ready.emit(self.dl_item)
a0.accept()
super(InstallDialog, self).closeEvent(a0)
def keyPressEvent(self, e: QKeyEvent) -> None:
if e.key() == Qt.Key_Escape:
@ -403,7 +420,4 @@ class TagCheckBox(QCheckBox):
self.tags = tags
def isChecked(self) -> Union[bool, List[str]]:
if super(TagCheckBox, self).isChecked():
return self.tags
else:
return False
return self.tags if super(TagCheckBox, self).isChecked() else False

View file

@ -14,8 +14,8 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_InstallDialog(object):
def setupUi(self, InstallDialog):
InstallDialog.setObjectName("InstallDialog")
InstallDialog.resize(383, 438)
InstallDialog.setWindowTitle("Rare")
InstallDialog.resize(324, 224)
InstallDialog.setWindowTitle("InstallDialog")
self.install_dialog_layout = QtWidgets.QFormLayout(InstallDialog)
self.install_dialog_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.install_dialog_layout.setObjectName("install_dialog_layout")
@ -47,119 +47,12 @@ class Ui_InstallDialog(object):
self.shortcut_check.setText("")
self.shortcut_check.setObjectName("shortcut_check")
self.install_dialog_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.shortcut_check)
self.sdl_list_label = QtWidgets.QLabel(InstallDialog)
self.sdl_list_label.setObjectName("sdl_list_label")
self.install_dialog_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.sdl_list_label)
self.sdl_list_frame = QtWidgets.QFrame(InstallDialog)
self.sdl_list_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.sdl_list_frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.sdl_list_frame.setObjectName("sdl_list_frame")
self.sdl_list_layout = QtWidgets.QVBoxLayout(self.sdl_list_frame)
self.sdl_list_layout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
self.sdl_list_layout.setContentsMargins(-1, 0, -1, 0)
self.sdl_list_layout.setSpacing(0)
self.sdl_list_layout.setObjectName("sdl_list_layout")
self.sdl_list_text = QtWidgets.QLabel(self.sdl_list_frame)
self.sdl_list_text.setObjectName("sdl_list_text")
self.sdl_list_layout.addWidget(self.sdl_list_text)
self.install_dialog_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.sdl_list_frame)
self.collapsible_layout = QtWidgets.QVBoxLayout()
self.collapsible_layout.setObjectName("collapsible_layout")
self.advanced_layout = QtWidgets.QFormLayout()
self.advanced_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.selectable_layout = QtWidgets.QVBoxLayout()
self.selectable_layout.setObjectName("selectable_layout")
self.install_dialog_layout.setLayout(4, QtWidgets.QFormLayout.SpanningRole, self.selectable_layout)
self.advanced_layout = QtWidgets.QVBoxLayout()
self.advanced_layout.setObjectName("advanced_layout")
self.max_workers_label = QtWidgets.QLabel(InstallDialog)
self.max_workers_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.max_workers_label.setObjectName("max_workers_label")
self.advanced_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.max_workers_label)
self.max_workers_layout = QtWidgets.QHBoxLayout()
self.max_workers_layout.setObjectName("max_workers_layout")
self.max_workers_spin = QtWidgets.QSpinBox(InstallDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.max_workers_spin.sizePolicy().hasHeightForWidth())
self.max_workers_spin.setSizePolicy(sizePolicy)
self.max_workers_spin.setObjectName("max_workers_spin")
self.max_workers_layout.addWidget(self.max_workers_spin)
self.max_workers_info_label = QtWidgets.QLabel(InstallDialog)
font = QtGui.QFont()
font.setItalic(True)
self.max_workers_info_label.setFont(font)
self.max_workers_info_label.setObjectName("max_workers_info_label")
self.max_workers_layout.addWidget(self.max_workers_info_label)
self.advanced_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.max_workers_layout)
self.max_memory_label = QtWidgets.QLabel(InstallDialog)
self.max_memory_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.max_memory_label.setObjectName("max_memory_label")
self.advanced_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.max_memory_label)
self.max_memory_layout = QtWidgets.QHBoxLayout()
self.max_memory_layout.setObjectName("max_memory_layout")
self.max_memory_spin = QtWidgets.QSpinBox(InstallDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.max_memory_spin.sizePolicy().hasHeightForWidth())
self.max_memory_spin.setSizePolicy(sizePolicy)
self.max_memory_spin.setMinimum(0)
self.max_memory_spin.setMaximum(10240)
self.max_memory_spin.setSingleStep(128)
self.max_memory_spin.setProperty("value", 1024)
self.max_memory_spin.setObjectName("max_memory_spin")
self.max_memory_layout.addWidget(self.max_memory_spin)
self.max_memory_info_label = QtWidgets.QLabel(InstallDialog)
font = QtGui.QFont()
font.setItalic(True)
self.max_memory_info_label.setFont(font)
self.max_memory_info_label.setObjectName("max_memory_info_label")
self.max_memory_layout.addWidget(self.max_memory_info_label)
self.advanced_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.max_memory_layout)
self.install_prereqs_label = QtWidgets.QLabel(InstallDialog)
self.install_prereqs_label.setObjectName("install_prereqs_label")
self.advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_prereqs_label)
self.install_prereqs_check = QtWidgets.QCheckBox(InstallDialog)
font = QtGui.QFont()
font.setItalic(True)
self.install_prereqs_check.setFont(font)
self.install_prereqs_check.setText("")
self.install_prereqs_check.setChecked(False)
self.install_prereqs_check.setObjectName("install_prereqs_check")
self.advanced_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.install_prereqs_check)
self.dl_optimizations_label = QtWidgets.QLabel(InstallDialog)
self.dl_optimizations_label.setObjectName("dl_optimizations_label")
self.advanced_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.dl_optimizations_label)
self.dl_optimizations_check = QtWidgets.QCheckBox(InstallDialog)
self.dl_optimizations_check.setText("")
self.dl_optimizations_check.setChecked(False)
self.dl_optimizations_check.setObjectName("dl_optimizations_check")
self.advanced_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.dl_optimizations_check)
self.force_download_label = QtWidgets.QLabel(InstallDialog)
self.force_download_label.setObjectName("force_download_label")
self.advanced_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.force_download_label)
self.force_download_check = QtWidgets.QCheckBox(InstallDialog)
self.force_download_check.setText("")
self.force_download_check.setObjectName("force_download_check")
self.advanced_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.force_download_check)
self.ignore_space_label = QtWidgets.QLabel(InstallDialog)
self.ignore_space_label.setObjectName("ignore_space_label")
self.advanced_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.ignore_space_label)
self.ignore_space_check = QtWidgets.QCheckBox(InstallDialog)
font = QtGui.QFont()
font.setItalic(True)
self.ignore_space_check.setFont(font)
self.ignore_space_check.setObjectName("ignore_space_check")
self.advanced_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.ignore_space_check)
self.download_only_label = QtWidgets.QLabel(InstallDialog)
self.download_only_label.setObjectName("download_only_label")
self.advanced_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.download_only_label)
self.download_only_check = QtWidgets.QCheckBox(InstallDialog)
font = QtGui.QFont()
font.setItalic(True)
self.download_only_check.setFont(font)
self.download_only_check.setObjectName("download_only_check")
self.advanced_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.download_only_check)
self.collapsible_layout.addLayout(self.advanced_layout)
self.install_dialog_layout.setLayout(5, QtWidgets.QFormLayout.SpanningRole, self.collapsible_layout)
self.install_dialog_layout.setLayout(5, QtWidgets.QFormLayout.SpanningRole, self.advanced_layout)
self.download_size_label = QtWidgets.QLabel(InstallDialog)
self.download_size_label.setObjectName("download_size_label")
self.install_dialog_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.download_size_label)
@ -215,20 +108,6 @@ class Ui_InstallDialog(object):
self.install_dir_label.setText(_translate("InstallDialog", "Install directory"))
self.platform_label.setText(_translate("InstallDialog", "Platform"))
self.shortcut_label.setText(_translate("InstallDialog", "Create shortcut"))
self.sdl_list_label.setText(_translate("InstallDialog", "Optional packs"))
self.sdl_list_text.setText(_translate("InstallDialog", "None"))
self.max_workers_label.setText(_translate("InstallDialog", "Max workers"))
self.max_workers_info_label.setText(_translate("InstallDialog", "Less is slower. (0: Default)"))
self.max_memory_label.setText(_translate("InstallDialog", "Max shared memory"))
self.max_memory_spin.setSuffix(_translate("InstallDialog", "MiB"))
self.max_memory_info_label.setText(_translate("InstallDialog", "Less is slower (0: Default)"))
self.install_prereqs_label.setText(_translate("InstallDialog", "Install prerequisites"))
self.dl_optimizations_label.setText(_translate("InstallDialog", "Enable reordering"))
self.force_download_label.setText(_translate("InstallDialog", "Force redownload"))
self.ignore_space_label.setText(_translate("InstallDialog", "Ignore free space"))
self.ignore_space_check.setText(_translate("InstallDialog", "Use with caution!"))
self.download_only_label.setText(_translate("InstallDialog", "Download only"))
self.download_only_check.setText(_translate("InstallDialog", "Do not try to install."))
self.download_size_label.setText(_translate("InstallDialog", "Download size"))
self.download_size_text.setText(_translate("InstallDialog", "Click verify..."))
self.install_size_label.setText(_translate("InstallDialog", "Total install size"))

View file

@ -6,12 +6,12 @@
<rect>
<x>0</x>
<y>0</y>
<width>383</width>
<height>438</height>
<width>324</width>
<height>224</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Rare</string>
<string notr="true">InstallDialog</string>
</property>
<layout class="QFormLayout" name="install_dialog_layout">
<property name="labelAlignment">
@ -68,232 +68,11 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="sdl_list_label">
<property name="text">
<string>Optional packs</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QFrame" name="sdl_list_frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="sdl_list_layout">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="sdl_list_text">
<property name="text">
<string>None</string>
</property>
</widget>
</item>
</layout>
</widget>
<item row="4" column="0" colspan="2">
<layout class="QVBoxLayout" name="selectable_layout"/>
</item>
<item row="5" column="0" colspan="2">
<layout class="QVBoxLayout" name="collapsible_layout">
<item>
<layout class="QFormLayout" name="advanced_layout">
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="max_workers_label">
<property name="text">
<string>Max workers</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="max_workers_layout">
<item>
<widget class="QSpinBox" name="max_workers_spin">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="max_workers_info_label">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Less is slower. (0: Default)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="max_memory_label">
<property name="text">
<string>Max shared memory</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="max_memory_layout">
<item>
<widget class="QSpinBox" name="max_memory_spin">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string>MiB</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>10240</number>
</property>
<property name="singleStep">
<number>128</number>
</property>
<property name="value">
<number>1024</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="max_memory_info_label">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Less is slower (0: Default)</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="install_prereqs_label">
<property name="text">
<string>Install prerequisites</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="install_prereqs_check">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="dl_optimizations_label">
<property name="text">
<string>Enable reordering</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="dl_optimizations_check">
<property name="text">
<string notr="true"/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="force_download_label">
<property name="text">
<string>Force redownload</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="force_download_check">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="ignore_space_label">
<property name="text">
<string>Ignore free space</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="ignore_space_check">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Use with caution!</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="download_only_label">
<property name="text">
<string>Download only</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="download_only_check">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Do not try to install.</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
<layout class="QVBoxLayout" name="advanced_layout"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="download_size_label">

View file

@ -15,6 +15,7 @@ class Ui_InstallDialogAdvanced(object):
def setupUi(self, InstallDialogAdvanced):
InstallDialogAdvanced.setObjectName("InstallDialogAdvanced")
InstallDialogAdvanced.resize(379, 208)
InstallDialogAdvanced.setWindowTitle("InstallDialogAdvanced")
self.install_dialog_advanced_layout = QtWidgets.QFormLayout(InstallDialogAdvanced)
self.install_dialog_advanced_layout.setObjectName("install_dialog_advanced_layout")
self.max_workers_label = QtWidgets.QLabel(InstallDialogAdvanced)
@ -31,12 +32,12 @@ class Ui_InstallDialogAdvanced(object):
self.max_workers_spin.setSizePolicy(sizePolicy)
self.max_workers_spin.setObjectName("max_workers_spin")
self.max_workers_layout.addWidget(self.max_workers_spin)
self.max_workers_info_label = QtWidgets.QLabel(InstallDialogAdvanced)
self.max_workers_info = QtWidgets.QLabel(InstallDialogAdvanced)
font = QtGui.QFont()
font.setItalic(True)
self.max_workers_info_label.setFont(font)
self.max_workers_info_label.setObjectName("max_workers_info_label")
self.max_workers_layout.addWidget(self.max_workers_info_label)
self.max_workers_info.setFont(font)
self.max_workers_info.setObjectName("max_workers_info")
self.max_workers_layout.addWidget(self.max_workers_info)
self.install_dialog_advanced_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.max_workers_layout)
self.max_memory_label = QtWidgets.QLabel(InstallDialogAdvanced)
self.max_memory_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
@ -56,16 +57,16 @@ class Ui_InstallDialogAdvanced(object):
self.max_memory_spin.setProperty("value", 1024)
self.max_memory_spin.setObjectName("max_memory_spin")
self.max_memory_layout.addWidget(self.max_memory_spin)
self.max_memory_info_label = QtWidgets.QLabel(InstallDialogAdvanced)
self.max_memory_info = QtWidgets.QLabel(InstallDialogAdvanced)
font = QtGui.QFont()
font.setItalic(True)
self.max_memory_info_label.setFont(font)
self.max_memory_info_label.setObjectName("max_memory_info_label")
self.max_memory_layout.addWidget(self.max_memory_info_label)
self.max_memory_info.setFont(font)
self.max_memory_info.setObjectName("max_memory_info")
self.max_memory_layout.addWidget(self.max_memory_info)
self.install_dialog_advanced_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.max_memory_layout)
self.install_prereqs_lbl = QtWidgets.QLabel(InstallDialogAdvanced)
self.install_prereqs_lbl.setObjectName("install_prereqs_lbl")
self.install_dialog_advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_prereqs_lbl)
self.install_prereqs_label = QtWidgets.QLabel(InstallDialogAdvanced)
self.install_prereqs_label.setObjectName("install_prereqs_label")
self.install_dialog_advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_prereqs_label)
self.install_prereqs_check = QtWidgets.QCheckBox(InstallDialogAdvanced)
font = QtGui.QFont()
font.setItalic(True)
@ -113,13 +114,12 @@ class Ui_InstallDialogAdvanced(object):
def retranslateUi(self, InstallDialogAdvanced):
_translate = QtCore.QCoreApplication.translate
InstallDialogAdvanced.setWindowTitle(_translate("InstallDialogAdvanced", "Form"))
self.max_workers_label.setText(_translate("InstallDialogAdvanced", "Max workers"))
self.max_workers_info_label.setText(_translate("InstallDialogAdvanced", "Less is slower. (0: Default)"))
self.max_workers_info.setText(_translate("InstallDialogAdvanced", "Less is slower. (0: Default)"))
self.max_memory_label.setText(_translate("InstallDialogAdvanced", "Max shared memory"))
self.max_memory_spin.setSuffix(_translate("InstallDialogAdvanced", "MiB"))
self.max_memory_info_label.setText(_translate("InstallDialogAdvanced", "Less is slower (0: Default)"))
self.install_prereqs_lbl.setText(_translate("InstallDialogAdvanced", "Install prerequisites"))
self.max_memory_info.setText(_translate("InstallDialogAdvanced", "Less is slower (0: Default)"))
self.install_prereqs_label.setText(_translate("InstallDialogAdvanced", "Install prerequisites"))
self.dl_optimizations_label.setText(_translate("InstallDialogAdvanced", "Enable reordering"))
self.force_download_label.setText(_translate("InstallDialogAdvanced", "Force redownload"))
self.ignore_space_label.setText(_translate("InstallDialogAdvanced", "Ignore free space"))

View file

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string notr="true">InstallDialogAdvanced</string>
</property>
<layout class="QFormLayout" name="install_dialog_advanced_layout">
<item row="0" column="0">
@ -37,7 +37,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="max_workers_info_label">
<widget class="QLabel" name="max_workers_info">
<property name="font">
<font>
<italic>true</italic>
@ -88,7 +88,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="max_memory_info_label">
<widget class="QLabel" name="max_memory_info">
<property name="font">
<font>
<italic>true</italic>
@ -102,7 +102,7 @@
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="install_prereqs_lbl">
<widget class="QLabel" name="install_prereqs_label">
<property name="text">
<string>Install prerequisites</string>
</property>

View file

@ -1,85 +1,210 @@
from PyQt5.QtCore import QParallelAnimationGroup, Qt, QPropertyAnimation, QAbstractAnimation
from PyQt5.QtWidgets import QWidget, QFrame, QToolButton, QGridLayout, QSizePolicy, QLayout
from PyQt5.QtWidgets import QApplication, QWidget, QFrame, QToolButton, QGridLayout, QSizePolicy, QGroupBox, QSpacerItem, QLabel
from rare.utils.misc import icon
# https://newbedev.com/how-to-make-an-expandable-collapsable-section-widget-in-qt
class CollapsibleWidget(QWidget):
class CollapsibleFrame(QFrame):
def __init__(
self, child_layout: QLayout = None, title: str = "", animation_duration: int = 200, parent=None
self, widget: QWidget = None, title: str = "", button_text: str = "", animation_duration: int = 200, parent=None
):
"""
References:
# Adapted from c++ version
https://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt
"""
super(CollapsibleWidget, self).__init__(parent=parent)
super(CollapsibleFrame, self).__init__(parent=parent)
self.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
self.animationDuration = animation_duration
self.toggleAnimation = QParallelAnimationGroup()
self.contentArea = QWidget()
self.headerLine = QFrame()
self.toggleButton = QToolButton()
self.mainLayout = QGridLayout()
self.content_area = None
self.animation_duration = animation_duration
toggleButton = self.toggleButton
toggleButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
toggleButton.setIcon(icon("fa.arrow-right"))
toggleButton.setText(str(title))
toggleButton.setCheckable(True)
toggleButton.setChecked(False)
self.toggle_button = QToolButton(self)
self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.toggle_button.setIcon(icon("fa.arrow-right"))
self.toggle_button.setText(button_text)
self.toggle_button.setCheckable(True)
self.toggle_button.setChecked(False)
headerLine = self.headerLine
headerLine.setFrameShape(QFrame.StyledPanel)
headerLine.setFrameShadow(QFrame.Plain)
headerLine.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
self.spacer_label = QLabel(title)
font = self.spacer_label.font()
font.setBold(True)
self.spacer_label.setFont(font)
self.spacer_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.contentArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
# start out collapsed
self.contentArea.setMaximumHeight(0)
self.contentArea.setMinimumHeight(0)
# let the entire widget grow and shrink with its content
toggleAnimation = self.toggleAnimation
toggleAnimation.addAnimation(QPropertyAnimation(self, b"minimumHeight"))
toggleAnimation.addAnimation(QPropertyAnimation(self, b"maximumHeight"))
toggleAnimation.addAnimation(QPropertyAnimation(self.contentArea, b"maximumHeight"))
self.toggle_animation = QParallelAnimationGroup(self)
self.toggle_animation.addAnimation(QPropertyAnimation(self, b"minimumHeight"))
self.toggle_animation.addAnimation(QPropertyAnimation(self, b"maximumHeight"))
# don't waste space
mainLayout = self.mainLayout
mainLayout.setVerticalSpacing(0)
mainLayout.setContentsMargins(0, 0, 0, 0)
row = 0
mainLayout.addWidget(self.toggleButton, row, 0, 1, 1, Qt.AlignLeft)
mainLayout.addWidget(self.headerLine, row, 2, 1, 1)
row += 1
mainLayout.addWidget(self.contentArea, row, 0, 1, 3)
self.setLayout(self.mainLayout)
self.main_layout = QGridLayout(self)
self.main_layout.setVerticalSpacing(0)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.addWidget(self.toggle_button, 0, 0, 1, 1, Qt.AlignLeft)
self.main_layout.addWidget(self.spacer_label, 0, 1, 1, 1)
self.main_layout.setColumnStretch(1, 1)
self.main_layout.setRowStretch(0, 0)
self.main_layout.setRowStretch(1, 1)
self.setLayout(self.main_layout)
def start_animation(checked):
arrow_type = icon("fa.arrow-down") if checked else icon("fa.arrow-right")
direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward
toggleButton.setIcon(arrow_type)
self.toggleAnimation.setDirection(direction)
self.toggleAnimation.start()
self.toggle_button.clicked.connect(self.animationStart)
self.toggleButton.clicked.connect(start_animation)
if widget is not None:
self.setWidget(widget)
if child_layout:
self.setContentLayout(child_layout)
def animationStart(self, checked):
arrow_type = icon("fa.arrow-down") if checked else icon("fa.arrow-right")
direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward
self.toggle_button.setIcon(arrow_type)
self.toggle_animation.setDirection(direction)
self.toggle_animation.start()
def setWidget(self, widget: QWidget):
if widget is None or widget is self.content_area:
return
if self.content_area is not None:
# Collapse the parent before replacing the child
if self.toggle_button.isChecked():
self.toggle_button.click()
self.toggle_animation.removeAnimation(self.content_toggle_animation)
self.content_area.setParent(None)
self.content_area.deleteLater()
self.content_area = widget
self.content_area.setParent(self)
self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.adjustSize()
# start out collapsed
if not self.toggle_button.isChecked():
self.content_area.setMaximumHeight(0)
self.content_area.setMinimumHeight(0)
self.content_toggle_animation = QPropertyAnimation(self.content_area, b"maximumHeight")
self.toggle_animation.addAnimation(self.content_toggle_animation)
self.main_layout.addWidget(self.content_area, 1, 0, 1, 2)
collapsed_height = self.sizeHint().height() - self.content_area.maximumHeight()
content_height = self.content_area.sizeHint().height()
for i in range(self.toggle_animation.animationCount() - 1):
spoiler_animation = self.toggle_animation.animationAt(i)
spoiler_animation.setDuration(self.animation_duration)
spoiler_animation.setStartValue(collapsed_height)
spoiler_animation.setEndValue(collapsed_height + content_height)
content_animation = self.toggle_animation.animationAt(self.toggle_animation.animationCount() - 1)
content_animation.setDuration(self.animation_duration)
content_animation.setStartValue(0)
content_animation.setEndValue(content_height)
class CollapsibleGroupBox(QGroupBox):
def __init__(
self, widget: QWidget = None, title: str = "", animation_duration: int = 200, parent=None
):
"""
References:
# Adapted from c++ version
https://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt
"""
super(CollapsibleGroupBox, self).__init__(parent=parent)
self.setTitle(title)
self.setCheckable(True)
self.content_area = None
self.animation_duration = animation_duration
# let the entire widget grow and shrink with its content
self.toggle_animation = QParallelAnimationGroup(self)
self.toggle_animation.addAnimation(QPropertyAnimation(self, b"minimumHeight"))
self.toggle_animation.addAnimation(QPropertyAnimation(self, b"maximumHeight"))
# don't waste space
self.main_layout = QVBoxLayout(self)
self.main_layout.setSpacing(0)
self.main_layout.setContentsMargins(0, 0, 0, -1)
self.setLayout(self.main_layout)
self.clicked.connect(self.animationStart)
if widget is not None:
self.setWidget(widget)
def animationStart(self, checked):
direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward
self.toggle_animation.setDirection(direction)
self.toggle_animation.start()
def setWidget(self, widget: QWidget):
if widget is None or widget is self.content_area:
return
if self.content_area is not None:
self.content_area.deleteLater()
self.content_area = widget
self.content_area.setParent(self)
self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
# start out collapsed
self.setChecked(False)
self.content_area.setMaximumHeight(0)
self.content_area.setMinimumHeight(0)
self.toggle_animation.addAnimation(QPropertyAnimation(self.content_area, b"maximumHeight"))
self.main_layout.addWidget(self.content_area)
collapsed_height = self.sizeHint().height() - self.content_area.maximumHeight()
content_height = self.content_area.sizeHint().height()
for i in range(self.toggle_animation.animationCount() - 1):
spoiler_animation = self.toggle_animation.animationAt(i)
spoiler_animation.setDuration(self.animation_duration)
spoiler_animation.setStartValue(collapsed_height)
spoiler_animation.setEndValue(collapsed_height + content_height)
content_animation = self.toggle_animation.animationAt(self.toggle_animation.animationCount() - 1)
content_animation.setDuration(self.animation_duration)
content_animation.setStartValue(0)
content_animation.setEndValue(content_height)
if __name__ == "__main__":
import sys
from PyQt5.QtWidgets import QApplication, QDialog, QVBoxLayout, QPushButton
from rare.ui.components.dialogs.install_dialog_advanced import Ui_InstallDialogAdvanced
import rare.resources.stylesheets.RareStyle
from rare.utils.misc import set_color_pallete, set_style_sheet
app = QApplication(sys.argv)
set_style_sheet("RareStyle")
ui_frame = Ui_InstallDialogAdvanced()
widget_frame = QWidget()
ui_frame.setupUi(widget_frame)
collapsible_frame = CollapsibleFrame(widget_frame, title="Frame me!")
collapsible_frame.setDisabled(False)
def replace_func(state):
widget2_frame = QWidget()
ui2_frame = Ui_InstallDialogAdvanced()
ui2_frame.setupUi(widget2_frame)
if state:
ui2_frame.install_dialog_advanced_layout.removeRow(3)
ui2_frame.install_dialog_advanced_layout.removeRow(4)
collapsible_frame.setWidget(widget2_frame)
replace_button = QToolButton()
replace_button.setText("Replace me!")
replace_button.setCheckable(True)
replace_button.setChecked(False)
replace_button.clicked.connect(replace_func)
ui_group = Ui_InstallDialogAdvanced()
widget_group = QWidget()
ui_group.setupUi(widget_group)
collapsible_group = CollapsibleGroupBox(widget_group, title="Group me!")
collapsible_group.setDisabled(False)
dialog = QDialog()
dialog.setLayout(QVBoxLayout())
dialog.layout().addWidget(replace_button)
dialog.layout().addWidget(collapsible_frame)
dialog.layout().addWidget(collapsible_group)
dialog.layout().setSizeConstraint(QVBoxLayout.SetFixedSize)
dialog.show()
sys.exit(app.exec_())
def setContentLayout(self, content_layout: QLayout):
# Not sure if this is equivalent to self.contentArea.destroy()
self.contentArea.destroy()
self.contentArea.setLayout(content_layout)
collapsedHeight = self.sizeHint().height() - self.contentArea.maximumHeight()
contentHeight = content_layout.sizeHint().height()
for i in range(self.toggleAnimation.animationCount() - 1):
spoilerAnimation = self.toggleAnimation.animationAt(i)
spoilerAnimation.setDuration(self.animationDuration)
spoilerAnimation.setStartValue(collapsedHeight)
spoilerAnimation.setEndValue(collapsedHeight + contentHeight)
contentAnimation = self.toggleAnimation.animationAt(self.toggleAnimation.animationCount() - 1)
contentAnimation.setDuration(self.animationDuration)
contentAnimation.setStartValue(0)
contentAnimation.setEndValue(contentHeight)