8ebcc3a700
Fixes a subtle bug that would cause increased CPU usage due to spawning multiple singleshot times with very short timeouts (15ms) until the Store tab was loaded.
272 lines
11 KiB
Python
272 lines
11 KiB
Python
import platform
|
|
import random
|
|
from logging import getLogger
|
|
|
|
from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot, QObject, QEvent, QTimer
|
|
from PyQt5.QtGui import QMouseEvent, QShowEvent, QPaintEvent
|
|
from PyQt5.QtWidgets import QMessageBox, QAction
|
|
|
|
from rare.models.game import RareGame
|
|
from rare.shared import (
|
|
LegendaryCoreSingleton,
|
|
GlobalSignalsSingleton,
|
|
ArgumentsSingleton,
|
|
ImageManagerSingleton,
|
|
)
|
|
from rare.utils.paths import desktop_links_supported, desktop_link_path, create_desktop_link
|
|
from .library_widget import LibraryWidget
|
|
|
|
logger = getLogger("GameWidget")
|
|
|
|
|
|
class GameWidget(LibraryWidget):
|
|
show_info = pyqtSignal(RareGame)
|
|
|
|
def __init__(self, rgame: RareGame, parent=None):
|
|
super(GameWidget, self).__init__(parent=parent)
|
|
self.core = LegendaryCoreSingleton()
|
|
self.signals = GlobalSignalsSingleton()
|
|
self.args = ArgumentsSingleton()
|
|
self.image_manager = ImageManagerSingleton()
|
|
|
|
self.rgame: RareGame = rgame
|
|
|
|
self.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
|
|
self.launch_action = QAction(self.tr("Launch"), self)
|
|
self.launch_action.triggered.connect(self._launch)
|
|
|
|
self.install_action = QAction(self.tr("Install"), self)
|
|
self.install_action.triggered.connect(self._install)
|
|
|
|
self.desktop_link_action = QAction(self)
|
|
self.desktop_link_action.triggered.connect(
|
|
lambda: self._create_link(self.rgame.folder_name, "desktop")
|
|
)
|
|
|
|
self.menu_link_action = QAction(self)
|
|
self.menu_link_action.triggered.connect(
|
|
lambda: self._create_link(self.rgame.folder_name, "start_menu")
|
|
)
|
|
|
|
self.reload_action = QAction(self.tr("Reload Image"), self)
|
|
self.reload_action.triggered.connect(self._on_reload_image)
|
|
|
|
self.uninstall_action = QAction(self.tr("Uninstall"), self)
|
|
self.uninstall_action.triggered.connect(self._uninstall)
|
|
|
|
self.update_actions()
|
|
|
|
# signals
|
|
self.rgame.signals.widget.update.connect(lambda: self.setPixmap(self.rgame.pixmap))
|
|
self.rgame.signals.widget.update.connect(self.update_buttons)
|
|
self.rgame.signals.widget.update.connect(self.update_state)
|
|
self.rgame.signals.game.installed.connect(self.update_actions)
|
|
self.rgame.signals.game.uninstalled.connect(self.update_actions)
|
|
|
|
self.rgame.signals.progress.start.connect(
|
|
lambda: self.showProgress(
|
|
self.image_manager.get_pixmap(self.rgame.app_name, True),
|
|
self.image_manager.get_pixmap(self.rgame.app_name, False)
|
|
)
|
|
)
|
|
self.rgame.signals.progress.update.connect(
|
|
lambda p: self.updateProgress(p)
|
|
)
|
|
self.rgame.signals.progress.finish.connect(
|
|
lambda e: self.hideProgress(e)
|
|
)
|
|
|
|
self.state_strings = {
|
|
RareGame.State.IDLE: "",
|
|
RareGame.State.RUNNING: self.tr("Running..."),
|
|
RareGame.State.DOWNLOADING: self.tr("Downloading..."),
|
|
RareGame.State.VERIFYING: self.tr("Verifying..."),
|
|
RareGame.State.MOVING: self.tr("Moving..."),
|
|
RareGame.State.UNINSTALLING: self.tr("Uninstalling..."),
|
|
RareGame.State.SYNCING: self.tr("Syncing saves..."),
|
|
"has_update": self.tr("Update available"),
|
|
"needs_verification": self.tr("Needs verification"),
|
|
"not_can_launch": self.tr("Can't launch"),
|
|
"save_not_up_to_date": self.tr("Save is not up-to-date")
|
|
}
|
|
|
|
self.hover_strings = {
|
|
"info": self.tr("Show information"),
|
|
"install": self.tr("Install game"),
|
|
"can_launch": self.tr("Launch game"),
|
|
"is_foreign": self.tr("Launch offline"),
|
|
"has_update": self.tr("Launch without version check"),
|
|
"is_origin": self.tr("Launch/Link"),
|
|
"not_can_launch": self.tr("Can't launch"),
|
|
}
|
|
|
|
# lk: abstract class for typing, the `self.ui` attribute should be used
|
|
# lk: by the Ui class in the children. It must contain at least the same
|
|
# lk: attributes as `GameWidgetUi` class
|
|
__slots__ = "ui"
|
|
|
|
def paintEvent(self, a0: QPaintEvent) -> None:
|
|
if not self.visibleRegion().isNull() and self.rgame.pixmap.isNull():
|
|
self.startTimer(random.randrange(42, 2361, 129), Qt.CoarseTimer)
|
|
# self.startTimer(random.randrange(42, 2361, 363), Qt.VeryCoarseTimer)
|
|
# self.rgame.load_pixmap()
|
|
super().paintEvent(a0)
|
|
|
|
def timerEvent(self, a0):
|
|
self.killTimer(a0.timerId())
|
|
self.rgame.load_pixmap()
|
|
|
|
def showEvent(self, a0: QShowEvent) -> None:
|
|
if a0.spontaneous():
|
|
return super().showEvent(a0)
|
|
super().showEvent(a0)
|
|
|
|
@pyqtSlot()
|
|
def update_state(self):
|
|
if self.rgame.is_idle:
|
|
if self.rgame.has_update:
|
|
self.ui.status_label.setText(self.state_strings["has_update"])
|
|
elif self.rgame.needs_verification:
|
|
self.ui.status_label.setText(self.state_strings["needs_verification"])
|
|
elif not self.rgame.can_launch and self.rgame.is_installed:
|
|
self.ui.status_label.setText(self.state_strings["not_can_launch"])
|
|
elif self.rgame.igame and (
|
|
self.rgame.game.supports_cloud_saves or self.rgame.game.supports_mac_cloud_saves
|
|
) and not self.rgame.is_save_up_to_date:
|
|
self.ui.status_label.setText(self.state_strings["save_not_up_to_date"])
|
|
else:
|
|
self.ui.status_label.setText(self.state_strings[self.rgame.state])
|
|
else:
|
|
self.ui.status_label.setText(self.state_strings[self.rgame.state])
|
|
self.ui.status_label.setVisible(bool(self.ui.status_label.text()))
|
|
|
|
@pyqtSlot()
|
|
def update_buttons(self):
|
|
self.ui.install_btn.setVisible(not self.rgame.is_installed)
|
|
self.ui.install_btn.setEnabled(not self.rgame.is_installed)
|
|
self.ui.launch_btn.setVisible(self.rgame.is_installed)
|
|
self.ui.launch_btn.setEnabled(self.rgame.can_launch)
|
|
|
|
@pyqtSlot()
|
|
def update_actions(self):
|
|
for action in self.actions():
|
|
self.removeAction(action)
|
|
|
|
if self.rgame.is_installed or self.rgame.is_origin:
|
|
self.addAction(self.launch_action)
|
|
else:
|
|
self.addAction(self.install_action)
|
|
|
|
if desktop_links_supported() and self.rgame.is_installed:
|
|
if desktop_link_path(self.rgame.folder_name, "desktop").exists():
|
|
self.desktop_link_action.setText(self.tr("Remove Desktop link"))
|
|
else:
|
|
self.desktop_link_action.setText(self.tr("Create Desktop link"))
|
|
self.addAction(self.desktop_link_action)
|
|
if desktop_link_path(self.rgame.folder_name, "start_menu").exists():
|
|
self.menu_link_action.setText(self.tr("Remove Start Menu link"))
|
|
else:
|
|
self.menu_link_action.setText(self.tr("Create Start Menu link"))
|
|
self.addAction(self.menu_link_action)
|
|
|
|
self.addAction(self.reload_action)
|
|
if self.rgame.is_installed and not self.rgame.is_origin:
|
|
self.addAction(self.uninstall_action)
|
|
|
|
def eventFilter(self, a0: QObject, a1: QEvent) -> bool:
|
|
if a0 is self.ui.launch_btn:
|
|
if a1.type() == QEvent.Enter:
|
|
if not self.rgame.can_launch:
|
|
self.ui.tooltip_label.setText(self.hover_strings["not_can_launch"])
|
|
elif self.rgame.is_origin:
|
|
self.ui.tooltip_label.setText(self.hover_strings["is_origin"])
|
|
elif self.rgame.has_update:
|
|
self.ui.tooltip_label.setText(self.hover_strings["has_update"])
|
|
elif self.rgame.is_foreign and self.rgame.can_run_offline:
|
|
self.ui.tooltip_label.setText(self.hover_strings["is_foreign"])
|
|
elif self.rgame.can_launch:
|
|
self.ui.tooltip_label.setText(self.hover_strings["can_launch"])
|
|
return True
|
|
if a1.type() == QEvent.Leave:
|
|
self.ui.tooltip_label.setText(self.hover_strings["info"])
|
|
# return True
|
|
if a0 is self.ui.install_btn:
|
|
if a1.type() == QEvent.Enter:
|
|
self.ui.tooltip_label.setText(self.hover_strings["install"])
|
|
return True
|
|
if a1.type() == QEvent.Leave:
|
|
self.ui.tooltip_label.setText(self.hover_strings["info"])
|
|
# return True
|
|
if a0 is self:
|
|
if a1.type() == QEvent.Enter:
|
|
self.ui.tooltip_label.setText(self.hover_strings["info"])
|
|
return super(GameWidget, self).eventFilter(a0, a1)
|
|
|
|
def mousePressEvent(self, e: QMouseEvent) -> None:
|
|
# left button
|
|
if e.button() == 1:
|
|
self.show_info.emit(self.rgame)
|
|
# right
|
|
elif e.button() == 2:
|
|
super(GameWidget, self).mousePressEvent(e)
|
|
|
|
@pyqtSlot()
|
|
def _on_reload_image(self) -> None:
|
|
self.rgame.refresh_pixmap()
|
|
|
|
@pyqtSlot()
|
|
@pyqtSlot(bool, bool)
|
|
def _launch(self, offline=False, skip_version_check=False):
|
|
if offline or (self.rgame.is_foreign and self.rgame.can_run_offline):
|
|
offline = True
|
|
if self.rgame.has_update:
|
|
skip_version_check = True
|
|
self.rgame.launch(
|
|
offline=offline, skip_update_check=skip_version_check
|
|
)
|
|
|
|
@pyqtSlot()
|
|
def _install(self):
|
|
self.show_info.emit(self.rgame)
|
|
|
|
@pyqtSlot()
|
|
def _uninstall(self):
|
|
self.show_info.emit(self.rgame)
|
|
|
|
def _create_link(self, name, link_type):
|
|
if not desktop_links_supported():
|
|
QMessageBox.warning(
|
|
self,
|
|
self.tr("Warning"),
|
|
self.tr("Creating shortcuts is currently unsupported on {}").format(platform.system()),
|
|
)
|
|
return
|
|
|
|
shortcut_path = desktop_link_path(name, link_type)
|
|
|
|
if not shortcut_path.exists():
|
|
try:
|
|
if not create_desktop_link(
|
|
app_name=self.rgame.app_name,
|
|
app_title=self.rgame.app_title,
|
|
link_name=self.rgame.folder_name,
|
|
link_type=link_type,
|
|
):
|
|
raise PermissionError
|
|
except PermissionError:
|
|
QMessageBox.warning(self, "Error", "Could not create shortcut.")
|
|
return
|
|
|
|
if link_type == "desktop":
|
|
self.desktop_link_action.setText(self.tr("Remove Desktop link"))
|
|
elif link_type == "start_menu":
|
|
self.menu_link_action.setText(self.tr("Remove Start Menu link"))
|
|
else:
|
|
if shortcut_path.exists():
|
|
shortcut_path.unlink(missing_ok=True)
|
|
|
|
if link_type == "desktop":
|
|
self.desktop_link_action.setText(self.tr("Create Desktop link"))
|
|
elif link_type == "start_menu":
|
|
self.menu_link_action.setText(self.tr("Create Start Menu link"))
|