2021-06-21 07:55:31 +12:00
|
|
|
import platform
|
2023-09-15 06:47:47 +12:00
|
|
|
import random
|
2021-03-25 23:49:27 +13:00
|
|
|
from logging import getLogger
|
|
|
|
|
2023-09-15 06:47:47 +12:00
|
|
|
from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot, QObject, QEvent, QTimer
|
2023-12-20 11:21:21 +13:00
|
|
|
from PyQt5.QtGui import QMouseEvent, QShowEvent, QPaintEvent
|
2023-02-19 04:27:18 +13:00
|
|
|
from PyQt5.QtWidgets import QMessageBox, QAction
|
2021-03-25 23:49:27 +13:00
|
|
|
|
2022-12-25 15:21:23 +13:00
|
|
|
from rare.models.game import RareGame
|
|
|
|
from rare.shared import (
|
|
|
|
LegendaryCoreSingleton,
|
|
|
|
GlobalSignalsSingleton,
|
|
|
|
ArgumentsSingleton,
|
|
|
|
ImageManagerSingleton,
|
|
|
|
)
|
2023-02-08 00:41:59 +13:00
|
|
|
from rare.utils.paths import desktop_links_supported, desktop_link_path, create_desktop_link
|
2022-12-25 15:21:23 +13:00
|
|
|
from .library_widget import LibraryWidget
|
2021-03-25 23:49:27 +13:00
|
|
|
|
2023-01-26 00:04:21 +13:00
|
|
|
logger = getLogger("GameWidget")
|
2021-03-25 23:49:27 +13:00
|
|
|
|
|
|
|
|
2022-12-25 15:21:23 +13:00
|
|
|
class GameWidget(LibraryWidget):
|
|
|
|
show_info = pyqtSignal(RareGame)
|
2021-03-25 23:49:27 +13:00
|
|
|
|
2023-01-25 02:40:21 +13:00
|
|
|
def __init__(self, rgame: RareGame, parent=None):
|
2022-12-25 15:21:23 +13:00
|
|
|
super(GameWidget, self).__init__(parent=parent)
|
2022-02-26 06:43:27 +13:00
|
|
|
self.core = LegendaryCoreSingleton()
|
|
|
|
self.signals = GlobalSignalsSingleton()
|
|
|
|
self.args = ArgumentsSingleton()
|
2022-06-19 06:45:36 +12:00
|
|
|
self.image_manager = ImageManagerSingleton()
|
2021-11-03 09:57:19 +13:00
|
|
|
|
2022-12-25 15:21:23 +13:00
|
|
|
self.rgame: RareGame = rgame
|
2021-12-04 13:11:20 +13:00
|
|
|
|
2021-04-14 02:56:44 +12:00
|
|
|
self.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
self.launch_action = QAction(self.tr("Launch"), self)
|
|
|
|
self.launch_action.triggered.connect(self._launch)
|
2021-04-14 05:08:49 +12:00
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
self.install_action = QAction(self.tr("Install"), self)
|
|
|
|
self.install_action.triggered.connect(self._install)
|
2021-04-14 02:56:44 +12:00
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
self.desktop_link_action = QAction(self)
|
|
|
|
self.desktop_link_action.triggered.connect(
|
|
|
|
lambda: self._create_link(self.rgame.folder_name, "desktop")
|
|
|
|
)
|
2021-04-14 02:56:44 +12:00
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
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()
|
2022-12-25 15:21:23 +13:00
|
|
|
|
2023-01-25 02:40:21 +13:00
|
|
|
# signals
|
2023-02-08 00:41:59 +13:00
|
|
|
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)
|
|
|
|
|
2023-01-25 02:40:21 +13:00
|
|
|
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)
|
|
|
|
)
|
2023-01-05 09:32:49 +13:00
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
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..."),
|
2023-02-06 05:28:02 +13:00
|
|
|
RareGame.State.SYNCING: self.tr("Syncing saves..."),
|
2023-02-08 00:41:59 +13:00
|
|
|
"has_update": self.tr("Update available"),
|
|
|
|
"needs_verification": self.tr("Needs verification"),
|
|
|
|
"not_can_launch": self.tr("Can't launch"),
|
2023-02-09 09:44:42 +13:00
|
|
|
"save_not_up_to_date": self.tr("Save is not up-to-date")
|
2023-02-08 00:41:59 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
self.hover_strings = {
|
2023-02-20 22:28:53 +13:00
|
|
|
"info": self.tr("Show information"),
|
2023-02-08 00:41:59 +13:00
|
|
|
"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"),
|
|
|
|
}
|
|
|
|
|
2023-02-09 02:14:50 +13:00
|
|
|
# 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"
|
2023-02-08 00:41:59 +13:00
|
|
|
|
2023-12-20 11:21:21 +13:00
|
|
|
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()
|
|
|
|
# QTimer.singleShot(random.randrange(42, 2361, 7), Qt.VeryCoarseTimer, self.rgame.load_pixmap)
|
|
|
|
super().paintEvent(a0)
|
|
|
|
|
|
|
|
def timerEvent(self, a0):
|
|
|
|
self.killTimer(a0.timerId())
|
|
|
|
self.rgame.load_pixmap()
|
|
|
|
|
2023-09-15 06:47:47 +12:00
|
|
|
def showEvent(self, a0: QShowEvent) -> None:
|
2023-09-24 06:17:30 +13:00
|
|
|
if a0.spontaneous():
|
|
|
|
return super().showEvent(a0)
|
2023-09-15 06:47:47 +12:00
|
|
|
super().showEvent(a0)
|
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
@pyqtSlot()
|
|
|
|
def update_state(self):
|
|
|
|
if self.rgame.is_idle:
|
2023-01-05 09:32:49 +13:00
|
|
|
if self.rgame.has_update:
|
2023-02-08 00:41:59 +13:00
|
|
|
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"])
|
2023-02-09 09:44:42 +13:00
|
|
|
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"])
|
2022-12-25 15:21:23 +13:00
|
|
|
else:
|
2023-02-08 00:41:59 +13:00
|
|
|
self.ui.status_label.setText(self.state_strings[self.rgame.state])
|
2022-12-25 15:21:23 +13:00
|
|
|
else:
|
2023-02-08 00:41:59 +13:00
|
|
|
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)
|
2022-12-25 15:21:23 +13:00
|
|
|
else:
|
2023-02-08 00:41:59 +13:00
|
|
|
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():
|
2023-02-09 02:14:50 +13:00
|
|
|
self.menu_link_action.setText(self.tr("Remove Start Menu link"))
|
2022-12-25 15:21:23 +13:00
|
|
|
else:
|
2023-02-09 02:14:50 +13:00
|
|
|
self.menu_link_action.setText(self.tr("Create Start Menu link"))
|
2023-02-08 00:41:59 +13:00
|
|
|
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"])
|
2023-03-02 12:05:53 +13:00
|
|
|
return super(GameWidget, self).eventFilter(a0, a1)
|
2022-12-25 15:21:23 +13:00
|
|
|
|
|
|
|
def mousePressEvent(self, e: QMouseEvent) -> None:
|
|
|
|
# left button
|
|
|
|
if e.button() == 1:
|
|
|
|
self.show_info.emit(self.rgame)
|
|
|
|
# right
|
|
|
|
elif e.button() == 2:
|
2023-01-26 00:04:21 +13:00
|
|
|
super(GameWidget, self).mousePressEvent(e)
|
2022-12-25 15:21:23 +13:00
|
|
|
|
2023-01-25 02:40:21 +13:00
|
|
|
@pyqtSlot()
|
|
|
|
def _on_reload_image(self) -> None:
|
2022-12-25 15:21:23 +13:00
|
|
|
self.rgame.refresh_pixmap()
|
|
|
|
|
2023-01-25 02:40:21 +13:00
|
|
|
@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):
|
2022-12-25 15:21:23 +13:00
|
|
|
self.show_info.emit(self.rgame)
|
2021-09-09 05:22:45 +12:00
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
def _create_link(self, name, link_type):
|
|
|
|
if not desktop_links_supported():
|
2021-12-24 22:09:50 +13:00
|
|
|
QMessageBox.warning(
|
|
|
|
self,
|
2023-02-08 00:41:59 +13:00
|
|
|
self.tr("Warning"),
|
|
|
|
self.tr("Creating shortcuts is currently unsupported on {}").format(platform.system()),
|
2021-12-24 22:09:50 +13:00
|
|
|
)
|
2021-06-21 08:03:14 +12:00
|
|
|
return
|
2022-04-01 08:29:31 +13:00
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
shortcut_path = desktop_link_path(name, link_type)
|
|
|
|
|
|
|
|
if not shortcut_path.exists():
|
2021-09-19 02:34:43 +12:00
|
|
|
try:
|
2023-02-08 00:41:59 +13:00
|
|
|
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
|
2021-09-19 02:34:43 +12:00
|
|
|
except PermissionError:
|
2023-02-08 00:41:59 +13:00
|
|
|
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"))
|
2021-04-14 04:01:25 +12:00
|
|
|
else:
|
2023-02-08 00:41:59 +13:00
|
|
|
if shortcut_path.exists():
|
|
|
|
shortcut_path.unlink(missing_ok=True)
|
2021-04-14 04:01:25 +12:00
|
|
|
|
2023-02-08 00:41:59 +13:00
|
|
|
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"))
|