1
0
Fork 0
mirror of synced 2024-06-26 18:20:50 +12:00
Rare/rare/utils/misc.py
lennard a66600efa3
Move cloud save ui to a new tab in game_info
Signed-off-by: loathingKernel <142770+loathingKernel@users.noreply.github.com>
2023-03-08 17:46:26 +02:00

257 lines
7.2 KiB
Python

import os
from configparser import ConfigParser
from logging import getLogger
from typing import List, Union, Type
import qtawesome
import requests
from PyQt5.QtCore import (
pyqtSignal,
QObject,
QRunnable,
QSettings,
QFile,
QDir,
Qt,
)
from PyQt5.QtGui import QPalette, QColor, QFontMetrics
from PyQt5.QtWidgets import qApp, QStyleFactory, QLabel
from PyQt5.sip import wrappertype
from legendary.core import LegendaryCore
from legendary.models.game import Game
from requests.exceptions import HTTPError
from rare.utils.paths import resources_path
logger = getLogger("Utils")
settings = QSettings("Rare", "Rare")
color_role_map = {
0: "WindowText",
1: "Button",
2: "Light",
3: "Midlight",
4: "Dark",
5: "Mid",
6: "Text",
7: "BrightText",
8: "ButtonText",
9: "Base",
10: "Window",
11: "Shadow",
12: "Highlight",
13: "HighlightedText",
14: "Link",
15: "LinkVisited",
16: "AlternateBase",
# 17: "NoRole",
18: "ToolTipBase",
19: "ToolTipText",
20: "PlaceholderText",
# 21: "NColorRoles",
}
color_group_map = {
0: "Active",
1: "Disabled",
2: "Inactive",
}
def load_color_scheme(path: str) -> QPalette:
palette = QPalette()
scheme = QSettings(path, QSettings.IniFormat)
try:
scheme.beginGroup("ColorScheme")
for g in color_group_map:
scheme.beginGroup(color_group_map[g])
group = QPalette.ColorGroup(g)
for r in color_role_map:
role = QPalette.ColorRole(r)
color = scheme.value(color_role_map[r], None)
if color is not None:
palette.setColor(group, role, QColor(color))
else:
palette.setColor(group, role, palette.color(QPalette.Active, role))
scheme.endGroup()
scheme.endGroup()
except:
palette = None
return palette
def get_static_style() -> str:
file = QFile(":/static_css/stylesheet.qss")
file.open(QFile.ReadOnly)
static = file.readAll().data().decode("utf-8")
file.close()
return static
def set_color_pallete(color_scheme: str) -> None:
static = get_static_style()
if not color_scheme:
qApp.setStyle(QStyleFactory.create(qApp.property("rareDefaultQtStyle")))
qApp.setPalette(qApp.style().standardPalette())
qApp.setStyleSheet(static)
return
qApp.setStyle(QStyleFactory.create("Fusion"))
custom_palette = load_color_scheme(f":/schemes/{color_scheme}")
if custom_palette is not None:
qApp.setPalette(custom_palette)
qApp.setStyleSheet(static)
icon_color = qApp.palette().color(QPalette.Foreground).name()
qtawesome.set_defaults(color=icon_color)
def get_color_schemes() -> List[str]:
colors = []
for file in QDir(":/schemes"):
colors.append(file)
return colors
def set_style_sheet(style_sheet: str) -> None:
static = get_static_style()
if not style_sheet:
qApp.setStyle(QStyleFactory.create(qApp.property("rareDefaultQtStyle")))
qApp.setStyleSheet(static)
return
qApp.setStyle(QStyleFactory.create("Fusion"))
file = QFile(f":/stylesheets/{style_sheet}/stylesheet.qss")
file.open(QFile.ReadOnly)
stylesheet = file.readAll().data().decode("utf-8")
file.close()
qApp.setStyleSheet(stylesheet + static)
icon_color = qApp.palette().color(QPalette.Text).name()
qtawesome.set_defaults(color="#eeeeee")
def get_style_sheets() -> List[str]:
styles = []
for file in QDir(":/stylesheets/"):
styles.append(file)
return styles
def get_translations():
langs = ["en"]
for i in os.listdir(os.path.join(resources_path, "languages")):
if i.endswith(".qm") and not i.startswith("qt_"):
langs.append(i.split(".")[0])
return langs
def get_latest_version():
try:
resp = requests.get(
"https://api.github.com/repos/Dummerle/Rare/releases/latest", timeout=2,
)
tag = resp.json()["tag_name"]
return tag
except requests.exceptions.ConnectionError:
return "0.0.0"
def path_size(path: Union[str, os.PathLike]) -> int:
return sum(
os.stat(os.path.join(dp, f)).st_size
for dp, dn, filenames in os.walk(path)
for f in filenames
)
def format_size(b: Union[int, float]) -> str:
for s in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"]:
if b < 1024:
return f"{b:.2f} {s}B"
b /= 1024
# this is a copied function from legendary.utils.wine_helpers, but registry file can be specified
def read_registry(registry: str, wine_pfx: str) -> ConfigParser:
accepted = ["system.reg", "user.reg"]
if registry not in accepted:
raise RuntimeError(f'Unknown target "{registry}" not in {accepted}')
reg = ConfigParser(comment_prefixes=(';', '#', '/', 'WINE'), allow_no_value=True,
strict=False)
reg.optionxform = str
reg.read(os.path.join(wine_pfx, 'system.reg'))
return reg
class CloudWorker(QRunnable):
class Signals(QObject):
# List[SaveGameFile]
result_ready = pyqtSignal(dict)
def __init__(self, core: LegendaryCore):
super(CloudWorker, self).__init__()
self.core = core
self.signals = CloudWorker.Signals()
self.setAutoDelete(True)
def run(self) -> None:
try:
saves = self.core.get_save_games()
except HTTPError:
self.signals.result_ready.emit(None)
return
save_games = set()
for igame in self.core.get_installed_list():
game = self.core.get_game(igame.app_name)
if self.core.is_installed(igame.app_name) and game.supports_cloud_saves:
save_games.add(igame.app_name)
latest_saves = dict()
for s in sorted(saves, key=lambda a: a.datetime):
if s.app_name in save_games:
latest_saves[s.app_name] = s
self.signals.result_ready.emit(latest_saves)
def get_raw_save_path(game: Game):
if game.supports_cloud_saves:
return (
game.metadata.get("customAttributes", {})
.get("CloudSaveFolder", {})
.get("value")
)
def icon(icn_str: str, fallback: str = None, **kwargs):
try:
return qtawesome.icon(icn_str, **kwargs)
except Exception as e:
if not fallback:
logger.warning(f"{e} {icn_str}")
if fallback:
try:
return qtawesome.icon(fallback, **kwargs)
except Exception as e:
logger.error(str(e))
if kwargs.get("color"):
kwargs["color"] = "red"
return qtawesome.icon("ei.error", **kwargs)
def widget_object_name(widget: Union[QObject,wrappertype,Type], suffix: str) -> str:
suffix = f"_{suffix}" if suffix else ""
if isinstance(widget, QObject):
return f"{type(widget).__name__}{suffix}"
elif isinstance(widget, wrappertype) or isinstance(widget, type):
return f"{widget.__name__}{suffix}"
else:
raise RuntimeError(f"Argument {widget} not a QObject or type of QObject")
def elide_text(label: QLabel, text: str) -> str:
metrics = QFontMetrics(label.font())
return metrics.elidedText(text, Qt.ElideRight, label.sizeHint().width())