from pathlib import Path from PySide6 import QtWidgets from PySide6.QtCore import QSize from PySide6.QtGui import QIcon, Qt, QPixmap from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QToolButton, \ QStackedWidget from PySide6.QtCore import Slot from PySide6.QtWidgets import QMessageBox, QFileDialog from core_lib.qt import messagebox from core_lib.qt.progress_dialog import ProgressDialog from core_lib.qt.messagebox import ask_yes_no_with_plain_text from constant import MAIN_REPO_URL from manager.widgets import AskForRequest, SelectPathRequest from pages.account import AccountPage from pages.create_profile import CreateProfilePage from pages.launch_profile import LaunchProfilePage from pages.test import TestPage from pages.settings import SettingsPage class ToolBar(QtWidgets.QToolBar): def __init__(self, app: QApplication, parent=None): super(ToolBar, self).__init__(parent) self.app = app self.spacer = QWidget() self.orientationChanged.connect(self._update_widget_size) def _update_widget_size(self, orientation): vertical = orientation == Qt.Orientation.Vertical if vertical: self.spacer.setSizePolicy( QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding, ) else: self.spacer.setSizePolicy( QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred, ) for button in self.findChildren(QToolButton): if vertical: button.setToolButtonStyle( Qt.ToolButtonStyle.ToolButtonIconOnly ) button.setFixedSize(60, 60) continue button.setMinimumSize(0, 0) button.setMaximumSize(16777215, 16777215) if not button.icon().isNull() and not button.text(): button.setToolButtonStyle( Qt.ToolButtonStyle.ToolButtonIconOnly ) button.setFixedSize(60, 60) elif button.icon().isNull(): button.setToolButtonStyle( Qt.ToolButtonStyle.ToolButtonTextOnly ) button.setFixedWidth(150) else: button.setToolButtonStyle( Qt.ToolButtonStyle.ToolButtonTextBesideIcon ) button.setMinimumWidth(60) def add_button(self, text=None, icon: QIcon=None) -> QToolButton: button = QtWidgets.QToolButton(self) if text: text = " "+text button.setText(text) # else: # button.setText("\u00a0") if icon: button.setIcon(icon) button.setIconSize(QSize(32, 32)) if text: button.setToolButtonStyle( Qt.ToolButtonStyle.ToolButtonTextBesideIcon ) else: button.setToolButtonStyle( Qt.ToolButtonStyle.ToolButtonIconOnly ) button.setAutoRaise(True) button.setFixedHeight(60) return button def update_all(self): self._update_widget_size(self.orientation()) self.update() class LauncherMainWindow(QMainWindow): def __init__(self, / ,app, parent: QWidget | None=None): super(LauncherMainWindow, self).__init__(parent) self.app = app self.widget_manager = app.widget_manager self.game_manager = app.game_manager # Main layout self.central = QStackedWidget() self.toolbar = ToolBar(self.app, self) # center message (will be deleted if launcher finished development) content = """Still digging!""" message = "If you found that something might be a issue. You can report it to the main repo! Any suggestion are welcome." self.icon_label = QLabel() self.icon_label.setObjectName("icon_label") self.dev_info_box = QLabel(content) self.dev_info_box.setObjectName("dev_info_box") self.dev_info_2 = QLabel(message) self.dev_info_2.setObjectName("dev_info_message") self.version_label = QLabel("Current version: {}".format(self.app.launcher_version)) self.version_label.setObjectName("version_label") self.repo_url_label = QLabel(f"Main repo") self.repo_url_label.setObjectName("repo_url_label") self.repo_url_label.setOpenExternalLinks(True) if Path(self.app.resources_dir, "pictures", "in_progress.png").exists(): image = QPixmap(Path(self.app.resources_dir, "pictures", "in_progress.png")) self.icon_label.setPixmap(image.scaled(300, 300)) else: self.icon_label.setText("Ouch. The icon is missing.") # Dialog self.download_dialog = ProgressDialog(self) # Homepage self.home_page = QWidget() self.home_layout = QVBoxLayout(self.home_page) self.home_layout.addStretch() self.home_layout.addWidget(self.icon_label, alignment=Qt.AlignmentFlag.AlignCenter) self.home_layout.addWidget(self.dev_info_box, alignment=Qt.AlignmentFlag.AlignHCenter) self.home_layout.addWidget(self.dev_info_2, alignment=Qt.AlignmentFlag.AlignHCenter) self.home_layout.addWidget(self.version_label, alignment=Qt.AlignmentFlag.AlignHCenter) self.home_layout.addWidget(self.repo_url_label, alignment=Qt.AlignmentFlag.AlignHCenter) self.home_layout.addStretch() # test page self.test_page = TestPage( app=self.app, parent=self, widget_manager=self.app.widget_manager ) self.launch_profile_page = LaunchProfilePage( app=self.app, parent=self, ) # Account page self.account_page = AccountPage(self.app, self) # Profile page self.create_profile_page = CreateProfilePage(self.app, self) # Settings page self.settings_page = SettingsPage(self.app, self) # Add page self.central.addWidget(self.home_page) self.central.addWidget(self.test_page) self.central.addWidget(self.account_page) self.central.addWidget(self.settings_page) self.central.addWidget(self.create_profile_page) self.central.addWidget(self.launch_profile_page) # Bind toolbar and center widget self.addToolBar(Qt.ToolBarArea.LeftToolBarArea, self.toolbar) self.setCentralWidget(self.central) # Apply qss self.app.apply_qss(Path("main.qss"), self.setStyleSheet) self.app.apply_qss(Path("toolbar.qss"), self.toolbar.setStyleSheet) # Toolbar # Test Window btn self.open_test_page = self.toolbar.add_button(" Tests", icon=self.app.get_icon(Path(self.app.icon_dir, "debug.png"))) self.open_test_page.setObjectName("open_test_page") # Launch profile btn self.open_launch_profile_page = self.toolbar.add_button(" Launch Profile", icon=self.app.get_icon(Path(self.app.icon_dir, "profile_default.png"), True)) # Home btn self.home_button = self.toolbar.add_button(icon=self.app.get_icon(Path(self.app.icon_dir, "home.png"))) # Settings btn (will be moved to the bottom of the toolbar) self.open_settings_page = self.toolbar.add_button(icon=self.app.get_icon(Path(self.app.icon_dir, "settings.png"))) # Account btn (will be moved to the bottom (or last one item) of the toolbar self.open_account_page = self.toolbar.add_button(icon=self.app.get_icon(Path(self.app.icon_dir, "head.png"), True)) # Profile btn self.open_create_profile_page = self.toolbar.add_button(icon=self.app.get_icon(Path(self.app.icon_dir, "add_temp.png"))) # Bind tool buttons self.toolbar.addWidget(self.home_button) self.toolbar.addWidget(self.open_test_page) self.toolbar.addWidget(self.open_create_profile_page) self.toolbar.addWidget(self.open_launch_profile_page) self.toolbar.setMovable(True) self.toolbar.setFloatable(False) self.toolbar.setAllowedAreas(Qt.ToolBarArea.AllToolBarAreas) self.toolbar.addWidget(self.toolbar.spacer) self.toolbar.addSeparator() self.toolbar.addWidget(self.open_settings_page) self.toolbar.addWidget(self.open_account_page) # Bind page-related button click event self.home_button.clicked.connect( lambda: self.set_current_page(self.home_page, self.home_button) ) self.open_test_page.clicked.connect( lambda: self.set_current_page(self.test_page, self.open_test_page) ) self.open_launch_profile_page.clicked.connect( lambda: self.set_current_page(self.launch_profile_page, self.open_launch_profile_page) ) self.open_settings_page.clicked.connect( lambda: self.set_current_page(self.settings_page, self.open_settings_page) ) self.open_account_page.clicked.connect( lambda: self.set_current_page(self.account_page, self.open_account_page) ) self.open_create_profile_page.clicked.connect( lambda: self.set_current_page(self.create_profile_page, self.open_create_profile_page) ) # Bind signal event self.bind_event() self.set_current_page(self.home_page, self.home_button) @Slot(object) def ask_request(self, context: AskForRequest): if not context.use_plain_text: msg = QMessageBox.question( self, context.title, context.message, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.Yes, ) result = msg == QMessageBox.StandardButton.Yes else: result = ask_yes_no_with_plain_text( self, context.title, context.message, context.details, ) if result: context.result_queue.put(True) else: context.result_queue.put(False) context.wait_event.set() @Slot(object) def ask_for_path(self, context: SelectPathRequest): path, _ = QFileDialog.getOpenFileName( self, context.title, "", context.filter, ) context.result_queue.put(path) context.wait_event.set() @Slot(dict) def show_and_print_error(self, context: dict): error = context.get("error", None) title = context.get("title", "Error") message = context.get("message", "No content") if isinstance(error, list): self.app.logger.error("".join(error)) elif isinstance(error, str): self.app.logger.error(error) elif isinstance(error, Exception): self.app.logger.exception(error) messagebox.error( self, title, message=message ) @Slot(object) def enable_widget(self, widget): widget.setEnabled(True) @Slot(object) def disable_widget(self, widget): widget.setDisabled(True) @Slot(str) def show_error(self, message): messagebox.error(self, "Error", message=message) @Slot(str) def show_warning(self, widget): messagebox.warning(self, "Warning", message=widget) @Slot(str) def show_info(self, widget): messagebox.info(self, "Info", message=widget) def set_current_page(self, page: QWidget, related_button: QToolButton): self.central.setCurrentWidget(page) related_button.setFocus() def bind_event(self): download_signal = self.widget_manager.download_signal widget_signal = self.widget_manager.signal download_signal.started.connect( self.download_dialog.add_task, Qt.ConnectionType.QueuedConnection, ) download_signal.progress.connect( self.download_dialog.update_task, Qt.ConnectionType.QueuedConnection, ) download_signal.finished.connect( self.download_dialog.finish_task, Qt.ConnectionType.QueuedConnection, ) download_signal.failed.connect( self.download_dialog.fail_task, Qt.ConnectionType.QueuedConnection, ) download_signal.removed.connect( self.download_dialog.remove_task, Qt.ConnectionType.QueuedConnection, ) widget_signal.show_error_message.connect( self.show_error, Qt.ConnectionType.QueuedConnection, ) widget_signal.show_warning_message.connect( self.show_warning, Qt.ConnectionType.QueuedConnection, ) widget_signal.show_info_message.connect( self.show_info, Qt.ConnectionType.QueuedConnection, ) widget_signal.show_and_print_error_message.connect( self.show_and_print_error ) widget_signal.enable_widget.connect( self.enable_widget, Qt.ConnectionType.QueuedConnection, ) widget_signal.disable_widget.connect( self.disable_widget, Qt.ConnectionType.QueuedConnection, ) widget_signal.askyesno.connect( self.ask_request ) widget_signal.ask_for_path.connect( self.ask_for_path )