Files
Launcher/app.py
T

332 lines
11 KiB
Python
Raw Normal View History

2026-07-10 23:27:21 +08:00
import logging
from pathlib import Path
from typing import Callable
2026-07-10 20:57:31 +08:00
from PySide6 import QtWidgets
from PySide6.QtCore import QSize
from PySide6.QtGui import QIcon, Qt, QPixmap
2026-07-14 22:22:58 +08:00
from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QStyle, QToolButton, \
QStackedWidget
2026-07-14 22:22:58 +08:00
from core_lib.qt.hack import move_window_to_center, is_light_theme, \
recolor_icon
from core_lib.qt import messagebox
2026-07-14 22:22:58 +08:00
from pages.account import AccountPage
from pages.test import TestPage
2026-07-10 20:57:31 +08:00
2026-07-14 22:22:58 +08:00
LAUNCHER_VERSION = "alpha_0.0.2"
2026-07-14 01:13:36 +08:00
MAIN_REPO_URL = "https://repo.weispace.net/wei/Launcher/"
class ToolBar(QtWidgets.QToolBar):
def __init__(self, app: QApplication, parent=None):
super(ToolBar, self).__init__(parent)
self.app = app
2026-07-14 22:22:58 +08:00
self.spacer = QWidget()
self.orientationChanged.connect(self._update_widget_size)
def _update_widget_size(self, orientation):
vertical = orientation == Qt.Orientation.Vertical
2026-07-14 22:22:58 +08:00
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.setFixedWidth(150)
def add_button(self, text=None, icon: QIcon=None) -> QToolButton:
button = QtWidgets.QToolButton(self)
if text:
text = " "+text
button.setText(text)
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)
return button
def update_all(self):
self._update_widget_size(self.orientation())
self.update()
2026-07-10 20:57:31 +08:00
class Launcher(QApplication):
def __init__(self):
super().__init__()
# Window config
2026-07-10 20:57:31 +08:00
self.setApplicationName("TestLauncher")
self.main_window = QMainWindow()
self.main_window.setGeometry(0, 0, 800, 600)
move_window_to_center(self.main_window)
# logger
2026-07-10 23:27:21 +08:00
self.logger = logging.getLogger("Launcher.MainWindow")
# dirs
self.program_dir = Path(__file__).parent
self.work_dir = Path.cwd()
2026-07-14 01:13:36 +08:00
# Set icon
if self.icon_path.exists():
self.setWindowIcon(QIcon(self.icon_path.as_posix()))
else:
self.logger.error("No icon found.")
# Main layout
self.central = QStackedWidget()
self.toolbar = ToolBar(self, self.main_window)
2026-07-14 01:13:36 +08:00
# 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.launcher_version))
self.version_label.setObjectName("version_label")
self.repo_url_label = QLabel(f"<a href=\"{MAIN_REPO_URL}\">Main repo</a>")
self.repo_url_label.setObjectName("repo_url_label")
self.repo_url_label.setOpenExternalLinks(True)
if Path(self.resources_dir, "pictures", "in_progress.png").exists():
image = QPixmap(Path(self.resources_dir, "pictures", "in_progress.png"))
self.icon_label.setPixmap(image.scaled(300, 300))
else:
self.icon_label.setText("Ouch. The icon is missing.")
# 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(self, self.main_window)
2026-07-14 01:13:36 +08:00
2026-07-14 22:22:58 +08:00
# Account page
self.account_page = AccountPage(self, self.main_window)
# Add page
self.central.addWidget(self.home_page)
self.central.addWidget(self.test_page)
2026-07-14 22:22:58 +08:00
self.central.addWidget(self.account_page)
# Bind toolbar and center widget
self.main_window.addToolBar(Qt.ToolBarArea.LeftToolBarArea, self.toolbar)
2026-07-14 01:13:36 +08:00
self.main_window.setCentralWidget(self.central)
# Apply qss
self.apply_qss(Path("main.qss"), self.setStyleSheet)
self.apply_qss(Path("toolbar.qss"), self.toolbar.setStyleSheet)
# Toolbar
# Test Window btn
2026-07-14 22:22:58 +08:00
self.open_test_page = self.toolbar.add_button(" Tests", icon=self.get_icon(Path(self.icon_dir, "debug.png")))
self.open_test_page.setObjectName("open_test_page")
# Home btn
2026-07-14 22:22:58 +08:00
self.home_button = self.toolbar.add_button(icon=self.get_icon(Path(self.icon_dir, "home.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.get_icon(Path(self.icon_dir, "head.png")))
# Profile page
# Bind tool buttons
self.toolbar.addWidget(self.home_button)
self.toolbar.addWidget(self.open_test_page)
self.toolbar.setMovable(True)
self.toolbar.setFloatable(False)
self.toolbar.setAllowedAreas(Qt.ToolBarArea.AllToolBarAreas)
2026-07-14 22:22:58 +08:00
self.toolbar.addWidget(self.toolbar.spacer)
self.toolbar.addSeparator()
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)
)
2026-07-14 22:22:58 +08:00
self.open_account_page.clicked.connect(
lambda: self.set_current_page(self.account_page, self.open_account_page)
)
self.set_current_page(self.home_page, self.home_button)
2026-07-10 20:57:31 +08:00
def exec(self):
self.main_window.show()
self.toolbar.update_all()
2026-07-10 23:27:21 +08:00
self.exec_()
def set_current_page(self, page: QWidget, related_button: QToolButton):
self.central.setCurrentWidget(page)
related_button.setFocus()
2026-07-14 22:22:58 +08:00
def get_icon(self, path: Path):
icon = self.style().standardIcon(QStyle.StandardPixmap.SP_MessageBoxWarning)
if not path.exists() or not path.is_file():
messagebox.error(
self.main_window,
"Resource Error",
"Missing icon file: {}".format(path)
)
return icon
try:
if is_light_theme() and path.name.endswith(".png"):
icon = recolor_icon(
path
)
else:
icon = QIcon(path.as_posix())
except Exception as e:
messagebox.error(
self.main_window,
"Resource Error",
"Failed to load icon {}: {}".format(path, e)
)
return icon
def get_picture(self, path: Path, size: QSize, custom_error: str=None) -> QPixmap:
picture = self.style().standardIcon(QStyle.StandardPixmap.SP_MessageBoxWarning).pixmap(size)
if not path.exists() or not path.is_file():
messagebox.error(
self.main_window,
"Resource Error",
"Missing icon file: {}".format(path) if not custom_error else custom_error
)
return picture
try:
picture = QPixmap(path.as_posix())
except Exception as e:
messagebox.error(
self.main_window,
"Resource Error",
"Failed to load icon {}: {}".format(path, e)
)
return picture
@property
def temp_dir(self):
return self.work_dir / "temp"
@property
def config_dir(self):
return self.work_dir / "config"
@property
def data_dir(self):
return self.work_dir / "data"
@property
def log_dir(self):
2026-07-14 01:13:36 +08:00
return self.work_dir / "log"
@property
def resources_dir(self):
return self.program_dir / "resources"
@property
def icon_path(self):
return self.resources_dir / "icons" / "icon.png"
@property
def icon_dir(self):
return self.resources_dir / "icons"
2026-07-14 01:13:36 +08:00
@property
def launcher_version(self):
return LAUNCHER_VERSION
@property
def styles_path(self):
return self.resources_dir / "styles"
def apply_qss(self, qss_relative_path: Path, apply_qss_callback: Callable[[str], None]) -> str:
full_path = self.styles_path / qss_relative_path
if not full_path.exists():
messagebox.error(
self.main_window,
"Resource Error",
"Missing stylesheet file: {}".format(full_path),
)
return ""
try:
data = full_path.read_text()
apply_qss_callback(data)
except Exception as e:
messagebox.error(
self.main_window,
"Resource Error",
"Unable to apply QSS stylesheet {}: {}".format(full_path, e),
)
return ""