Break out a base class for game actions, and use it for service games.

We want a real service games menu, but this blocks access to inappropriate commands at least.
This commit is contained in:
Daniel Johnson 2023-11-10 06:08:25 -05:00
parent 2f69520f03
commit e0e741c1b8
3 changed files with 79 additions and 22 deletions

View file

@ -28,29 +28,91 @@ from lutris.util.system import path_exists
from lutris.util.wine.shader_cache import update_shader_cache
class GameActions:
"""Regroup a list of callbacks for a game"""
def get_game_actions(game, window, application=None):
if game.is_db_stored:
return GameActions(game, window, application)
else:
return BaseGameActions(game, window, application)
class BaseGameActions:
def __init__(self, game, window, application=None):
self.application = application or Gio.Application.get_default()
self.window = window # also used as a LaunchUIDelegate
self.game = game
def get_game_actions(self):
"""Return a list of game actions and their callbacks"""
return []
def get_displayed_entries(self):
"""Return a dictionary of actions that should be shown for a game"""
return {}
@property
def is_game_launchable(self):
return False
def on_game_launch(self, *_args):
"""Launch a game"""
pass
@property
def is_game_running(self):
return False
def on_game_stop(self, *_args):
"""Stops the game"""
pass
@property
def is_installable(self):
return False
def on_install_clicked(self, *_args):
"""Install a game"""
pass
def on_locate_installed_game(self, _button, game):
"""Show the user a dialog to import an existing install to a DRM free service
Params:
game (Game): Game instance without a database ID, populated with a fields the service can provides
"""
AddGameDialog(self.window, game=game)
@property
def is_game_removable(self):
return False
def on_remove_game(self, *_args):
"""Callback that present the uninstall dialog to the user"""
pass
class GameActions(BaseGameActions):
"""Regroup a list of callbacks for a game"""
def __init__(self, game, window, application=None):
super().__init__(game, window, application)
@property
def is_game_launchable(self):
return self.game and self.game.is_installed and not self.is_game_running
@property
def is_game_running(self):
return self.game and self.game.is_db_stored and bool(self.application.get_running_game_by_id(self.game.id))
@property
def is_installable(self):
return not self.game.is_installed
@property
def is_game_removable(self):
return self.game and (self.game.is_installed or self.game.is_db_stored)
def on_game_state_changed(self, game):
"""Handler called when the game has changed state"""
if self.game and game.id == self.game.get_safe_id():
self.game = game
def get_game_actions(self):
"""Return a list of game actions and their callbacks"""
return [
("play", _("Play"), self.on_game_launch),
("stop", _("Stop"), self.on_game_stop),
@ -94,8 +156,8 @@ class GameActions:
return {
"add": not self.game.is_installed,
"duplicate": self.game.is_installed,
"install": not self.game.is_installed,
"play": self.game.is_installed and not self.is_game_running,
"install": self.is_installable,
"play": self.is_game_launchable,
"update": self.game.is_updatable,
"update-shader-cache": self.game.is_cache_managed,
"install_dlcs": self.game.is_updatable,
@ -190,14 +252,6 @@ class GameActions:
def on_update_shader_cache(self, _widget):
update_shader_cache(self.game)
def on_locate_installed_game(self, _button, game):
"""Show the user a dialog to import an existing install to a DRM free service
Params:
game (Game): Game instance without a database ID, populated with a fields the service can provides
"""
AddGameDialog(self.window, game=game)
def on_add_manually(self, _widget, *_args):
"""Callback that presents the Add game dialog"""
return AddGameDialog(self.window, game=self.game, runner=self.game.runner_name)

View file

@ -3,7 +3,7 @@ from gi.repository import Gdk, Gio, GObject, Gtk
from lutris.database.games import get_game_for_service
from lutris.database.services import ServiceGameCollection
from lutris.game import Game
from lutris.game_actions import GameActions
from lutris.game_actions import GameActions, get_game_actions
from lutris.gui.views import COL_ID
from lutris.gui.widgets.contextual_menu import ContextualMenu
@ -56,7 +56,7 @@ class GameView:
else:
return None
return GameActions(game, window=self.get_toplevel())
return get_game_actions(game, window=self.get_toplevel())
def get_game_by_id(self, game_id):
application = Gio.Application.get_default()

View file

@ -7,7 +7,7 @@ from lutris import runners, services
from lutris.database.games import get_game_for_service
from lutris.exceptions import watch_errors
from lutris.game import Game
from lutris.game_actions import GameActions
from lutris.game_actions import GameActions, get_game_actions
from lutris.gui.dialogs import ErrorDialog
from lutris.gui.widgets.contextual_menu import update_action_widget_visibility
from lutris.util.strings import gtk_safe
@ -74,7 +74,7 @@ class GameBar(Gtk.Box):
def update_view(self):
"""Populate the view with widgets"""
game_actions = GameActions(self.game, window=self.window, application=self.application)
game_actions = get_game_actions(self.game, window=self.window, application=self.application)
game_label = self.get_game_name_label()
game_label.set_halign(Gtk.Align.START)
@ -212,15 +212,18 @@ class GameBar(Gtk.Box):
if self.game.state == self.game.STATE_STOPPED:
button.set_label(_("Play"))
button.connect("clicked", game_actions.on_game_launch)
button.set_sensitive(game_actions.is_game_launchable)
elif self.game.state == self.game.STATE_LAUNCHING:
button.set_label(_("Launching"))
button.set_sensitive(False)
else:
button.set_label(_("Stop"))
button.connect("clicked", game_actions.on_game_stop)
button.set_sensitive(game_actions.is_game_running)
else:
button.set_label(_("Install"))
button.connect("clicked", game_actions.on_install_clicked)
button.set_sensitive(game_actions.is_installable)
if self.service:
if self.service.local:
# Local services don't show an install dialog, they can be launched directly