Skip to content

Commit

Permalink
Wrappers/Proton/Wine WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
loathingKernel committed Nov 20, 2023
1 parent 94d9c25 commit 9770816
Show file tree
Hide file tree
Showing 29 changed files with 1,168 additions and 662 deletions.
39 changes: 21 additions & 18 deletions rare/components/tabs/games/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from rare.widgets.library_layout import LibraryLayout
from rare.widgets.sliding_stack import SlidingStackedWidget
from .game_info import GameInfoTabs
from .game_widgets import LibraryWidgetController
from .game_widgets import LibraryWidgetController, LibraryFilter, LibraryOrder
from .game_widgets.icon_game_widget import IconGameWidget
from .game_widgets.list_game_widget import ListGameWidget
from .head_bar import GameListHeadBar
Expand All @@ -33,8 +33,6 @@ def __init__(self, parent=None):
self.image_manager = ImageManagerSingleton()
self.settings = QSettings()

self.active_filter: int = 0

self.games_page = QWidget(parent=self)
games_page_layout = QVBoxLayout(self.games_page)
self.addWidget(self.games_page)
Expand Down Expand Up @@ -94,14 +92,11 @@ def __init__(self, parent=None):
self.head_bar.search_bar.textChanged.connect(self.scroll_to_top)
self.head_bar.filterChanged.connect(self.filter_games)
self.head_bar.filterChanged.connect(self.scroll_to_top)
self.head_bar.refresh_list.clicked.connect(self.library_controller.update_list)
self.head_bar.orderChanged.connect(self.order_games)
self.head_bar.orderChanged.connect(self.scroll_to_top)
self.head_bar.refresh_list.clicked.connect(self.library_controller.update_game_views)
self.head_bar.view.toggled.connect(self.toggle_view)

f = self.settings.value("filter", 0, int)
if f >= len(self.head_bar.available_filters):
f = 0
self.active_filter = self.head_bar.available_filters[f]

# signals
self.signals.game.installed.connect(self.update_count_games_label)
self.signals.game.uninstalled.connect(self.update_count_games_label)
Expand Down Expand Up @@ -153,7 +148,7 @@ def setup_game_list(self):
continue
self.icon_view.layout().addWidget(icon_widget)
self.list_view.layout().addWidget(list_widget)
self.filter_games(self.active_filter)
self.filter_games(self.head_bar.current_filter())
self.update_count_games_label()

def add_library_widget(self, rgame: RareGame):
Expand All @@ -167,18 +162,26 @@ def add_library_widget(self, rgame: RareGame):
list_widget.show_info.connect(self.show_game_info)
return icon_widget, list_widget

@pyqtSlot(str)
@pyqtSlot(str, str)
def filter_games(self, filter_name="all", search_text: str = ""):
@pyqtSlot(int)
@pyqtSlot(int, str)
def filter_games(self, library_filter: LibraryFilter = LibraryFilter.ALL, search_text: str = ""):
if not search_text and (t := self.head_bar.search_bar.text()):
search_text = t

if filter_name:
self.active_filter = filter_name
if not filter_name and (t := self.active_filter):
filter_name = t
# if library_filter:
# self.active_filter = filter_type
# if not library_filter and (t := self.active_filter):
# library_filter = t

self.library_controller.filter_game_views(library_filter, search_text.lower())

@pyqtSlot(int)
@pyqtSlot(int, str)
def order_games(self, library_order: LibraryOrder = LibraryFilter.ALL, search_text: str = ""):
if not search_text and (t := self.head_bar.search_bar.text()):
search_text = t

self.library_controller.filter_list(filter_name, search_text.lower())
self.library_controller.order_game_views(library_order, search_text.lower())

def toggle_view(self):
self.settings.setValue("icon_view", not self.head_bar.view.isChecked())
Expand Down
22 changes: 11 additions & 11 deletions rare/components/tabs/games/game_info/cloud_saves.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from logging import getLogger
from typing import Tuple

