diff --git a/NUSGet.py b/NUSGet.py index 02e04e7..6dee9b4 100644 --- a/NUSGet.py +++ b/NUSGet.py @@ -19,12 +19,11 @@ # nuitka-project: --include-data-dir={MAIN_DIRECTORY}/resources=resources import sys -import platform import webbrowser from importlib.metadata import version from PySide6.QtGui import QIcon -from PySide6.QtWidgets import QApplication, QMainWindow, QMessageBox, QStyleFactory, QFileDialog +from PySide6.QtWidgets import QApplication, QMainWindow, QMessageBox, QFileDialog, QListView from PySide6.QtCore import QRunnable, Slot, QThreadPool, Signal, QObject, QLibraryInfo, QTranslator, QLocale from qt.py.ui_AboutDialog import AboutNUSGet @@ -84,50 +83,45 @@ class MainWindow(QMainWindow, Ui_MainWindow): # About and About Qt Buttons self.ui.actionAbout.triggered.connect(self.about_nusget) self.ui.actionAbout_Qt.triggered.connect(lambda: QMessageBox.aboutQt(self)) - self.ui.pack_archive_chkbox.toggled.connect( - lambda: connect_is_enabled_to_checkbox([self.ui.archive_file_entry], self.ui.pack_archive_chkbox)) - self.ui.custom_out_dir_chkbox.toggled.connect( + self.ui.pack_archive_checkbox.toggled.connect( + lambda: connect_is_enabled_to_checkbox([self.ui.archive_file_entry], self.ui.pack_archive_checkbox)) + self.ui.custom_out_dir_checkbox.toggled.connect( lambda: connect_is_enabled_to_checkbox([self.ui.custom_out_dir_entry, self.ui.custom_out_dir_btn], - self.ui.custom_out_dir_chkbox)) + self.ui.custom_out_dir_checkbox)) # Load auto-update settings, and initialize them if they don't exist. try: - self.ui.auto_update_chkbox.setChecked(config_data["auto_update"]) + self.ui.auto_update_checkbox.setChecked(config_data["auto_update"]) except KeyError: - update_setting(config_data, "auto_update", self.ui.auto_update_chkbox.isChecked()) - self.ui.auto_update_chkbox.toggled.connect( - lambda: update_setting(config_data, "auto_update", self.ui.auto_update_chkbox.isChecked())) + update_setting(config_data, "auto_update", self.ui.auto_update_checkbox.isChecked()) + self.ui.auto_update_checkbox.toggled.connect( + lambda: update_setting(config_data, "auto_update", self.ui.auto_update_checkbox.isChecked())) # Load custom output directory if one is saved and it is valid. Only enable the checkbox to actually use the - # custom dir if use_out_path is set to true. + # custom dir if "use_out_path" is set to true. try: out_dir = pathlib.Path(config_data["out_path"]) if out_dir.exists() and out_dir.is_dir(): self.ui.custom_out_dir_entry.setText(str(out_dir)) if config_data["use_out_path"]: - self.ui.custom_out_dir_chkbox.setChecked(True) + self.ui.custom_out_dir_checkbox.setChecked(True) except KeyError: pass # Register this callback after the previous check to avoid an extra config write. - self.ui.custom_out_dir_chkbox.toggled.connect( - lambda: update_setting(config_data, "use_out_path", self.ui.custom_out_dir_chkbox.isChecked())) + self.ui.custom_out_dir_checkbox.toggled.connect( + lambda: update_setting(config_data, "use_out_path", self.ui.custom_out_dir_checkbox.isChecked())) self.ui.tid_entry.textChanged.connect(self.tid_updated) self.ui.custom_out_dir_entry.textChanged.connect(self.custom_output_dir_changed) # Basic intro text set to automatically show when the app loads. This may be changed in the future. - libwiipy_version = "v" + version("libWiiPy") - libtwlpy_version = "v" + version("libTWLPy") - self.log_text = (app.translate("MainWindow", "NUSGet v{nusget_version}\nDeveloped by NinjaCheetah\nPowered by libWiiPy " - "{libwiipy_version}\nDSi support provided by libTWLPy {libtwlpy_version}\n\n" - "Select a title from the list on the left, or enter a Title ID to begin.\n\n" - "Titles marked with a checkmark are free and have a ticket available, and can" - " be decrypted and/or packed into a WAD or TAD. Titles with an X do not have " - "a ticket, and only their encrypted contents can be saved.\n\nBy default, titles will be " - "downloaded to a folder named \"NUSGet Downloads\" inside your downloads folder.") - .format(nusget_version=nusget_version, libwiipy_version=libwiipy_version, - libtwlpy_version=libtwlpy_version)) + self.log_text = app.translate("MainWindow", "Select a title from the list on the left, or enter a " + "Title ID to begin.\n\nTitles marked with a checkmark are free and have a ticket " + "available, and can be decrypted and/or packed into a WAD or TAD. Titles with an X do not" + " have a ticket, and only their encrypted contents can be saved.\n\nBy default, titles " + "will be downloaded to a folder named \"NUSGet Downloads\" inside your downloads folder.") self.ui.log_text_browser.setText(self.log_text) # Add console entries to dropdown and attach on change signal. - self.ui.console_select_dropdown.addItem("Wii") - self.ui.console_select_dropdown.addItem("vWii") - self.ui.console_select_dropdown.addItem("DSi") + self.ui.console_select_dropdown.addItems(["Wii", "vWii", "DSi"]) + list_view = QListView() + list_view.setMouseTracking(True) + self.ui.console_select_dropdown.setView(list_view) self.ui.console_select_dropdown.currentIndexChanged.connect(self.selected_console_changed) # Title tree loading code. Now powered by Models:tm: wii_model = NUSGetTreeModel(wii_database, root_name="Wii Titles") @@ -152,15 +146,18 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.setFixedSize(self.size()) # These connections allow for clicking the checkbox labels to toggle the checkboxes, if they're enabled. This is # required because checkboxes can't word wrap, so regular labels must be used in their place. - connect_label_to_checkbox(self.ui.pack_archive_chkbox_lbl, self.ui.pack_archive_chkbox) - connect_label_to_checkbox(self.ui.keep_enc_chkbox_lbl, self.ui.keep_enc_chkbox) - connect_label_to_checkbox(self.ui.create_dec_chkbox_lbl, self.ui.create_dec_chkbox) - connect_label_to_checkbox(self.ui.use_local_chkbox_lbl, self.ui.use_local_chkbox) - connect_label_to_checkbox(self.ui.use_wiiu_nus_chkbox_lbl, self.ui.use_wiiu_nus_chkbox) - connect_label_to_checkbox(self.ui.patch_ios_chkbox_lbl, self.ui.patch_ios_chkbox) - connect_label_to_checkbox(self.ui.pack_vwii_mode_chkbox_lbl, self.ui.pack_vwii_mode_chkbox) - connect_label_to_checkbox(self.ui.auto_update_chkbox_lbl, self.ui.auto_update_chkbox) - connect_label_to_checkbox(self.ui.custom_out_dir_chkbox_lbl, self.ui.custom_out_dir_chkbox) + self.ui.pack_archive_checkbox.label.setText(app.translate("MainWindow", "Pack installable archive (WAD/TAD)")) + self.ui.pack_archive_checkbox.setChecked(True) + self.ui.keep_enc_checkbox.label.setText(app.translate("MainWindow", "Keep encrypted contents")) + self.ui.keep_enc_checkbox.setChecked(True) + self.ui.create_dec_checkbox.label.setText(app.translate("MainWindow", "Create decrypted contents (*.app)")) + self.ui.use_local_checkbox.label.setText(app.translate("MainWindow", "Use local files, if they exist")) + self.ui.use_wiiu_nus_checkbox.label.setText(app.translate("MainWindow", "Use the Wii U NUS (faster, only effects Wii/vWii)")) + self.ui.use_wiiu_nus_checkbox.setChecked(True) + self.ui.patch_ios_checkbox.label.setText(app.translate("MainWindow", "Apply patches to IOS (Applies to WADs only)")) + self.ui.pack_vwii_mode_checkbox.label.setText(app.translate("MainWindow", "Re-encrypt title using the Wii Common Key")) + self.ui.auto_update_checkbox.label.setText(app.translate("MainWindow", "Check for updates on startup")) + self.ui.custom_out_dir_checkbox.label.setText(app.translate("MainWindow", "Use a custom download directory")) try: auto_update = config_data["auto_update"] except KeyError: @@ -205,9 +202,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): tid = self.ui.tid_entry.text() if len(tid) == 16: if tid[:8] == "00000001" and int(tid[-2:], 16) > 2: - self.ui.patch_ios_chkbox.setEnabled(True) + self.ui.patch_ios_checkbox.setEnabled(True) return - self.ui.patch_ios_chkbox.setEnabled(False) + self.ui.patch_ios_checkbox.setEnabled(False) def update_log_text(self, new_text): # This method primarily exists to be the handler for the progress signal emitted by the worker thread. @@ -225,7 +222,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): msg_box.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) msg_box.setDefaultButton(QMessageBox.StandardButton.Yes) msg_box.setWindowTitle(app.translate("MainWindow", "NUSGet Update Available")) - msg_box.setText(app.translate("MainWindow", "There's a newer version of NUSGet available!")) + msg_box.setText(app.translate("MainWindow", "There's a newer version of NUSGet available!")) msg_box.setInformativeText(app.translate("MainWindow", "You're currently running v{nusget_version}, " "but v{new_version} is available on GitHub. Would you like to view" " the latest version?" @@ -281,17 +278,17 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.ui.version_entry.setEnabled(False) self.ui.download_btn.setEnabled(False) self.ui.script_btn.setEnabled(False) - self.ui.pack_archive_chkbox.setEnabled(False) - self.ui.keep_enc_chkbox.setEnabled(False) - self.ui.create_dec_chkbox.setEnabled(False) - self.ui.use_local_chkbox.setEnabled(False) - self.ui.patch_ios_chkbox.setEnabled(False) - self.ui.use_wiiu_nus_chkbox.setEnabled(False) - self.ui.pack_vwii_mode_chkbox.setEnabled(False) + self.ui.pack_archive_checkbox.setEnabled(False) + self.ui.keep_enc_checkbox.setEnabled(False) + self.ui.create_dec_checkbox.setEnabled(False) + self.ui.use_local_checkbox.setEnabled(False) + self.ui.patch_ios_checkbox.setEnabled(False) + self.ui.use_wiiu_nus_checkbox.setEnabled(False) + self.ui.pack_vwii_mode_checkbox.setEnabled(False) self.ui.archive_file_entry.setEnabled(False) self.ui.console_select_dropdown.setEnabled(False) - self.ui.auto_update_chkbox.setEnabled(False) - self.ui.custom_out_dir_chkbox.setEnabled(False) + self.ui.auto_update_checkbox.setEnabled(False) + self.ui.custom_out_dir_checkbox.setEnabled(False) self.ui.custom_out_dir_entry.setEnabled(False) self.ui.custom_out_dir_btn.setEnabled(False) self.log_text = "" @@ -303,25 +300,25 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.ui.version_entry.setEnabled(True) self.ui.download_btn.setEnabled(True) self.ui.script_btn.setEnabled(True) - self.ui.pack_archive_chkbox.setEnabled(True) - self.ui.keep_enc_chkbox.setEnabled(True) - self.ui.create_dec_chkbox.setEnabled(True) - self.ui.use_local_chkbox.setEnabled(True) - self.ui.patch_ios_chkbox.setEnabled(True) - self.ui.use_wiiu_nus_chkbox.setEnabled(True) + self.ui.pack_archive_checkbox.setEnabled(True) + self.ui.keep_enc_checkbox.setEnabled(True) + self.ui.create_dec_checkbox.setEnabled(True) + self.ui.use_local_checkbox.setEnabled(True) + self.ui.patch_ios_checkbox.setEnabled(True) + self.ui.use_wiiu_nus_checkbox.setEnabled(True) self.ui.console_select_dropdown.setEnabled(True) - if self.ui.pack_archive_chkbox.isChecked() is True: + if self.ui.pack_archive_checkbox.isChecked() is True: self.ui.archive_file_entry.setEnabled(True) - self.ui.auto_update_chkbox.setEnabled(True) - self.ui.custom_out_dir_chkbox.setEnabled(True) - if self.ui.custom_out_dir_chkbox.isChecked() is True: + self.ui.auto_update_checkbox.setEnabled(True) + self.ui.custom_out_dir_checkbox.setEnabled(True) + if self.ui.custom_out_dir_checkbox.isChecked() is True: self.ui.custom_out_dir_entry.setEnabled(True) self.ui.custom_out_dir_btn.setEnabled(True) def download_btn_pressed(self): # Throw an error and make a message box appear if you haven't selected any options to output the title. - if (self.ui.pack_archive_chkbox.isChecked() is False and self.ui.keep_enc_chkbox.isChecked() is False and - self.ui.create_dec_chkbox.isChecked() is False): + if (self.ui.pack_archive_checkbox.isChecked() is False and self.ui.keep_enc_checkbox.isChecked() is False and + self.ui.create_dec_checkbox.isChecked() is False): msg_box = QMessageBox() msg_box.setIcon(QMessageBox.Icon.Critical) msg_box.setStandardButtons(QMessageBox.StandardButton.Ok) @@ -334,7 +331,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): return self.lock_ui() # Check for a custom output directory, and ensure that it's valid. If it is, then use that. - if self.ui.custom_out_dir_chkbox.isChecked() and self.ui.custom_out_dir_entry.text() != "": + if self.ui.custom_out_dir_checkbox.isChecked() and self.ui.custom_out_dir_entry.text() != "": out_path = pathlib.Path(self.ui.custom_out_dir_entry.text()) if not out_path.exists() or not out_path.is_dir(): msg_box = QMessageBox() @@ -353,15 +350,15 @@ class MainWindow(QMainWindow, Ui_MainWindow): # Create a new worker object to handle the download in a new thread. if self.ui.console_select_dropdown.currentText() == "DSi": worker = Worker(run_nus_download_dsi, out_path, self.ui.tid_entry.text(), - self.ui.version_entry.text(), self.ui.pack_archive_chkbox.isChecked(), - self.ui.keep_enc_chkbox.isChecked(), self.ui.create_dec_chkbox.isChecked(), - self.ui.use_local_chkbox.isChecked(), self.ui.archive_file_entry.text()) + self.ui.version_entry.text(), self.ui.pack_archive_checkbox.isChecked(), + self.ui.keep_enc_checkbox.isChecked(), self.ui.create_dec_checkbox.isChecked(), + self.ui.use_local_checkbox.isChecked(), self.ui.archive_file_entry.text()) else: worker = Worker(run_nus_download_wii, out_path, self.ui.tid_entry.text(), - self.ui.version_entry.text(), self.ui.pack_archive_chkbox.isChecked(), - self.ui.keep_enc_chkbox.isChecked(), self.ui.create_dec_chkbox.isChecked(), - self.ui.use_wiiu_nus_chkbox.isChecked(), self.ui.use_local_chkbox.isChecked(), - self.ui.pack_vwii_mode_chkbox.isChecked(), self.ui.patch_ios_chkbox.isChecked(), + self.ui.version_entry.text(), self.ui.pack_archive_checkbox.isChecked(), + self.ui.keep_enc_checkbox.isChecked(), self.ui.create_dec_checkbox.isChecked(), + self.ui.use_wiiu_nus_checkbox.isChecked(), self.ui.use_local_checkbox.isChecked(), + self.ui.pack_vwii_mode_checkbox.isChecked(), self.ui.patch_ios_checkbox.isChecked(), self.ui.archive_file_entry.text()) worker.signals.result.connect(self.check_download_result) worker.signals.progress.connect(self.update_log_text) @@ -375,30 +372,30 @@ class MainWindow(QMainWindow, Ui_MainWindow): msg_box.setDefaultButton(QMessageBox.StandardButton.Ok) if result == -1: window_title = app.translate("MainWindow", "Invalid Title ID") - title_text = app.translate("MainWindow", "The Title ID you have entered is not in a valid format!") + title_text = app.translate("MainWindow", "The Title ID you have entered is not in a valid format!") body_text = app.translate("MainWindow", "Title IDs must be 16 digit strings of numbers and letters. Please enter a correctly " "formatted Title ID, or select one from the menu on the left.") elif result == -2: window_title = app.translate("MainWindow", "Title ID/Version Not Found") - title_text = app.translate("MainWindow", "No title with the provided Title ID or version could be found!") + title_text = app.translate("MainWindow", "No title with the provided Title ID or version could be found!") body_text = app.translate("MainWindow", "Please make sure that you have entered a valid Title ID, or selected one from the " "title database, and that the provided version exists for the title you are attempting to download.") elif result == -3: window_title = app.translate("MainWindow", "Content Decryption Failed") - title_text = app.translate("MainWindow", "Content decryption was not successful! Decrypted contents could not be created.") + title_text = app.translate("MainWindow", "Content decryption was not successful! Decrypted contents could not be created.") body_text = app.translate("MainWindow", "Your TMD or Ticket may be damaged, or they may not correspond with the content being " "decrypted. If you have checked \"Use local files, if they exist\", try disabling that " "option before trying the download again to fix potential issues with local data.") elif result == 1: msg_box.setIcon(QMessageBox.Icon.Warning) window_title = app.translate("MainWindow", "Ticket Not Available") - title_text = app.translate("MainWindow", "No Ticket is Available for the Requested Title!") + title_text = app.translate("MainWindow", "No Ticket is Available for the Requested Title!") body_text = app.translate("MainWindow", "A ticket could not be downloaded for the requested title, but you have selected \"Pack" " installable archive\" or \"Create decrypted contents\". These options are not " "available for titles without a ticket. Only encrypted contents have been saved.") else: window_title = app.translate("MainWindow", "Unknown Error") - title_text = app.translate("MainWindow", "An Unknown Error has Occurred!") + title_text = app.translate("MainWindow", "An Unknown Error has Occurred!") body_text = app.translate("MainWindow", "Please try again. If this issue persists, please open a new issue on GitHub detailing" " what you were trying to do when this error occurred.") if result != 0: @@ -421,7 +418,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): msg_box.setStandardButtons(QMessageBox.StandardButton.Ok) msg_box.setDefaultButton(QMessageBox.StandardButton.Ok) msg_box.setWindowTitle(app.translate("MainWindow", "Script Issues Occurred")) - msg_box.setText(app.translate("MainWindow", "Some issues occurred while running the download script.")) + msg_box.setText(app.translate("MainWindow", "Some issues occurred while running the download script.")) msg_box.setInformativeText( app.translate("MainWindow", "Check the log for more details about what issues were encountered.")) msg_box.exec() @@ -448,11 +445,11 @@ class MainWindow(QMainWindow, Ui_MainWindow): def selected_console_changed(self): # Callback function to enable or disable console-specific settings based on the selected console. if self.ui.console_select_dropdown.currentText() == "vWii": - self.ui.pack_vwii_mode_chkbox.setEnabled(True) + self.ui.pack_vwii_mode_checkbox.setEnabled(True) elif self.ui.console_select_dropdown.currentText() == "Wii": - self.ui.pack_vwii_mode_chkbox.setEnabled(False) + self.ui.pack_vwii_mode_checkbox.setEnabled(False) elif self.ui.console_select_dropdown.currentText() == "DSi": - self.ui.pack_vwii_mode_chkbox.setEnabled(False) + self.ui.pack_vwii_mode_checkbox.setEnabled(False) def script_btn_pressed(self): msg_box = QMessageBox() @@ -471,7 +468,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): with open(file_name[0]) as script_file: script_data = json.load(script_file) except json.JSONDecodeError as e: - msg_box.setText(app.translate("MainWindow", "An error occurred while parsing the script file!")) + msg_box.setText(app.translate("MainWindow", "An error occurred while parsing the script file!")) msg_box.setInformativeText(app.translate("MainWindow", f"Error encountered at line {e.lineno}, column {e.colno}. Please double-check the script and try again.")) msg_box.exec() return @@ -481,7 +478,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): try: tid = title["Title ID"] except KeyError: - msg_box.setText(app.translate("MainWindow", "An error occurred while parsing Title IDs!")) + msg_box.setText(app.translate("MainWindow", "An error occurred while parsing Title IDs!")) msg_box.setInformativeText(app.translate("MainWindow", f"The title at index {script_data.index(title)} does not have a Title ID!")) msg_box.exec() return @@ -524,10 +521,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): break titles.append(BatchTitleData(tid, title_version, console, archive_name)) self.lock_ui() - worker = Worker(run_nus_download_batch, out_folder, titles, self.ui.pack_archive_chkbox.isChecked(), - self.ui.keep_enc_chkbox.isChecked(), self.ui.create_dec_chkbox.isChecked(), - self.ui.use_wiiu_nus_chkbox.isChecked(), self.ui.use_local_chkbox.isChecked(), - self.ui.pack_vwii_mode_chkbox.isChecked(), self.ui.patch_ios_chkbox.isChecked()) + worker = Worker(run_nus_download_batch, out_folder, titles, self.ui.pack_archive_checkbox.isChecked(), + self.ui.keep_enc_checkbox.isChecked(), self.ui.create_dec_checkbox.isChecked(), + self.ui.use_wiiu_nus_checkbox.isChecked(), self.ui.use_local_checkbox.isChecked(), + self.ui.pack_vwii_mode_checkbox.isChecked(), self.ui.patch_ios_checkbox.isChecked()) worker.signals.result.connect(self.check_batch_result) worker.signals.progress.connect(self.update_log_text) self.threadpool.start(worker) @@ -546,7 +543,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): msg_box.setStandardButtons(QMessageBox.StandardButton.Ok) msg_box.setDefaultButton(QMessageBox.StandardButton.Ok) msg_box.setWindowTitle(app.translate("MainWindow", "Invalid Download Directory")) - msg_box.setText(app.translate("MainWindow", "The specified download directory does not exist!")) + msg_box.setText(app.translate("MainWindow", "The specified download directory does not exist!")) msg_box.setInformativeText(app.translate("MainWindow", "Please make sure the download directory you want to use exists, and " "that you have permission to access it.")) @@ -569,19 +566,18 @@ class MainWindow(QMainWindow, Ui_MainWindow): save_config(config_data) def about_nusget(self): - version_str = app.translate("MainWindow", "Version {nusget_version}".format(nusget_version=nusget_version)) - about_box = AboutNUSGet(version_str) + about_box = AboutNUSGet([nusget_version, version("libWiiPy"), version("libTWLPy")]) about_box.exec() if __name__ == "__main__": app = QApplication(sys.argv) # Load the database files, this will work for both the raw Python file and compiled standalone/onefile binaries. - database_file = open(os.path.join(os.path.dirname(__file__), "data/wii-database.json")) + database_file = open(os.path.join(os.path.dirname(__file__), "data", "wii-database.json")) wii_database = json.load(database_file) - database_file = open(os.path.join(os.path.dirname(__file__), "data/vwii-database.json")) + database_file = open(os.path.join(os.path.dirname(__file__), "data", "vwii-database.json")) vwii_database = json.load(database_file) - database_file = open(os.path.join(os.path.dirname(__file__), "data/dsi-database.json")) + database_file = open(os.path.join(os.path.dirname(__file__), "data", "dsi-database.json")) dsi_database = json.load(database_file) # Load the user's Downloads directory, which of course requires different steps on Windows vs macOS/Linux. if os.name == 'nt': @@ -610,28 +606,34 @@ if __name__ == "__main__": config_data: dict = {"auto_update": True} save_config(config_data) - # Load the system plugins directory on Linux for system styles, if it exists. Try using Breeze if available, because - # it looks nice, but fallback on kvantum if it isn't, since kvantum is likely to exist. If all else fails, fusion. - if platform.system() == "Linux": - if os.path.isdir("/usr/lib/qt6/plugins"): - import subprocess - try: - # This CANNOT be the best way to get the system Qt version, but it's what I came up with for now. - result = subprocess.run(['/usr/lib/qt6/bin/qtdiag'], stdout=subprocess.PIPE) - result_str = result.stdout.decode("utf-8").split("\n")[0] - sys_qt_ver = result_str.split(" ")[1].split(".") - pyside_qt_ver = version("PySide6").split(".") - if sys_qt_ver[0:2] == pyside_qt_ver[0:2]: - app.addLibraryPath("/usr/lib/qt6/plugins") - if "Breeze" in QStyleFactory.keys(): - app.setStyle("Breeze") - elif "kvantum" in QStyleFactory.keys(): - app.setStyle("kvantum") - except Exception as e: - print(e) - # The macOS Qt theme sucks, so let's avoid using it. - elif platform.system() == "Darwin": - app.setStyle("fusion") + # This is essentially obsolete now with the addition of the custom stylesheet, but I'm keeping it just in case. + # # Load the system plugins directory on Linux for system styles, if it exists. Try using Breeze if available, because + # # it looks nice, but fallback on kvantum if it isn't, since kvantum is likely to exist. If all else fails, fusion. + # if platform.system() == "Linux": + # if os.path.isdir("/usr/lib/qt6/plugins"): + # import subprocess + # try: + # # This CANNOT be the best way to get the system Qt version, but it's what I came up with for now. + # result = subprocess.run(['/usr/lib/qt6/bin/qtdiag'], stdout=subprocess.PIPE) + # result_str = result.stdout.decode("utf-8").split("\n")[0] + # sys_qt_ver = result_str.split(" ")[1].split(".") + # pyside_qt_ver = version("PySide6").split(".") + # if sys_qt_ver[0:2] == pyside_qt_ver[0:2]: + # app.addLibraryPath("/usr/lib/qt6/plugins") + # if "Breeze" in QStyleFactory.keys(): + # app.setStyle("Breeze") + # elif "kvantum" in QStyleFactory.keys(): + # app.setStyle("kvantum") + # except Exception as e: + # print(e) + + # Load Fusion because that's objectively the best base theme, and then load the fancy stylesheet on top to make + # NUSGet look nice and pretty. + app.setStyle("fusion") + stylesheet = open(os.path.join(os.path.dirname(__file__), "resources", "style.qss")).read() + image_path_prefix = pathlib.Path(os.path.join(os.path.dirname(__file__), "resources")).resolve().as_posix() + stylesheet = stylesheet.replace("{IMAGE_PREFIX}", image_path_prefix) + app.setStyleSheet(stylesheet) # Load base Qt translations, and then app-specific translations. path = QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath) @@ -639,13 +641,13 @@ if __name__ == "__main__": if translator.load(QLocale.system(), 'qtbase', '_', path): app.installTranslator(translator) translator = QTranslator(app) - path = os.path.join(os.path.dirname(__file__), "resources/translations") + path = os.path.join(os.path.dirname(__file__), "resources", "translations") if translator.load(QLocale.system(), 'nusget', '_', path): app.installTranslator(translator) window = MainWindow() window.setWindowTitle("NUSGet") - window.setWindowIcon(QIcon(os.path.join(os.path.dirname(__file__), "resources/icon.png"))) + app.setWindowIcon(QIcon(os.path.join(os.path.dirname(__file__), "resources", "icon.png"))) window.show() sys.exit(app.exec()) diff --git a/NUSGet.pyproject b/NUSGet.pyproject index 1b987c2..1a6f5e9 100644 --- a/NUSGet.pyproject +++ b/NUSGet.pyproject @@ -3,7 +3,7 @@ "NUSGet.py", "./modules/core.py", "./qt/ui/MainMenu.ui", - "./qt/ui/AboutNUSGet.ui", + "./qt/py/ui_AboutDialog.py", "./resources/translations/nusget_es.ts", "./resources/translations/nusget_no.ts", "./resources/translations/nusget_nb.ts", diff --git a/modules/core.py b/modules/core.py index 11820a2..f510d6c 100644 --- a/modules/core.py +++ b/modules/core.py @@ -64,7 +64,9 @@ def check_nusget_updates(app, current_version: str, progress_callback=None) -> s new_version_split = new_version.split('.') current_version_split = current_version.split('.') for place in range(len(new_version_split)): - if new_version_split[place] > current_version_split[place]: + if new_version_split[place] < current_version_split[place]: + return None + elif new_version_split[place] > current_version_split[place]: progress_callback.emit(app.translate("MainWindow", "\n\nThere's a newer version of NUSGet available!")) return new_version progress_callback.emit(app.translate("MainWindow", "\n\nYou're running the latest release of NUSGet.")) diff --git a/qt/py/ui_AboutDialog.py b/qt/py/ui_AboutDialog.py index 16cc3e2..ac4558a 100644 --- a/qt/py/ui_AboutDialog.py +++ b/qt/py/ui_AboutDialog.py @@ -1,13 +1,158 @@ # "qt/py/ui_AboutDialog.py", licensed under the MIT license # Copyright 2024-2025 NinjaCheetah and Contributors +# Thanks Isla and Alex for making such a nice about dialog that I could then "borrow" :p -from PySide6.QtWidgets import QDialog -from qt.py.ui_AboutNUSGet import Ui_AboutNUSGet +import os +import pathlib +import webbrowser + +from PySide6.QtCore import Qt, QCoreApplication +from PySide6.QtWidgets import QDialog, QLabel, QVBoxLayout, QPushButton +from PySide6.QtGui import QIcon class AboutNUSGet(QDialog): - def __init__(self, version_str): + def __init__(self, versions): super().__init__() - self.ui = Ui_AboutNUSGet() - self.ui.setupUi(self) + self.setWindowTitle(self.tr("About NUSGet")) + self.setFixedWidth(450) + self.setFixedHeight(500) - self.ui.version_lbl.setText(version_str) + # Set background color to match main app + self.setStyleSheet(""" + Credits { + background-color: #222222; + color: #ffffff; + } + QLabel { + color: #ffffff; + } + QLabel[class="title"] { + font-size: 20px; + font-weight: bold; + color: #ffffff; + } + QLabel[class="version"] { + font-size: 13px; + color: #aaaaaa; + } + QLabel[class="copyright"] { + font-size: 12px; + color: #888888; + } + QLabel[class="header"] { + font-size: 14px; + font-weight: bold; + border-bottom: 1px solid #444444; + padding-bottom: 4px; + margin-top: 8px; + } + QPushButton { + background-color: transparent; + border: 1px solid rgba(70, 70, 70, 1); + border-radius: 8px; + padding: 8px 12px; + margin: 4px 0px; + font-size: 13px; + font-weight: 500; + color: #ffffff; + text-align: center; + } + QPushButton:hover { + background-color: rgba(60, 60, 60, 1); + border-color: #4a86e8; + } + QPushButton:pressed { + background-color: rgba(26, 115, 232, 0.15); + border: 1px solid #1a73e8; + }""") + + # Create main layout + self.layout = QVBoxLayout() + self.layout.setSpacing(4) + self.layout.setContentsMargins(30, 20, 30, 20) + + # Logo + logo_label = QLabel() + icon = QIcon(os.path.join(pathlib.Path(os.path.dirname(__file__)).resolve().parent.parent, "resources", "icon.png")) + logo_pixmap = icon.pixmap(96, 96) + logo_label.setPixmap(logo_pixmap) + logo_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + + # Title + title_label = QLabel(self.tr("NUSGet")) + title_label.setProperty("class", "title") + title_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + + # NUSGet Version + version_label = QLabel(self.tr("Version {nusget_version}".format(nusget_version=versions[0]))) + version_label.setProperty("class", "version") + version_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + + # Library Versions + libraries_label = QLabel(self.tr("Using libWiiPy {libwiipy_version} & libTWLPy {libtwlpy_version}" + .format(libwiipy_version=versions[1], libtwlpy_version=versions[2]))) + libraries_label.setProperty("class", "version") + libraries_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + + # Copyright + copyright_label = QLabel(self.tr("© 2024-2025 NinjaCheetah & Contributors")) + copyright_label.setProperty("class", "copyright") + copyright_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + + # Add header section + self.layout.addWidget(logo_label) + self.layout.addWidget(title_label) + self.layout.addWidget(version_label) + self.layout.addWidget(libraries_label) + self.layout.addWidget(copyright_label) + self.layout.addSpacing(15) + + # External links layout + links_layout = QVBoxLayout() + + # GitHub button + self.github_button = QPushButton(self.tr("View Project on GitHub")) + self.github_button.clicked.connect(lambda: webbrowser.open("https://github.com/NinjaCheetah/NUSGet")) + links_layout.addWidget(self.github_button) + + # Add the links layout to main layout + self.layout.addLayout(links_layout) + self.layout.addSpacing(15) + + # Add a horizontal line + line = QLabel() + line.setStyleSheet("background-color: #444444; height: 1px;") + line.setFixedHeight(1) + self.layout.addWidget(line) + self.layout.addSpacing(10) + + # Team members header + team_header = QLabel(self.tr("Translations")) + team_header.setProperty("class", "header") + self.layout.addWidget(team_header) + self.layout.addSpacing(5) + + # Team members with roles + self.people = { + "yeah-its-gloria": QLabel(self.tr( + "German (Deutsch): yeah-its-gloria")), + "LNLenost": QLabel(self.tr( + "Italian (Italiano): LNLenost")), + "DDinghoya": QLabel(self.tr( + "Korean (\ud55c\uad6d\uc5b4): DDinghoya")), + "rolfiee": QLabel(self.tr( + "Norwegian (Norsk): rolfiee")), + "NotImplementedLife": QLabel(self.tr( + "Romanian (Rom\u00e2n\u0103): NotImplementedLife")) + } + + # Add team members to layout + for credit in self.people.values(): + credit.setOpenExternalLinks(True) + credit.setContentsMargins(15, 0, 0, 0) + self.layout.addWidget(credit) + + # Add spacer at the bottom + self.layout.addStretch() + + self.setLayout(self.layout) diff --git a/qt/py/ui_AboutNUSGet.py b/qt/py/ui_AboutNUSGet.py deleted file mode 100644 index 457ef46..0000000 --- a/qt/py/ui_AboutNUSGet.py +++ /dev/null @@ -1,131 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'AboutNUSGet.ui' -## -## Created by: Qt User Interface Compiler version 6.9.0 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, - QMetaObject, QObject, QPoint, QRect, - QSize, QTime, QUrl, Qt) -from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, - QFont, QFontDatabase, QGradient, QIcon, - QImage, QKeySequence, QLinearGradient, QPainter, - QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox, - QHBoxLayout, QLabel, QLayout, QSizePolicy, - QSpacerItem, QTextBrowser, QVBoxLayout, QWidget) - -class Ui_AboutNUSGet(object): - def setupUi(self, AboutNUSGet): - if not AboutNUSGet.objectName(): - AboutNUSGet.setObjectName(u"AboutNUSGet") - AboutNUSGet.resize(400, 300) - self.verticalLayout = QVBoxLayout(AboutNUSGet) - self.verticalLayout.setObjectName(u"verticalLayout") - self.outer_layout = QHBoxLayout() - self.outer_layout.setObjectName(u"outer_layout") - self.icon_layout = QVBoxLayout() - self.icon_layout.setObjectName(u"icon_layout") - self.icon_layout.setSizeConstraint(QLayout.SizeConstraint.SetDefaultConstraint) - self.icon_lbl = QLabel(AboutNUSGet) - icon = QIcon("resources/icon.png") - pixmap = icon.pixmap(QSize(75, 75)) - self.icon_lbl.setPixmap(pixmap) - self.icon_lbl.setObjectName(u"icon_lbl") - self.icon_lbl.setMaximumSize(QSize(75, 75)) - - self.icon_layout.addWidget(self.icon_lbl) - - self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) - - self.icon_layout.addItem(self.verticalSpacer) - - - self.outer_layout.addLayout(self.icon_layout) - - self.details_layout = QVBoxLayout() - self.details_layout.setObjectName(u"details_layout") - self.about_title_lbl = QLabel(AboutNUSGet) - self.about_title_lbl.setObjectName(u"about_title_lbl") - font = QFont() - font.setPointSize(15) - font.setBold(True) - self.about_title_lbl.setFont(font) - - self.details_layout.addWidget(self.about_title_lbl) - - self.version_lbl = QLabel(AboutNUSGet) - self.version_lbl.setObjectName(u"version_lbl") - font1 = QFont() - font1.setBold(True) - self.version_lbl.setFont(font1) - - self.details_layout.addWidget(self.version_lbl) - - self.detail_text_lbl = QLabel(AboutNUSGet) - self.detail_text_lbl.setObjectName(u"detail_text_lbl") - self.detail_text_lbl.setWordWrap(True) - - self.details_layout.addWidget(self.detail_text_lbl) - - self.textBrowser = QTextBrowser(AboutNUSGet) - self.textBrowser.setObjectName(u"textBrowser") - - self.details_layout.addWidget(self.textBrowser) - - self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) - - self.details_layout.addItem(self.verticalSpacer_2) - - self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) - - self.details_layout.addItem(self.horizontalSpacer) - - - self.outer_layout.addLayout(self.details_layout) - - - self.verticalLayout.addLayout(self.outer_layout) - - self.buttonBox = QDialogButtonBox(AboutNUSGet) - self.buttonBox.setObjectName(u"buttonBox") - self.buttonBox.setOrientation(Qt.Orientation.Horizontal) - self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Close) - - self.verticalLayout.addWidget(self.buttonBox) - - - self.retranslateUi(AboutNUSGet) - self.buttonBox.accepted.connect(AboutNUSGet.accept) - self.buttonBox.rejected.connect(AboutNUSGet.reject) - - QMetaObject.connectSlotsByName(AboutNUSGet) - # setupUi - - def retranslateUi(self, AboutNUSGet): - AboutNUSGet.setWindowTitle(QCoreApplication.translate("AboutNUSGet", u"Dialog", None)) - self.icon_lbl.setText("") - self.about_title_lbl.setText(QCoreApplication.translate("AboutNUSGet", u"About NUSGet", None)) - self.version_lbl.setText(QCoreApplication.translate("AboutNUSGet", u"Placeholder Version String", None)) - self.detail_text_lbl.setText(QCoreApplication.translate("AboutNUSGet", u"Copyright (c) 2024-2025 NinjaCheetah & Contributors", None)) - self.textBrowser.setHtml(QCoreApplication.translate("AboutNUSGet", u"\n" -"
\n" -"Translations
\n" -"German (Deutsch): yeah-its-gloria
\n" -"Italian (Italiano): LNLenost
\n" -"Korean (\ud55c\uad6d\uc5b4): DDinghoya
\n" -"Norwegian (Norsk): rolfiee
\n" -"Romanian (Rom\u00e2n\u0103): " - "NotImplementedLife
", None)) - # retranslateUi - diff --git a/qt/py/ui_MainMenu.py b/qt/py/ui_MainMenu.py index f5f7095..d984b3e 100644 --- a/qt/py/ui_MainMenu.py +++ b/qt/py/ui_MainMenu.py @@ -16,19 +16,21 @@ from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient, QIcon, QImage, QKeySequence, QLinearGradient, QPainter, QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QHBoxLayout, - QHeaderView, QLabel, QLayout, QLineEdit, - QMainWindow, QMenu, QMenuBar, QPushButton, - QSizePolicy, QSpacerItem, QTabWidget, QTextBrowser, - QTreeView, QVBoxLayout, QWidget) +from PySide6.QtWidgets import (QApplication, QComboBox, QHBoxLayout, QHeaderView, + QLabel, QLayout, QLineEdit, QMainWindow, + QMenu, QMenuBar, QPushButton, QSizePolicy, + QSpacerItem, QTabWidget, QTextBrowser, QTreeView, + QVBoxLayout, QWidget) + +from qt.py.ui_WrapCheckboxWidget import WrapCheckboxWidget class Ui_MainWindow(object): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") - MainWindow.resize(1010, 625) - MainWindow.setMinimumSize(QSize(1010, 625)) - MainWindow.setMaximumSize(QSize(1010, 625)) + MainWindow.resize(1010, 675) + MainWindow.setMinimumSize(QSize(1010, 675)) + MainWindow.setMaximumSize(QSize(1010, 675)) self.actionAbout = QAction(MainWindow) self.actionAbout.setObjectName(u"actionAbout") icon = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.HelpAbout)) @@ -175,7 +177,7 @@ class Ui_MainWindow(object): self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") self.horizontalLayout_5.setSizeConstraint(QLayout.SizeConstraint.SetMinimumSize) self.verticalLayout_7 = QVBoxLayout() - self.verticalLayout_7.setSpacing(5) + self.verticalLayout_7.setSpacing(4) self.verticalLayout_7.setObjectName(u"verticalLayout_7") self.verticalLayout_7.setSizeConstraint(QLayout.SizeConstraint.SetMinimumSize) self.label_3 = QLabel(self.centralwidget) @@ -186,31 +188,10 @@ class Ui_MainWindow(object): self.verticalLayout_7.addWidget(self.label_3) - self.pack_archive_row = QHBoxLayout() - self.pack_archive_row.setSpacing(10) - self.pack_archive_row.setObjectName(u"pack_archive_row") - self.pack_archive_chkbox = QCheckBox(self.centralwidget) - self.pack_archive_chkbox.setObjectName(u"pack_archive_chkbox") - sizePolicy1.setHeightForWidth(self.pack_archive_chkbox.sizePolicy().hasHeightForWidth()) - self.pack_archive_chkbox.setSizePolicy(sizePolicy1) - self.pack_archive_chkbox.setText(u"") - self.pack_archive_chkbox.setChecked(True) + self.pack_archive_checkbox = WrapCheckboxWidget(self.centralwidget) + self.pack_archive_checkbox.setObjectName(u"pack_archive_checkbox") - self.pack_archive_row.addWidget(self.pack_archive_chkbox) - - self.pack_archive_chkbox_lbl = QLabel(self.centralwidget) - self.pack_archive_chkbox_lbl.setObjectName(u"pack_archive_chkbox_lbl") - sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.MinimumExpanding) - sizePolicy4.setHorizontalStretch(0) - sizePolicy4.setVerticalStretch(0) - sizePolicy4.setHeightForWidth(self.pack_archive_chkbox_lbl.sizePolicy().hasHeightForWidth()) - self.pack_archive_chkbox_lbl.setSizePolicy(sizePolicy4) - self.pack_archive_chkbox_lbl.setWordWrap(True) - - self.pack_archive_row.addWidget(self.pack_archive_chkbox_lbl) - - - self.verticalLayout_7.addLayout(self.pack_archive_row) + self.verticalLayout_7.addWidget(self.pack_archive_checkbox) self.archive_file_entry = QLineEdit(self.centralwidget) self.archive_file_entry.setObjectName(u"archive_file_entry") @@ -218,124 +199,33 @@ class Ui_MainWindow(object): self.verticalLayout_7.addWidget(self.archive_file_entry) - self.keep_enc_row = QHBoxLayout() - self.keep_enc_row.setSpacing(10) - self.keep_enc_row.setObjectName(u"keep_enc_row") - self.keep_enc_chkbox = QCheckBox(self.centralwidget) - self.keep_enc_chkbox.setObjectName(u"keep_enc_chkbox") - sizePolicy1.setHeightForWidth(self.keep_enc_chkbox.sizePolicy().hasHeightForWidth()) - self.keep_enc_chkbox.setSizePolicy(sizePolicy1) - self.keep_enc_chkbox.setText(u"") - self.keep_enc_chkbox.setChecked(True) + self.keep_enc_checkbox = WrapCheckboxWidget(self.centralwidget) + self.keep_enc_checkbox.setObjectName(u"keep_enc_checkbox") - self.keep_enc_row.addWidget(self.keep_enc_chkbox) + self.verticalLayout_7.addWidget(self.keep_enc_checkbox) - self.keep_enc_chkbox_lbl = QLabel(self.centralwidget) - self.keep_enc_chkbox_lbl.setObjectName(u"keep_enc_chkbox_lbl") - sizePolicy4.setHeightForWidth(self.keep_enc_chkbox_lbl.sizePolicy().hasHeightForWidth()) - self.keep_enc_chkbox_lbl.setSizePolicy(sizePolicy4) - self.keep_enc_chkbox_lbl.setWordWrap(True) + self.create_dec_checkbox = WrapCheckboxWidget(self.centralwidget) + self.create_dec_checkbox.setObjectName(u"create_dec_checkbox") - self.keep_enc_row.addWidget(self.keep_enc_chkbox_lbl) + self.verticalLayout_7.addWidget(self.create_dec_checkbox) + self.use_local_checkbox = WrapCheckboxWidget(self.centralwidget) + self.use_local_checkbox.setObjectName(u"use_local_checkbox") - self.verticalLayout_7.addLayout(self.keep_enc_row) + self.verticalLayout_7.addWidget(self.use_local_checkbox) - self.create_dec_row = QHBoxLayout() - self.create_dec_row.setSpacing(10) - self.create_dec_row.setObjectName(u"create_dec_row") - self.create_dec_chkbox = QCheckBox(self.centralwidget) - self.create_dec_chkbox.setObjectName(u"create_dec_chkbox") - sizePolicy1.setHeightForWidth(self.create_dec_chkbox.sizePolicy().hasHeightForWidth()) - self.create_dec_chkbox.setSizePolicy(sizePolicy1) - self.create_dec_chkbox.setText(u"") + self.use_wiiu_nus_checkbox = WrapCheckboxWidget(self.centralwidget) + self.use_wiiu_nus_checkbox.setObjectName(u"use_wiiu_nus_checkbox") - self.create_dec_row.addWidget(self.create_dec_chkbox) + self.verticalLayout_7.addWidget(self.use_wiiu_nus_checkbox) - self.create_dec_chkbox_lbl = QLabel(self.centralwidget) - self.create_dec_chkbox_lbl.setObjectName(u"create_dec_chkbox_lbl") - sizePolicy4.setHeightForWidth(self.create_dec_chkbox_lbl.sizePolicy().hasHeightForWidth()) - self.create_dec_chkbox_lbl.setSizePolicy(sizePolicy4) - self.create_dec_chkbox_lbl.setWordWrap(True) + self.patch_ios_checkbox = WrapCheckboxWidget(self.centralwidget) + self.patch_ios_checkbox.setObjectName(u"patch_ios_checkbox") + self.patch_ios_checkbox.setEnabled(False) - self.create_dec_row.addWidget(self.create_dec_chkbox_lbl) + self.verticalLayout_7.addWidget(self.patch_ios_checkbox) - - self.verticalLayout_7.addLayout(self.create_dec_row) - - self.use_local_row = QHBoxLayout() - self.use_local_row.setSpacing(10) - self.use_local_row.setObjectName(u"use_local_row") - self.use_local_chkbox = QCheckBox(self.centralwidget) - self.use_local_chkbox.setObjectName(u"use_local_chkbox") - self.use_local_chkbox.setEnabled(True) - sizePolicy1.setHeightForWidth(self.use_local_chkbox.sizePolicy().hasHeightForWidth()) - self.use_local_chkbox.setSizePolicy(sizePolicy1) - self.use_local_chkbox.setText(u"") - - self.use_local_row.addWidget(self.use_local_chkbox) - - self.use_local_chkbox_lbl = QLabel(self.centralwidget) - self.use_local_chkbox_lbl.setObjectName(u"use_local_chkbox_lbl") - sizePolicy4.setHeightForWidth(self.use_local_chkbox_lbl.sizePolicy().hasHeightForWidth()) - self.use_local_chkbox_lbl.setSizePolicy(sizePolicy4) - self.use_local_chkbox_lbl.setWordWrap(True) - - self.use_local_row.addWidget(self.use_local_chkbox_lbl) - - - self.verticalLayout_7.addLayout(self.use_local_row) - - self.use_wiiu_nus_row = QHBoxLayout() - self.use_wiiu_nus_row.setSpacing(10) - self.use_wiiu_nus_row.setObjectName(u"use_wiiu_nus_row") - self.use_wiiu_nus_row.setSizeConstraint(QLayout.SizeConstraint.SetDefaultConstraint) - self.use_wiiu_nus_chkbox = QCheckBox(self.centralwidget) - self.use_wiiu_nus_chkbox.setObjectName(u"use_wiiu_nus_chkbox") - sizePolicy2.setHeightForWidth(self.use_wiiu_nus_chkbox.sizePolicy().hasHeightForWidth()) - self.use_wiiu_nus_chkbox.setSizePolicy(sizePolicy2) - self.use_wiiu_nus_chkbox.setLayoutDirection(Qt.LayoutDirection.LeftToRight) - self.use_wiiu_nus_chkbox.setText(u"") - self.use_wiiu_nus_chkbox.setChecked(True) - - self.use_wiiu_nus_row.addWidget(self.use_wiiu_nus_chkbox) - - self.use_wiiu_nus_chkbox_lbl = QLabel(self.centralwidget) - self.use_wiiu_nus_chkbox_lbl.setObjectName(u"use_wiiu_nus_chkbox_lbl") - sizePolicy4.setHeightForWidth(self.use_wiiu_nus_chkbox_lbl.sizePolicy().hasHeightForWidth()) - self.use_wiiu_nus_chkbox_lbl.setSizePolicy(sizePolicy4) - self.use_wiiu_nus_chkbox_lbl.setWordWrap(True) - - self.use_wiiu_nus_row.addWidget(self.use_wiiu_nus_chkbox_lbl) - - - self.verticalLayout_7.addLayout(self.use_wiiu_nus_row) - - self.patch_ios_row = QHBoxLayout() - self.patch_ios_row.setSpacing(10) - self.patch_ios_row.setObjectName(u"patch_ios_row") - self.patch_ios_chkbox = QCheckBox(self.centralwidget) - self.patch_ios_chkbox.setObjectName(u"patch_ios_chkbox") - self.patch_ios_chkbox.setEnabled(False) - sizePolicy1.setHeightForWidth(self.patch_ios_chkbox.sizePolicy().hasHeightForWidth()) - self.patch_ios_chkbox.setSizePolicy(sizePolicy1) - self.patch_ios_chkbox.setText(u"") - - self.patch_ios_row.addWidget(self.patch_ios_chkbox) - - self.patch_ios_chkbox_lbl = QLabel(self.centralwidget) - self.patch_ios_chkbox_lbl.setObjectName(u"patch_ios_chkbox_lbl") - self.patch_ios_chkbox_lbl.setEnabled(True) - sizePolicy4.setHeightForWidth(self.patch_ios_chkbox_lbl.sizePolicy().hasHeightForWidth()) - self.patch_ios_chkbox_lbl.setSizePolicy(sizePolicy4) - self.patch_ios_chkbox_lbl.setWordWrap(True) - - self.patch_ios_row.addWidget(self.patch_ios_chkbox_lbl) - - - self.verticalLayout_7.addLayout(self.patch_ios_row) - - self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Ignored) + self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) self.verticalLayout_7.addItem(self.verticalSpacer_2) @@ -355,31 +245,11 @@ class Ui_MainWindow(object): self.verticalLayout_8.addWidget(self.label_4) - self.pack_vwii_mode_row = QHBoxLayout() - self.pack_vwii_mode_row.setObjectName(u"pack_vwii_mode_row") - self.pack_vwii_mode_chkbox = QCheckBox(self.centralwidget) - self.pack_vwii_mode_chkbox.setObjectName(u"pack_vwii_mode_chkbox") - self.pack_vwii_mode_chkbox.setEnabled(False) - sizePolicy1.setHeightForWidth(self.pack_vwii_mode_chkbox.sizePolicy().hasHeightForWidth()) - self.pack_vwii_mode_chkbox.setSizePolicy(sizePolicy1) - self.pack_vwii_mode_chkbox.setText(u"") + self.pack_vwii_mode_checkbox = WrapCheckboxWidget(self.centralwidget) + self.pack_vwii_mode_checkbox.setObjectName(u"pack_vwii_mode_checkbox") + self.pack_vwii_mode_checkbox.setEnabled(False) - self.pack_vwii_mode_row.addWidget(self.pack_vwii_mode_chkbox) - - self.pack_vwii_mode_chkbox_lbl = QLabel(self.centralwidget) - self.pack_vwii_mode_chkbox_lbl.setObjectName(u"pack_vwii_mode_chkbox_lbl") - self.pack_vwii_mode_chkbox_lbl.setEnabled(True) - sizePolicy5 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred) - sizePolicy5.setHorizontalStretch(0) - sizePolicy5.setVerticalStretch(0) - sizePolicy5.setHeightForWidth(self.pack_vwii_mode_chkbox_lbl.sizePolicy().hasHeightForWidth()) - self.pack_vwii_mode_chkbox_lbl.setSizePolicy(sizePolicy5) - self.pack_vwii_mode_chkbox_lbl.setWordWrap(True) - - self.pack_vwii_mode_row.addWidget(self.pack_vwii_mode_chkbox_lbl) - - - self.verticalLayout_8.addLayout(self.pack_vwii_mode_row) + self.verticalLayout_8.addWidget(self.pack_vwii_mode_checkbox) self.label_2 = QLabel(self.centralwidget) self.label_2.setObjectName(u"label_2") @@ -387,39 +257,15 @@ class Ui_MainWindow(object): self.verticalLayout_8.addWidget(self.label_2) - self.auto_update_row = QHBoxLayout() - self.auto_update_row.setObjectName(u"auto_update_row") - self.auto_update_chkbox = QCheckBox(self.centralwidget) - self.auto_update_chkbox.setObjectName(u"auto_update_chkbox") - sizePolicy1.setHeightForWidth(self.auto_update_chkbox.sizePolicy().hasHeightForWidth()) - self.auto_update_chkbox.setSizePolicy(sizePolicy1) + self.auto_update_checkbox = WrapCheckboxWidget(self.centralwidget) + self.auto_update_checkbox.setObjectName(u"auto_update_checkbox") - self.auto_update_row.addWidget(self.auto_update_chkbox) + self.verticalLayout_8.addWidget(self.auto_update_checkbox) - self.auto_update_chkbox_lbl = QLabel(self.centralwidget) - self.auto_update_chkbox_lbl.setObjectName(u"auto_update_chkbox_lbl") + self.custom_out_dir_checkbox = WrapCheckboxWidget(self.centralwidget) + self.custom_out_dir_checkbox.setObjectName(u"custom_out_dir_checkbox") - self.auto_update_row.addWidget(self.auto_update_chkbox_lbl) - - - self.verticalLayout_8.addLayout(self.auto_update_row) - - self.custom_out_dir_row = QHBoxLayout() - self.custom_out_dir_row.setObjectName(u"custom_out_dir_row") - self.custom_out_dir_chkbox = QCheckBox(self.centralwidget) - self.custom_out_dir_chkbox.setObjectName(u"custom_out_dir_chkbox") - sizePolicy1.setHeightForWidth(self.custom_out_dir_chkbox.sizePolicy().hasHeightForWidth()) - self.custom_out_dir_chkbox.setSizePolicy(sizePolicy1) - - self.custom_out_dir_row.addWidget(self.custom_out_dir_chkbox) - - self.custom_out_dir_chkbox_lbl = QLabel(self.centralwidget) - self.custom_out_dir_chkbox_lbl.setObjectName(u"custom_out_dir_chkbox_lbl") - - self.custom_out_dir_row.addWidget(self.custom_out_dir_chkbox_lbl) - - - self.verticalLayout_8.addLayout(self.custom_out_dir_row) + self.verticalLayout_8.addWidget(self.custom_out_dir_checkbox) self.custom_out_dir_entry_row = QHBoxLayout() self.custom_out_dir_entry_row.setObjectName(u"custom_out_dir_entry_row") @@ -438,7 +284,7 @@ class Ui_MainWindow(object): self.verticalLayout_8.addLayout(self.custom_out_dir_entry_row) - self.verticalSpacer = QSpacerItem(20, 50, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.MinimumExpanding) + self.verticalSpacer = QSpacerItem(20, 50, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) self.verticalLayout_8.addItem(self.verticalSpacer) @@ -464,7 +310,7 @@ class Ui_MainWindow(object): MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menubar.setObjectName(u"menubar") - self.menubar.setGeometry(QRect(0, 0, 1010, 21)) + self.menubar.setGeometry(QRect(0, 0, 1010, 30)) self.menuHelp = QMenu(self.menubar) self.menuHelp.setObjectName(u"menuHelp") MainWindow.setMenuBar(self.menubar) @@ -501,20 +347,9 @@ class Ui_MainWindow(object): self.download_btn.setText(QCoreApplication.translate("MainWindow", u"Start Download", None)) self.script_btn.setText(QCoreApplication.translate("MainWindow", u"Run Script", None)) self.label_3.setText(QCoreApplication.translate("MainWindow", u"General Settings", None)) - self.pack_archive_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Pack installable archive (WAD/TAD)", None)) self.archive_file_entry.setPlaceholderText(QCoreApplication.translate("MainWindow", u"File Name", None)) - self.keep_enc_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Keep encrypted contents", None)) - self.create_dec_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Create decrypted contents (*.app)", None)) - self.use_local_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Use local files, if they exist", None)) - self.use_wiiu_nus_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Use the Wii U NUS (faster, only effects Wii/vWii)", None)) - self.patch_ios_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Apply patches to IOS (Applies to WADs only)", None)) self.label_4.setText(QCoreApplication.translate("MainWindow", u"vWii Title Settings", None)) - self.pack_vwii_mode_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Re-encrypt title using the Wii Common Key", None)) self.label_2.setText(QCoreApplication.translate("MainWindow", u"App Settings", None)) - self.auto_update_chkbox.setText("") - self.auto_update_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Check for updates on startup", None)) - self.custom_out_dir_chkbox.setText("") - self.custom_out_dir_chkbox_lbl.setText(QCoreApplication.translate("MainWindow", u"Use a custom download directory", None)) self.custom_out_dir_entry.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Output Path", None)) self.custom_out_dir_btn.setText(QCoreApplication.translate("MainWindow", u"Select...", None)) self.log_text_browser.setMarkdown("") @@ -524,7 +359,7 @@ class Ui_MainWindow(object): "hr { height: 1px; border-width: 0; }\n" "li.unchecked::marker { content: \"\\2610\"; }\n" "li.checked::marker { content: \"\\2612\"; }\n" -"\n" +"\n" "