Code launch profile page ui/ux.
This commit is contained in:
@@ -19,85 +19,6 @@ from manager.profile import ProfileManager
|
|||||||
from manager.widgets import WidgetManager
|
from manager.widgets import WidgetManager
|
||||||
from window import LauncherMainWindow
|
from window import LauncherMainWindow
|
||||||
|
|
||||||
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 Launcher(QApplication, LauncherObject):
|
class Launcher(QApplication, LauncherObject):
|
||||||
def __init__(self, logger):
|
def __init__(self, logger):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|||||||
@@ -89,4 +89,17 @@ def is_light_theme(widget=None) -> bool:
|
|||||||
|
|
||||||
return luminance >= 0.5
|
return luminance >= 0.5
|
||||||
|
|
||||||
|
def add_icon_padding(icon: QIcon, icon_size=32, padding=6) -> QIcon:
|
||||||
|
source = icon.pixmap(icon_size, icon_size)
|
||||||
|
|
||||||
|
canvas_size = icon_size + padding * 2
|
||||||
|
canvas = QPixmap(canvas_size, canvas_size)
|
||||||
|
canvas.fill(Qt.GlobalColor.transparent)
|
||||||
|
|
||||||
|
painter = QPainter(canvas)
|
||||||
|
painter.drawPixmap(padding, padding, source)
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
return QIcon(canvas)
|
||||||
|
|
||||||
# ======================== AI generated END ========================
|
# ======================== AI generated END ========================
|
||||||
@@ -101,6 +101,8 @@ class ProfileManager(QObject):
|
|||||||
self.load,
|
self.load,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.load()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def default_profile_path(self):
|
def default_profile_path(self):
|
||||||
return Path(self.app.work_dir, DEFAuLT_PROFILE_RELATIVE_PATH)
|
return Path(self.app.work_dir, DEFAuLT_PROFILE_RELATIVE_PATH)
|
||||||
|
|||||||
+1
-25
@@ -53,6 +53,7 @@ class AccountWidget(QWidget):
|
|||||||
elif selected_action == check_log_stat_action and callable(self.check_account_callback): self.check_account_callback()
|
elif selected_action == check_log_stat_action and callable(self.check_account_callback): self.check_account_callback()
|
||||||
elif selected_action == switch_acc_action and callable(self.switch_account_callback): self.switch_account_callback()
|
elif selected_action == switch_acc_action and callable(self.switch_account_callback): self.switch_account_callback()
|
||||||
|
|
||||||
|
|
||||||
class AccountPage(QWidget):
|
class AccountPage(QWidget):
|
||||||
def __init__(self, app, parent=None):
|
def __init__(self, app, parent=None):
|
||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
@@ -60,31 +61,6 @@ class AccountPage(QWidget):
|
|||||||
|
|
||||||
self.layout = QHBoxLayout()
|
self.layout = QHBoxLayout()
|
||||||
|
|
||||||
# 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.layout.addStretch()
|
|
||||||
# self.layout.addWidget(self.icon_label, alignment=Qt.AlignmentFlag.AlignCenter)
|
|
||||||
# self.layout.addWidget(self.dev_info_box, alignment=Qt.AlignmentFlag.AlignHCenter)
|
|
||||||
# self.layout.addWidget(self.dev_info_2, alignment=Qt.AlignmentFlag.AlignHCenter)
|
|
||||||
# self.layout.addStretch()
|
|
||||||
#
|
|
||||||
# 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.")
|
|
||||||
#
|
|
||||||
# self.setLayout(self.layout)
|
|
||||||
# self.app.apply_qss(Path("main.qss"), self.setStyleSheet)
|
|
||||||
|
|
||||||
self.main_layout = QVBoxLayout()
|
self.main_layout = QVBoxLayout()
|
||||||
self.right_layout = QVBoxLayout()
|
self.right_layout = QVBoxLayout()
|
||||||
|
|
||||||
|
|||||||
@@ -156,16 +156,28 @@ class CreateProfilePage(QWidget):
|
|||||||
self.start_load_mod_loader_version
|
self.start_load_mod_loader_version
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.mod_loader_dropdown.currentTextChanged.connect(
|
||||||
|
self.update_mod_loader_icon
|
||||||
|
)
|
||||||
|
|
||||||
self.loader_list = {
|
self.loader_list = {
|
||||||
"Don't Install": {
|
"Don't Install": {
|
||||||
"type": "vanilla",
|
"type": "vanilla",
|
||||||
|
"icon": Path(self.app.icon_dir, "vanilla.png"),
|
||||||
"loadVersionMethod": self.load_vanilla_version_list,
|
"loadVersionMethod": self.load_vanilla_version_list,
|
||||||
"profileCreateHandler": self.handle_vanilla_profile_create,
|
"profileCreateHandler": self.handle_vanilla_profile_create,
|
||||||
},
|
},
|
||||||
"Fabric": {
|
"Fabric": {
|
||||||
"type": "modded",
|
"type": "modded",
|
||||||
|
"icon": Path(self.app.icon_dir, "modLoader", "fabric.png"),
|
||||||
"loadVersionMethod": getattr(self, "load_fabric_version_list", None),
|
"loadVersionMethod": getattr(self, "load_fabric_version_list", None),
|
||||||
"profileCreateHandler": self.handle_fabric_profile_create,
|
"profileCreateHandler": self.handle_fabric_profile_create,
|
||||||
|
},
|
||||||
|
"NeoForge": {
|
||||||
|
"type": "modded",
|
||||||
|
"icon": Path(self.app.icon_dir, "modLoader", "neoforged.ico"),
|
||||||
|
"loadVersionMethod": getattr(self, "load_neoforge_version_list", None),
|
||||||
|
"profileCreateHandler": self.handle_neoforge_profile_create,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.init_all()
|
self.init_all()
|
||||||
@@ -243,6 +255,34 @@ class CreateProfilePage(QWidget):
|
|||||||
if callable(request.complete_callback):
|
if callable(request.complete_callback):
|
||||||
request.complete_callback()
|
request.complete_callback()
|
||||||
|
|
||||||
|
@Slot(str)
|
||||||
|
def update_mod_loader_icon(self, loader_name: str):
|
||||||
|
loader = self.loader_list.get(loader_name)
|
||||||
|
if not loader:
|
||||||
|
self.app.logger.warning(
|
||||||
|
"Mod Loader {} not found".format(loader_name)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
icon_path = loader.get("icon")
|
||||||
|
if not isinstance(icon_path, Path):
|
||||||
|
self.app.logger.warning(
|
||||||
|
"Mod Loader {} icon path not found or is not Path type".format(loader_name)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
pixmap = self.app.get_picture(
|
||||||
|
icon_path,
|
||||||
|
QSize(100, 100),
|
||||||
|
)
|
||||||
|
|
||||||
|
pixmap = pixmap.scaled(
|
||||||
|
QSize(100, 100),
|
||||||
|
Qt.AspectRatioMode.KeepAspectRatio,
|
||||||
|
Qt.TransformationMode.SmoothTransformation,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.mod_loader_icon_label.setPixmap(pixmap)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def clean_list(target_list: QListWidget | QComboBox):
|
def clean_list(target_list: QListWidget | QComboBox):
|
||||||
|
|||||||
+351
-1
@@ -1,7 +1,357 @@
|
|||||||
from PySide6.QtWidgets import QWidget
|
from pathlib import Path
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt, Signal, QPointF
|
||||||
|
from PySide6.QtGui import QIcon, QMouseEvent, QHideEvent, QPixmap, QPainter, QColor
|
||||||
|
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, QScrollArea, QGridLayout, \
|
||||||
|
QComboBox, QFrame, QSizePolicy, QApplication, QGraphicsDropShadowEffect
|
||||||
|
|
||||||
|
from manager.profile import ProfileSummary
|
||||||
|
|
||||||
|
|
||||||
|
class ProfileButton(QFrame):
|
||||||
|
clicked = Signal()
|
||||||
|
"""
|
||||||
|
ProfileButton
|
||||||
|
|
||||||
|
This object is coded by codex!
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, app, parent: QWidget | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.app = app
|
||||||
|
self.setObjectName("profileButton")
|
||||||
|
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
|
self.setMinimumHeight(64)
|
||||||
|
self.setMaximumHeight(64)
|
||||||
|
|
||||||
|
# Layout
|
||||||
|
self.layout = QHBoxLayout(self)
|
||||||
|
self.layout.setContentsMargins(12, 8, 12, 8)
|
||||||
|
self.layout.setSpacing(12)
|
||||||
|
self.text_layout = QVBoxLayout()
|
||||||
|
self.text_layout.setSpacing(1)
|
||||||
|
|
||||||
|
# Widget
|
||||||
|
self.icon_label = QLabel()
|
||||||
|
self.icon_label.setFixedSize(40, 40)
|
||||||
|
self.icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
|
self.name_label = QLabel()
|
||||||
|
self.name_label.setObjectName("profileName")
|
||||||
|
self.version_label = QLabel()
|
||||||
|
self.version_label.setObjectName("profileVersion")
|
||||||
|
self.arrow_label = QLabel("▾")
|
||||||
|
self.arrow_label.setObjectName("profileArrow")
|
||||||
|
self.arrow_label.setStyleSheet("border-style:solid; background-color: transparent; ")
|
||||||
|
self.arrow_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.arrow_label.setFixedWidth(24)
|
||||||
|
|
||||||
|
# Bind
|
||||||
|
self.text_layout.addWidget(self.name_label)
|
||||||
|
self.text_layout.addWidget(self.version_label)
|
||||||
|
|
||||||
|
self.layout.addWidget(self.icon_label)
|
||||||
|
self.layout.addLayout(self.text_layout, 1)
|
||||||
|
self.layout.addWidget(self.arrow_label)
|
||||||
|
|
||||||
|
def set_profile(self, profile: ProfileSummary) -> None:
|
||||||
|
"""
|
||||||
|
Set current profile id
|
||||||
|
:param profile:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.setProperty("profile_id", profile.id)
|
||||||
|
self.name_label.setText(profile.name)
|
||||||
|
self.version_label.setText(profile.version_id)
|
||||||
|
|
||||||
|
icon_path = profile.icon
|
||||||
|
|
||||||
|
if not isinstance(icon_path, Path):
|
||||||
|
icon_path = Path(icon_path)
|
||||||
|
|
||||||
|
if not icon_path.exists() or not icon_path.is_file():
|
||||||
|
# Use default
|
||||||
|
icon_path = Path(self.app.icon_dir, "profile_default.png")
|
||||||
|
|
||||||
|
self.icon_label.setPixmap(QIcon(icon_path.as_posix()).pixmap(36, 36))
|
||||||
|
|
||||||
|
def set_popup_open(self, opened: bool) -> None:
|
||||||
|
self.arrow_label.setText("▴" if opened else "▾")
|
||||||
|
|
||||||
|
def mousePressEvent(self, event: QMouseEvent) -> None:
|
||||||
|
if event.button() == Qt.MouseButton.LeftButton:
|
||||||
|
self.clicked.emit()
|
||||||
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
|
class ProfileListItem(QPushButton):
|
||||||
|
selected = Signal(object)
|
||||||
|
|
||||||
|
def __init__(self, profile: ProfileSummary, parent: QWidget | None = None) -> None:
|
||||||
|
super().__init__(parent)
|
||||||
|
self.profile = profile
|
||||||
|
self.setObjectName("profileItem")
|
||||||
|
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||||
|
self.setMinimumHeight(62)
|
||||||
|
|
||||||
|
layout = QHBoxLayout(self)
|
||||||
|
layout.setContentsMargins(12, 7, 12, 7)
|
||||||
|
layout.setSpacing(12)
|
||||||
|
|
||||||
|
self.icon_label = QLabel()
|
||||||
|
self.icon_label.setFixedSize(40, 40)
|
||||||
|
self.icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
|
text_layout = QVBoxLayout()
|
||||||
|
text_layout.setSpacing(1)
|
||||||
|
name_label = QLabel(profile.name)
|
||||||
|
name_label.setObjectName("itemName")
|
||||||
|
version_label = QLabel(profile.version_id)
|
||||||
|
version_label.setObjectName("itemVersion")
|
||||||
|
text_layout.addWidget(name_label)
|
||||||
|
text_layout.addWidget(version_label)
|
||||||
|
|
||||||
|
layout.addWidget(self.icon_label)
|
||||||
|
layout.addLayout(text_layout, 1)
|
||||||
|
self.clicked.connect(lambda: self.selected.emit(self.profile))
|
||||||
|
|
||||||
|
def set_icon(self, icon_path: Path) -> None:
|
||||||
|
self.icon_label.setPixmap(QIcon(icon_path.as_posix()).pixmap(36, 36))
|
||||||
|
|
||||||
|
class ProfilePopup(QFrame):
|
||||||
|
profile_selected = Signal(object)
|
||||||
|
closed = Signal()
|
||||||
|
|
||||||
|
def __init__(self, app, parent: QWidget | None = None) -> None:
|
||||||
|
super().__init__(parent, Qt.WindowType.Popup)
|
||||||
|
self.app = app
|
||||||
|
self.setFixedHeight(210)
|
||||||
|
self.setObjectName("profilePopup")
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout(self)
|
||||||
|
self.layout.setContentsMargins(4, 4, 4, 4)
|
||||||
|
self.layout.setSpacing(0)
|
||||||
|
|
||||||
|
self.scroll_area = QScrollArea(self)
|
||||||
|
self.scroll_area.setObjectName("profileScrollArea")
|
||||||
|
self.scroll_area.setWidgetResizable(True)
|
||||||
|
self.scroll_area.setFrameShape(QFrame.Shape.NoFrame)
|
||||||
|
self.scroll_area.setHorizontalScrollBarPolicy(
|
||||||
|
Qt.ScrollBarPolicy.ScrollBarAlwaysOff
|
||||||
|
)
|
||||||
|
self.scroll_area.setVerticalScrollBarPolicy(
|
||||||
|
Qt.ScrollBarPolicy.ScrollBarAsNeeded
|
||||||
|
)
|
||||||
|
|
||||||
|
self.content = QWidget()
|
||||||
|
self.content.setObjectName("profileListContent")
|
||||||
|
self.content_layout = QVBoxLayout(self.content)
|
||||||
|
self.content_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.content_layout.setSpacing(2)
|
||||||
|
|
||||||
|
self.scroll_area.setWidget(self.content)
|
||||||
|
self.layout.addWidget(self.scroll_area)
|
||||||
|
self.content_layout.setAlignment(
|
||||||
|
Qt.AlignmentFlag.AlignTop
|
||||||
|
)
|
||||||
|
|
||||||
|
def load_profiles(self, profiles: list[ProfileSummary]) -> None:
|
||||||
|
for profile in profiles:
|
||||||
|
icon_path = profile.icon
|
||||||
|
|
||||||
|
if not isinstance(icon_path, Path):
|
||||||
|
icon_path = Path(icon_path)
|
||||||
|
|
||||||
|
if not icon_path.exists() or not icon_path.is_file():
|
||||||
|
# Use default
|
||||||
|
icon_path = Path(self.app.icon_dir, "profile_default.png")
|
||||||
|
|
||||||
|
item = ProfileListItem(profile, self)
|
||||||
|
item.selected.connect(self.profile_selected)
|
||||||
|
item.set_icon(icon_path)
|
||||||
|
self.content_layout.addWidget(item)
|
||||||
|
|
||||||
|
|
||||||
|
def hideEvent(self, event: QHideEvent) -> None:
|
||||||
|
self.closed.emit()
|
||||||
|
super().hideEvent(event)
|
||||||
|
|
||||||
|
|
||||||
class LaunchProfilePage(QWidget):
|
class LaunchProfilePage(QWidget):
|
||||||
def __init__(self, app, parent=None):
|
def __init__(self, app, parent=None):
|
||||||
super(LaunchProfilePage, self).__init__(parent)
|
super(LaunchProfilePage, self).__init__(parent)
|
||||||
self.app = app
|
self.app = app
|
||||||
|
self.profile_manager = app.profile_manager
|
||||||
|
|
||||||
|
# Layout
|
||||||
|
self.layout = QVBoxLayout(self)
|
||||||
|
self.bottom_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
# Widgets
|
||||||
|
self.status_label = QLabel("Select a version to launch")
|
||||||
|
self.status_label.setStyleSheet("font-size: 12px; font-weight: 600;")
|
||||||
|
self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
|
# Profile button (just like the official launcher look like)
|
||||||
|
self.profile_button = ProfileButton(self.app)
|
||||||
|
self.profile_button.setMinimumWidth(260)
|
||||||
|
self.profile_button.setMaximumWidth(360)
|
||||||
|
self.profile_popup = ProfilePopup(parent=self, app=self.app)
|
||||||
|
self.profile_button.clicked.connect(self.toggle_profile_popup)
|
||||||
|
self.profile_popup.profile_selected.connect(self.select_profile)
|
||||||
|
self.profile_popup.closed.connect(self.refresh_profile_button)
|
||||||
|
|
||||||
|
launch_button = QPushButton("Launch Game")
|
||||||
|
launch_button.setObjectName("launchButton")
|
||||||
|
launch_button.setMinimumWidth(120)
|
||||||
|
launch_button.setMinimumHeight(42)
|
||||||
|
launch_button.setMaximumHeight(64)
|
||||||
|
launch_button.setSizePolicy(
|
||||||
|
QSizePolicy.Policy.Fixed,
|
||||||
|
QSizePolicy.Policy.Expanding,
|
||||||
|
)
|
||||||
|
launch_button.clicked.connect(self.launch_profile)
|
||||||
|
|
||||||
|
# Profile overlay
|
||||||
|
self.profile_frame = self.ProfileBackgroundFrame(
|
||||||
|
parent=self,
|
||||||
|
image_path=Path(
|
||||||
|
self.app.icon_dir,
|
||||||
|
"profile_default.png",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.profile_frame.setObjectName("profileFrame")
|
||||||
|
|
||||||
|
# Frame layout and overlay
|
||||||
|
frame_layout = QVBoxLayout(self.profile_frame)
|
||||||
|
frame_layout.setContentsMargins(20, 20, 20, 20)
|
||||||
|
|
||||||
|
self.profile_overlay = QFrame(self.profile_frame)
|
||||||
|
self.profile_overlay.setObjectName("header")
|
||||||
|
|
||||||
|
# Add a nice shadow
|
||||||
|
# shadow = QGraphicsDropShadowEffect(self.profile_frame)
|
||||||
|
# shadow.setBlurRadius(24)
|
||||||
|
# shadow.setOffset(QPointF(0, 6))
|
||||||
|
# shadow.setColor(QColor(0, 0, 0, 150))
|
||||||
|
|
||||||
|
# self.profile_frame.setGraphicsEffect(shadow)
|
||||||
|
|
||||||
|
# Header
|
||||||
|
self.header_label = QLabel("Launch Profile")
|
||||||
|
self.header_label.setObjectName("headerLabel")
|
||||||
|
|
||||||
|
self.header_layout = QHBoxLayout(self.profile_overlay)
|
||||||
|
self.header_layout.addWidget(self.header_label)
|
||||||
|
self.header_layout.addStretch()
|
||||||
|
|
||||||
|
frame_layout.addWidget(self.profile_overlay)
|
||||||
|
frame_layout.addStretch()
|
||||||
|
|
||||||
|
# Bind button widget
|
||||||
|
self.bottom_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.bottom_layout.setSpacing(10)
|
||||||
|
self.bottom_layout.addWidget(self.profile_button)
|
||||||
|
self.bottom_layout.addStretch()
|
||||||
|
self.bottom_layout.addWidget(self.status_label)
|
||||||
|
self.bottom_layout.addStretch()
|
||||||
|
self.bottom_layout.addWidget(launch_button)
|
||||||
|
|
||||||
|
self.layout.addWidget(self.profile_frame, 1)
|
||||||
|
self.layout.addLayout(self.bottom_layout)
|
||||||
|
|
||||||
|
self.app.apply_qss(Path("profile.qss"), self.setStyleSheet)
|
||||||
|
|
||||||
|
self.load_profiles()
|
||||||
|
|
||||||
|
class ProfileBackgroundFrame(QFrame):
|
||||||
|
def __init__(self, image_path, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.background = QPixmap(str(image_path))
|
||||||
|
|
||||||
|
def paintEvent(self, event):
|
||||||
|
super().paintEvent(event)
|
||||||
|
|
||||||
|
painter = QPainter(self)
|
||||||
|
|
||||||
|
if not self.background.isNull():
|
||||||
|
scaled = self.background.scaled(
|
||||||
|
self.size(),
|
||||||
|
Qt.AspectRatioMode.KeepAspectRatioByExpanding,
|
||||||
|
Qt.TransformationMode.SmoothTransformation,
|
||||||
|
)
|
||||||
|
|
||||||
|
x = (self.width() - scaled.width()) // 2
|
||||||
|
y = (self.height() - scaled.height()) // 2
|
||||||
|
painter.drawPixmap(x, y, scaled)
|
||||||
|
|
||||||
|
def load_profiles(self):
|
||||||
|
profiles: list[ProfileSummary] = self.profile_manager.list_profiles()
|
||||||
|
self.profile_popup.load_profiles(profiles)
|
||||||
|
|
||||||
|
if len(profiles) > 0:
|
||||||
|
self.select_profile(profiles[0])
|
||||||
|
|
||||||
|
def toggle_profile_popup(self) -> None:
|
||||||
|
if self.profile_popup.isVisible():
|
||||||
|
self.profile_popup.hide()
|
||||||
|
self.profile_button.set_popup_open(False)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.profile_popup.setFixedWidth(self.profile_button.width())
|
||||||
|
|
||||||
|
button_top = self.profile_button.mapToGlobal(
|
||||||
|
self.profile_button.rect().topLeft()
|
||||||
|
)
|
||||||
|
button_bottom = self.profile_button.mapToGlobal(
|
||||||
|
self.profile_button.rect().bottomLeft()
|
||||||
|
)
|
||||||
|
|
||||||
|
screen = QApplication.screenAt(
|
||||||
|
self.profile_button.mapToGlobal(
|
||||||
|
self.profile_button.rect().center()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if screen is None:
|
||||||
|
screen = QApplication.primaryScreen()
|
||||||
|
|
||||||
|
# Show profile popup at bottom if screen space is enough to render (if not, render at top of the button)
|
||||||
|
available = screen.availableGeometry()
|
||||||
|
popup_width = self.profile_popup.width()
|
||||||
|
popup_height = self.profile_popup.height()
|
||||||
|
space_below = available.bottom() - button_bottom.y()
|
||||||
|
space_above = button_top.y() - available.top()
|
||||||
|
|
||||||
|
if space_below < popup_height and space_above > space_below:
|
||||||
|
popup_y = button_top.y() - popup_height
|
||||||
|
else:
|
||||||
|
popup_y = button_bottom.y() + 1
|
||||||
|
|
||||||
|
popup_x = max(
|
||||||
|
available.left(),
|
||||||
|
min(button_bottom.x(), available.right() - popup_width + 1),
|
||||||
|
)
|
||||||
|
popup_y = max(
|
||||||
|
available.top(),
|
||||||
|
min(popup_y, available.bottom() - popup_height + 1),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.profile_popup.move(popup_x, popup_y)
|
||||||
|
self.profile_popup.show()
|
||||||
|
self.profile_button.set_popup_open(True)
|
||||||
|
|
||||||
|
def refresh_profile_button(self) -> None:
|
||||||
|
# Refresh profile button (Due to some unknown issue, the button arrow have a black
|
||||||
|
# background after profile menu profile_popup. Rerender the button can fix this issue)
|
||||||
|
self.profile_button.set_popup_open(False)
|
||||||
|
self.profile_button.updateGeometry()
|
||||||
|
self.profile_button.repaint()
|
||||||
|
|
||||||
|
def select_profile(self, profile: ProfileSummary) -> None:
|
||||||
|
# Update select profile id
|
||||||
|
self.profile_button.set_profile(profile)
|
||||||
|
self.profile_popup.hide()
|
||||||
|
self.profile_button.set_popup_open(False)
|
||||||
|
|
||||||
|
def launch_profile(self) -> None:
|
||||||
|
profile_id = self.profile_button.property("profile_id")
|
||||||
|
self.status_label.setText(f"Preparing to launch...")
|
||||||
@@ -6,5 +6,5 @@
|
|||||||
- profile_default.png : [Source](https://www.pixilart.com/art/minecraft-crafting-table-8aa9e1b9aee1a62)
|
- profile_default.png : [Source](https://www.pixilart.com/art/minecraft-crafting-table-8aa9e1b9aee1a62)
|
||||||
- modLoader/fabric.png : [Source](https://fabricmc.net/assets/logo.png)
|
- modLoader/fabric.png : [Source](https://fabricmc.net/assets/logo.png)
|
||||||
- modLoader/neoforged.png : [Source](https://raw.githubusercontent.com/neoforged/.github/refs/heads/main/art/neoforged.ico)
|
- modLoader/neoforged.png : [Source](https://raw.githubusercontent.com/neoforged/.github/refs/heads/main/art/neoforged.ico)
|
||||||
|
- vanilla.png : [Source](https://en.wikipedia.org/wiki/File:Updated_Minecraft_cube.svg)
|
||||||
## For the icon owner: If you want to take down icon that infringing upon your copyright. Contact us with this [link](https://repo.weispace.net/wei/Launcher)
|
## For the icon owner: If you want to take down icon that infringing upon your copyright. Contact us with this [link](https://repo.weispace.net/wei/Launcher)
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,56 @@
|
|||||||
|
QFrame#profileButton {
|
||||||
|
background: palette(mid);
|
||||||
|
border: 1px solid palette(midlight);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFrame#profileButton:hover {
|
||||||
|
background: palette(midlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#profileName, QLabel#itemName {
|
||||||
|
color: #f4f6f8;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#profileVersion, QLabel#itemVersion {
|
||||||
|
color: #aeb6c2;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#profileArrow {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
QFrame#profilePopup {
|
||||||
|
background: palette(mid);
|
||||||
|
border: 1px solid palette(midlight);
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#profileItem {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#profileItem:hover {
|
||||||
|
background: #3d6fb4;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPushButton#launchButton {
|
||||||
|
min-width: 150px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel#headerLabel {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
QFrame#profileFrame {
|
||||||
|
background-color: palette(base);
|
||||||
|
border: 1px solid palette(mid);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user