from PyQt5.QtCore import QThreadPool, QSettings
from PyQt5.QtCore import QThreadPool, QSettings, pyqtSlot
from PyQt5.QtWidgets import (
QWidget,
QFileDialog,
Expand All @@ -19,10 +19,11 @@

from rare.models.game import RareGame
from rare.shared import RareCore
from rare.shared.workers.wine_resolver import WineResolver
from rare.shared.workers.wine_resolver import WineSavePathResolver
from rare.ui.components.tabs.games.game_info.cloud_widget import Ui_CloudWidget
from rare.ui.components.tabs.games.game_info.sync_widget import Ui_SyncWidget
from rare.utils.misc import icon
from rare.utils.metrics import timelogger
from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon
from rare.widgets.loading_widget import LoadingWidget
from rare.widgets.side_tab import SideTabContents
Expand Down Expand Up @@ -110,13 +111,14 @@ def download(self):
def compute_save_path(self):
if self.rgame.is_installed and self.rgame.game.supports_cloud_saves:
try:
new_path = self.core.get_save_path(self.rgame.app_name)
with timelogger(logger, "Detecting save path"):
new_path = self.core.get_save_path(self.rgame.app_name)
if platform.system() != "Windows" and not os.path.exists(new_path):
raise ValueError(f'Path "{new_path}" does not exist.')
except Exception as e:
logger.warning(str(e))
resolver = WineResolver(self.core, self.rgame.raw_save_path, self.rgame.app_name)
if not resolver.wine_env.get("WINEPREFIX"):
resolver = WineSavePathResolver(self.core, self.rgame)
if not resolver.environment.get("WINEPREFIX"):
del resolver
self.cloud_save_path_edit.setText("")
QMessageBox.warning(self, "Warning", "No wine prefix selected. Please set it in settings")
Expand All @@ -125,21 +127,21 @@ def compute_save_path(self):
self.cloud_save_path_edit.setDisabled(True)
self.compute_save_path_button.setDisabled(True)

app_name = self.rgame.app_name
resolver.signals.result_ready.connect(lambda x: self.wine_resolver_finished(x, app_name))
resolver.signals.result_ready.connect(self.__on_wine_resolver_result)
QThreadPool.globalInstance().start(resolver)
return
else:
self.cloud_save_path_edit.setText(new_path)

def wine_resolver_finished(self, path, app_name):
@pyqtSlot(str, str)
def __on_wine_resolver_result(self, path, app_name):
logger.info(f"Wine resolver finished for {app_name}. Computed save path: {path}")
if app_name == self.rgame.app_name:
self.cloud_save_path_edit.setDisabled(False)
self.compute_save_path_button.setDisabled(False)
if path and not os.path.exists(path):
try:
os.makedirs(path)
os.makedirs(path, exist_ok=True)
except PermissionError:
self.cloud_save_path_edit.setText("")
QMessageBox.warning(
Expand All @@ -154,8 +156,6 @@ def wine_resolver_finished(self, path, app_name):
self.cloud_save_path_edit.setText("")
return
self.cloud_save_path_edit.setText(path)
elif path:
self.rcore.get_game(app_name).save_path = path

def __update_widget(self):
supports_saves = self.rgame.igame is not None and (
Expand Down
109 changes: 70 additions & 39 deletions rare/components/tabs/games/game_widgets/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Tuple, List, Union, Optional
from enum import IntEnum
from typing import Tuple, List, Union

from PyQt5.QtCore import QObject, pyqtSlot
from PyQt5.QtWidgets import QWidget
Expand All @@ -11,6 +12,24 @@
from .list_game_widget import ListGameWidget


class LibraryFilter(IntEnum):
ALL = 1
INSTALLED = 2
OFFLINE = 3
HIDDEN = 4
WIN32 = 5
MAC = 6
INSTALLABLE = 7
INCLUDE_UE = 8


class LibraryOrder(IntEnum):
TITLE = 1
RECENT = 2
NEWEST = 3
OLDEST = 4


class LibraryWidgetController(QObject):
def __init__(self, icon_container: QWidget, list_container: QWidget, parent: QWidget = None):
super(LibraryWidgetController, self).__init__(parent=parent)
Expand All @@ -20,8 +39,8 @@ def __init__(self, icon_container: QWidget, list_container: QWidget, parent: QWi
self.core: LegendaryCore = self.rcore.core()
self.signals: GlobalSignals = self.rcore.signals()

self.signals.game.installed.connect(self.sort_list)
self.signals.game.uninstalled.connect(self.sort_list)
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)
Expand All @@ -32,24 +51,26 @@ def add_widgets(self, rgame: RareGame) -> Tuple[IconGameWidget, ListGameWidget]:
return icon_widget, list_widget

@staticmethod
def __visibility(widget: Union[IconGameWidget,ListGameWidget], filter_name, search_text) -> Tuple[bool, float]:
if filter_name == "hidden":
def __visibility(
widget: Union[IconGameWidget, ListGameWidget], 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 filter_name == "installed":
elif library_filter == LibraryFilter.INSTALLED:
visible = widget.rgame.is_installed
elif filter_name == "offline":
elif library_filter == LibraryFilter.OFFLINE:
visible = widget.rgame.can_run_offline
elif filter_name == "32bit":
elif library_filter == LibraryFilter.WIN32:
visible = widget.rgame.is_win32
elif filter_name == "mac":
elif library_filter == LibraryFilter.MAC:
visible = widget.rgame.is_mac
elif filter_name == "installable":
elif library_filter == LibraryFilter.INSTALLABLE:
visible = not widget.rgame.is_non_asset
elif filter_name == "include_ue":
elif library_filter == LibraryFilter.INCLUDE_UE:
visible = True
elif filter_name == "all":
elif library_filter == LibraryFilter.ALL:
visible = not widget.rgame.is_unreal
else:
visible = True
Expand All @@ -64,7 +85,7 @@ def __visibility(widget: Union[IconGameWidget,ListGameWidget], filter_name, sear

return visible, opacity

def filter_list(self, filter_name="all", search_text: str = ""):
def filter_game_views(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:
Expand All @@ -75,42 +96,52 @@ def filter_list(self, filter_name="all", search_text: str = ""):
visibility, opacity = self.__visibility(lw, filter_name, search_text)
lw.setOpacity(opacity)
lw.setVisible(visibility)
self.sort_list(search_text)
self.order_game_views(search_text=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:
def order_game_views(self, order_by: LibraryOrder = LibraryOrder.TITLE, search_text: str = ""):
list_widgets = self._list_container.findChildren(ListGameWidget)
if search_text:
self._icon_container.layout().sort(
key=lambda x: (
# Sort by grant date
# x.widget().rgame.is_installed,
# not x.widget().rgame.is_non_asset,
# x.widget().rgame.grant_date(),
# ), reverse=True
not x.widget().rgame.is_installed,
x.widget().rgame.is_non_asset,
x.widget().rgame.app_title,
)
lambda x: (search_text not in x.widget().rgame.app_title.lower(),)
)
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(),))
list_widgets.sort(key=lambda x: (search_text not in x.rgame.app_title.lower(),))
else:
list_widgets.sort(
if (newest := order_by == LibraryOrder.NEWEST) or order_by == LibraryOrder.OLDEST:
# Sort by grant date
# key=lambda x: (x.rgame.is_installed, not x.rgame.is_non_asset, x.rgame.grant_date()), reverse=True
key=lambda x: (not x.rgame.is_installed, x.rgame.is_non_asset, x.rgame.app_title)
)
self._icon_container.layout().sort(
key=lambda x: (x.widget().rgame.is_installed, not x.widget().rgame.is_non_asset, x.widget().rgame.grant_date()),
reverse=newest,
)
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:
# Sort by recently played
self._icon_container.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,
)
list_widgets.sort(
key=lambda x: (not x.rgame.is_installed, x.rgame.is_non_asset, x.rgame.metadata.last_played),
reverse=True,
)
else:
# Sort by title
self._icon_container.layout().sort(
key=lambda x: (not x.widget().rgame.is_installed, x.widget().rgame.is_non_asset, x.widget().rgame.app_title)
)
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):
def update_game_views(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)
Expand All @@ -129,7 +160,7 @@ def update_list(self, app_names: List[str] = None):
game = self.rcore.get_game(app_name)
lw = ListGameWidget(game)
self._list_container.layout().addWidget(lw)
self.sort_list()
self.order_game_views()

def __find_widget(self, app_name: str) -> Tuple[Union[IconGameWidget, None], Union[ListGameWidget, None]]:
iw = self._icon_container.findChild(IconGameWidget, app_name)
Expand Down
Loading

0 comments on commit 9770816

Please sign in to comment.