mirror of
https://github.com/outbackdingo/OpCore-Simplify.git
synced 2026-01-27 10:19:49 +00:00
Add GUI Support for OpCore Simplify (#512)
* Refactor OpCore-Simplify to GUI version * New ConfigEditor * Add requirement checks and installation in launchers * Add GitHub Actions workflow to generate manifest.json * Set compression level for asset * Skip .git and __pycache__ folders * Refactor update process to include integrity checker * Add SMBIOS model selection * Update README.md * Update to main branch
This commit is contained in:
183
Scripts/ui_utils.py
Normal file
183
Scripts/ui_utils.py
Normal file
@@ -0,0 +1,183 @@
|
||||
from typing import Optional, Tuple, TYPE_CHECKING
|
||||
|
||||
from PyQt6.QtWidgets import QWidget, QLabel, QHBoxLayout, QVBoxLayout
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QColor
|
||||
from qfluentwidgets import FluentIcon, BodyLabel, CardWidget, StrongBodyLabel
|
||||
|
||||
from .styles import SPACING, COLORS, RADIUS
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from qfluentwidgets import GroupHeaderCardWidget, CardGroupWidget
|
||||
|
||||
class ProgressStatusHelper:
|
||||
def __init__(self, status_icon_label, progress_label, progress_bar, progress_container):
|
||||
self.status_icon_label = status_icon_label
|
||||
self.progress_label = progress_label
|
||||
self.progress_bar = progress_bar
|
||||
self.progress_container = progress_container
|
||||
|
||||
def update(self, status, message, progress=None):
|
||||
icon_size = 28
|
||||
icon_map = {
|
||||
"loading": (FluentIcon.SYNC, COLORS["primary"]),
|
||||
"success": (FluentIcon.COMPLETED, COLORS["success"]),
|
||||
"error": (FluentIcon.CLOSE, COLORS["error"]),
|
||||
"warning": (FluentIcon.INFO, COLORS["warning"]),
|
||||
}
|
||||
|
||||
if status in icon_map:
|
||||
icon, color = icon_map[status]
|
||||
pixmap = icon.icon(color=color).pixmap(icon_size, icon_size)
|
||||
self.status_icon_label.setPixmap(pixmap)
|
||||
|
||||
self.progress_label.setText(message)
|
||||
if status == "success":
|
||||
self.progress_label.setStyleSheet("color: {}; font-size: 15px; font-weight: 600;".format(COLORS["success"]))
|
||||
elif status == "error":
|
||||
self.progress_label.setStyleSheet("color: {}; font-size: 15px; font-weight: 600;".format(COLORS["error"]))
|
||||
elif status == "warning":
|
||||
self.progress_label.setStyleSheet("color: {}; font-size: 15px; font-weight: 600;".format(COLORS["warning"]))
|
||||
else:
|
||||
self.progress_label.setStyleSheet("color: {}; font-size: 15px; font-weight: 600;".format(COLORS["primary"]))
|
||||
|
||||
if progress is not None:
|
||||
self.progress_bar.setRange(0, 100)
|
||||
self.progress_bar.setValue(progress)
|
||||
else:
|
||||
self.progress_bar.setRange(0, 0)
|
||||
|
||||
self.progress_container.setVisible(True)
|
||||
|
||||
class UIUtils:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def build_icon_label(self, icon: FluentIcon, color: str, size: int = 32) -> QLabel:
|
||||
label = QLabel()
|
||||
label.setPixmap(icon.icon(color=color).pixmap(size, size))
|
||||
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
label.setFixedSize(size + 12, size + 12)
|
||||
return label
|
||||
|
||||
def create_info_widget(self, text: str, color: Optional[str] = None) -> QWidget:
|
||||
if not text:
|
||||
return QWidget()
|
||||
|
||||
label = BodyLabel(text)
|
||||
label.setWordWrap(True)
|
||||
if color:
|
||||
label.setStyleSheet("color: {};".format(color))
|
||||
return label
|
||||
|
||||
def colored_icon(self, icon: FluentIcon, color_hex: str) -> FluentIcon:
|
||||
if not icon or not color_hex:
|
||||
return icon
|
||||
|
||||
tint = QColor(color_hex)
|
||||
return icon.colored(tint, tint)
|
||||
|
||||
def get_compatibility_icon(self, compat_tuple: Optional[Tuple[Optional[str], Optional[str]]]) -> FluentIcon:
|
||||
if not compat_tuple or compat_tuple == (None, None):
|
||||
return self.colored_icon(FluentIcon.CLOSE, COLORS["error"])
|
||||
return self.colored_icon(FluentIcon.ACCEPT, COLORS["success"])
|
||||
|
||||
def add_group_with_indent(self, card: "GroupHeaderCardWidget", icon: FluentIcon, title: str, content: str, widget: Optional[QWidget] = None, indent_level: int = 0) -> "CardGroupWidget":
|
||||
if widget is None:
|
||||
widget = QWidget()
|
||||
|
||||
group = card.addGroup(icon, title, content, widget)
|
||||
|
||||
if indent_level > 0:
|
||||
base_margin = 24
|
||||
indent = 20 * indent_level
|
||||
group.hBoxLayout.setContentsMargins(base_margin + indent, 10, 24, 10)
|
||||
|
||||
return group
|
||||
|
||||
def create_step_indicator(self, step_number: int, total_steps: int = 4, color: str = "#0078D4") -> BodyLabel:
|
||||
label = BodyLabel("STEP {} OF {}".format(step_number, total_steps))
|
||||
label.setStyleSheet("color: {}; font-weight: bold;".format(color))
|
||||
return label
|
||||
|
||||
def create_vertical_spacer(self, spacing: int = SPACING["medium"]) -> QWidget:
|
||||
spacer = QWidget()
|
||||
spacer.setFixedHeight(spacing)
|
||||
return spacer
|
||||
|
||||
def custom_card(self, card_type: str = "note", icon: Optional[FluentIcon] = None, title: str = "", body: str = "", custom_widget: Optional[QWidget] = None, parent: Optional[QWidget] = None) -> CardWidget:
|
||||
card_styles = {
|
||||
"note": {
|
||||
"bg": COLORS["note_bg"],
|
||||
"text": COLORS["note_text"],
|
||||
"border": "rgba(21, 101, 192, 0.2)",
|
||||
"default_icon": FluentIcon.INFO
|
||||
},
|
||||
"warning": {
|
||||
"bg": COLORS["warning_bg"],
|
||||
"text": COLORS["warning_text"],
|
||||
"border": "rgba(245, 124, 0, 0.25)",
|
||||
"default_icon": FluentIcon.MEGAPHONE
|
||||
},
|
||||
"success": {
|
||||
"bg": COLORS["success_bg"],
|
||||
"text": COLORS["success"],
|
||||
"border": "rgba(16, 124, 16, 0.2)",
|
||||
"default_icon": FluentIcon.COMPLETED
|
||||
},
|
||||
"error": {
|
||||
"bg": "#FFEBEE",
|
||||
"text": COLORS["error"],
|
||||
"border": "rgba(232, 17, 35, 0.25)",
|
||||
"default_icon": FluentIcon.CLOSE
|
||||
},
|
||||
"info": {
|
||||
"bg": COLORS["note_bg"],
|
||||
"text": COLORS["info"],
|
||||
"border": "rgba(0, 120, 212, 0.2)",
|
||||
"default_icon": FluentIcon.INFO
|
||||
}
|
||||
}
|
||||
|
||||
style = card_styles.get(card_type, card_styles["note"])
|
||||
|
||||
if icon is None:
|
||||
icon = style["default_icon"]
|
||||
|
||||
card = CardWidget(parent)
|
||||
card.setStyleSheet(f"""
|
||||
CardWidget {{
|
||||
background-color: {style["bg"]};
|
||||
border: 1px solid {style["border"]};
|
||||
border-radius: {RADIUS["card"]}px;
|
||||
}}
|
||||
""")
|
||||
|
||||
main_layout = QHBoxLayout(card)
|
||||
main_layout.setContentsMargins(SPACING["large"], SPACING["large"], SPACING["large"], SPACING["large"])
|
||||
main_layout.setSpacing(SPACING["large"])
|
||||
|
||||
icon_label = self.build_icon_label(icon, style["text"], size=40)
|
||||
main_layout.addWidget(icon_label, 0, Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
text_layout = QVBoxLayout()
|
||||
text_layout.setSpacing(SPACING["small"])
|
||||
|
||||
if title:
|
||||
title_label = StrongBodyLabel(title)
|
||||
title_label.setStyleSheet("color: {}; font-size: 16px;".format(style["text"]))
|
||||
text_layout.addWidget(title_label)
|
||||
|
||||
if body:
|
||||
body_label = BodyLabel(body)
|
||||
body_label.setWordWrap(True)
|
||||
body_label.setOpenExternalLinks(True)
|
||||
body_label.setStyleSheet("color: #424242; line-height: 1.6;")
|
||||
text_layout.addWidget(body_label)
|
||||
|
||||
if custom_widget:
|
||||
text_layout.addWidget(custom_widget)
|
||||
|
||||
main_layout.addLayout(text_layout)
|
||||
|
||||
return card
|
||||
Reference in New Issue
Block a user