Library: Introduce new tile design from refactor_backend
Currently broken but Rare starts Signed-off-by: loathingKernel <142770+loathingKernel@users.noreply.github.com>
This commit is contained in:
parent
ab858b87d3
commit
96b80bc423
23 changed files with 1084 additions and 1040 deletions
|
@ -25,18 +25,18 @@ class TabWidget(QTabWidget):
|
||||||
self.setTabBar(MainTabBar(disabled_tab))
|
self.setTabBar(MainTabBar(disabled_tab))
|
||||||
|
|
||||||
# Generate Tabs
|
# Generate Tabs
|
||||||
self.games_tab = GamesTab()
|
self.games_tab = GamesTab(self)
|
||||||
self.addTab(self.games_tab, self.tr("Games"))
|
self.addTab(self.games_tab, self.tr("Games"))
|
||||||
|
|
||||||
if not self.args.offline:
|
if not self.args.offline:
|
||||||
# updates = self.games_tab.default_widget.game_list.updates
|
# updates = self.games_tab.default_widget.game_list.updates
|
||||||
self.downloads_tab = DownloadsTab(self.games_tab.updates)
|
self.downloads_tab = DownloadsTab(self.games_tab.game_updates, self)
|
||||||
self.addTab(
|
self.addTab(
|
||||||
self.downloads_tab,
|
self.downloads_tab,
|
||||||
"Downloads"
|
"Downloads"
|
||||||
+ (
|
+ (
|
||||||
" (" + str(len(self.games_tab.updates)) + ")"
|
" (" + str(len(self.games_tab.game_updates)) + ")"
|
||||||
if len(self.games_tab.updates) != 0
|
if len(self.games_tab.game_updates) != 0
|
||||||
else ""
|
else ""
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import datetime
|
import datetime
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from typing import List, Dict, Union, Set
|
from typing import List, Dict, Union, Set, Optional
|
||||||
|
|
||||||
from PyQt5.QtCore import QThread, pyqtSignal, QSettings, pyqtSlot
|
from PyQt5.QtCore import QThread, pyqtSignal, QSettings, pyqtSlot
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
|
@ -18,6 +18,7 @@ from rare.components.dialogs.install_dialog import InstallDialog
|
||||||
from rare.components.tabs.downloads.dl_queue_widget import DlQueueWidget, DlWidget
|
from rare.components.tabs.downloads.dl_queue_widget import DlQueueWidget, DlWidget
|
||||||
from rare.components.tabs.downloads.download_thread import DownloadThread
|
from rare.components.tabs.downloads.download_thread import DownloadThread
|
||||||
from rare.lgndr.models.downloading import UIUpdate
|
from rare.lgndr.models.downloading import UIUpdate
|
||||||
|
from rare.models.game import RareGame
|
||||||
from rare.models.install import InstallOptionsModel, InstallQueueItemModel
|
from rare.models.install import InstallOptionsModel, InstallQueueItemModel
|
||||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
|
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
|
||||||
from rare.ui.components.tabs.downloads.downloads_tab import Ui_DownloadsTab
|
from rare.ui.components.tabs.downloads.downloads_tab import Ui_DownloadsTab
|
||||||
|
@ -31,12 +32,13 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
dl_queue: List[InstallQueueItemModel] = []
|
dl_queue: List[InstallQueueItemModel] = []
|
||||||
dl_status = pyqtSignal(int)
|
dl_status = pyqtSignal(int)
|
||||||
|
|
||||||
def __init__(self, updates: Set):
|
def __init__(self, game_updates: Set[RareGame], parent=None):
|
||||||
super(DownloadsTab, self).__init__()
|
super(DownloadsTab, self).__init__(parent=parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.core = LegendaryCoreSingleton()
|
self.core = LegendaryCoreSingleton()
|
||||||
self.signals = GlobalSignalsSingleton()
|
self.signals = GlobalSignalsSingleton()
|
||||||
self.active_game: Game = None
|
|
||||||
|
self.active_game: Optional[Game] = None
|
||||||
self.analysis = None
|
self.analysis = None
|
||||||
|
|
||||||
self.kill_button.clicked.connect(self.stop_download)
|
self.kill_button.clicked.connect(self.stop_download)
|
||||||
|
@ -54,21 +56,21 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
|
|
||||||
self.update_text = QLabel(self.tr("No updates available"))
|
self.update_text = QLabel(self.tr("No updates available"))
|
||||||
self.update_layout.addWidget(self.update_text)
|
self.update_layout.addWidget(self.update_text)
|
||||||
self.update_text.setVisible(len(updates) == 0)
|
self.update_text.setVisible(len(game_updates) == 0)
|
||||||
|
|
||||||
for app_name in updates:
|
for rgame in game_updates:
|
||||||
self.add_update(app_name)
|
self.add_update(rgame)
|
||||||
|
|
||||||
self.queue_widget.item_removed.connect(self.queue_item_removed)
|
self.queue_widget.item_removed.connect(self.queue_item_removed)
|
||||||
|
|
||||||
self.signals.install_game.connect(self.get_install_options)
|
self.signals.game.install.connect(self.get_install_options)
|
||||||
self.signals.game_uninstalled.connect(self.queue_item_removed)
|
self.signals.game.uninstalled.connect(self.queue_item_removed)
|
||||||
self.signals.game_uninstalled.connect(self.remove_update)
|
self.signals.game.uninstalled.connect(self.remove_update)
|
||||||
|
|
||||||
self.signals.add_download.connect(
|
self.signals.download.enqueue_game.connect(
|
||||||
lambda app_name: self.add_update(app_name)
|
lambda app_name: self.add_update(app_name)
|
||||||
)
|
)
|
||||||
self.signals.game_uninstalled.connect(self.game_uninstalled)
|
self.signals.game.uninstalled.connect(self.game_uninstalled)
|
||||||
|
|
||||||
self.reset_infos()
|
self.reset_infos()
|
||||||
|
|
||||||
|
@ -77,17 +79,17 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
w.update_button.setDisabled(False)
|
w.update_button.setDisabled(False)
|
||||||
w.update_with_settings.setDisabled(False)
|
w.update_with_settings.setDisabled(False)
|
||||||
|
|
||||||
def add_update(self, app_name: str):
|
def add_update(self, rgame: RareGame):
|
||||||
if old_widget := self.update_widgets.get(app_name, False):
|
if old_widget := self.update_widgets.get(rgame.app_name, False):
|
||||||
old_widget.deleteLater()
|
old_widget.deleteLater()
|
||||||
self.update_widgets.pop(app_name)
|
self.update_widgets.pop(rgame.app_name)
|
||||||
widget = UpdateWidget(self.core, app_name, self)
|
widget = UpdateWidget(self.core, rgame, self)
|
||||||
self.update_layout.addWidget(widget)
|
self.update_layout.addWidget(widget)
|
||||||
self.update_widgets[app_name] = widget
|
self.update_widgets[rgame.app_name] = widget
|
||||||
widget.update_signal.connect(self.get_install_options)
|
widget.update_signal.connect(self.get_install_options)
|
||||||
if QSettings().value("auto_update", False, bool):
|
if QSettings().value("auto_update", False, bool):
|
||||||
self.get_install_options(
|
self.get_install_options(
|
||||||
InstallOptionsModel(app_name=app_name, update=True, silent=True)
|
InstallOptionsModel(app_name=rgame.app_name, update=True, silent=True)
|
||||||
)
|
)
|
||||||
widget.update_button.setDisabled(True)
|
widget.update_button.setDisabled(True)
|
||||||
self.update_text.setVisible(False)
|
self.update_text.setVisible(False)
|
||||||
|
@ -145,7 +147,7 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
self.analysis = queue_item.download.analysis
|
self.analysis = queue_item.download.analysis
|
||||||
self.dl_name.setText(self.active_game.app_title)
|
self.dl_name.setText(self.active_game.app_title)
|
||||||
|
|
||||||
self.signals.installation_started.emit(self.active_game.app_name)
|
self.signals.progress.started.emit(self.active_game.app_name)
|
||||||
|
|
||||||
@pyqtSlot(DownloadThread.ReturnStatus)
|
@pyqtSlot(DownloadThread.ReturnStatus)
|
||||||
def status(self, result: DownloadThread.ReturnStatus):
|
def status(self, result: DownloadThread.ReturnStatus):
|
||||||
|
@ -179,10 +181,10 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
self.remove_update(game.app_name)
|
self.remove_update(game.app_name)
|
||||||
|
|
||||||
self.signals.send_notification.emit(game.app_title)
|
self.signals.send_notification.emit(game.app_title)
|
||||||
self.signals.update_gamelist.emit([game.app_name])
|
self.signals.game.installed.emit([game.app_name])
|
||||||
self.signals.update_download_tab_text.emit()
|
self.signals.update_download_tab_text.emit()
|
||||||
|
|
||||||
self.signals.installation_finished.emit(True, game.app_name)
|
self.signals.progress.finished.emit(game.app_name, True)
|
||||||
|
|
||||||
self.reset_infos()
|
self.reset_infos()
|
||||||
|
|
||||||
|
@ -199,7 +201,7 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
if w := self.update_widgets.get(self.active_game.app_name):
|
if w := self.update_widgets.get(self.active_game.app_name):
|
||||||
w.update_button.setDisabled(False)
|
w.update_button.setDisabled(False)
|
||||||
w.update_with_settings.setDisabled(False)
|
w.update_with_settings.setDisabled(False)
|
||||||
self.signals.installation_finished.emit(False, self.active_game.app_name)
|
self.signals.progress.finished.emit(self.active_game.app_name, False)
|
||||||
self.active_game = None
|
self.active_game = None
|
||||||
if self.dl_queue:
|
if self.dl_queue:
|
||||||
self.start_installation(self.dl_queue[0])
|
self.start_installation(self.dl_queue[0])
|
||||||
|
@ -214,7 +216,8 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
self.downloaded.setText("n/a")
|
self.downloaded.setText("n/a")
|
||||||
self.analysis = None
|
self.analysis = None
|
||||||
|
|
||||||
def progress_update(self, ui_update: UIUpdate):
|
@pyqtSlot(str, UIUpdate)
|
||||||
|
def progress_update(self, app_name: str, ui_update: UIUpdate):
|
||||||
self.progress_bar.setValue(
|
self.progress_bar.setValue(
|
||||||
100 * ui_update.total_downloaded // self.analysis.dl_size
|
100 * ui_update.total_downloaded // self.analysis.dl_size
|
||||||
)
|
)
|
||||||
|
@ -226,7 +229,8 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
f"{get_size(ui_update.total_downloaded)} / {get_size(self.analysis.dl_size)}"
|
f"{get_size(ui_update.total_downloaded)} / {get_size(self.analysis.dl_size)}"
|
||||||
)
|
)
|
||||||
self.time_left.setText(self.get_time(ui_update.estimated_time_left))
|
self.time_left.setText(self.get_time(ui_update.estimated_time_left))
|
||||||
self.signals.dl_progress.emit(
|
self.signals.progress.value.emit(
|
||||||
|
app_name,
|
||||||
100 * ui_update.total_downloaded // self.analysis.dl_size
|
100 * ui_update.total_downloaded // self.analysis.dl_size
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -265,14 +269,13 @@ class DownloadsTab(QWidget, Ui_DownloadsTab):
|
||||||
class UpdateWidget(QWidget):
|
class UpdateWidget(QWidget):
|
||||||
update_signal = pyqtSignal(InstallOptionsModel)
|
update_signal = pyqtSignal(InstallOptionsModel)
|
||||||
|
|
||||||
def __init__(self, core: LegendaryCore, app_name: str, parent):
|
def __init__(self, core: LegendaryCore, rgame: RareGame, parent):
|
||||||
super(UpdateWidget, self).__init__(parent=parent)
|
super(UpdateWidget, self).__init__(parent=parent)
|
||||||
self.core = core
|
self.core = core
|
||||||
self.game: Game = core.get_game(app_name)
|
self.rgame = rgame
|
||||||
self.igame: InstalledGame = self.core.get_installed_game(app_name)
|
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
self.title = QLabel(self.igame.title)
|
self.title = QLabel(self.rgame.app_title)
|
||||||
layout.addWidget(self.title)
|
layout.addWidget(self.title)
|
||||||
|
|
||||||
self.update_button = QPushButton(self.tr("Update Game"))
|
self.update_button = QPushButton(self.tr("Update Game"))
|
||||||
|
@ -284,7 +287,7 @@ class UpdateWidget(QWidget):
|
||||||
layout.addWidget(
|
layout.addWidget(
|
||||||
QLabel(
|
QLabel(
|
||||||
self.tr("Version: <b>{}</b> >> <b>{}</b>")
|
self.tr("Version: <b>{}</b> >> <b>{}</b>")
|
||||||
.format(self.igame.version, self.game.app_version(self.igame.platform))
|
.format(self.rgame.version, self.rgame.remote_version)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -294,5 +297,5 @@ class UpdateWidget(QWidget):
|
||||||
self.update_button.setDisabled(True)
|
self.update_button.setDisabled(True)
|
||||||
self.update_with_settings.setDisabled(True)
|
self.update_with_settings.setDisabled(True)
|
||||||
self.update_signal.emit(
|
self.update_signal.emit(
|
||||||
InstallOptionsModel(app_name=self.igame.app_name, update=True, silent=auto)
|
InstallOptionsModel(app_name=self.rgame.app_name, update=True, silent=auto)
|
||||||
) # True if settings
|
) # True if settings
|
||||||
|
|
|
@ -36,7 +36,7 @@ class DownloadThread(QThread):
|
||||||
shortcuts: bool = False
|
shortcuts: bool = False
|
||||||
|
|
||||||
ret_status = pyqtSignal(ReturnStatus)
|
ret_status = pyqtSignal(ReturnStatus)
|
||||||
ui_update = pyqtSignal(UIUpdate)
|
ui_update = pyqtSignal(str, UIUpdate)
|
||||||
|
|
||||||
def __init__(self, core: LegendaryCore, item: InstallQueueItemModel):
|
def __init__(self, core: LegendaryCore, item: InstallQueueItemModel):
|
||||||
super(DownloadThread, self).__init__()
|
super(DownloadThread, self).__init__()
|
||||||
|
@ -56,7 +56,8 @@ class DownloadThread(QThread):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
while self.item.download.dlm.is_alive():
|
while self.item.download.dlm.is_alive():
|
||||||
try:
|
try:
|
||||||
self.ui_update.emit(self.item.download.dlm.status_queue.get(timeout=1.0))
|
self.ui_update.emit(self.item.download.game.app_name,
|
||||||
|
self.item.download.dlm.status_queue.get(timeout=1.0))
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
pass
|
pass
|
||||||
if self.dlm_signals.update:
|
if self.dlm_signals.update:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import time
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from typing import Tuple, Dict, Union, List, Set
|
from typing import Tuple, Dict, Union, List, Set
|
||||||
|
|
||||||
|
@ -5,6 +6,7 @@ from PyQt5.QtCore import QSettings, Qt, pyqtSlot
|
||||||
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
|
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
|
||||||
from legendary.models.game import InstalledGame, Game
|
from legendary.models.game import InstalledGame, Game
|
||||||
|
|
||||||
|
from rare.models.game import RareGame
|
||||||
from rare.shared import (
|
from rare.shared import (
|
||||||
LegendaryCoreSingleton,
|
LegendaryCoreSingleton,
|
||||||
GlobalSignalsSingleton,
|
GlobalSignalsSingleton,
|
||||||
|
@ -17,13 +19,9 @@ from rare.widgets.sliding_stack import SlidingStackedWidget
|
||||||
from .cloud_save_utils import CloudSaveUtils
|
from .cloud_save_utils import CloudSaveUtils
|
||||||
from .game_info import GameInfoTabs
|
from .game_info import GameInfoTabs
|
||||||
from .game_utils import GameUtils
|
from .game_utils import GameUtils
|
||||||
from .game_widgets.base_installed_widget import BaseInstalledWidget
|
from .game_widgets import LibraryWidgetController
|
||||||
from .game_widgets.base_uninstalled_widget import BaseUninstalledWidget
|
from .game_widgets.icon_game_widget import IconGameWidget
|
||||||
from .game_widgets.installed_icon_widget import InstalledIconWidget
|
from .game_widgets.list_game_widget import ListGameWidget
|
||||||
from .game_widgets.installed_list_widget import InstalledListWidget
|
|
||||||
from .game_widgets.installing_game_widget import InstallingGameWidget
|
|
||||||
from .game_widgets.uninstalled_icon_widget import UninstalledIconWidget
|
|
||||||
from .game_widgets.uninstalled_list_widget import UninstalledListWidget
|
|
||||||
from .head_bar import GameListHeadBar
|
from .head_bar import GameListHeadBar
|
||||||
from .integrations import IntegrationsTabs
|
from .integrations import IntegrationsTabs
|
||||||
|
|
||||||
|
@ -40,17 +38,15 @@ class GamesTab(QStackedWidget):
|
||||||
self.image_manager = ImageManagerSingleton()
|
self.image_manager = ImageManagerSingleton()
|
||||||
self.settings = QSettings()
|
self.settings = QSettings()
|
||||||
|
|
||||||
self.widgets: Dict[str, Tuple[
|
self.widgets: Dict[str, Tuple[IconGameWidget, ListGameWidget]] = {}
|
||||||
Union[InstalledIconWidget, UninstalledIconWidget], Union[InstalledListWidget, UninstalledListWidget]]] = {}
|
self.game_updates: Set[RareGame] = set()
|
||||||
self.updates: Set = set()
|
|
||||||
self.active_filter: int = 0
|
self.active_filter: int = 0
|
||||||
self.uninstalled_games: List[Game] = []
|
|
||||||
|
|
||||||
self.game_list: List[Game] = self.api_results.game_list
|
self.game_list: List[Game] = self.api_results.game_list
|
||||||
self.dlcs = self.api_results.dlcs
|
self.dlcs: Dict[str, List[Game]] = self.api_results.dlcs
|
||||||
self.bit32 = self.api_results.bit32_games
|
self.bit32: List[str] = self.api_results.bit32_games
|
||||||
self.mac_games = self.api_results.mac_games
|
self.mac_games: List[str] = self.api_results.mac_games
|
||||||
self.no_assets = self.api_results.no_asset_games
|
self.no_assets: List[Game] = self.api_results.no_asset_games
|
||||||
|
|
||||||
self.game_utils = GameUtils(parent=self)
|
self.game_utils = GameUtils(parent=self)
|
||||||
|
|
||||||
|
@ -64,13 +60,10 @@ class GamesTab(QStackedWidget):
|
||||||
self.head_bar.goto_eos_ubisoft.connect(self.show_eos_ubisoft)
|
self.head_bar.goto_eos_ubisoft.connect(self.show_eos_ubisoft)
|
||||||
self.games.layout().addWidget(self.head_bar)
|
self.games.layout().addWidget(self.head_bar)
|
||||||
|
|
||||||
self.game_info_tabs = GameInfoTabs(self.dlcs, self.game_utils, self)
|
self.game_info_tabs = GameInfoTabs(self.game_utils, self)
|
||||||
self.game_info_tabs.back_clicked.connect(lambda: self.setCurrentWidget(self.games))
|
self.game_info_tabs.back_clicked.connect(lambda: self.setCurrentWidget(self.games))
|
||||||
self.addWidget(self.game_info_tabs)
|
self.addWidget(self.game_info_tabs)
|
||||||
|
|
||||||
self.game_info_tabs.info.verification_finished.connect(
|
|
||||||
self.verification_finished
|
|
||||||
)
|
|
||||||
self.game_info_tabs.info.uninstalled.connect(lambda x: self.setCurrentWidget(self.games))
|
self.game_info_tabs.info.uninstalled.connect(lambda x: self.setCurrentWidget(self.games))
|
||||||
|
|
||||||
self.integrations_tabs = IntegrationsTabs(self)
|
self.integrations_tabs = IntegrationsTabs(self)
|
||||||
|
@ -96,8 +89,6 @@ class GamesTab(QStackedWidget):
|
||||||
else:
|
else:
|
||||||
self.no_assets = []
|
self.no_assets = []
|
||||||
|
|
||||||
self.installed = self.core.get_installed_list()
|
|
||||||
|
|
||||||
self.view_stack = SlidingStackedWidget(self.games)
|
self.view_stack = SlidingStackedWidget(self.games)
|
||||||
self.view_stack.setFrameStyle(QFrame.NoFrame)
|
self.view_stack.setFrameStyle(QFrame.NoFrame)
|
||||||
self.icon_view_scroll = QScrollArea(self.view_stack)
|
self.icon_view_scroll = QScrollArea(self.view_stack)
|
||||||
|
@ -116,17 +107,15 @@ class GamesTab(QStackedWidget):
|
||||||
self.list_view.setLayout(QVBoxLayout(self.list_view))
|
self.list_view.setLayout(QVBoxLayout(self.list_view))
|
||||||
self.list_view.layout().setContentsMargins(3, 3, 9, 3)
|
self.list_view.layout().setContentsMargins(3, 3, 9, 3)
|
||||||
self.list_view.layout().setAlignment(Qt.AlignTop)
|
self.list_view.layout().setAlignment(Qt.AlignTop)
|
||||||
|
self.library_controller = LibraryWidgetController(
|
||||||
|
self.icon_view, self.list_view, self
|
||||||
|
)
|
||||||
self.icon_view_scroll.setWidget(self.icon_view)
|
self.icon_view_scroll.setWidget(self.icon_view)
|
||||||
self.list_view_scroll.setWidget(self.list_view)
|
self.list_view_scroll.setWidget(self.list_view)
|
||||||
self.view_stack.addWidget(self.icon_view_scroll)
|
self.view_stack.addWidget(self.icon_view_scroll)
|
||||||
self.view_stack.addWidget(self.list_view_scroll)
|
self.view_stack.addWidget(self.list_view_scroll)
|
||||||
self.games.layout().addWidget(self.view_stack)
|
self.games.layout().addWidget(self.view_stack)
|
||||||
|
|
||||||
# add installing game widget for icon view: List view not supported
|
|
||||||
self.installing_widget = InstallingGameWidget()
|
|
||||||
self.icon_view.layout().addWidget(self.installing_widget)
|
|
||||||
self.installing_widget.setVisible(False)
|
|
||||||
|
|
||||||
if not self.settings.value("icon_view", True, bool):
|
if not self.settings.value("icon_view", True, bool):
|
||||||
self.view_stack.setCurrentWidget(self.list_view_scroll)
|
self.view_stack.setCurrentWidget(self.list_view_scroll)
|
||||||
self.head_bar.view.list()
|
self.head_bar.view.list()
|
||||||
|
@ -145,7 +134,7 @@ class GamesTab(QStackedWidget):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.head_bar.filterChanged.connect(self.filter_games)
|
self.head_bar.filterChanged.connect(self.filter_games)
|
||||||
self.head_bar.refresh_list.clicked.connect(self.update_list)
|
self.head_bar.refresh_list.clicked.connect(self.library_controller.update_list)
|
||||||
self.head_bar.view.toggled.connect(self.toggle_view)
|
self.head_bar.view.toggled.connect(self.toggle_view)
|
||||||
|
|
||||||
f = self.settings.value("filter", 0, int)
|
f = self.settings.value("filter", 0, int)
|
||||||
|
@ -154,40 +143,16 @@ class GamesTab(QStackedWidget):
|
||||||
self.active_filter = self.head_bar.available_filters[f]
|
self.active_filter = self.head_bar.available_filters[f]
|
||||||
|
|
||||||
# signals
|
# signals
|
||||||
self.signals.dl_progress.connect(self.installing_widget.set_status)
|
self.signals.game.installed.connect(self.update_count_games_label)
|
||||||
self.signals.installation_started.connect(self.installation_started)
|
self.signals.game.uninstalled.connect(self.update_count_games_label)
|
||||||
self.signals.update_gamelist.connect(self.update_list)
|
self.signals.game.uninstalled.connect(lambda x: self.setCurrentIndex(0))
|
||||||
self.signals.installation_finished.connect(
|
|
||||||
self.installation_finished
|
|
||||||
)
|
|
||||||
self.signals.game_uninstalled.connect(lambda name: self.update_list([name]))
|
|
||||||
|
|
||||||
self.game_utils.update_list.connect(self.update_list)
|
# self.signals.update_gamelist.connect(self.library_controller.update_list)
|
||||||
|
# self.game_utils.update_list.connect(self.library_controller.update_list)
|
||||||
|
|
||||||
|
start_t = time.time()
|
||||||
self.setup_game_list()
|
self.setup_game_list()
|
||||||
|
print(f"Game list setup time: {time.time() - start_t}")
|
||||||
def installation_finished(self, app_name: str):
|
|
||||||
self.installing_widget.setVisible(False)
|
|
||||||
self.installing_widget.set_game("")
|
|
||||||
self.filter_games("")
|
|
||||||
|
|
||||||
def installation_started(self, app_name: str):
|
|
||||||
self.installing_widget.set_game(app_name)
|
|
||||||
|
|
||||||
i_widget, l_widget = self.widgets.get(app_name, (None, None))
|
|
||||||
if not i_widget or not l_widget:
|
|
||||||
return
|
|
||||||
i_widget.setVisible(False)
|
|
||||||
l_widget.setVisible(False)
|
|
||||||
|
|
||||||
def verification_finished(self, igame: InstalledGame):
|
|
||||||
# only if igame needs verification
|
|
||||||
i_widget, l_widget = self.widgets[igame.app_name]
|
|
||||||
i_widget.igame = igame
|
|
||||||
l_widget.igame = igame
|
|
||||||
|
|
||||||
i_widget.leaveEvent(None)
|
|
||||||
l_widget.update_text()
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def show_import(self):
|
def show_import(self):
|
||||||
|
@ -204,93 +169,55 @@ class GamesTab(QStackedWidget):
|
||||||
self.setCurrentWidget(self.integrations_tabs)
|
self.setCurrentWidget(self.integrations_tabs)
|
||||||
self.integrations_tabs.show_eos_ubisoft()
|
self.integrations_tabs.show_eos_ubisoft()
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(RareGame)
|
||||||
def show_game_info(self, app_name):
|
def show_game_info(self, rgame):
|
||||||
self.game_info_tabs.update_game(app_name)
|
self.game_info_tabs.update_game(rgame)
|
||||||
self.setCurrentWidget(self.game_info_tabs)
|
self.setCurrentWidget(self.game_info_tabs)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def update_count_games_label(self):
|
def update_count_games_label(self):
|
||||||
self.head_bar.set_games_count(len(self.core.get_installed_list()), len(self.game_list))
|
self.head_bar.set_games_count(len(self.core.get_installed_list()), len(self.game_list))
|
||||||
|
|
||||||
|
# FIXME: Remove this when RareCore is in place
|
||||||
|
def __create_game_with_dlcs(self, game: Game) -> RareGame:
|
||||||
|
rgame = RareGame(game, self.core, self.image_manager)
|
||||||
|
if rgame.has_update:
|
||||||
|
self.game_updates.add(rgame)
|
||||||
|
if game_dlcs := self.dlcs[rgame.game.catalog_item_id]:
|
||||||
|
for dlc in game_dlcs:
|
||||||
|
rdlc = RareGame(dlc, self.core, self.image_manager)
|
||||||
|
if rdlc.has_update:
|
||||||
|
self.game_updates.add(rdlc)
|
||||||
|
rdlc.set_pixmap()
|
||||||
|
rgame.owned_dlcs.append(rdlc)
|
||||||
|
return rgame
|
||||||
|
|
||||||
def setup_game_list(self):
|
def setup_game_list(self):
|
||||||
self.update_count_games_label()
|
self.update_count_games_label()
|
||||||
|
for game in self.game_list + self.no_assets:
|
||||||
# add installed games
|
rgame = self.__create_game_with_dlcs(game)
|
||||||
for igame in sorted(self.core.get_installed_list(), key=lambda x: x.title):
|
icon_widget, list_widget = self.add_library_widget(rgame)
|
||||||
icon_widget, list_widget = self.add_installed_widget(igame.app_name)
|
|
||||||
self.icon_view.layout().addWidget(icon_widget)
|
|
||||||
self.list_view.layout().addWidget(list_widget)
|
|
||||||
|
|
||||||
for game in self.no_assets:
|
|
||||||
if not game.metadata.get("customAttributes", {}).get("ThirdPartyManagedApp", {}).get("value") == "Origin":
|
|
||||||
icon_widget, list_widget = self.add_uninstalled_widget(game)
|
|
||||||
else:
|
|
||||||
icon_widget, list_widget = self.add_installed_widget(game.app_name)
|
|
||||||
if not icon_widget or not list_widget:
|
if not icon_widget or not list_widget:
|
||||||
logger.warning(f"Ignoring {game.app_name} in game list")
|
logger.warning(f"Excluding {rgame.app_name} from the game list")
|
||||||
continue
|
continue
|
||||||
self.icon_view.layout().addWidget(icon_widget)
|
self.icon_view.layout().addWidget(icon_widget)
|
||||||
self.list_view.layout().addWidget(list_widget)
|
self.list_view.layout().addWidget(list_widget)
|
||||||
|
rgame.set_pixmap()
|
||||||
for game in sorted(self.game_list, key=lambda x: x.app_title):
|
|
||||||
if not self.core.is_installed(game.app_name):
|
|
||||||
self.uninstalled_games.append(game)
|
|
||||||
icon_widget, list_widget = self.add_uninstalled_widget(game)
|
|
||||||
self.icon_view.layout().addWidget(icon_widget)
|
|
||||||
self.list_view.layout().addWidget(list_widget)
|
|
||||||
self.filter_games(self.active_filter)
|
self.filter_games(self.active_filter)
|
||||||
|
|
||||||
def add_installed_widget(self, app_name):
|
def add_library_widget(self, rgame: RareGame):
|
||||||
pixmap = self.image_manager.get_pixmap(app_name)
|
|
||||||
try:
|
try:
|
||||||
if pixmap.isNull():
|
icon_widget, list_widget = self.library_controller.add_game(rgame, self.game_utils, self)
|
||||||
logger.info(f"{app_name} has a corrupt image.")
|
|
||||||
if app_name in self.no_asset_names and self.core.get_asset(app_name).namespace != "ue":
|
|
||||||
self.image_manager.download_image_blocking(self.core.get_game(app_name), force=True)
|
|
||||||
pixmap = self.image_manager.get_pixmap(app_name)
|
|
||||||
elif self.ue_name:
|
|
||||||
pixmap = self.image_manager.get_pixmap(self.ue_name)
|
|
||||||
|
|
||||||
icon_widget = InstalledIconWidget(app_name, pixmap, self.game_utils)
|
|
||||||
list_widget = InstalledListWidget(app_name, pixmap, self.game_utils)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"{app_name} is broken. Don't add it to game list: {e}")
|
logger.error(f"{rgame.app_name} is broken. Don't add it to game list: {e}")
|
||||||
return None, None
|
return None, None
|
||||||
|
self.widgets[rgame.app_name] = (icon_widget, list_widget)
|
||||||
self.widgets[app_name] = (icon_widget, list_widget)
|
|
||||||
|
|
||||||
icon_widget.show_info.connect(self.show_game_info)
|
icon_widget.show_info.connect(self.show_game_info)
|
||||||
list_widget.show_info.connect(self.show_game_info)
|
list_widget.show_info.connect(self.show_game_info)
|
||||||
|
|
||||||
if icon_widget.update_available:
|
|
||||||
self.updates.add(app_name)
|
|
||||||
return icon_widget, list_widget
|
|
||||||
|
|
||||||
def add_uninstalled_widget(self, game):
|
|
||||||
pixmap = self.image_manager.get_pixmap(game.app_name, color=False)
|
|
||||||
try:
|
|
||||||
if pixmap.isNull():
|
|
||||||
if self.core.get_asset(game.app_name).namespace != "ue":
|
|
||||||
logger.warning(f"{game.app_title} has a corrupt image. Reloading...")
|
|
||||||
self.image_manager.download_image_blocking(game, force=True)
|
|
||||||
pixmap = self.image_manager.get_pixmap(game.app_name, color=False)
|
|
||||||
elif self.ue_name:
|
|
||||||
pixmap = self.image_manager.get_pixmap(self.ue_name, color=False)
|
|
||||||
|
|
||||||
icon_widget = UninstalledIconWidget(game, self.core, pixmap)
|
|
||||||
list_widget = UninstalledListWidget(self.core, game, pixmap)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"{game.app_name} is broken. Don't add it to game list: {e}")
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
icon_widget.show_info.connect(self.show_game_info)
|
|
||||||
list_widget.show_info.connect(self.show_game_info)
|
|
||||||
|
|
||||||
self.widgets[game.app_name] = (icon_widget, list_widget)
|
|
||||||
|
|
||||||
return icon_widget, list_widget
|
return icon_widget, list_widget
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
@pyqtSlot(str, str)
|
||||||
def filter_games(self, filter_name="all", search_text: str = ""):
|
def filter_games(self, filter_name="all", search_text: str = ""):
|
||||||
if not search_text and (t := self.head_bar.search_bar.text()):
|
if not search_text and (t := self.head_bar.search_bar.text()):
|
||||||
search_text = t
|
search_text = t
|
||||||
|
@ -300,177 +227,7 @@ class GamesTab(QStackedWidget):
|
||||||
if not filter_name and (t := self.active_filter):
|
if not filter_name and (t := self.active_filter):
|
||||||
filter_name = t
|
filter_name = t
|
||||||
|
|
||||||
def get_visibility(widget) -> Tuple[bool, float]:
|
self.library_controller.filter_list(filter_name, search_text.lower())
|
||||||
app_name = widget.game.app_name
|
|
||||||
|
|
||||||
if not isinstance(widget,
|
|
||||||
InstallingGameWidget) and self.installing_widget.game and self.installing_widget.game.app_name == app_name:
|
|
||||||
visible = False
|
|
||||||
elif filter_name == "installed":
|
|
||||||
visible = self.core.is_installed(app_name)
|
|
||||||
elif filter_name == "offline":
|
|
||||||
if self.core.is_installed(app_name) and not isinstance(widget, InstallingGameWidget):
|
|
||||||
visible = widget.igame.can_run_offline
|
|
||||||
else:
|
|
||||||
visible = False
|
|
||||||
elif filter_name == "32bit" and self.bit32:
|
|
||||||
visible = app_name in self.bit32
|
|
||||||
elif filter_name == "mac" and self.mac_games:
|
|
||||||
visible = app_name in self.mac_games
|
|
||||||
elif filter_name == "installable":
|
|
||||||
visible = app_name not in self.no_asset_names
|
|
||||||
elif filter_name == "include_ue":
|
|
||||||
visible = True
|
|
||||||
elif filter_name == "all":
|
|
||||||
# All visible except ue
|
|
||||||
try:
|
|
||||||
visible = self.core.get_asset(app_name, update=False).namespace != "ue"
|
|
||||||
except ValueError:
|
|
||||||
visible = True
|
|
||||||
else:
|
|
||||||
visible = True
|
|
||||||
|
|
||||||
if (
|
|
||||||
search_text.lower() not in widget.game.app_name.lower()
|
|
||||||
and search_text.lower() not in widget.game.app_title.lower()
|
|
||||||
):
|
|
||||||
opacity = 0.25
|
|
||||||
else:
|
|
||||||
opacity = 1.0
|
|
||||||
return visible, opacity
|
|
||||||
|
|
||||||
for t in self.widgets.values():
|
|
||||||
visible, opacity = get_visibility(t[0])
|
|
||||||
for w in t:
|
|
||||||
w.setVisible(visible)
|
|
||||||
w.image.setOpacity(opacity)
|
|
||||||
|
|
||||||
self.sort_list(search_text)
|
|
||||||
|
|
||||||
if self.installing_widget.game:
|
|
||||||
self.installing_widget.setVisible(get_visibility(self.installing_widget)[0])
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def sort_list(self, sort_by: str = ""):
|
|
||||||
# lk: this is the existing sorting implemenation
|
|
||||||
# lk: it sorts by installed then by title
|
|
||||||
installing_widget = self.icon_view.layout().remove(type(self.installing_widget).__name__)
|
|
||||||
if sort_by:
|
|
||||||
self.icon_view.layout().sort(lambda x: (sort_by.lower() not in x.widget().game.app_title.lower(),))
|
|
||||||
else:
|
|
||||||
self.icon_view.layout().sort(
|
|
||||||
lambda x: (
|
|
||||||
not x.widget().is_installed,
|
|
||||||
x.widget().is_non_asset,
|
|
||||||
x.widget().app_title,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.icon_view.layout().insert(0, installing_widget)
|
|
||||||
list_widgets = self.list_view.findChildren(InstalledListWidget) + self.list_view.findChildren(
|
|
||||||
UninstalledListWidget)
|
|
||||||
if sort_by:
|
|
||||||
list_widgets.sort(key=lambda x: (sort_by not in x.game.app_title.lower(),))
|
|
||||||
else:
|
|
||||||
list_widgets.sort(
|
|
||||||
key=lambda x: (not x.is_installed, x.is_non_asset, x.app_title)
|
|
||||||
)
|
|
||||||
for idx, wl in enumerate(list_widgets):
|
|
||||||
self.list_view.layout().insertWidget(idx, wl)
|
|
||||||
|
|
||||||
def __remove_from_layout(self, app_name):
|
|
||||||
self.icon_view.layout().removeWidget(self.widgets[app_name][0])
|
|
||||||
self.list_view.layout().removeWidget(self.widgets[app_name][1])
|
|
||||||
self.widgets[app_name][0].deleteLater()
|
|
||||||
self.widgets[app_name][1].deleteLater()
|
|
||||||
self.widgets.pop(app_name)
|
|
||||||
|
|
||||||
def __update_installed(self, app_name):
|
|
||||||
self.__remove_from_layout(app_name)
|
|
||||||
icon_widget, list_widget = self.add_installed_widget(app_name)
|
|
||||||
self.icon_view.layout().addWidget(icon_widget)
|
|
||||||
self.list_view.layout().addWidget(list_widget)
|
|
||||||
|
|
||||||
def __update_uninstalled(self, app_name):
|
|
||||||
self.__remove_from_layout(app_name)
|
|
||||||
game = self.core.get_game(app_name, False)
|
|
||||||
try:
|
|
||||||
icon_widget, list_widget = self.add_uninstalled_widget(game)
|
|
||||||
self.icon_view.layout().addWidget(icon_widget)
|
|
||||||
self.list_view.layout().addWidget(list_widget)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def update_list(self, app_names: list = None):
|
|
||||||
logger.debug(f"Updating list for {app_names}")
|
|
||||||
if app_names:
|
|
||||||
update_list = False
|
|
||||||
for app_name in app_names:
|
|
||||||
if widgets := self.widgets.get(app_name):
|
|
||||||
|
|
||||||
# from update
|
|
||||||
if self.core.is_installed(widgets[0].game.app_name) and isinstance(
|
|
||||||
widgets[0], BaseInstalledWidget
|
|
||||||
):
|
|
||||||
logger.debug(f"Update Gamelist: Updated: {app_name}")
|
|
||||||
igame = self.core.get_installed_game(app_name)
|
|
||||||
for w in widgets:
|
|
||||||
w.igame = igame
|
|
||||||
w.update_available = (
|
|
||||||
self.core.get_asset(
|
|
||||||
w.game.app_name, w.igame.platform, False
|
|
||||||
).build_version
|
|
||||||
!= igame.version
|
|
||||||
)
|
|
||||||
widgets[0].leaveEvent(None)
|
|
||||||
# new installed
|
|
||||||
elif self.core.is_installed(app_name) and isinstance(
|
|
||||||
widgets[0], BaseUninstalledWidget
|
|
||||||
):
|
|
||||||
logger.debug(f"Update Gamelist: New installed {app_name}")
|
|
||||||
self.__update_installed(app_name)
|
|
||||||
update_list = True
|
|
||||||
|
|
||||||
# uninstalled
|
|
||||||
elif not self.core.is_installed(
|
|
||||||
widgets[0].game.app_name
|
|
||||||
) and isinstance(widgets[0], BaseInstalledWidget):
|
|
||||||
logger.debug(f"Update list: Uninstalled: {app_name}")
|
|
||||||
self.__update_uninstalled(app_name)
|
|
||||||
update_list = True
|
|
||||||
|
|
||||||
# do not update, if only update finished
|
|
||||||
if update_list:
|
|
||||||
self.sort_list()
|
|
||||||
|
|
||||||
else:
|
|
||||||
installed_names = [i.app_name for i in self.core.get_installed_list()]
|
|
||||||
# get Uninstalled games
|
|
||||||
uninstalled_names = []
|
|
||||||
games = self.core.get_game_list(True)
|
|
||||||
for game in sorted(games, key=lambda x: x.app_title):
|
|
||||||
if not game.app_name in installed_names:
|
|
||||||
uninstalled_names.append(game.app_name)
|
|
||||||
|
|
||||||
new_installed_games = list(
|
|
||||||
set(installed_names) - set([i.app_name for i in self.installed])
|
|
||||||
)
|
|
||||||
new_uninstalled_games = list(
|
|
||||||
set(uninstalled_names)
|
|
||||||
- set([i.app_name for i in self.uninstalled_games])
|
|
||||||
)
|
|
||||||
|
|
||||||
if (not new_uninstalled_games) and (not new_installed_games):
|
|
||||||
return
|
|
||||||
|
|
||||||
if new_installed_games:
|
|
||||||
for name in new_installed_games:
|
|
||||||
self.__update_installed(name)
|
|
||||||
|
|
||||||
for name in new_uninstalled_games:
|
|
||||||
self.__update_uninstalled(name)
|
|
||||||
|
|
||||||
self.sort_list()
|
|
||||||
self.update_count_games_label()
|
|
||||||
|
|
||||||
def toggle_view(self):
|
def toggle_view(self):
|
||||||
self.settings.setValue("icon_view", not self.head_bar.view.isChecked())
|
self.settings.setValue("icon_view", not self.head_bar.view.isChecked())
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtGui import QKeyEvent
|
from PyQt5.QtGui import QKeyEvent
|
||||||
from PyQt5.QtWidgets import QTreeView
|
from PyQt5.QtWidgets import QTreeView
|
||||||
from legendary.models.game import Game
|
|
||||||
|
|
||||||
from rare.components.tabs.games.game_utils import GameUtils
|
from rare.components.tabs.games.game_utils import GameUtils
|
||||||
|
from rare.models.game import RareGame
|
||||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
|
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
|
||||||
from rare.utils.extra_widgets import SideTabWidget
|
from rare.utils.extra_widgets import SideTabWidget
|
||||||
from rare.utils.json_formatter import QJsonModel
|
from rare.utils.json_formatter import QJsonModel
|
||||||
|
@ -15,7 +15,7 @@ from .game_settings import GameSettings
|
||||||
|
|
||||||
|
|
||||||
class GameInfoTabs(SideTabWidget):
|
class GameInfoTabs(SideTabWidget):
|
||||||
def __init__(self, dlcs: dict, game_utils: GameUtils, parent=None):
|
def __init__(self, game_utils: GameUtils, parent=None):
|
||||||
super(GameInfoTabs, self).__init__(show_back=True, parent=parent)
|
super(GameInfoTabs, self).__init__(show_back=True, parent=parent)
|
||||||
self.core = LegendaryCoreSingleton()
|
self.core = LegendaryCoreSingleton()
|
||||||
self.signals = GlobalSignalsSingleton()
|
self.signals = GlobalSignalsSingleton()
|
||||||
|
@ -26,8 +26,7 @@ class GameInfoTabs(SideTabWidget):
|
||||||
self.settings = GameSettings(self)
|
self.settings = GameSettings(self)
|
||||||
self.addTab(self.settings, self.tr("Settings"))
|
self.addTab(self.settings, self.tr("Settings"))
|
||||||
|
|
||||||
self.dlc_list = dlcs
|
self.dlc = GameDlc(game_utils, self)
|
||||||
self.dlc = GameDlc(self.dlc_list, game_utils, self)
|
|
||||||
self.addTab(self.dlc, self.tr("Downloadable Content"))
|
self.addTab(self.dlc, self.tr("Downloadable Content"))
|
||||||
|
|
||||||
self.view = GameMetadataView()
|
self.view = GameMetadataView()
|
||||||
|
@ -35,20 +34,16 @@ class GameInfoTabs(SideTabWidget):
|
||||||
|
|
||||||
self.tabBar().setCurrentIndex(1)
|
self.tabBar().setCurrentIndex(1)
|
||||||
|
|
||||||
def update_game(self, app_name: str):
|
def update_game(self, rgame: RareGame):
|
||||||
installed = bool(self.core.get_installed_game(app_name))
|
self.info.update_game(rgame)
|
||||||
|
|
||||||
self.info.update_game(app_name)
|
self.settings.load_settings(rgame)
|
||||||
|
self.settings.setEnabled(rgame.is_installed)
|
||||||
|
|
||||||
self.settings.load_settings(app_name)
|
self.dlc.update_dlcs(rgame)
|
||||||
self.settings.setEnabled(installed)
|
self.dlc.setEnabled(bool(rgame.owned_dlcs))
|
||||||
|
|
||||||
self.dlc.setEnabled(
|
self.view.update_game(rgame)
|
||||||
not bool(len(self.dlc_list.get(self.core.get_game(app_name).catalog_item_id, [])) == 0)
|
|
||||||
)
|
|
||||||
self.dlc.update_dlcs(app_name)
|
|
||||||
|
|
||||||
self.view.update_game(self.core.get_game(app_name))
|
|
||||||
|
|
||||||
self.setCurrentIndex(1)
|
self.setCurrentIndex(1)
|
||||||
|
|
||||||
|
@ -64,14 +59,14 @@ class GameMetadataView(QTreeView):
|
||||||
self.setWordWrap(True)
|
self.setWordWrap(True)
|
||||||
self.model = QJsonModel()
|
self.model = QJsonModel()
|
||||||
self.setModel(self.model)
|
self.setModel(self.model)
|
||||||
self.game: Optional[Game] = None
|
self.rgame: Optional[RareGame] = None
|
||||||
|
|
||||||
def update_game(self, game: Game):
|
def update_game(self, rgame: RareGame):
|
||||||
self.game = game
|
self.rgame = rgame
|
||||||
self.title.setTitle(self.game.app_title)
|
self.title.setTitle(self.rgame.app_title)
|
||||||
self.model.clear()
|
self.model.clear()
|
||||||
try:
|
try:
|
||||||
self.model.load(game.__dict__)
|
self.model.load(rgame.game.__dict__)
|
||||||
except:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
self.resizeColumnToContents(0)
|
self.resizeColumnToContents(0)
|
||||||
|
|
|
@ -2,11 +2,11 @@ from typing import Optional
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
||||||
from PyQt5.QtWidgets import QFrame, QWidget, QMessageBox
|
from PyQt5.QtWidgets import QFrame, QWidget, QMessageBox
|
||||||
from legendary.models.game import Game
|
|
||||||
|
|
||||||
from rare.components.tabs.games.game_utils import GameUtils
|
from rare.components.tabs.games.game_utils import GameUtils
|
||||||
|
from rare.models.game import RareGame
|
||||||
from rare.models.install import InstallOptionsModel
|
from rare.models.install import InstallOptionsModel
|
||||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ImageManagerSingleton
|
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
|
||||||
from rare.shared.image_manager import ImageSize
|
from rare.shared.image_manager import ImageSize
|
||||||
from rare.ui.components.tabs.games.game_info.game_dlc import Ui_GameDlc
|
from rare.ui.components.tabs.games.game_info.game_dlc import Ui_GameDlc
|
||||||
from rare.ui.components.tabs.games.game_info.game_dlc_widget import Ui_GameDlcWidget
|
from rare.ui.components.tabs.games.game_info.game_dlc_widget import Ui_GameDlcWidget
|
||||||
|
@ -16,27 +16,25 @@ from rare.widgets.image_widget import ImageWidget
|
||||||
class GameDlc(QWidget):
|
class GameDlc(QWidget):
|
||||||
install_dlc = pyqtSignal(str, bool)
|
install_dlc = pyqtSignal(str, bool)
|
||||||
|
|
||||||
def __init__(self, dlcs: dict, game_utils: GameUtils, parent=None):
|
def __init__(self, game_utils: GameUtils, parent=None):
|
||||||
super(GameDlc, self).__init__(parent=parent)
|
super(GameDlc, self).__init__(parent=parent)
|
||||||
self.ui = Ui_GameDlc()
|
self.ui = Ui_GameDlc()
|
||||||
self.ui.setupUi(self)
|
self.ui.setupUi(self)
|
||||||
self.core = LegendaryCoreSingleton()
|
self.core = LegendaryCoreSingleton()
|
||||||
self.signals = GlobalSignalsSingleton()
|
self.signals = GlobalSignalsSingleton()
|
||||||
|
|
||||||
self.game: Optional[Game] = None
|
self.rgame: Optional[RareGame] = None
|
||||||
self.game_utils = game_utils
|
self.game_utils = game_utils
|
||||||
|
|
||||||
self.ui.available_dlc_scroll.setFrameStyle(QFrame.NoFrame)
|
self.ui.available_dlc_scroll.setFrameStyle(QFrame.NoFrame)
|
||||||
self.ui.installed_dlc_scroll.setFrameStyle(QFrame.NoFrame)
|
self.ui.installed_dlc_scroll.setFrameStyle(QFrame.NoFrame)
|
||||||
|
|
||||||
self.dlcs = dlcs
|
|
||||||
self.installed_dlc_widgets = list()
|
self.installed_dlc_widgets = list()
|
||||||
self.available_dlc_widgets = list()
|
self.available_dlc_widgets = list()
|
||||||
|
|
||||||
def update_dlcs(self, app_name):
|
def update_dlcs(self, rgame: RareGame):
|
||||||
self.game = self.core.get_game(app_name)
|
self.rgame = rgame
|
||||||
dlcs = self.dlcs[self.game.catalog_item_id]
|
self.title.setTitle(self.rgame.app_title)
|
||||||
self.title.setTitle(self.game.app_title)
|
|
||||||
|
|
||||||
if self.installed_dlc_widgets:
|
if self.installed_dlc_widgets:
|
||||||
for dlc_widget in self.installed_dlc_widgets:
|
for dlc_widget in self.installed_dlc_widgets:
|
||||||
|
@ -49,8 +47,8 @@ class GameDlc(QWidget):
|
||||||
dlc_widget.deleteLater()
|
dlc_widget.deleteLater()
|
||||||
self.available_dlc_widgets.clear()
|
self.available_dlc_widgets.clear()
|
||||||
|
|
||||||
for dlc in sorted(dlcs, key=lambda x: x.app_title):
|
for dlc in sorted(self.rgame.owned_dlcs, key=lambda x: x.app_title):
|
||||||
if self.core.is_installed(dlc.app_name):
|
if dlc.is_installed:
|
||||||
dlc_widget = GameDlcWidget(dlc, True)
|
dlc_widget = GameDlcWidget(dlc, True)
|
||||||
self.ui.installed_dlc_contents_layout.addWidget(dlc_widget)
|
self.ui.installed_dlc_contents_layout.addWidget(dlc_widget)
|
||||||
dlc_widget.uninstall.connect(self.uninstall)
|
dlc_widget.uninstall.connect(self.uninstall)
|
||||||
|
@ -68,34 +66,29 @@ class GameDlc(QWidget):
|
||||||
self.ui.available_dlc_label.setVisible(not self.available_dlc_widgets)
|
self.ui.available_dlc_label.setVisible(not self.available_dlc_widgets)
|
||||||
self.ui.available_dlc_scroll.setVisible(bool(self.available_dlc_widgets))
|
self.ui.available_dlc_scroll.setVisible(bool(self.available_dlc_widgets))
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(RareGame)
|
||||||
def uninstall(self, app_name):
|
def uninstall(self, rgame: RareGame):
|
||||||
if self.game_utils.uninstall_game(app_name):
|
if self.game_utils.uninstall_game(rgame.app_name):
|
||||||
self.update_dlcs(self.game.app_name)
|
self.update_dlcs(self.rgame)
|
||||||
|
|
||||||
def install(self, app_name):
|
def install(self, app_name):
|
||||||
if not self.core.is_installed(self.game.app_name):
|
if not self.core.is_installed(self.rgame.app_name):
|
||||||
QMessageBox.warning(
|
QMessageBox.warning(
|
||||||
self,
|
self,
|
||||||
"Error",
|
"Error",
|
||||||
self.tr("Base Game is not installed. Please install {} first").format(
|
self.tr("Base Game is not installed. Please install {} first").format(self.rgame.app_title),
|
||||||
self.game.app_title
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.signals.install_game.emit(
|
self.signals.game.install.emit(InstallOptionsModel(app_name=app_name, update=True))
|
||||||
InstallOptionsModel(app_name=app_name, update=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class GameDlcWidget(QFrame):
|
class GameDlcWidget(QFrame):
|
||||||
install = pyqtSignal(str) # Appname
|
install = pyqtSignal(RareGame)
|
||||||
uninstall = pyqtSignal(str)
|
uninstall = pyqtSignal(RareGame)
|
||||||
|
|
||||||
def __init__(self, dlc: Game, installed: bool, parent=None):
|
def __init__(self, dlc: RareGame, installed: bool, parent=None):
|
||||||
super(GameDlcWidget, self).__init__(parent=parent)
|
super(GameDlcWidget, self).__init__(parent=parent)
|
||||||
self.image_manager = ImageManagerSingleton()
|
|
||||||
self.ui = Ui_GameDlcWidget()
|
self.ui = Ui_GameDlcWidget()
|
||||||
self.ui.setupUi(self)
|
self.ui.setupUi(self)
|
||||||
self.dlc = dlc
|
self.dlc = dlc
|
||||||
|
@ -105,10 +98,10 @@ class GameDlcWidget(QFrame):
|
||||||
self.ui.dlc_layout.insertWidget(0, self.image)
|
self.ui.dlc_layout.insertWidget(0, self.image)
|
||||||
|
|
||||||
self.ui.dlc_name.setText(dlc.app_title)
|
self.ui.dlc_name.setText(dlc.app_title)
|
||||||
self.ui.version.setText(dlc.app_version())
|
self.ui.version.setText(dlc.version)
|
||||||
self.ui.app_name.setText(dlc.app_name)
|
self.ui.app_name.setText(dlc.app_name)
|
||||||
|
|
||||||
self.image.setPixmap(self.image_manager.get_pixmap(dlc.app_name))
|
self.image.setPixmap(dlc.pixmap)
|
||||||
|
|
||||||
if installed:
|
if installed:
|
||||||
self.ui.action_button.setProperty("uninstall", 1)
|
self.ui.action_button.setProperty("uninstall", 1)
|
||||||
|
@ -122,9 +115,9 @@ class GameDlcWidget(QFrame):
|
||||||
def uninstall_dlc(self):
|
def uninstall_dlc(self):
|
||||||
self.ui.action_button.setDisabled(True)
|
self.ui.action_button.setDisabled(True)
|
||||||
self.ui.action_button.setText(self.tr("Uninstalling"))
|
self.ui.action_button.setText(self.tr("Uninstalling"))
|
||||||
self.uninstall.emit(self.dlc.app_name)
|
self.uninstall.emit(self.dlc)
|
||||||
|
|
||||||
def install_game(self):
|
def install_game(self):
|
||||||
self.ui.action_button.setDisabled(True)
|
self.ui.action_button.setDisabled(True)
|
||||||
self.ui.action_button.setText(self.tr("Installing"))
|
self.ui.action_button.setText(self.tr("Installing"))
|
||||||
self.install.emit(self.dlc.app_name)
|
self.install.emit(self.dlc)
|
||||||
|
|
|
@ -23,6 +23,7 @@ from PyQt5.QtWidgets import (
|
||||||
)
|
)
|
||||||
from legendary.models.game import Game, InstalledGame
|
from legendary.models.game import Game, InstalledGame
|
||||||
|
|
||||||
|
from rare.models.game import RareGame
|
||||||
from rare.models.install import InstallOptionsModel
|
from rare.models.install import InstallOptionsModel
|
||||||
from rare.shared import (
|
from rare.shared import (
|
||||||
LegendaryCoreSingleton,
|
LegendaryCoreSingleton,
|
||||||
|
@ -313,12 +314,13 @@ class GameInfo(QWidget, Ui_GameInfo):
|
||||||
def show_menu_after_browse(self):
|
def show_menu_after_browse(self):
|
||||||
self.move_button.showMenu()
|
self.move_button.showMenu()
|
||||||
|
|
||||||
def update_game(self, app_name: str):
|
def update_game(self, rgame: RareGame):
|
||||||
self.game = self.core.get_game(app_name)
|
# FIXME: Use RareGame for the rest of the code
|
||||||
self.igame = self.core.get_installed_game(self.game.app_name)
|
self.game = rgame.game
|
||||||
|
self.igame = rgame.igame
|
||||||
self.title.setTitle(self.game.app_title)
|
self.title.setTitle(self.game.app_title)
|
||||||
|
|
||||||
self.image.setPixmap(self.image_manager.get_pixmap(self.game.app_name, color=True))
|
self.image.setPixmap(rgame.pixmap)
|
||||||
|
|
||||||
self.app_name.setText(self.game.app_name)
|
self.app_name.setText(self.game.app_name)
|
||||||
if self.igame:
|
if self.igame:
|
||||||
|
@ -361,7 +363,7 @@ class GameInfo(QWidget, Ui_GameInfo):
|
||||||
self.game_actions_stack.setCurrentIndex(0)
|
self.game_actions_stack.setCurrentIndex(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
is_ue = self.core.get_asset(app_name).namespace == "ue"
|
is_ue = self.core.get_asset(rgame.app_name).namespace == "ue"
|
||||||
except ValueError:
|
except ValueError:
|
||||||
is_ue = False
|
is_ue = False
|
||||||
grade_visible = not is_ue and platform.system() != "Windows"
|
grade_visible = not is_ue and platform.system() != "Windows"
|
||||||
|
@ -403,5 +405,5 @@ class GameInfo(QWidget, Ui_GameInfo):
|
||||||
self.move_button.setEnabled(False)
|
self.move_button.setEnabled(False)
|
||||||
self.verify_button.setEnabled(False)
|
self.verify_button.setEnabled(False)
|
||||||
|
|
||||||
self.move_game_pop_up.update_game(app_name)
|
self.move_game_pop_up.update_game(rgame.app_name)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from legendary.models.game import Game, InstalledGame
|
||||||
|
|
||||||
from rare.components.tabs.settings import DefaultGameSettings
|
from rare.components.tabs.settings import DefaultGameSettings
|
||||||
from rare.components.tabs.settings.widgets.pre_launch import PreLaunchSettings
|
from rare.components.tabs.settings.widgets.pre_launch import PreLaunchSettings
|
||||||
|
from rare.models.game import RareGame
|
||||||
from rare.shared.workers.wine_resolver import WineResolver
|
from rare.shared.workers.wine_resolver import WineResolver
|
||||||
from rare.utils import config_helper
|
from rare.utils import config_helper
|
||||||
from rare.utils.extra_widgets import PathEdit
|
from rare.utils.extra_widgets import PathEdit
|
||||||
|
@ -133,11 +134,13 @@ class GameSettings(DefaultGameSettings):
|
||||||
config_helper.remove_option(self.game.app_name, option)
|
config_helper.remove_option(self.game.app_name, option)
|
||||||
config_helper.save_config()
|
config_helper.save_config()
|
||||||
|
|
||||||
def load_settings(self, app_name):
|
def load_settings(self, rgame: RareGame):
|
||||||
self.change = False
|
self.change = False
|
||||||
|
# FIXME: Use RareGame for the rest of the code
|
||||||
|
app_name = rgame.app_name
|
||||||
super(GameSettings, self).load_settings(app_name)
|
super(GameSettings, self).load_settings(app_name)
|
||||||
self.game = self.core.get_game(app_name)
|
self.game = rgame.game
|
||||||
self.igame = self.core.get_installed_game(self.game.app_name)
|
self.igame = rgame.igame
|
||||||
if self.igame:
|
if self.igame:
|
||||||
if self.igame.can_run_offline:
|
if self.igame.can_run_offline:
|
||||||
offline = self.core.lgd.config.get(self.game.app_name, "offline", fallback="unset")
|
offline = self.core.lgd.config.get(self.game.app_name, "offline", fallback="unset")
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
from typing import Tuple, List, Union, Optional
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QObject, pyqtSlot
|
||||||
|
from PyQt5.QtWidgets import QWidget
|
||||||
|
|
||||||
|
from rare.components.tabs.games.game_utils import GameUtils
|
||||||
|
from rare.lgndr.core import LegendaryCore
|
||||||
|
from rare.models.game import RareGame
|
||||||
|
from rare.models.signals import GlobalSignals
|
||||||
|
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ApiResultsSingleton
|
||||||
|
from .icon_game_widget import IconGameWidget
|
||||||
|
from .list_game_widget import ListGameWidget
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryWidgetController(QObject):
|
||||||
|
def __init__(self, icon_container: QWidget, list_container: QWidget, parent: QWidget = None):
|
||||||
|
super(LibraryWidgetController, self).__init__(parent=parent)
|
||||||
|
self._icon_container: QWidget = icon_container
|
||||||
|
self._list_container: QWidget = list_container
|
||||||
|
self.core: LegendaryCore = LegendaryCoreSingleton()
|
||||||
|
self.signals: GlobalSignals = GlobalSignalsSingleton()
|
||||||
|
self.api_results = ApiResultsSingleton()
|
||||||
|
|
||||||
|
self.signals.progress.started.connect(self.start_progress)
|
||||||
|
self.signals.progress.value.connect(self.update_progress)
|
||||||
|
self.signals.progress.finished.connect(self.finish_progress)
|
||||||
|
|
||||||
|
self.signals.game.installed.connect(self.on_install)
|
||||||
|
self.signals.game.uninstalled.connect(self.on_uninstall)
|
||||||
|
self.signals.game.verified.connect(self.on_verified)
|
||||||
|
|
||||||
|
def add_game(self, rgame: RareGame, game_utils: GameUtils, parent):
|
||||||
|
return self.add_widgets(rgame, game_utils, parent)
|
||||||
|
|
||||||
|
def add_widgets(self, rgame: RareGame, game_utils: GameUtils, parent) -> Tuple[IconGameWidget, ListGameWidget]:
|
||||||
|
icon_widget = IconGameWidget(rgame, game_utils, parent)
|
||||||
|
list_widget = ListGameWidget(rgame, game_utils, parent)
|
||||||
|
return icon_widget, list_widget
|
||||||
|
|
||||||
|
def __find_widget(self, app_name: str) -> Tuple[Union[IconGameWidget, None], Union[ListGameWidget, None]]:
|
||||||
|
iw = self._icon_container.findChild(IconGameWidget, app_name)
|
||||||
|
lw = self._list_container.findChild(ListGameWidget, app_name)
|
||||||
|
return iw, lw
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __visibility(widget, filter_name, search_text) -> Tuple[bool, float]:
|
||||||
|
if filter_name == "installed":
|
||||||
|
visible = widget.rgame.is_installed
|
||||||
|
elif filter_name == "offline":
|
||||||
|
visible = widget.rgame.can_run_offline
|
||||||
|
elif filter_name == "32bit":
|
||||||
|
visible = widget.rgame.is_win32
|
||||||
|
elif filter_name == "mac":
|
||||||
|
visible = widget.rgame.is_mac
|
||||||
|
elif filter_name == "installable":
|
||||||
|
visible = not widget.rgame.is_non_asset
|
||||||
|
elif filter_name == "include_ue":
|
||||||
|
visible = True
|
||||||
|
elif filter_name == "all":
|
||||||
|
visible = not widget.rgame.is_unreal
|
||||||
|
else:
|
||||||
|
visible = True
|
||||||
|
|
||||||
|
if (
|
||||||
|
search_text not in widget.rgame.app_name.lower()
|
||||||
|
and search_text not in widget.rgame.app_title.lower()
|
||||||
|
):
|
||||||
|
opacity = 0.25
|
||||||
|
else:
|
||||||
|
opacity = 1.0
|
||||||
|
|
||||||
|
return visible, opacity
|
||||||
|
|
||||||
|
def filter_list(self, filter_name="all", search_text: str = ""):
|
||||||
|
icon_widgets = self._icon_container.findChildren(IconGameWidget)
|
||||||
|
list_widgets = self._list_container.findChildren(ListGameWidget)
|
||||||
|
for iw in icon_widgets:
|
||||||
|
visibility, opacity = self.__visibility(iw, filter_name, search_text)
|
||||||
|
iw.setOpacity(opacity)
|
||||||
|
iw.setVisible(visibility)
|
||||||
|
for lw in list_widgets:
|
||||||
|
visibility, opacity = self.__visibility(lw, filter_name, search_text)
|
||||||
|
lw.setOpacity(opacity)
|
||||||
|
lw.setVisible(visibility)
|
||||||
|
self.sort_list(search_text)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def sort_list(self, sort_by: str = ""):
|
||||||
|
# lk: this is the existing sorting implemenation
|
||||||
|
# lk: it sorts by installed then by title
|
||||||
|
if sort_by:
|
||||||
|
self._icon_container.layout().sort(lambda x: (sort_by not in x.widget().rgame.app_title.lower(),))
|
||||||
|
else:
|
||||||
|
self._icon_container.layout().sort(
|
||||||
|
lambda x: (
|
||||||
|
not x.widget().rgame.is_installed,
|
||||||
|
x.widget().rgame.is_non_asset,
|
||||||
|
x.widget().rgame.app_title,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
list_widgets = self._list_container.findChildren(ListGameWidget)
|
||||||
|
if sort_by:
|
||||||
|
list_widgets.sort(key=lambda x: (sort_by not in x.rgame.app_title.lower(),))
|
||||||
|
else:
|
||||||
|
list_widgets.sort(
|
||||||
|
key=lambda x: (not x.rgame.is_installed, x.rgame.is_non_asset, x.rgame.app_title)
|
||||||
|
)
|
||||||
|
for idx, wl in enumerate(list_widgets):
|
||||||
|
self._list_container.layout().insertWidget(idx, wl)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
@pyqtSlot(list)
|
||||||
|
def update_list(self, app_names: List[str] = None):
|
||||||
|
if not app_names:
|
||||||
|
# lk: base it on icon widgets, the two lists should be identical
|
||||||
|
icon_widgets = self._icon_container.findChildren(IconGameWidget)
|
||||||
|
list_widgets = self._list_container.findChildren(ListGameWidget)
|
||||||
|
icon_app_names = set([iw.rgame.app_name for iw in icon_widgets])
|
||||||
|
list_app_names = set([lw.rgame.app_name for lw in list_widgets])
|
||||||
|
games = self.api_results.game_list + self.api_results.no_asset_games
|
||||||
|
game_app_names = set([g.app_name for g in games])
|
||||||
|
new_icon_app_names = game_app_names.difference(icon_app_names)
|
||||||
|
new_list_app_names = game_app_names.difference(list_app_names)
|
||||||
|
for app_name in new_icon_app_names:
|
||||||
|
game = self.rare_core.get_game(app_name)
|
||||||
|
iw = IconGameWidget(game)
|
||||||
|
self._icon_container.layout().addWidget(iw)
|
||||||
|
for app_name in new_list_app_names:
|
||||||
|
game = self.rare_core.get_game(app_name)
|
||||||
|
lw = ListGameWidget(game)
|
||||||
|
self._list_container.layout().addWidget(lw)
|
||||||
|
self.sort_list()
|
||||||
|
|
||||||
|
@pyqtSlot(list)
|
||||||
|
def on_install(self, app_names: List[str]):
|
||||||
|
for app_name in app_names:
|
||||||
|
iw, lw = self.__find_widget(app_name)
|
||||||
|
if iw is not None:
|
||||||
|
iw.rgame.set_installed(True)
|
||||||
|
if lw is not None:
|
||||||
|
lw.rgame.set_installed(True)
|
||||||
|
self.sort_list()
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def on_uninstall(self, app_name: str):
|
||||||
|
iw, lw = self.__find_widget(app_name)
|
||||||
|
if iw is not None:
|
||||||
|
iw.rgame.set_installed(False)
|
||||||
|
if lw is not None:
|
||||||
|
lw.rgame.set_installed(False)
|
||||||
|
self.sort_list()
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def on_verified(self, app_name: str):
|
||||||
|
iw, lw = self.__find_widget(app_name)
|
||||||
|
if iw is not None:
|
||||||
|
iw.rgame.needs_verification = False
|
||||||
|
if lw is not None:
|
||||||
|
lw.rgame.needs_verification = False
|
||||||
|
|
||||||
|
# lk: this should go in downloads and happen once
|
||||||
|
def __find_game_for_dlc(self, app_name: str) -> Optional[str]:
|
||||||
|
game = self.core.get_game(app_name, False)
|
||||||
|
# lk: how can an app_name not refer to a game?
|
||||||
|
if not game:
|
||||||
|
return None
|
||||||
|
if game.is_dlc:
|
||||||
|
game_list = self.core.get_game_list(update_assets=False)
|
||||||
|
game = list(
|
||||||
|
filter(
|
||||||
|
lambda x: x.asset_infos["Windows"].catalog_item_id == game.metadata["mainGameItem"]["id"],
|
||||||
|
game_list,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return game[0].app_name
|
||||||
|
return app_name
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def start_progress(self, app_name: str):
|
||||||
|
iw, lw = self.__find_widget(app_name)
|
||||||
|
if iw is not None:
|
||||||
|
iw.rgame.start_progress()
|
||||||
|
if lw is not None:
|
||||||
|
lw.rgame.start_progress()
|
||||||
|
|
||||||
|
@pyqtSlot(str, int)
|
||||||
|
def update_progress(self, app_name: str, progress: int):
|
||||||
|
iw, lw = self.__find_widget(app_name)
|
||||||
|
if iw is not None:
|
||||||
|
iw.rgame.update_progress(progress)
|
||||||
|
if lw is not None:
|
||||||
|
lw.rgame.update_progress(progress)
|
||||||
|
|
||||||
|
@pyqtSlot(str, bool)
|
||||||
|
def finish_progress(self, app_name: str, stopped: bool):
|
||||||
|
iw, lw = self.__find_widget(app_name)
|
||||||
|
if iw is not None:
|
||||||
|
iw.rgame.finish_progress(not stopped, 0, "")
|
||||||
|
if lw is not None:
|
||||||
|
lw.rgame.finish_progress(not stopped, 0, "")
|
|
@ -1,72 +0,0 @@
|
||||||
from logging import getLogger
|
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, Qt
|
|
||||||
from PyQt5.QtWidgets import QFrame, QAction
|
|
||||||
from legendary.models.game import Game
|
|
||||||
|
|
||||||
from rare.shared import ImageManagerSingleton
|
|
||||||
from rare.shared.image_manager import ImageSize
|
|
||||||
from rare.widgets.image_widget import ImageWidget
|
|
||||||
|
|
||||||
logger = getLogger("Uninstalled")
|
|
||||||
|
|
||||||
|
|
||||||
class BaseUninstalledWidget(QFrame):
|
|
||||||
show_info = pyqtSignal(str)
|
|
||||||
|
|
||||||
def __init__(self, game, core, pixmap):
|
|
||||||
super(BaseUninstalledWidget, self).__init__()
|
|
||||||
self.image_manager = ImageManagerSingleton()
|
|
||||||
|
|
||||||
self.game = game
|
|
||||||
if self.game.app_title == "Unreal Engine":
|
|
||||||
self.game.app_title = f"{self.game.app_title} {self.game.app_name.split('_')[-1]}"
|
|
||||||
|
|
||||||
self.core = core
|
|
||||||
self.image = ImageWidget(self)
|
|
||||||
self.image.setFixedSize(ImageSize.Display)
|
|
||||||
self.image.setPixmap(pixmap)
|
|
||||||
self.installing = False
|
|
||||||
self.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
||||||
|
|
||||||
reload_image = QAction(self.tr("Reload Image"), self)
|
|
||||||
reload_image.triggered.connect(self.reload_image)
|
|
||||||
self.addAction(reload_image)
|
|
||||||
|
|
||||||
def reload_image(self):
|
|
||||||
self.image_manager.download_image_blocking(self.game, force=True)
|
|
||||||
pm = self.image_manager.get_pixmap(self.game.app_name, color=False)
|
|
||||||
self.image.setPixmap(pm)
|
|
||||||
|
|
||||||
def install(self):
|
|
||||||
self.show_info.emit(self.game.app_name)
|
|
||||||
|
|
||||||
# From RareGame, added from sorting to work
|
|
||||||
@property
|
|
||||||
def is_non_asset(self) -> bool:
|
|
||||||
"""!
|
|
||||||
@brief Property to report if a Game doesn't have assets
|
|
||||||
|
|
||||||
Typically, games have assets, however some games that require
|
|
||||||
other launchers do not have them. Rare treats these games as installed
|
|
||||||
offering to execute their launcher.
|
|
||||||
|
|
||||||
@return bool If the game doesn't have assets
|
|
||||||
"""
|
|
||||||
return not self.game.asset_infos
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_installed(self) -> bool:
|
|
||||||
"""!
|
|
||||||
@brief Property to report if a game is installed
|
|
||||||
|
|
||||||
This returns True if InstalledGame data have been loaded for the game
|
|
||||||
or if the game is a game without assets, for example an Origin game.
|
|
||||||
|
|
||||||
@return bool If the game should be considered installed
|
|
||||||
"""
|
|
||||||
return False or self.is_non_asset
|
|
||||||
|
|
||||||
@property
|
|
||||||
def app_title(self) -> str:
|
|
||||||
return self.game.app_title
|
|
|
@ -1,40 +1,124 @@
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, QProcess, QSettings, QStandardPaths, Qt, QByteArray
|
from PyQt5.QtCore import pyqtSignal, QSettings, QStandardPaths, Qt
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QMouseEvent
|
||||||
from PyQt5.QtWidgets import QFrame, QMessageBox, QAction
|
from PyQt5.QtWidgets import QMessageBox, QAction
|
||||||
|
from legendary.models.game import Game, InstalledGame
|
||||||
|
|
||||||
from rare.components.tabs.games.game_utils import GameUtils
|
from rare.components.tabs.games.game_utils import GameUtils
|
||||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton, ImageManagerSingleton
|
from rare.models.game import RareGame
|
||||||
from rare.shared.image_manager import ImageSize
|
from rare.shared import (
|
||||||
|
LegendaryCoreSingleton,
|
||||||
|
GlobalSignalsSingleton,
|
||||||
|
ArgumentsSingleton,
|
||||||
|
ImageManagerSingleton,
|
||||||
|
)
|
||||||
from rare.utils.misc import create_desktop_link
|
from rare.utils.misc import create_desktop_link
|
||||||
from rare.widgets.image_widget import ImageWidget
|
from .library_widget import LibraryWidget
|
||||||
|
|
||||||
logger = getLogger("Game")
|
logger = getLogger("BaseGameWidget")
|
||||||
|
|
||||||
|
|
||||||
class BaseInstalledWidget(QFrame):
|
class GameWidget(LibraryWidget):
|
||||||
launch_signal = pyqtSignal(str, QProcess, list)
|
show_info = pyqtSignal(RareGame)
|
||||||
show_info = pyqtSignal(str)
|
|
||||||
finish_signal = pyqtSignal(str, int)
|
|
||||||
proc: QProcess()
|
|
||||||
|
|
||||||
def __init__(self, app_name, pixmap: QPixmap, game_utils: GameUtils):
|
def __init__(self, rgame: RareGame, game_utils: GameUtils, parent=None):
|
||||||
super(BaseInstalledWidget, self).__init__()
|
super(GameWidget, self).__init__(parent=parent)
|
||||||
self.core = LegendaryCoreSingleton()
|
self.core = LegendaryCoreSingleton()
|
||||||
self.signals = GlobalSignalsSingleton()
|
self.signals = GlobalSignalsSingleton()
|
||||||
self.args = ArgumentsSingleton()
|
self.args = ArgumentsSingleton()
|
||||||
self.image_manager = ImageManagerSingleton()
|
self.image_manager = ImageManagerSingleton()
|
||||||
|
|
||||||
self.game_utils = game_utils
|
self.game_utils = game_utils
|
||||||
|
|
||||||
|
self.rgame = rgame
|
||||||
|
self.rgame.signals.widget.update.connect(
|
||||||
|
lambda: self.setPixmap(self.rgame.pixmap)
|
||||||
|
)
|
||||||
|
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.rgame: RareGame = rgame
|
||||||
self.syncing_cloud_saves = False
|
self.syncing_cloud_saves = False
|
||||||
|
|
||||||
|
self.game_running = False
|
||||||
|
|
||||||
|
self.settings = QSettings()
|
||||||
|
|
||||||
|
self.installing = False
|
||||||
|
self.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||||
|
launch = QAction(self.tr("Launch"), self)
|
||||||
|
launch.triggered.connect(self.launch)
|
||||||
|
self.addAction(launch)
|
||||||
|
|
||||||
|
if self.rgame.game.supports_cloud_saves:
|
||||||
|
sync = QAction(self.tr("Sync with cloud"), self)
|
||||||
|
sync.triggered.connect(self.sync_game)
|
||||||
|
self.addAction(sync)
|
||||||
|
|
||||||
|
desktop = QStandardPaths.writableLocation(QStandardPaths.DesktopLocation)
|
||||||
|
if os.path.exists(
|
||||||
|
os.path.join(desktop, f"{self.rgame.app_title}.desktop")
|
||||||
|
) or os.path.exists(os.path.join(desktop, f"{self.rgame.app_title}.lnk")):
|
||||||
|
self.create_desktop = QAction(self.tr("Remove Desktop link"))
|
||||||
|
else:
|
||||||
|
self.create_desktop = QAction(self.tr("Create Desktop link"))
|
||||||
|
if self.rgame.is_installed:
|
||||||
|
self.create_desktop.triggered.connect(
|
||||||
|
lambda: self.create_desktop_link("desktop")
|
||||||
|
)
|
||||||
|
self.addAction(self.create_desktop)
|
||||||
|
|
||||||
|
applications = QStandardPaths.writableLocation(QStandardPaths.ApplicationsLocation)
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
start_menu_file = os.path.join(applications, f"{self.rgame.app_title}.desktop")
|
||||||
|
elif platform.system() == "Windows":
|
||||||
|
start_menu_file = os.path.join(applications, "..", f"{self.rgame.app_title}.lnk")
|
||||||
|
else:
|
||||||
|
start_menu_file = ""
|
||||||
|
if platform.system() in ["Windows", "Linux"]:
|
||||||
|
if os.path.exists(start_menu_file):
|
||||||
|
self.create_start_menu = QAction(self.tr("Remove start menu link"))
|
||||||
|
else:
|
||||||
|
self.create_start_menu = QAction(self.tr("Create start menu link"))
|
||||||
|
if self.rgame.is_installed:
|
||||||
|
self.create_start_menu.triggered.connect(
|
||||||
|
lambda: self.create_desktop_link("start_menu")
|
||||||
|
)
|
||||||
|
self.addAction(self.create_start_menu)
|
||||||
|
|
||||||
|
reload_image = QAction(self.tr("Reload Image"), self)
|
||||||
|
reload_image.triggered.connect(self.reload_image)
|
||||||
|
self.addAction(reload_image)
|
||||||
|
|
||||||
|
if not self.rgame.is_origin:
|
||||||
|
uninstall = QAction(self.tr("Uninstall"), self)
|
||||||
|
self.addAction(uninstall)
|
||||||
|
uninstall.triggered.connect(
|
||||||
|
lambda: self.signals.game.uninstalled.emit(self.rgame.app_name)
|
||||||
|
if self.game_utils.uninstall_game(self.rgame.app_name)
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
self.texts = {
|
self.texts = {
|
||||||
|
"static": {
|
||||||
"needs_verification": self.tr("Please verify game before playing"),
|
"needs_verification": self.tr("Please verify game before playing"),
|
||||||
|
},
|
||||||
"hover": {
|
"hover": {
|
||||||
"update_available": self.tr("Start game without version check"),
|
"update_available": self.tr("Start without version check"),
|
||||||
"launch": self.tr("Launch Game"),
|
"launch": self.tr("Launch Game"),
|
||||||
"launch_origin": self.tr("Launch/Link"),
|
"launch_origin": self.tr("Launch/Link"),
|
||||||
"running": self.tr("Game running"),
|
"running": self.tr("Game running"),
|
||||||
|
@ -49,101 +133,60 @@ class BaseInstalledWidget(QFrame):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self.game = self.core.get_game(app_name)
|
@property
|
||||||
self.igame = self.core.get_installed_game(app_name) # None if origin
|
def enterEventText(self) -> str:
|
||||||
|
if self.rgame.is_installed:
|
||||||
if self.game.app_title == "Unreal Engine":
|
if self.game_running:
|
||||||
self.game.app_title = f"{self.game.app_title} {self.game.app_name.split('_')[-1]}"
|
return self.texts["hover"]["running"]
|
||||||
|
elif (not self.rgame.is_origin) and self.rgame.needs_verification:
|
||||||
self.is_only_offline = False
|
return self.texts["static"]["needs_verification"]
|
||||||
|
elif self.rgame.is_foreign:
|
||||||
try:
|
return self.texts["hover"]["launch_offline"]
|
||||||
self.core.get_asset(app_name, platform=self.igame.platform).build_version
|
elif self.rgame.has_update:
|
||||||
except ValueError:
|
return self.texts["hover"]["update_available"]
|
||||||
logger.warning(f"Game {self.game.app_title} has no metadata. Set offline true")
|
|
||||||
self.is_only_offline = True
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.image = ImageWidget(self)
|
|
||||||
self.image.setFixedSize(ImageSize.Display)
|
|
||||||
self.image.setPixmap(pixmap)
|
|
||||||
self.game_running = False
|
|
||||||
self.offline = self.args.offline
|
|
||||||
self.update_available = False
|
|
||||||
if self.igame and self.core.lgd.assets:
|
|
||||||
try:
|
|
||||||
remote_version = self.core.get_asset(
|
|
||||||
self.game.app_name, platform=self.igame.platform, update=False
|
|
||||||
).build_version
|
|
||||||
except ValueError:
|
|
||||||
logger.error(f"Asset error for {self.game.app_title}")
|
|
||||||
self.update_available = False
|
|
||||||
else:
|
else:
|
||||||
if remote_version != self.igame.version:
|
return self.tr("Game Info")
|
||||||
self.update_available = True
|
# return self.texts["hover"]["launch" if self.igame else "launch_origin"]
|
||||||
|
|
||||||
self.data = QByteArray()
|
|
||||||
self.settings = QSettings()
|
|
||||||
|
|
||||||
self.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
||||||
launch = QAction(self.tr("Launch"), self)
|
|
||||||
launch.triggered.connect(self.launch)
|
|
||||||
self.addAction(launch)
|
|
||||||
|
|
||||||
if self.game.supports_cloud_saves:
|
|
||||||
sync = QAction(self.tr("Sync with cloud"), self)
|
|
||||||
sync.triggered.connect(self.sync_game)
|
|
||||||
self.addAction(sync)
|
|
||||||
|
|
||||||
desktop = QStandardPaths.writableLocation(QStandardPaths.DesktopLocation)
|
|
||||||
if os.path.exists(
|
|
||||||
os.path.join(desktop, f"{self.game.app_title}.desktop")
|
|
||||||
) or os.path.exists(os.path.join(desktop, f"{self.game.app_title}.lnk")):
|
|
||||||
self.create_desktop = QAction(self.tr("Remove Desktop link"))
|
|
||||||
else:
|
else:
|
||||||
self.create_desktop = QAction(self.tr("Create Desktop link"))
|
if not self.installing:
|
||||||
if self.igame:
|
return self.tr("Game Info")
|
||||||
self.create_desktop.triggered.connect(
|
|
||||||
lambda: self.create_desktop_link("desktop")
|
|
||||||
)
|
|
||||||
self.addAction(self.create_desktop)
|
|
||||||
|
|
||||||
applications = QStandardPaths.writableLocation(QStandardPaths.ApplicationsLocation)
|
|
||||||
if platform.system() == "Linux":
|
|
||||||
start_menu_file = os.path.join(applications, f"{self.game.app_title}.desktop")
|
|
||||||
elif platform.system() == "Windows":
|
|
||||||
start_menu_file = os.path.join(applications, "..", f"{self.game.app_title}.lnk")
|
|
||||||
else:
|
else:
|
||||||
start_menu_file = ""
|
return self.tr("Installation running")
|
||||||
if platform.system() in ["Windows", "Linux"]:
|
|
||||||
if os.path.exists(start_menu_file):
|
@property
|
||||||
self.create_start_menu = QAction(self.tr("Remove start menu link"))
|
def leaveEventText(self) -> str:
|
||||||
|
if self.rgame.is_installed:
|
||||||
|
if self.game_running:
|
||||||
|
return self.texts["default"]["running"]
|
||||||
|
elif self.syncing_cloud_saves:
|
||||||
|
return self.texts["default"]["syncing"]
|
||||||
|
elif self.rgame.is_foreign:
|
||||||
|
return self.texts["default"]["no_meta"]
|
||||||
|
elif self.rgame.has_update:
|
||||||
|
return self.texts["default"]["update_available"]
|
||||||
|
elif (not self.rgame.is_origin) and self.rgame.needs_verification:
|
||||||
|
return self.texts["static"]["needs_verification"]
|
||||||
else:
|
else:
|
||||||
self.create_start_menu = QAction(self.tr("Create start menu link"))
|
return ""
|
||||||
if self.igame:
|
else:
|
||||||
self.create_start_menu.triggered.connect(
|
if self.installing:
|
||||||
lambda: self.create_desktop_link("start_menu")
|
return "Installation..."
|
||||||
)
|
else:
|
||||||
self.addAction(self.create_start_menu)
|
return ""
|
||||||
|
|
||||||
reload_image = QAction(self.tr("Reload Image"), self)
|
def mousePressEvent(self, e: QMouseEvent) -> None:
|
||||||
reload_image.triggered.connect(self.reload_image)
|
# left button
|
||||||
self.addAction(reload_image)
|
if e.button() == 1:
|
||||||
|
self.show_info.emit(self.rgame)
|
||||||
|
# right
|
||||||
|
elif e.button() == 2:
|
||||||
|
pass # self.showMenu(e)
|
||||||
|
|
||||||
if self.igame is not None:
|
def reload_image(self) -> None:
|
||||||
uninstall = QAction(self.tr("Uninstall"), self)
|
self.rgame.refresh_pixmap()
|
||||||
self.addAction(uninstall)
|
|
||||||
uninstall.triggered.connect(
|
|
||||||
lambda: self.signals.update_gamelist.emit([self.game.app_name])
|
|
||||||
if self.game_utils.uninstall_game(self.game.app_name)
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
def reload_image(self):
|
def install(self):
|
||||||
self.image_manager.download_image_blocking(self.game, force=True)
|
self.show_info.emit(self.rgame)
|
||||||
pm = self.image_manager.get_pixmap(self.game.app_name, color=True)
|
|
||||||
self.image.setPixmap(pm)
|
|
||||||
|
|
||||||
def create_desktop_link(self, type_of_link):
|
def create_desktop_link(self, type_of_link):
|
||||||
if type_of_link == "desktop":
|
if type_of_link == "desktop":
|
||||||
|
@ -154,9 +197,9 @@ class BaseInstalledWidget(QFrame):
|
||||||
return
|
return
|
||||||
|
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
shortcut_path = os.path.join(shortcut_path, f"{self.game.app_title}.lnk")
|
shortcut_path = os.path.join(shortcut_path, f"{self.rgame.app_title}.lnk")
|
||||||
elif platform.system() == "Linux":
|
elif platform.system() == "Linux":
|
||||||
shortcut_path = os.path.join(shortcut_path, f"{self.game.app_title}.desktop")
|
shortcut_path = os.path.join(shortcut_path, f"{self.rgame.app_title}.desktop")
|
||||||
else:
|
else:
|
||||||
QMessageBox.warning(
|
QMessageBox.warning(
|
||||||
self,
|
self,
|
||||||
|
@ -167,7 +210,7 @@ class BaseInstalledWidget(QFrame):
|
||||||
|
|
||||||
if not os.path.exists(shortcut_path):
|
if not os.path.exists(shortcut_path):
|
||||||
try:
|
try:
|
||||||
if not create_desktop_link(self.game.app_name, self.core, type_of_link):
|
if not create_desktop_link(self.rgame.app_name, self.core, type_of_link):
|
||||||
return
|
return
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
QMessageBox.warning(
|
QMessageBox.warning(
|
||||||
|
@ -189,16 +232,16 @@ class BaseInstalledWidget(QFrame):
|
||||||
def launch(self, offline=False, skip_version_check=False):
|
def launch(self, offline=False, skip_version_check=False):
|
||||||
if self.game_running:
|
if self.game_running:
|
||||||
return
|
return
|
||||||
offline = offline or self.is_only_offline
|
offline = offline or self.rgame.is_foreign
|
||||||
if self.is_only_offline and not self.igame.can_run_offline:
|
if self.rgame.is_foreign and not self.rgame.can_run_offline:
|
||||||
QMessageBox.warning(self, "Warning",
|
QMessageBox.warning(self, "Warning",
|
||||||
self.tr("This game is probably not in your library and it cannot be launched offline"))
|
self.tr("This game is probably not in your library and it cannot be launched offline"))
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.game.supports_cloud_saves and not offline:
|
if self.rgame.game.supports_cloud_saves and not offline:
|
||||||
self.syncing_cloud_saves = True
|
self.syncing_cloud_saves = True
|
||||||
self.game_utils.prepare_launch(
|
self.game_utils.prepare_launch(
|
||||||
self.game.app_name, offline, skip_version_check
|
self.rgame, offline, skip_version_check
|
||||||
)
|
)
|
||||||
|
|
||||||
def sync_finished(self, app_name):
|
def sync_finished(self, app_name):
|
||||||
|
@ -207,7 +250,7 @@ class BaseInstalledWidget(QFrame):
|
||||||
def sync_game(self):
|
def sync_game(self):
|
||||||
try:
|
try:
|
||||||
sync = self.game_utils.cloud_save_utils.sync_before_launch_game(
|
sync = self.game_utils.cloud_save_utils.sync_before_launch_game(
|
||||||
self.game.app_name, True
|
self.rgame.app_name, True
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
sync = False
|
sync = False
|
||||||
|
@ -218,37 +261,3 @@ class BaseInstalledWidget(QFrame):
|
||||||
if error:
|
if error:
|
||||||
QMessageBox.warning(self, "Error", error)
|
QMessageBox.warning(self, "Error", error)
|
||||||
self.game_running = False
|
self.game_running = False
|
||||||
|
|
||||||
# From RareGame, added from sorting to work
|
|
||||||
@property
|
|
||||||
def is_non_asset(self) -> bool:
|
|
||||||
"""!
|
|
||||||
@brief Property to report if a Game doesn't have assets
|
|
||||||
|
|
||||||
Typically, games have assets, however some games that require
|
|
||||||
other launchers do not have them. Rare treats these games as installed
|
|
||||||
offering to execute their launcher.
|
|
||||||
|
|
||||||
@return bool If the game doesn't have assets
|
|
||||||
"""
|
|
||||||
return not self.game.asset_infos
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_origin(self) -> bool:
|
|
||||||
return self.game.metadata.get("customAttributes", {}).get("ThirdPartyManagedApp", {}).get("value") == "Origin"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_installed(self) -> bool:
|
|
||||||
"""!
|
|
||||||
@brief Property to report if a game is installed
|
|
||||||
|
|
||||||
This returns True if InstalledGame data have been loaded for the game
|
|
||||||
or if the game is a game without assets, for example an Origin game.
|
|
||||||
|
|
||||||
@return bool If the game should be considered installed
|
|
||||||
"""
|
|
||||||
return (self.igame is not None) or self.is_non_asset
|
|
||||||
|
|
||||||
@property
|
|
||||||
def app_title(self) -> str:
|
|
||||||
return self.igame.title if self.igame is not None else self.game.app_title
|
|
77
rare/components/tabs/games/game_widgets/icon_game_widget.py
Normal file
77
rare/components/tabs/games/game_widgets/icon_game_widget.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QEvent, pyqtSignal
|
||||||
|
|
||||||
|
from rare.components.tabs.games.game_utils import GameUtils
|
||||||
|
from rare.models.game import RareGame
|
||||||
|
from rare.shared.image_manager import ImageSize
|
||||||
|
from .game_widget import GameWidget
|
||||||
|
from .icon_widget import IconWidget
|
||||||
|
|
||||||
|
logger = getLogger("IconGameWidget")
|
||||||
|
|
||||||
|
|
||||||
|
class IconGameWidget(GameWidget):
|
||||||
|
is_ready = False
|
||||||
|
update_game = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, rgame: RareGame, game_utils: GameUtils, parent=None):
|
||||||
|
super(IconGameWidget, self).__init__(rgame, game_utils, parent)
|
||||||
|
self.setObjectName(f"{rgame.app_name}")
|
||||||
|
self.setFixedSize(ImageSize.Display)
|
||||||
|
self.ui = IconWidget()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
self.game_utils.finished.connect(self.game_finished)
|
||||||
|
|
||||||
|
self.ui.title_label.setText(f"<h4>{self.rgame.app_title}</h4>")
|
||||||
|
self.ui.launch_btn.clicked.connect(self.game_launch)
|
||||||
|
self.ui.launch_btn.setVisible(self.rgame.is_installed)
|
||||||
|
self.ui.install_btn.clicked.connect(self.install)
|
||||||
|
self.ui.install_btn.setVisible(not self.rgame.is_installed)
|
||||||
|
|
||||||
|
if self.rgame.igame and self.rgame.needs_verification:
|
||||||
|
self.ui.status_label.setText(self.texts["static"]["needs_verification"])
|
||||||
|
|
||||||
|
self.game_utils.game_launched.connect(self.game_started)
|
||||||
|
|
||||||
|
self.is_ready = True
|
||||||
|
self.ui.launch_btn.setEnabled(self.rgame.can_launch)
|
||||||
|
|
||||||
|
def enterEvent(self, a0: QEvent = None) -> None:
|
||||||
|
if a0 is not None:
|
||||||
|
a0.accept()
|
||||||
|
self.ui.status_label.setText(self.enterEventText)
|
||||||
|
self.ui.enterAnimation(self)
|
||||||
|
|
||||||
|
def leaveEvent(self, a0: QEvent = None) -> None:
|
||||||
|
if a0 is not None:
|
||||||
|
a0.accept()
|
||||||
|
self.ui.leaveAnimation(self)
|
||||||
|
self.ui.status_label.setText(self.leaveEventText)
|
||||||
|
|
||||||
|
def game_launch(self):
|
||||||
|
if not self.game_running:
|
||||||
|
if self.rgame.igame and self.rgame.needs_verification:
|
||||||
|
return
|
||||||
|
if self.rgame.has_update:
|
||||||
|
self.launch(skip_version_check=True)
|
||||||
|
else:
|
||||||
|
self.launch()
|
||||||
|
|
||||||
|
def sync_finished(self, app_name):
|
||||||
|
if not app_name == self.rgame.app_name:
|
||||||
|
return
|
||||||
|
super().sync_finished(app_name)
|
||||||
|
self.leaveEvent(None)
|
||||||
|
|
||||||
|
def game_finished(self, app_name, error):
|
||||||
|
if app_name != self.rgame.app_name:
|
||||||
|
return
|
||||||
|
self.game_running = False
|
||||||
|
self.leaveEvent(None)
|
||||||
|
|
||||||
|
def game_started(self, app_name):
|
||||||
|
if app_name == self.rgame.app_name:
|
||||||
|
self.game_running = True
|
||||||
|
self.leaveEvent(None)
|
160
rare/components/tabs/games/game_widgets/icon_widget.py
Normal file
160
rare/components/tabs/games/game_widgets/icon_widget.py
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
from PyQt5.QtCore import Qt, QPropertyAnimation, QEasingCurve, QSize
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QWidget,
|
||||||
|
QVBoxLayout,
|
||||||
|
QGraphicsOpacityEffect,
|
||||||
|
QSpacerItem,
|
||||||
|
QSizePolicy,
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QPushButton,
|
||||||
|
)
|
||||||
|
|
||||||
|
from rare.utils.misc import icon
|
||||||
|
from rare.widgets.elide_label import ElideLabel
|
||||||
|
|
||||||
|
|
||||||
|
class IconWidget(object):
|
||||||
|
_effect = None
|
||||||
|
_animation = None
|
||||||
|
|
||||||
|
def setupUi(self, widget: QWidget):
|
||||||
|
# on-hover popup
|
||||||
|
self.mini_widget = QWidget(parent=widget)
|
||||||
|
self.mini_widget.setObjectName(f"{type(self).__name__}MiniWidget")
|
||||||
|
self.mini_widget.setStyleSheet(
|
||||||
|
f"QWidget#{self.mini_widget.objectName()}"
|
||||||
|
"{"
|
||||||
|
"color: rgb(238, 238, 238);"
|
||||||
|
"background-color: rgba(0, 0, 0, 65%);"
|
||||||
|
"border-radius: 5%;"
|
||||||
|
"border-bottom-left-radius: 9%;"
|
||||||
|
"border-bottom-right-radius: 9%;"
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
self.mini_widget.setFixedHeight(widget.height() // 3)
|
||||||
|
|
||||||
|
self.mini_effect = QGraphicsOpacityEffect(self.mini_widget)
|
||||||
|
self.mini_widget.setGraphicsEffect(self.mini_effect)
|
||||||
|
|
||||||
|
# game title
|
||||||
|
self.title_label = QLabel(parent=self.mini_widget)
|
||||||
|
self.title_label.setObjectName(f"{type(self).__name__}TitleLabel")
|
||||||
|
self.title_label.setStyleSheet(
|
||||||
|
f"QLabel#{self.title_label.objectName()}"
|
||||||
|
"{"
|
||||||
|
"background-color: rgba(0, 0, 0, 0%); color: white;"
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
self.title_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
|
self.title_label.setAlignment(Qt.AlignTop)
|
||||||
|
self.title_label.setAutoFillBackground(False)
|
||||||
|
self.title_label.setWordWrap(True)
|
||||||
|
|
||||||
|
# information below title
|
||||||
|
self.status_label = ElideLabel(parent=self.mini_widget)
|
||||||
|
self.status_label.setObjectName(f"{type(self).__name__}StatusLabel")
|
||||||
|
self.status_label.setStyleSheet(
|
||||||
|
f"QLabel#{self.status_label.objectName()}"
|
||||||
|
"{"
|
||||||
|
"background-color: rgba(0, 0, 0, 0%); color: white;"
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
self.status_label.setAutoFillBackground(False)
|
||||||
|
|
||||||
|
# play button
|
||||||
|
self.launch_btn = QPushButton(parent=self.mini_widget)
|
||||||
|
self.launch_btn.setObjectName(f"{type(self).__name__}LaunchButton")
|
||||||
|
self.launch_btn.setStyleSheet(
|
||||||
|
f"QPushButton#{self.launch_btn.objectName()}"
|
||||||
|
"{"
|
||||||
|
"border-radius: 10%;"
|
||||||
|
"background-color: rgba(0, 0, 0, 65%);"
|
||||||
|
"border-color: black; border-width: 1px;"
|
||||||
|
"}"
|
||||||
|
f"QPushButton#{self.launch_btn.objectName()}::hover"
|
||||||
|
"{"
|
||||||
|
"border-color: gray;"
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
self.launch_btn.setIcon(icon("ei.play-alt", color="white"))
|
||||||
|
self.launch_btn.setIconSize(QSize(20, 20))
|
||||||
|
self.launch_btn.setFixedSize(QSize(widget.width() // 4, widget.width() // 4))
|
||||||
|
|
||||||
|
self.install_btn = QPushButton(parent=self.mini_widget)
|
||||||
|
self.install_btn.setObjectName(f"{type(self).__name__}InstallButton")
|
||||||
|
self.install_btn.setStyleSheet(
|
||||||
|
f"QPushButton#{self.install_btn.objectName()}"
|
||||||
|
"{"
|
||||||
|
"border-radius: 10%;"
|
||||||
|
"background-color: rgba(0, 0, 0, 65%);"
|
||||||
|
"border-color: black; border-width: 1px;"
|
||||||
|
"}"
|
||||||
|
f"QPushButton#{self.install_btn.objectName()}::hover"
|
||||||
|
"{"
|
||||||
|
"border-color: gray;"
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
self.install_btn.setIcon(icon("ri.install-fill", color="white"))
|
||||||
|
self.install_btn.setIconSize(QSize(20, 20))
|
||||||
|
self.install_btn.setFixedSize(QSize(widget.width() // 4, widget.width() // 4))
|
||||||
|
|
||||||
|
# Create layouts
|
||||||
|
# layout for the whole widget, holds the image
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSizeConstraint(QVBoxLayout.SetFixedSize)
|
||||||
|
|
||||||
|
# layout for the image, holds the mini widget and a spacer item
|
||||||
|
image_layout = QVBoxLayout()
|
||||||
|
image_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
|
||||||
|
# layout for the mini widget, holds the top row and the info label
|
||||||
|
mini_layout = QVBoxLayout()
|
||||||
|
mini_layout.setSpacing(0)
|
||||||
|
|
||||||
|
# layout for the top row, holds the title and the launch button
|
||||||
|
row_layout = QHBoxLayout()
|
||||||
|
row_layout.setSpacing(0)
|
||||||
|
row_layout.setAlignment(Qt.AlignTop)
|
||||||
|
|
||||||
|
# Layout the widgets
|
||||||
|
# (from inner to outer)
|
||||||
|
row_layout.addWidget(self.title_label, stretch=2)
|
||||||
|
row_layout.addWidget(self.launch_btn)
|
||||||
|
row_layout.addWidget(self.install_btn)
|
||||||
|
mini_layout.addLayout(row_layout, stretch=2)
|
||||||
|
mini_layout.addWidget(self.status_label)
|
||||||
|
self.mini_widget.setLayout(mini_layout)
|
||||||
|
|
||||||
|
image_layout.addSpacerItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Expanding))
|
||||||
|
image_layout.addWidget(self.mini_widget)
|
||||||
|
widget.setLayout(image_layout)
|
||||||
|
|
||||||
|
# layout.addWidget(widget.image)
|
||||||
|
# widget.setLayout(layout)
|
||||||
|
|
||||||
|
widget.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||||
|
widget.leaveEvent(None)
|
||||||
|
|
||||||
|
self.translateUi(widget)
|
||||||
|
|
||||||
|
def translateUi(self, widget: QWidget):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def enterAnimation(self, widget: QWidget):
|
||||||
|
self._animation = QPropertyAnimation(self.mini_effect, b"opacity")
|
||||||
|
self._animation.setDuration(250)
|
||||||
|
self._animation.setStartValue(0)
|
||||||
|
self._animation.setEndValue(1)
|
||||||
|
self._animation.setEasingCurve(QEasingCurve.InSine)
|
||||||
|
self._animation.start(QPropertyAnimation.DeleteWhenStopped)
|
||||||
|
|
||||||
|
def leaveAnimation(self, widget: QWidget):
|
||||||
|
self._animation = QPropertyAnimation(self.mini_effect, b"opacity")
|
||||||
|
self._animation.setDuration(150)
|
||||||
|
self._animation.setStartValue(1)
|
||||||
|
self._animation.setEndValue(0)
|
||||||
|
self._animation.setEasingCurve(QEasingCurve.OutSine)
|
||||||
|
self._animation.start(QPropertyAnimation.DeleteWhenStopped)
|
|
@ -1,137 +0,0 @@
|
||||||
from logging import getLogger
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QEvent, pyqtSignal, Qt
|
|
||||||
from PyQt5.QtGui import QMouseEvent
|
|
||||||
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QPushButton, QWidget
|
|
||||||
|
|
||||||
from rare.components.tabs.games.game_widgets.base_installed_widget import (
|
|
||||||
BaseInstalledWidget,
|
|
||||||
)
|
|
||||||
from rare.shared import LegendaryCoreSingleton
|
|
||||||
from rare.shared.image_manager import ImageSize
|
|
||||||
from rare.utils.misc import icon
|
|
||||||
from rare.widgets.elide_label import ElideLabel
|
|
||||||
|
|
||||||
logger = getLogger("GameWidgetInstalled")
|
|
||||||
|
|
||||||
|
|
||||||
class InstalledIconWidget(BaseInstalledWidget):
|
|
||||||
update_game = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, app_name, pixmap, game_utils):
|
|
||||||
super(InstalledIconWidget, self).__init__(app_name, pixmap, game_utils)
|
|
||||||
self.setObjectName(type(self).__name__)
|
|
||||||
|
|
||||||
self.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
layout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.setFixedWidth(ImageSize.Display.size.width())
|
|
||||||
self.core = LegendaryCoreSingleton()
|
|
||||||
|
|
||||||
if self.update_available:
|
|
||||||
logger.info(f"Update available for game: {self.game.app_name}")
|
|
||||||
|
|
||||||
layout.addWidget(self.image)
|
|
||||||
|
|
||||||
self.game_utils.finished.connect(self.game_finished)
|
|
||||||
self.game_utils.cloud_save_finished.connect(self.sync_finished)
|
|
||||||
|
|
||||||
miniwidget = QWidget(self)
|
|
||||||
miniwidget.setFixedWidth(ImageSize.Display.size.width())
|
|
||||||
minilayout = QHBoxLayout()
|
|
||||||
minilayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
minilayout.setSpacing(0)
|
|
||||||
miniwidget.setLayout(minilayout)
|
|
||||||
|
|
||||||
self.title_label = ElideLabel(f"<b>{self.game.app_title}</b>", parent=miniwidget)
|
|
||||||
self.title_label.setAlignment(Qt.AlignTop)
|
|
||||||
self.title_label.setObjectName("game_widget")
|
|
||||||
minilayout.addWidget(self.title_label, stretch=2)
|
|
||||||
|
|
||||||
# Info Button
|
|
||||||
self.menu_btn = QPushButton(parent=miniwidget)
|
|
||||||
self.menu_btn.setIcon(icon("ei.info-circle"))
|
|
||||||
# self.menu_btn.setObjectName("installed_menu_button")
|
|
||||||
self.menu_btn.enterEvent = lambda x: self.info_label.setText(self.tr("Information"))
|
|
||||||
self.menu_btn.leaveEvent = lambda x: self.enterEvent(None)
|
|
||||||
# remove Border
|
|
||||||
|
|
||||||
self.menu_btn.setObjectName("menu_button")
|
|
||||||
|
|
||||||
self.menu_btn.clicked.connect(lambda: self.show_info.emit(self.game.app_name))
|
|
||||||
self.menu_btn.setFixedSize(22, 22)
|
|
||||||
minilayout.addWidget(self.menu_btn, stretch=0)
|
|
||||||
minilayout.setAlignment(Qt.AlignTop)
|
|
||||||
layout.addWidget(miniwidget)
|
|
||||||
|
|
||||||
self.info_label = ElideLabel(" ", parent=self)
|
|
||||||
self.info_label.setFixedWidth(ImageSize.Display.size.width())
|
|
||||||
self.leaveEvent(None)
|
|
||||||
self.info_label.setObjectName("info_label")
|
|
||||||
layout.addWidget(self.info_label)
|
|
||||||
|
|
||||||
if self.igame and self.igame.needs_verification:
|
|
||||||
self.info_label.setText(self.texts["needs_verification"])
|
|
||||||
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
self.game_utils.game_launched.connect(self.game_started)
|
|
||||||
|
|
||||||
def enterEvent(self, a0: QEvent = None) -> None:
|
|
||||||
if self.game_running:
|
|
||||||
self.info_label.setText(self.texts["hover"]["running"])
|
|
||||||
elif self.igame and self.igame.needs_verification:
|
|
||||||
self.info_label.setText(self.texts["needs_verification"])
|
|
||||||
elif self.is_only_offline:
|
|
||||||
self.info_label.setText(self.texts["hover"]["launch_offline"])
|
|
||||||
elif self.update_available:
|
|
||||||
self.info_label.setText(self.texts["hover"]["update_available"])
|
|
||||||
else:
|
|
||||||
self.info_label.setText(
|
|
||||||
self.texts["hover"]["launch" if self.igame else "launch_origin" if self.is_origin else "no_launch"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def leaveEvent(self, a0: QEvent = None) -> None:
|
|
||||||
if self.game_running:
|
|
||||||
self.info_label.setText(self.texts["default"]["running"])
|
|
||||||
elif self.syncing_cloud_saves:
|
|
||||||
self.info_label.setText(self.texts["default"]["syncing"])
|
|
||||||
elif self.is_only_offline:
|
|
||||||
self.info_label.setText(self.texts["default"]["no_meta"])
|
|
||||||
elif self.update_available:
|
|
||||||
self.info_label.setText(self.texts["default"]["update_available"])
|
|
||||||
elif self.igame and self.igame.needs_verification:
|
|
||||||
self.info_label.setText(self.texts["needs_verification"])
|
|
||||||
else:
|
|
||||||
self.info_label.setText(" ") # invisible text, cheap way to always vertical have size in label
|
|
||||||
|
|
||||||
def mousePressEvent(self, e: QMouseEvent):
|
|
||||||
# left button
|
|
||||||
if e.button() == 1 and not self.game_running:
|
|
||||||
if self.igame and self.igame.needs_verification:
|
|
||||||
return
|
|
||||||
if self.update_available:
|
|
||||||
self.launch(skip_version_check=True)
|
|
||||||
else:
|
|
||||||
self.launch()
|
|
||||||
|
|
||||||
# right
|
|
||||||
elif e.button() == 2:
|
|
||||||
pass # self.showMenu(e)
|
|
||||||
|
|
||||||
def sync_finished(self, app_name):
|
|
||||||
if not app_name == self.game.app_name:
|
|
||||||
return
|
|
||||||
super().sync_finished(app_name)
|
|
||||||
self.leaveEvent(None)
|
|
||||||
|
|
||||||
def game_finished(self, app_name, error):
|
|
||||||
if app_name != self.game.app_name:
|
|
||||||
return
|
|
||||||
self.game_running = False
|
|
||||||
self.leaveEvent(None)
|
|
||||||
|
|
||||||
def game_started(self, app_name):
|
|
||||||
if app_name == self.game.app_name:
|
|
||||||
self.game_running = True
|
|
||||||
self.leaveEvent(None)
|
|
|
@ -1,110 +0,0 @@
|
||||||
from logging import getLogger
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QProcess, pyqtSignal, Qt
|
|
||||||
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QPushButton, QVBoxLayout
|
|
||||||
|
|
||||||
from rare.components.tabs.games.game_widgets.base_installed_widget import (
|
|
||||||
BaseInstalledWidget,
|
|
||||||
)
|
|
||||||
from rare.utils.misc import icon, get_size
|
|
||||||
|
|
||||||
logger = getLogger("GameWidget")
|
|
||||||
|
|
||||||
|
|
||||||
class InstalledListWidget(BaseInstalledWidget):
|
|
||||||
proc: QProcess
|
|
||||||
signal = pyqtSignal(str)
|
|
||||||
update_game = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, app_name, pixmap, game_utils):
|
|
||||||
super(InstalledListWidget, self).__init__(app_name, pixmap, game_utils)
|
|
||||||
self.setFrameStyle(self.StyledPanel)
|
|
||||||
self.dev = self.game.metadata["developer"]
|
|
||||||
if self.igame:
|
|
||||||
self.size = self.igame.install_size
|
|
||||||
else:
|
|
||||||
self.size = 0
|
|
||||||
|
|
||||||
self.layout = QHBoxLayout()
|
|
||||||
self.setLayout(self.layout)
|
|
||||||
self.layout.addWidget(self.image)
|
|
||||||
|
|
||||||
# Layout on the right
|
|
||||||
self.childLayout = QVBoxLayout()
|
|
||||||
self.layout.addLayout(self.childLayout)
|
|
||||||
|
|
||||||
play_icon = icon("ei.play")
|
|
||||||
self.title_label = QLabel(f"<h1>{self.game.app_title}</h1>")
|
|
||||||
self.title_label.setWordWrap(True)
|
|
||||||
self.childLayout.addWidget(self.title_label)
|
|
||||||
self.app_name_label = QLabel(self.game.app_name)
|
|
||||||
self.launch_button = QPushButton(
|
|
||||||
play_icon,
|
|
||||||
self.tr("Launch") if self.igame else self.tr("Link/Play") if self.is_origin else self.texts["hover"][
|
|
||||||
"no_launch"]
|
|
||||||
)
|
|
||||||
if not self.is_origin and not self.igame:
|
|
||||||
self.launch_button.setDisabled(True)
|
|
||||||
|
|
||||||
self.launch_button.setObjectName("launch_game_button")
|
|
||||||
self.launch_button.setFixedWidth(150)
|
|
||||||
|
|
||||||
self.info = QPushButton("Info")
|
|
||||||
self.info.clicked.connect(lambda: self.show_info.emit(self.game.app_name))
|
|
||||||
self.info.setFixedWidth(80)
|
|
||||||
|
|
||||||
self.info_label = QLabel("")
|
|
||||||
self.childLayout.addWidget(self.info_label)
|
|
||||||
self.update_text()
|
|
||||||
|
|
||||||
self.launch_button.clicked.connect(self.launch)
|
|
||||||
|
|
||||||
self.childLayout.addWidget(self.launch_button)
|
|
||||||
self.childLayout.addWidget(self.info)
|
|
||||||
self.childLayout.addWidget(self.app_name_label)
|
|
||||||
self.developer_label = QLabel(self.tr("Developer: {}").format(self.dev))
|
|
||||||
self.childLayout.addWidget(self.developer_label)
|
|
||||||
if self.igame:
|
|
||||||
self.version_label = QLabel(f"Version: {self.igame.version}")
|
|
||||||
self.size_label = QLabel(
|
|
||||||
f"{self.tr('Installed size')}: {get_size(self.size)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.childLayout.addWidget(self.version_label)
|
|
||||||
self.childLayout.addWidget(self.size_label)
|
|
||||||
|
|
||||||
self.childLayout.setAlignment(Qt.AlignTop)
|
|
||||||
self.layout.setAlignment(Qt.AlignLeft)
|
|
||||||
|
|
||||||
self.game_utils.cloud_save_finished.connect(self.sync_finished)
|
|
||||||
self.game_utils.finished.connect(self.game_finished)
|
|
||||||
|
|
||||||
self.leaveEvent = self.update_text
|
|
||||||
self.enterEvent = self.update_text
|
|
||||||
|
|
||||||
self.game_utils.game_launched.connect(self.game_started)
|
|
||||||
|
|
||||||
def update_text(self, e=None):
|
|
||||||
if self.update_available:
|
|
||||||
self.info_label.setText(self.texts["default"]["update_available"])
|
|
||||||
elif self.is_only_offline:
|
|
||||||
self.info_label.setText(self.texts["default"]["no_meta"])
|
|
||||||
elif self.igame and self.igame.needs_verification:
|
|
||||||
self.info_label.setText(self.texts["needs_verification"])
|
|
||||||
elif self.syncing_cloud_saves:
|
|
||||||
self.info_label.setText(self.texts["default"]["syncing"])
|
|
||||||
else:
|
|
||||||
self.info_label.setText("")
|
|
||||||
|
|
||||||
def game_started(self, app_name):
|
|
||||||
if app_name == self.game.app_name:
|
|
||||||
self.game_running = True
|
|
||||||
self.update_text()
|
|
||||||
self.launch_button.setDisabled(True)
|
|
||||||
|
|
||||||
def game_finished(self, app_name, error):
|
|
||||||
if app_name != self.game.app_name:
|
|
||||||
return
|
|
||||||
super().game_finished(app_name, error)
|
|
||||||
self.update_text(None)
|
|
||||||
self.launch_button.setDisabled(False)
|
|
|
@ -1,66 +0,0 @@
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from PyQt5.QtGui import QPixmap
|
|
||||||
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QFrame
|
|
||||||
from legendary.models.game import Game
|
|
||||||
|
|
||||||
from rare.shared import LegendaryCoreSingleton, ImageManagerSingleton
|
|
||||||
from rare.shared.image_manager import ImageSize
|
|
||||||
from rare.widgets.elide_label import ElideLabel
|
|
||||||
from .library_widget import LibraryWidget
|
|
||||||
|
|
||||||
|
|
||||||
class InstallingGameWidget(QFrame):
|
|
||||||
game: Game = None
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super(InstallingGameWidget, self).__init__()
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
layout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.setFixedWidth(ImageSize.Display.size.width())
|
|
||||||
self.setObjectName(type(self).__name__)
|
|
||||||
|
|
||||||
self.core = LegendaryCoreSingleton()
|
|
||||||
self.image_manager = ImageManagerSingleton()
|
|
||||||
|
|
||||||
self.pixmap = QPixmap()
|
|
||||||
self.image = LibraryWidget(parent=self)
|
|
||||||
self.image.setFixedSize(ImageSize.Display)
|
|
||||||
layout.addWidget(self.image)
|
|
||||||
|
|
||||||
miniwidget = QWidget(self)
|
|
||||||
miniwidget.setFixedWidth(ImageSize.Display.size.width())
|
|
||||||
minilayout = QHBoxLayout()
|
|
||||||
minilayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
minilayout.setSpacing(0)
|
|
||||||
miniwidget.setLayout(minilayout)
|
|
||||||
|
|
||||||
self.title_label = ElideLabel(f"<h4>Error</h4>", parent=miniwidget)
|
|
||||||
self.title_label.setAlignment(Qt.AlignTop)
|
|
||||||
self.title_label.setObjectName("game_widget")
|
|
||||||
minilayout.addWidget(self.title_label, stretch=2)
|
|
||||||
|
|
||||||
minilayout.setAlignment(Qt.AlignTop)
|
|
||||||
layout.addWidget(miniwidget)
|
|
||||||
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
def set_game(self, app_name):
|
|
||||||
self.game = self.core.get_game(app_name, False)
|
|
||||||
if (not self.game) or self.game.is_dlc:
|
|
||||||
# Don't show for EOS Overlay or DLCs
|
|
||||||
self.game = None
|
|
||||||
self.setVisible(False)
|
|
||||||
return
|
|
||||||
self.setVisible(True)
|
|
||||||
self.title_label.setText(f"<h4>{self.game.app_title}</h4>")
|
|
||||||
self.image.hideProgress(True)
|
|
||||||
self.image.showProgress(
|
|
||||||
self.image_manager.get_pixmap(app_name, color=True),
|
|
||||||
self.image_manager.get_pixmap(app_name, color=False),
|
|
||||||
)
|
|
||||||
|
|
||||||
def set_status(self, s: int):
|
|
||||||
if not self.game:
|
|
||||||
# Don't show for EOS Overlay or DLCs
|
|
||||||
return
|
|
||||||
self.image.updateProgress(s)
|
|
181
rare/components/tabs/games/game_widgets/list_game_widget.py
Normal file
181
rare/components/tabs/games/game_widgets/list_game_widget.py
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
|
from PyQt5.QtCore import Qt, QEvent, QRect
|
||||||
|
from PyQt5.QtCore import pyqtSignal
|
||||||
|
from PyQt5.QtGui import (
|
||||||
|
QPalette,
|
||||||
|
QBrush,
|
||||||
|
QPaintEvent,
|
||||||
|
QPainter,
|
||||||
|
QLinearGradient,
|
||||||
|
QPixmap, QImage, QResizeEvent,
|
||||||
|
)
|
||||||
|
|
||||||
|
from rare.components.tabs.games.game_utils import GameUtils
|
||||||
|
from rare.models.game import RareGame
|
||||||
|
from rare.utils.misc import get_size
|
||||||
|
from rare.widgets.image_widget import ImageWidget
|
||||||
|
from .game_widget import GameWidget
|
||||||
|
from .list_widget import ListWidget
|
||||||
|
|
||||||
|
logger = getLogger("ListGameWidget")
|
||||||
|
|
||||||
|
|
||||||
|
class ListGameWidget(GameWidget):
|
||||||
|
signal = pyqtSignal(str)
|
||||||
|
update_game = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, rgame: RareGame, game_utils: GameUtils, parent=None):
|
||||||
|
super(ListGameWidget, self).__init__(rgame, game_utils, parent)
|
||||||
|
self.setObjectName(f"{rgame.app_name}")
|
||||||
|
self.ui = ListWidget()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
|
||||||
|
self.ui.title_label.setText(f"<h3>{self.rgame.app_title}</h3>")
|
||||||
|
|
||||||
|
self.update_text()
|
||||||
|
|
||||||
|
self.ui.install_btn.setVisible(not self.rgame.is_installed)
|
||||||
|
self.ui.install_btn.clicked.connect(self.install)
|
||||||
|
|
||||||
|
self.ui.launch_btn.setText(
|
||||||
|
self.tr("Launch") if not self.rgame.is_origin else self.tr("Link/Play")
|
||||||
|
)
|
||||||
|
self.ui.launch_btn.clicked.connect(self.launch)
|
||||||
|
self.ui.launch_btn.setVisible(self.rgame.is_installed)
|
||||||
|
|
||||||
|
self.ui.developer_text.setText(self.rgame.developer)
|
||||||
|
# self.version_label.setVisible(self.is_installed)
|
||||||
|
if self.rgame.igame:
|
||||||
|
self.ui.version_text.setText(self.rgame.version)
|
||||||
|
|
||||||
|
self.ui.size_text.setText(get_size(self.rgame.install_size) if self.rgame.install_size else "")
|
||||||
|
|
||||||
|
# self.game_utils.cloud_save_finished.connect(self.sync_finished)
|
||||||
|
# self.game_utils.finished.connect(self.game_finished)
|
||||||
|
|
||||||
|
# self.game_utils.game_launched.connect(self.game_started)
|
||||||
|
|
||||||
|
self.ui.launch_btn.setEnabled(self.rgame.can_launch)
|
||||||
|
|
||||||
|
def update_text(self, e=None):
|
||||||
|
if self.rgame.is_installed:
|
||||||
|
if self.rgame.has_update:
|
||||||
|
self.ui.status_label.setText(self.texts["default"]["update_available"])
|
||||||
|
elif self.rgame.is_foreign:
|
||||||
|
self.ui.status_label.setText(self.texts["default"]["no_meta"])
|
||||||
|
elif self.rgame.igame and self.rgame.needs_verification:
|
||||||
|
self.ui.status_label.setText(self.texts["static"]["needs_verification"])
|
||||||
|
elif self.syncing_cloud_saves:
|
||||||
|
self.ui.status_label.setText(self.texts["default"]["syncing"])
|
||||||
|
else:
|
||||||
|
self.ui.status_label.setText("")
|
||||||
|
self.ui.status_label.setVisible(False)
|
||||||
|
else:
|
||||||
|
self.ui.status_label.setVisible(False)
|
||||||
|
|
||||||
|
def enterEvent(self, a0: QEvent = None) -> None:
|
||||||
|
status = self.enterEventText
|
||||||
|
self.ui.status_label.setText(status)
|
||||||
|
self.ui.status_label.setVisible(bool(status))
|
||||||
|
|
||||||
|
def leaveEvent(self, a0: QEvent = None) -> None:
|
||||||
|
status = self.leaveEventText
|
||||||
|
self.ui.status_label.setText(status)
|
||||||
|
self.ui.status_label.setVisible(bool(status))
|
||||||
|
|
||||||
|
def game_started(self, app_name):
|
||||||
|
if app_name == self.rgame.app_name:
|
||||||
|
self.game_running = True
|
||||||
|
self.update_text()
|
||||||
|
self.ui.launch_btn.setDisabled(True)
|
||||||
|
|
||||||
|
def game_finished(self, app_name, error):
|
||||||
|
if app_name != self.rgame.app_name:
|
||||||
|
return
|
||||||
|
super().game_finished(app_name, error)
|
||||||
|
self.update_text(None)
|
||||||
|
self.ui.launch_btn.setDisabled(False)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Painting and progress overrides.
|
||||||
|
Let them live here until a better alternative is divised.
|
||||||
|
|
||||||
|
The list widget and these painting functions can be
|
||||||
|
refactored to be used in downloads and/or dlcs
|
||||||
|
"""
|
||||||
|
|
||||||
|
def event(self, e: QEvent) -> bool:
|
||||||
|
if e.type() == QEvent.LayoutRequest:
|
||||||
|
if self.progress_label.isVisible():
|
||||||
|
width = int(self._pixmap.width() / self._pixmap.devicePixelRatioF())
|
||||||
|
origin = self.width() - width
|
||||||
|
fill_rect = QRect(origin, 0, width, self.sizeHint().height())
|
||||||
|
self.progress_label.setGeometry(fill_rect)
|
||||||
|
return ImageWidget.event(self, e)
|
||||||
|
|
||||||
|
def resizeEvent(self, a0: QResizeEvent) -> None:
|
||||||
|
if self.progress_label.isVisible():
|
||||||
|
width = int(self._pixmap.width() / self._pixmap.devicePixelRatioF())
|
||||||
|
origin = self.width() - width
|
||||||
|
fill_rect = QRect(origin, 0, width, self.sizeHint().height())
|
||||||
|
self.progress_label.setGeometry(fill_rect)
|
||||||
|
ImageWidget.resizeEvent(self, a0)
|
||||||
|
|
||||||
|
def prepare_pixmap(self, pixmap: QPixmap) -> QPixmap:
|
||||||
|
device: QImage = QImage(
|
||||||
|
pixmap.size().width() * 3,
|
||||||
|
int(self.sizeHint().height() * pixmap.devicePixelRatioF()) + 1,
|
||||||
|
QImage.Format_ARGB32_Premultiplied
|
||||||
|
)
|
||||||
|
painter = QPainter(device)
|
||||||
|
brush = QBrush(pixmap)
|
||||||
|
painter.fillRect(device.rect(), brush)
|
||||||
|
# the gradient could be cached and reused as it is expensive
|
||||||
|
gradient = QLinearGradient(0, 0, device.width(), 0)
|
||||||
|
gradient.setColorAt(0.15, Qt.transparent)
|
||||||
|
gradient.setColorAt(0.5, Qt.black)
|
||||||
|
gradient.setColorAt(0.85, Qt.transparent)
|
||||||
|
painter.setCompositionMode(QPainter.CompositionMode_DestinationIn)
|
||||||
|
painter.fillRect(device.rect(), gradient)
|
||||||
|
painter.end()
|
||||||
|
ret = QPixmap.fromImage(device)
|
||||||
|
ret.setDevicePixelRatio(pixmap.devicePixelRatioF())
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def setPixmap(self, pixmap: QPixmap) -> None:
|
||||||
|
# lk: trade some possible delay and start-up time
|
||||||
|
# lk: for faster rendering. Gradients are expensive
|
||||||
|
# lk: so pre-generate the image
|
||||||
|
super(ListGameWidget, self).setPixmap(self.prepare_pixmap(pixmap))
|
||||||
|
|
||||||
|
def paint_image_cover(self, painter: QPainter, a0: QPaintEvent) -> None:
|
||||||
|
painter.setOpacity(self._opacity)
|
||||||
|
color = self.palette().color(QPalette.Background).darker(75)
|
||||||
|
painter.fillRect(self.rect(), color)
|
||||||
|
brush = QBrush(self._pixmap)
|
||||||
|
brush.setTransform(self._transform)
|
||||||
|
width = int(self._pixmap.width() / self._pixmap.devicePixelRatioF())
|
||||||
|
origin = self.width() - width
|
||||||
|
painter.setBrushOrigin(origin, 0)
|
||||||
|
fill_rect = QRect(origin, 0, width, self.height())
|
||||||
|
painter.fillRect(fill_rect, brush)
|
||||||
|
|
||||||
|
def progressPixmap(self, color: QPixmap, gray: QPixmap, progress: int) -> QPixmap:
|
||||||
|
# lk: so about that +1 after the in convertion, casting to int rounds down
|
||||||
|
# lk: and that can create a weird line at the bottom, add 1 to round up.
|
||||||
|
device = QPixmap(
|
||||||
|
color.size().width(),
|
||||||
|
int(self.sizeHint().height() * color.devicePixelRatioF()) + 1,
|
||||||
|
)
|
||||||
|
painter = QPainter(device)
|
||||||
|
painter.setRenderHint(QPainter.SmoothPixmapTransform, self._smooth_transform)
|
||||||
|
painter.setCompositionMode(QPainter.CompositionMode_Source)
|
||||||
|
prog_h = (device.height() * progress // 100)
|
||||||
|
brush = QBrush(gray)
|
||||||
|
painter.fillRect(device.rect().adjusted(0, 0, 0, -prog_h), brush)
|
||||||
|
brush.setTexture(color)
|
||||||
|
painter.fillRect(device.rect().adjusted(0, device.height() - prog_h, 0, 0), brush)
|
||||||
|
painter.end()
|
||||||
|
device.setDevicePixelRatio(color.devicePixelRatioF())
|
||||||
|
return device
|
135
rare/components/tabs/games/game_widgets/list_widget.py
Normal file
135
rare/components/tabs/games/game_widgets/list_widget.py
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtGui import QFont
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QLabel,
|
||||||
|
QPushButton,
|
||||||
|
QSizePolicy,
|
||||||
|
QVBoxLayout,
|
||||||
|
QHBoxLayout,
|
||||||
|
QSpacerItem,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
from rare.utils.misc import icon
|
||||||
|
from rare.widgets.elide_label import ElideLabel
|
||||||
|
|
||||||
|
|
||||||
|
class ListWidget(object):
|
||||||
|
def setupUi(self, widget: QWidget):
|
||||||
|
self.title_label = QLabel(parent=widget)
|
||||||
|
self.title_label.setWordWrap(False)
|
||||||
|
|
||||||
|
self.status_label = QLabel(parent=widget)
|
||||||
|
self.status_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||||
|
self.status_label.setStyleSheet(
|
||||||
|
"background-color: rgba(0,0,0,75%);"
|
||||||
|
"border: 1px solid black;"
|
||||||
|
"border-radius: 5px;"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.install_btn = QPushButton(parent=widget)
|
||||||
|
self.install_btn.setIcon(icon("ri.install-fill"))
|
||||||
|
self.install_btn.setStyleSheet("text-align:left")
|
||||||
|
self.install_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||||
|
self.install_btn.setFixedWidth(120)
|
||||||
|
|
||||||
|
self.launch_btn = QPushButton(parent=widget)
|
||||||
|
self.launch_btn.setIcon(icon("ei.play-alt"))
|
||||||
|
self.launch_btn.setStyleSheet("text-align:left")
|
||||||
|
self.launch_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||||
|
self.launch_btn.setFixedWidth(120)
|
||||||
|
|
||||||
|
# self.info_btn = QPushButton(parent=widget)
|
||||||
|
# self.info_btn.setIcon(icon("ei.info-circle"))
|
||||||
|
# self.info_btn.setStyleSheet("text-align:left")
|
||||||
|
# self.info_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||||
|
# self.info_btn.setFixedWidth(120)
|
||||||
|
|
||||||
|
font = QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
# font.setWeight(75)
|
||||||
|
|
||||||
|
# self.developer_label = QLabel(parent=widget)
|
||||||
|
# self.developer_label.setStyleSheet(f"color: #999;")
|
||||||
|
# self.developer_label.setFont(font)
|
||||||
|
self.developer_text = ElideLabel(parent=widget)
|
||||||
|
self.developer_text.setFixedWidth(120)
|
||||||
|
self.developer_text.setStyleSheet(f"color: #999;")
|
||||||
|
|
||||||
|
# self.version_label = QLabel(parent=widget)
|
||||||
|
# self.version_label.setStyleSheet(f"color: #999;")
|
||||||
|
# self.version_label.setFont(font)
|
||||||
|
self.version_text = ElideLabel(parent=widget)
|
||||||
|
self.version_text.setFixedWidth(120)
|
||||||
|
self.version_text.setStyleSheet(f"color: #999;")
|
||||||
|
|
||||||
|
# self.size_label = QLabel(parent=widget)
|
||||||
|
# self.size_label.setStyleSheet(f"color: #999;")
|
||||||
|
# self.size_label.setFont(font)
|
||||||
|
self.size_text = ElideLabel(parent=widget)
|
||||||
|
self.size_text.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
|
||||||
|
self.size_text.setFixedWidth(60)
|
||||||
|
self.size_text.setStyleSheet(f"color: #999;")
|
||||||
|
|
||||||
|
# Create layouts
|
||||||
|
top_layout = QHBoxLayout()
|
||||||
|
top_layout.setAlignment(Qt.AlignLeft)
|
||||||
|
|
||||||
|
bottom_layout = QHBoxLayout()
|
||||||
|
bottom_layout.setAlignment(Qt.AlignRight)
|
||||||
|
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.setSpacing(0)
|
||||||
|
layout.setContentsMargins(3, 3, 3, 3)
|
||||||
|
|
||||||
|
# Layout the widgets
|
||||||
|
# (from inner to outer)
|
||||||
|
top_layout.addWidget(self.title_label, stretch=1)
|
||||||
|
# top_layout.addWidget(self.status_label, stretch=0)
|
||||||
|
|
||||||
|
bottom_layout.addWidget(self.developer_text, stretch=0, alignment=Qt.AlignLeft)
|
||||||
|
bottom_layout.addItem(QSpacerItem(20, 0, QSizePolicy.Fixed, QSizePolicy.Minimum))
|
||||||
|
bottom_layout.addWidget(self.version_text, stretch=0, alignment=Qt.AlignLeft)
|
||||||
|
bottom_layout.addItem(QSpacerItem(20, 0, QSizePolicy.Fixed, QSizePolicy.Minimum))
|
||||||
|
bottom_layout.addWidget(self.size_text, stretch=0, alignment=Qt.AlignLeft)
|
||||||
|
bottom_layout.addItem(QSpacerItem(20, 0, QSizePolicy.Expanding, QSizePolicy.Minimum))
|
||||||
|
bottom_layout.addWidget(self.status_label, stretch=0, alignment=Qt.AlignRight)
|
||||||
|
# bottom_layout.addWidget(self.info_btn, stretch=0, alignment=Qt.AlignRight)
|
||||||
|
bottom_layout.addWidget(self.install_btn, stretch=0, alignment=Qt.AlignRight)
|
||||||
|
bottom_layout.addWidget(self.launch_btn, stretch=0, alignment=Qt.AlignRight)
|
||||||
|
|
||||||
|
layout.addLayout(top_layout)
|
||||||
|
layout.addLayout(bottom_layout)
|
||||||
|
|
||||||
|
widget.setLayout(layout)
|
||||||
|
|
||||||
|
widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
|
||||||
|
|
||||||
|
# lk: for debug, DO NOT REMOVE
|
||||||
|
# self.image.setObjectName(f"{type(self).__name__}_image")
|
||||||
|
# self.title_label.setObjectName(f"{type(self).__name__}_title_label")
|
||||||
|
# self.status_label.setObjectName(f"{type(self).__name__}_status_label")
|
||||||
|
# self.status_label.setObjectName(f"{type(self).__name__}_progress")
|
||||||
|
# self.install_btn.setObjectName(f"{type(self).__name__}_install_btn")
|
||||||
|
# self.launch_btn.setObjectName(f"{type(self).__name__}_launch_btn")
|
||||||
|
# self.info_btn.setObjectName(f"{type(self).__name__}_info_btn")
|
||||||
|
# self.developer_label.setObjectName(f"{type(self).__name__}_developer_label")
|
||||||
|
# self.developer_text.setObjectName(f"{type(self).__name__}_developer_text")
|
||||||
|
# self.version_label.setObjectName(f"{type(self).__name__}_version_label")
|
||||||
|
# self.version_text.setObjectName(f"{type(self).__name__}_version_text")
|
||||||
|
# self.size_label.setObjectName(f"{type(self).__name__}_size_label")
|
||||||
|
# self.size_text.setObjectName(f"{type(self).__name__}_size_text")
|
||||||
|
# middle_layout.setObjectName(f"{type(self).__name__}_info_layout")
|
||||||
|
# form_layout.setObjectName(f"{type(self).__name__}_form_layout")
|
||||||
|
# right_layout.setObjectName(f"{type(self).__name__}_button_layout")
|
||||||
|
# right_layout.setObjectName(f"{type(self).__name__}_right_layout")
|
||||||
|
# layout.setObjectName(f"{type(self).__name__}_layout")
|
||||||
|
|
||||||
|
self.translateUi(widget)
|
||||||
|
|
||||||
|
def translateUi(self, widget: QWidget):
|
||||||
|
# self.info_btn.setText(widget.tr("Information"))
|
||||||
|
self.install_btn.setText(widget.tr("Install"))
|
||||||
|
# self.developer_label.setText(widget.tr("Developer"))
|
||||||
|
# self.version_label.setText(widget.tr("Version"))
|
||||||
|
# self.size_label.setText(widget.tr("Installed size"))
|
|
@ -1,67 +0,0 @@
|
||||||
from logging import getLogger
|
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from PyQt5.QtWidgets import QVBoxLayout, QWidget, QHBoxLayout
|
|
||||||
from legendary.core import LegendaryCore
|
|
||||||
from legendary.models.game import Game
|
|
||||||
|
|
||||||
from rare.components.tabs.games.game_widgets.base_uninstalled_widget import (
|
|
||||||
BaseUninstalledWidget,
|
|
||||||
)
|
|
||||||
from rare.shared.image_manager import ImageSize
|
|
||||||
from rare.widgets.elide_label import ElideLabel
|
|
||||||
|
|
||||||
logger = getLogger("Uninstalled")
|
|
||||||
|
|
||||||
|
|
||||||
class UninstalledIconWidget(BaseUninstalledWidget):
|
|
||||||
def __init__(self, game: Game, core: LegendaryCore, pixmap):
|
|
||||||
super(UninstalledIconWidget, self).__init__(game, core, pixmap)
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
layout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.setObjectName(type(self).__name__)
|
|
||||||
layout.addWidget(self.image)
|
|
||||||
|
|
||||||
miniwidget = QWidget(self)
|
|
||||||
miniwidget.setFixedWidth(ImageSize.Display.size.width())
|
|
||||||
minilayout = QHBoxLayout()
|
|
||||||
minilayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
minilayout.setSpacing(0)
|
|
||||||
miniwidget.setLayout(minilayout)
|
|
||||||
|
|
||||||
self.title_label = ElideLabel(f"<b>{game.app_title}</b>", parent=miniwidget)
|
|
||||||
self.title_label.setAlignment(Qt.AlignTop)
|
|
||||||
self.title_label.setObjectName("game_widget")
|
|
||||||
minilayout.addWidget(self.title_label, stretch=2)
|
|
||||||
|
|
||||||
minilayout.setAlignment(Qt.AlignTop)
|
|
||||||
layout.addWidget(miniwidget)
|
|
||||||
|
|
||||||
self.info_label = ElideLabel(" ", parent=self)
|
|
||||||
self.info_label.setFixedWidth(ImageSize.Display.size.width())
|
|
||||||
self.leaveEvent(None)
|
|
||||||
self.info_label.setObjectName("info_label")
|
|
||||||
layout.addWidget(self.info_label)
|
|
||||||
|
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
def mousePressEvent(self, e) -> None:
|
|
||||||
# left button
|
|
||||||
if e.button() == 1 and not self.installing:
|
|
||||||
self.install()
|
|
||||||
|
|
||||||
# right
|
|
||||||
elif e.button() == 2:
|
|
||||||
pass # self.showMenu(e)
|
|
||||||
|
|
||||||
def enterEvent(self, e):
|
|
||||||
if not self.installing:
|
|
||||||
self.info_label.setText(self.tr("Game Info"))
|
|
||||||
else:
|
|
||||||
self.info_label.setText(self.tr("Installation running"))
|
|
||||||
|
|
||||||
def leaveEvent(self, e):
|
|
||||||
if self.installing:
|
|
||||||
self.info_label.setText("Installation...")
|
|
||||||
else:
|
|
||||||
self.info_label.setText(" ") # invisible text, cheap way to always have vertical size in label
|
|
|
@ -1,36 +0,0 @@
|
||||||
from logging import getLogger
|
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from PyQt5.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QPushButton
|
|
||||||
|
|
||||||
from legendary.core import LegendaryCore
|
|
||||||
from rare.components.tabs.games.game_widgets.base_uninstalled_widget import (
|
|
||||||
BaseUninstalledWidget,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = getLogger("Game")
|
|
||||||
|
|
||||||
|
|
||||||
class UninstalledListWidget(BaseUninstalledWidget):
|
|
||||||
def __init__(self, core: LegendaryCore, game, pixmap):
|
|
||||||
super(UninstalledListWidget, self).__init__(game, core, pixmap)
|
|
||||||
self.setFrameStyle(self.StyledPanel)
|
|
||||||
layout = QHBoxLayout()
|
|
||||||
self.setLayout(layout)
|
|
||||||
layout.addWidget(self.image)
|
|
||||||
|
|
||||||
self.child_layout = QVBoxLayout()
|
|
||||||
layout.addLayout(self.child_layout)
|
|
||||||
|
|
||||||
self.title_label = QLabel(f"<h2>{self.game.app_title}</h2>")
|
|
||||||
self.app_name_label = QLabel(f"App Name: {self.game.app_name}")
|
|
||||||
self.install_button = QPushButton(self.tr("Install"))
|
|
||||||
self.install_button.setFixedWidth(120)
|
|
||||||
self.install_button.clicked.connect(self.install)
|
|
||||||
|
|
||||||
self.child_layout.addWidget(self.title_label)
|
|
||||||
self.child_layout.addWidget(self.app_name_label)
|
|
||||||
self.child_layout.addWidget(self.install_button)
|
|
||||||
|
|
||||||
layout.setAlignment(Qt.AlignLeft)
|
|
||||||
self.child_layout.setAlignment(Qt.AlignTop)
|
|
|
@ -66,7 +66,7 @@ class TrayIcon(QSystemTrayIcon):
|
||||||
self.setContextMenu(self.menu)
|
self.setContextMenu(self.menu)
|
||||||
|
|
||||||
self.signals = GlobalSignalsSingleton()
|
self.signals = GlobalSignalsSingleton()
|
||||||
self.signals.game_uninstalled.connect(self.remove_button)
|
self.signals.game.uninstalled.connect(self.remove_button)
|
||||||
|
|
||||||
def remove_button(self, app_name: str):
|
def remove_button(self, app_name: str):
|
||||||
if action := next((i for i in self.game_actions if i.property("app_name") == app_name), None):
|
if action := next((i for i in self.game_actions if i.property("app_name") == app_name), None):
|
||||||
|
|
|
@ -71,17 +71,17 @@ class RareGame(QObject):
|
||||||
progress: int = 0
|
progress: int = 0
|
||||||
active_thread: Optional[QRunnable] = None
|
active_thread: Optional[QRunnable] = None
|
||||||
|
|
||||||
def __init__(self, legendary_core: LegendaryCore, image_manager: ImageManager, game: Game):
|
def __init__(self, game: Game, legendary_core: LegendaryCore, image_manager: ImageManager):
|
||||||
super(RareGame, self).__init__()
|
super(RareGame, self).__init__()
|
||||||
self.signals = RareGame.Signals()
|
self.signals = RareGame.Signals()
|
||||||
|
|
||||||
self.core = legendary_core
|
self.core = legendary_core
|
||||||
self.image_manager = image_manager
|
self.image_manager = image_manager
|
||||||
|
|
||||||
# Update names for Unreal Engine
|
|
||||||
if game.app_title == "Unreal Engine":
|
|
||||||
game.app_title += f" {game.app_name.split('_')[-1]}"
|
|
||||||
self.game: Game = game
|
self.game: Game = game
|
||||||
|
# Update names for Unreal Engine
|
||||||
|
if self.game.app_title == "Unreal Engine":
|
||||||
|
self.game.app_title += f" {self.game.app_name.split('_')[-1]}"
|
||||||
|
|
||||||
# None if origin or not installed
|
# None if origin or not installed
|
||||||
self.igame: Optional[InstalledGame] = self.core.get_installed_game(game.app_name)
|
self.igame: Optional[InstalledGame] = self.core.get_installed_game(game.app_name)
|
||||||
|
|
|
@ -10,18 +10,34 @@ class GlobalSignals(QObject):
|
||||||
set_main_tab_index = pyqtSignal(int) # tab index
|
set_main_tab_index = pyqtSignal(int) # tab index
|
||||||
update_download_tab_text = pyqtSignal()
|
update_download_tab_text = pyqtSignal()
|
||||||
|
|
||||||
dl_progress = pyqtSignal(int) # 0-100
|
class ProgressSignals(QObject):
|
||||||
# set visibility of installing widget in games tab
|
# str: app_name
|
||||||
installation_started = pyqtSignal(str) # app_name
|
started = pyqtSignal(str)
|
||||||
add_download = pyqtSignal(str)
|
# str: app_name, int: progress
|
||||||
|
value = pyqtSignal(str, int)
|
||||||
|
# str: app_name, bool: stopped
|
||||||
|
finished = pyqtSignal(str, bool)
|
||||||
|
progress = ProgressSignals()
|
||||||
|
|
||||||
install_game = pyqtSignal(InstallOptionsModel)
|
class GameSignals(QObject):
|
||||||
installation_finished = pyqtSignal(bool, str)
|
install = pyqtSignal(InstallOptionsModel)
|
||||||
|
# list of app_name
|
||||||
|
installed = pyqtSignal(list)
|
||||||
|
# str: app_name
|
||||||
|
uninstalled = pyqtSignal(str)
|
||||||
|
# str: app_name
|
||||||
|
verified = pyqtSignal(str)
|
||||||
|
game = GameSignals()
|
||||||
|
|
||||||
|
class DownloadSignals(QObject):
|
||||||
|
# str: app_name
|
||||||
|
enqueue_game = pyqtSignal(str)
|
||||||
|
download = DownloadSignals()
|
||||||
|
|
||||||
overlay_installation_finished = pyqtSignal()
|
overlay_installation_finished = pyqtSignal()
|
||||||
|
|
||||||
update_gamelist = pyqtSignal(list)
|
# update_gamelist = pyqtSignal(list)
|
||||||
game_uninstalled = pyqtSignal(str) # appname
|
# game_uninstalled = pyqtSignal(str)
|
||||||
|
|
||||||
set_discord_rpc = pyqtSignal(str) # app_name of running game
|
set_discord_rpc = pyqtSignal(str) # app_name of running game
|
||||||
rpc_settings_updated = pyqtSignal()
|
rpc_settings_updated = pyqtSignal()
|
||||||
|
|
Loading…
Reference in a new issue