1
0
Fork 0
mirror of synced 2024-06-02 02:34:40 +12:00
Rare/rare/components/tabs/games/game_widgets/__init__.py
loathingKernel b1e537af43 Library: Initialize only one view on each run
Do not create multiple library views and remove the ability to switch
between them on the fly. Add an option in settings to select the preferred
view. The view will be used the next time Rare is started.
2024-02-12 21:52:08 +02:00

218 lines
8.8 KiB
Python

from abc import abstractmethod
from typing import Tuple, List, Union, Type, TypeVar
from PyQt5.QtCore import QObject, pyqtSlot, Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QScrollArea
from rare.lgndr.core import LegendaryCore
from rare.models.game import RareGame
from rare.models.signals import GlobalSignals
from rare.models.library import LibraryFilter, LibraryOrder, LibraryView
from rare.shared import RareCore
from rare.widgets.library_layout import LibraryLayout
from .icon_game_widget import IconGameWidget
from .list_game_widget import ListGameWidget
ViewWidget = TypeVar("ViewWidget", IconGameWidget, ListGameWidget)
class ViewContainer(QWidget):
def __init__(self, rcore: RareCore, parent=None):
super().__init__(parent=parent)
self.rcore: RareCore = rcore
def _add_widget(self, widget_type: Type[ViewWidget], rgame: RareGame) -> ViewWidget:
widget = widget_type(rgame, self)
self.layout().addWidget(widget)
return widget
@staticmethod
def __visibility(widget: ViewWidget, library_filter, search_text) -> Tuple[bool, float]:
if library_filter == LibraryFilter.HIDDEN:
visible = "hidden" in widget.rgame.metadata.tags
elif "hidden" in widget.rgame.metadata.tags:
visible = False
elif library_filter == LibraryFilter.INSTALLED:
visible = widget.rgame.is_installed and not widget.rgame.is_unreal
elif library_filter == LibraryFilter.OFFLINE:
visible = widget.rgame.can_run_offline and not widget.rgame.is_unreal
elif library_filter == LibraryFilter.WIN32:
visible = widget.rgame.is_win32 and not widget.rgame.is_unreal
elif library_filter == LibraryFilter.MAC:
visible = widget.rgame.is_mac and not widget.rgame.is_unreal
elif library_filter == LibraryFilter.INSTALLABLE:
visible = not widget.rgame.is_non_asset and not widget.rgame.is_unreal
elif library_filter == LibraryFilter.INCLUDE_UE:
visible = True
elif library_filter == LibraryFilter.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_view(self, widget_type: Type[ViewWidget], filter_by: LibraryFilter = LibraryFilter.ALL, search_text: str = ""):
widgets = self.findChildren(widget_type)
for iw in widgets:
visibility, opacity = self.__visibility(iw, filter_by, search_text)
iw.setOpacity(opacity)
iw.setVisible(visibility)
def _update_view(self, widget_type: Type[ViewWidget]):
widgets = self.findChildren(widget_type)
app_names = {iw.rgame.app_name for iw in widgets}
games = list(self.rcore.games)
game_app_names = {g.app_name for g in games}
new_app_names = game_app_names.difference(app_names)
for app_name in new_app_names:
game = self.rcore.get_game(app_name)
w = widget_type(game, self)
self.layout().addWidget(w)
def _find_widget(self, widget_type: Type[ViewWidget], app_name: str) -> ViewWidget:
w = self.findChild(widget_type, app_name)
return w
@abstractmethod
def order_view(self):
pass
class IconViewContainer(ViewContainer):
def __init__(self, rcore: RareCore, parent=None):
super().__init__(rcore, parent=parent)
view_layout = LibraryLayout(self)
view_layout.setSpacing(9)
view_layout.setContentsMargins(0, 13, 0, 13)
view_layout.setAlignment(Qt.AlignTop)
self.setLayout(view_layout)
def add_widget(self, rgame: RareGame) -> IconGameWidget:
return self._add_widget(IconGameWidget, rgame)
def filter_view(self, filter_by: LibraryFilter = LibraryFilter.ALL, search_text: str = ""):
self._filter_view(IconGameWidget, filter_by, search_text)
def update_view(self):
self._update_view(IconGameWidget)
def find_widget(self, app_name: str) -> ViewWidget:
return self._find_widget(IconGameWidget, app_name)
def order_view(self, order_by: LibraryOrder = LibraryOrder.TITLE, search_text: str = ""):
if search_text:
self.layout().sort(
lambda x: (search_text not in x.widget().rgame.app_title.lower(),)
)
else:
if (newest := order_by == LibraryOrder.NEWEST) or order_by == LibraryOrder.OLDEST:
# Sort by grant date
self.layout().sort(
key=lambda x: (x.widget().rgame.is_installed, not x.widget().rgame.is_non_asset, x.widget().rgame.grant_date()),
reverse=newest,
)
elif order_by == LibraryOrder.RECENT:
# Sort by recently played
self.layout().sort(
key=lambda x: (not x.widget().rgame.is_installed, x.widget().rgame.is_non_asset, x.widget().rgame.metadata.last_played),
reverse=True,
)
else:
# Sort by title
self.layout().sort(
key=lambda x: (not x.widget().rgame.is_installed, x.widget().rgame.is_non_asset, x.widget().rgame.app_title)
)
class ListViewContainer(ViewContainer):
def __init__(self, rcore, parent=None):
super().__init__(rcore, parent=parent)
view_layout = QVBoxLayout(self)
view_layout.setContentsMargins(3, 3, 9, 3)
view_layout.setAlignment(Qt.AlignTop)
self.setLayout(view_layout)
def add_widget(self, rgame: RareGame) -> ListGameWidget:
return self._add_widget(ListGameWidget, rgame)
def filter_view(self, filter_by: LibraryFilter = LibraryFilter.ALL, search_text: str = ""):
self._filter_view(ListGameWidget, filter_by, search_text)
def update_view(self):
self._update_view(ListGameWidget)
def find_widget(self, app_name: str) -> ViewWidget:
return self._find_widget(ListGameWidget, app_name)
def order_view(self, order_by: LibraryOrder = LibraryOrder.TITLE, search_text: str = ""):
list_widgets = self.findChildren(ListGameWidget)
if search_text:
list_widgets.sort(key=lambda x: (search_text not in x.rgame.app_title.lower(),))
else:
if (newest := order_by == LibraryOrder.NEWEST) or order_by == LibraryOrder.OLDEST:
list_widgets.sort(
key=lambda x: (x.rgame.is_installed, not x.rgame.is_non_asset, x.rgame.grant_date()),
reverse=newest,
)
elif order_by == LibraryOrder.RECENT:
list_widgets.sort(
key=lambda x: (not x.rgame.is_installed, x.rgame.is_non_asset, x.rgame.metadata.last_played),
reverse=True,
)
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.layout().insertWidget(idx, wl)
class LibraryWidgetController(QObject):
def __init__(self, view: LibraryView, parent: QScrollArea = None):
super(LibraryWidgetController, self).__init__(parent=parent)
self.rcore = RareCore.instance()
self.core: LegendaryCore = self.rcore.core()
self.signals: GlobalSignals = self.rcore.signals()
if view == LibraryView.COVER:
self._container: IconViewContainer = IconViewContainer(self.rcore, parent)
else:
self._container: ListViewContainer = ListViewContainer(self.rcore, parent)
parent.setWidget(self._container)
self.signals.game.installed.connect(self.order_game_views)
self.signals.game.uninstalled.connect(self.order_game_views)
def add_game(self, rgame: RareGame):
return self.add_widgets(rgame)
def add_widgets(self, rgame: RareGame) -> ViewWidget:
return self._container.add_widget(rgame)
def filter_game_views(self, filter_by: LibraryFilter = LibraryFilter.ALL, search_text: str = ""):
self._container.filter_view(filter_by, search_text)
self.order_game_views(search_text=search_text)
@pyqtSlot()
def order_game_views(self, order_by: LibraryOrder = LibraryOrder.TITLE, search_text: str = ""):
self._container.order_view(order_by, search_text)
@pyqtSlot()
@pyqtSlot(list)
def update_game_views(self, app_names: List[str] = None):
if app_names:
return
self._container.update_view()
self.order_game_views()
def __find_widget(self, app_name: str) -> Union[ViewWidget, None]:
return self._container.find_widget(app_name)