Move DetailsWindow to its own class
This commit is contained in:
236
src/details_window.py
Normal file
236
src/details_window.py
Normal file
@@ -0,0 +1,236 @@
|
||||
# details_window.py
|
||||
#
|
||||
# Copyright 2022-2023 kramo
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import os
|
||||
import shlex
|
||||
from time import time
|
||||
|
||||
from gi.repository import Adw, Gio, GLib, Gtk
|
||||
from PIL import Image
|
||||
|
||||
from .create_dialog import create_dialog
|
||||
from .game import Game
|
||||
from .game_cover import GameCover
|
||||
from .save_cover import resize_cover, save_cover
|
||||
from .steamgriddb import SGDBSave
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/hu/kramo/Cartridges/gtk/details_window.ui")
|
||||
class DetailsWindow(Adw.Window):
|
||||
__gtype_name__ = "DetailsWindow"
|
||||
|
||||
cover = Gtk.Template.Child()
|
||||
cover_button_edit = Gtk.Template.Child()
|
||||
cover_button_delete_revealer = Gtk.Template.Child()
|
||||
cover_button_delete = Gtk.Template.Child()
|
||||
|
||||
name = Gtk.Template.Child()
|
||||
developer = Gtk.Template.Child()
|
||||
executable = Gtk.Template.Child()
|
||||
|
||||
exec_info_label = Gtk.Template.Child()
|
||||
|
||||
apply_button = Gtk.Template.Child()
|
||||
|
||||
cover_changed = False
|
||||
|
||||
def delete_pixbuf(self, *_args):
|
||||
self.game_cover.new_cover()
|
||||
|
||||
self.cover_button_delete_revealer.set_reveal_child(False)
|
||||
self.cover_changed = True
|
||||
|
||||
def __init__(self, win, game=None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.set_transient_for(win)
|
||||
|
||||
self.win = win
|
||||
self.game = game
|
||||
self.game_cover = GameCover({self.cover})
|
||||
|
||||
if self.game:
|
||||
self.set_title(_("Edit Game Details"))
|
||||
self.name.set_text(self.game.name)
|
||||
self.developer.set_text(self.game.developer)
|
||||
self.executable.set_text(shlex.join(self.game.executable))
|
||||
self.apply_button.set_label(_("Apply"))
|
||||
|
||||
self.game_cover.new_cover(self.game.get_cover_path())
|
||||
if self.game_cover.get_pixbuf():
|
||||
self.cover_button_delete_revealer.set_reveal_child(True)
|
||||
else:
|
||||
self.set_title(_("Add New Game"))
|
||||
self.apply_button.set_label(_("Confirm"))
|
||||
|
||||
image_filter = Gtk.FileFilter(name=_("Images"))
|
||||
for extension in Image.registered_extensions():
|
||||
image_filter.add_suffix(extension[1:])
|
||||
|
||||
file_filters = Gio.ListStore.new(Gtk.FileFilter)
|
||||
file_filters.append(image_filter)
|
||||
self.file_dialog = Gtk.FileDialog()
|
||||
self.file_dialog.set_filters(file_filters)
|
||||
|
||||
# Translate this string as you would translate "file"
|
||||
file_name = _("file.txt")
|
||||
# As in software
|
||||
exe_name = _("program")
|
||||
|
||||
if os.name == "nt":
|
||||
exe_name += ".exe"
|
||||
# Translate this string as you would translate "path to {}"
|
||||
exe_path = _("C:\\path\\to\\{}").format(exe_name)
|
||||
# Translate this string as you would translate "path to {}"
|
||||
file_path = _("C:\\path\\to\\{}").format(file_name)
|
||||
command = "start"
|
||||
else:
|
||||
# Translate this string as you would translate "path to {}"
|
||||
exe_path = _("/path/to/{}").format(exe_name)
|
||||
# Translate this string as you would translate "path to {}"
|
||||
file_path = _("/path/to/{}").format(file_name)
|
||||
command = "xdg-open"
|
||||
|
||||
exec_info_text = _(
|
||||
'To launch the executable "{}", use the command:\n\n<tt>"{}"</tt>\n\nTo open the file "{}" with the default application, use:\n\n<tt>{} "{}"</tt>\n\nIf the path contains spaces, make sure to wrap it in double quotes!'
|
||||
).format(exe_name, exe_path, file_name, command, file_path)
|
||||
|
||||
self.exec_info_label.set_label(exec_info_text)
|
||||
|
||||
self.cover_button_delete.connect("clicked", self.delete_pixbuf)
|
||||
self.cover_button_edit.connect("clicked", self.choose_cover)
|
||||
self.apply_button.connect("clicked", self.apply_preferences)
|
||||
|
||||
self.name.connect("activate", self.focus_executable)
|
||||
self.developer.connect("activate", self.focus_executable)
|
||||
self.executable.connect("activate", self.apply_preferences)
|
||||
|
||||
self.set_focus(self.name)
|
||||
self.present()
|
||||
|
||||
def apply_preferences(self, *_args):
|
||||
final_name = self.name.get_text()
|
||||
final_developer = self.developer.get_text()
|
||||
final_executable = self.executable.get_text()
|
||||
|
||||
try:
|
||||
# Attempt to parse using shell parsing rules (doesn't verify executable existence).
|
||||
final_executable_split = shlex.split(
|
||||
final_executable, comments=False, posix=True
|
||||
)
|
||||
except ValueError as exception:
|
||||
create_dialog(
|
||||
self,
|
||||
_("Couldn't Add Game")
|
||||
if not self.game
|
||||
else _("Couldn't Apply Preferences"),
|
||||
f'{_("Executable")}: {exception}.',
|
||||
)
|
||||
return
|
||||
|
||||
if not self.game:
|
||||
if final_name == "":
|
||||
create_dialog(
|
||||
self, _("Couldn't Add Game"), _("Game title cannot be empty.")
|
||||
)
|
||||
return
|
||||
|
||||
if final_executable == "":
|
||||
create_dialog(
|
||||
self, _("Couldn't Add Game"), _("Executable cannot be empty.")
|
||||
)
|
||||
return
|
||||
|
||||
# Increment the number after the game id (eg. imported_1, imported_2)
|
||||
|
||||
numbers = [0]
|
||||
|
||||
for current_game in self.win.games:
|
||||
if "imported_" in current_game:
|
||||
numbers.append(int(current_game.replace("imported_", "")))
|
||||
|
||||
self.game = Game(
|
||||
self.win,
|
||||
{
|
||||
"game_id": f"imported_{str(max(numbers) + 1)}",
|
||||
"hidden": False,
|
||||
"source": "imported",
|
||||
"added": int(time()),
|
||||
"last_played": 0,
|
||||
},
|
||||
)
|
||||
|
||||
else:
|
||||
if final_name == "":
|
||||
create_dialog(
|
||||
self,
|
||||
_("Couldn't Apply Preferences"),
|
||||
_("Game title cannot be empty."),
|
||||
)
|
||||
return
|
||||
|
||||
if final_executable == "":
|
||||
create_dialog(
|
||||
self,
|
||||
_("Couldn't Apply Preferences"),
|
||||
_("Executable cannot be empty."),
|
||||
)
|
||||
return
|
||||
|
||||
self.game.name = final_name
|
||||
self.game.developer = final_developer or None
|
||||
self.game.executable = final_executable_split
|
||||
|
||||
if self.game.game_id in self.win.game_covers.keys():
|
||||
self.win.game_covers[self.game.game_id].animation = None
|
||||
|
||||
self.win.game_covers[self.game.game_id] = self.game_cover
|
||||
|
||||
if self.cover_changed:
|
||||
save_cover(
|
||||
self.win,
|
||||
self.game.game_id,
|
||||
self.game_cover.path,
|
||||
)
|
||||
|
||||
self.game.save()
|
||||
|
||||
if not self.game_cover.get_pixbuf():
|
||||
SGDBSave(self.win, {self.game})
|
||||
|
||||
self.game_cover.pictures.remove(self.cover)
|
||||
|
||||
self.close()
|
||||
self.win.show_details_view(self.game)
|
||||
|
||||
def focus_executable(self):
|
||||
self.set_focus(self.executable)
|
||||
|
||||
def set_cover(self, _source, result, *_args):
|
||||
try:
|
||||
path = self.file_dialog.open_finish(result).get_path()
|
||||
except GLib.GError:
|
||||
return
|
||||
|
||||
self.cover_button_delete_revealer.set_reveal_child(True)
|
||||
self.cover_changed = True
|
||||
|
||||
self.game_cover.new_cover(resize_cover(self.win, path))
|
||||
|
||||
def choose_cover(self, *_args):
|
||||
self.file_dialog.open(self, None, self.set_cover)
|
||||
Reference in New Issue
Block a user