#!python3 ''' Usage: gamechest.py --gamelist=GAMELIST.YAML --gamedir=GAMEDIR ''' import logging import os from logging import debug, info, warning, critical import docopt import yaml import gi from . import gamemanager gi.require_version("Gtk", "3.0") from gi.repository import Gtk as gtk, GLib as glib, GdkPixbuf as gdkpixbuf from gi.repository.GdkPixbuf import Pixbuf class GameList: def __init__(self, gamelist, gamedir): debug(f'managing gamedir {gamedir}') debug(f'reading gamelist from {gamelist}') with open(gamelist) as stream: self.yaml_data = yaml.safe_load(stream) self.gamedir = gamedir debug('loaded data: %d bytes', len(self.yaml_data)) class Handler: def __init__(self, builder, gamelist, gamelist_dir, gamedir): self.builder = builder self.gamelist = gamelist self.gamelist_dir = gamelist_dir self.gamedir = gamedir repository_host = gamelist.yaml_data['repository']['host'] repository_path = gamelist.yaml_data['repository']['path'] self.game_installer = gamemanager.GameInstaller( repository_host, repository_path, gamedir) self.game_remover = gamemanager.GameRemover( repository_host, repository_path, gamedir) self.game_status = gamemanager.GameStatus( repository_host, repository_path, gamedir) self.game_title = builder.get_object('game_title') self.game_image = builder.get_object('game_image') self.game_characteristics = builder.get_object('game_characteristics') self.game_description = builder.get_object('game_description') self.btn_install = builder.get_object('btn_install') self.btn_update = builder.get_object('btn_update') self.btn_remove = builder.get_object('btn_remove') self.game_install_stop_btn = builder.get_object('game_install_stop_btn') self.game_install_progress = builder.get_object('game_install_progress') self.global_progression = builder.get_object('global_progression') self.game_install_timeout_id = None self.current_selected_game = None self.game_image_pixbuf = None def on_destroy(self, *args): gtk.main_quit() def on_quit_clicked(self, *args): print('quit') gtk.main_quit() def gamelist_on_changed(self, selection, *args): model, treeiter = selection.get_selected() if treeiter is None: return index = model[treeiter][2] #print("You selected", self.gamelist['games'][model[treeiter][2]]) debug('selected index: %d', index) game_item = self.gamelist.yaml_data['games'][index] self.current_selected_game = game_item info("You selected (title): %s", game_item['title']) self.game_title.set_label(game_item['title']) if image := game_item.get('image', None): image_path = f'{self.gamelist_dir}/{image}' debug('image path: %s', image_path) if os.path.exists(image_path): #self.game_image.set_from_file(image_path) self.game_image_pixbuf = Pixbuf.new_from_file(image_path) self.game_image_draw() self.game_characteristics.set_text( game_item.get('characteristics', 'Unfilled characteristics')) description = game_item.get('description', 'No description') self.game_description.set_text(description) if self.game_status.exists(game_item['name']): debug('game status exists') self.btn_install.hide() self.btn_update.show() self.btn_remove.show() else: debug('game status does not exist') def game_image_on_draw(self, widget, cr, *args): self.game_image_draw() def game_image_draw(self): if not self.game_image_pixbuf: return orig_width = self.game_image_pixbuf.get_width() orig_height = self.game_image_pixbuf.get_height() dest_width = self.game_image.get_allocated_width() dest_height = self.game_image.get_allocated_height() ratio_width = dest_width / orig_width ratio_height = dest_height / orig_height ratio = min(ratio_width, ratio_height) #width, height = self.game_image.get_allocated_size() pixbuftmp = self.game_image_pixbuf.scale_simple( orig_width*ratio, orig_height*ratio, gdkpixbuf.InterpType.BILINEAR) self.game_image.set_from_pixbuf(pixbuftmp) def on_draw(self, widget, cr, data): context = widget.get_style_context() width = widget.get_allocated_width() height = widget.get_allocated_height() Gtk.render_background(context, cr, 0, 0, width, height) r, g, b, a = data["color"] cr.set_source_rgba(r, g, b, a) cr.rectangle(0, 0, width, height) cr.fill() ############################################################ # install management ############################################################ def game_install_on_clicked(self, *args): if not self.current_selected_game: return self.game_install_timeout_id = \ glib.timeout_add(250, self.game_install_on_timeout, None) self.game_install_stop_btn.show() game_item = self.current_selected_game self.game_installer.start(game_item) # set progress bar to 0.0001 in order to update them the first time on # timeout (most useful for global advance) self.global_progression.set_fraction(0.0001) self.game_install_progress.set_fraction(0.0001) def game_install_stop(self): if not self.game_install_timeout_id: return glib.source_remove(self.game_install_timeout_id) self.game_install_timeout_id = None self.game_installer.stop() #self.game_install_progress.set_fraction(1) self.game_install_stop_btn.hide() def game_installstop_on_clicked(self, *args): self.game_install_stop() def game_install_on_timeout(self, *args): status, progress1, progress2 = self.game_installer.poll() #print(f'status {status} progress1 {progress1} progress2 {progress2}') old_progress1 = self.global_progression.get_fraction() if (progress1/100) != old_progress1: self.global_progression.set_fraction(progress1/100) self.global_progression.set_text(f'global {progress1:.2f}%') old_progress2 = self.game_install_progress.get_fraction() if (progress2/100) != old_progress2: self.game_install_progress.set_fraction(progress2/100) self.game_install_progress.set_text(f'step {progress2:.2f}%') # returning False value means stop timer if status == self.game_installer.State.ONGOING: return True self.game_install_stop() return False def main(): logging.basicConfig(level=logging.DEBUG) logging.getLogger().handlers[0].setFormatter(logging.Formatter( "gamechest: %(levelname)s: %(funcName)s:%(lineno)s: %(message)s")) args = docopt.docopt(__doc__) debug('args: %s', args) gamelist_dir = ( os.path.dirname(args['--gamelist']) + '/.' + os.path.basename(args['--gamelist']) + '.d' ) gamelist = GameList(args['--gamelist'], args['--gamedir']) builder = gtk.Builder() builder.add_from_file('gamechest.glade') builder.connect_signals( Handler(builder, gamelist, gamelist_dir, args['--gamedir'])) window = builder.get_object('window2') window.show_all() gamelist_store = builder.get_object('gamelist_store') gamelist_store.clear() for index, game in enumerate(gamelist.yaml_data['games']): gamelist_store.append((False, game['title'], index)) info('%d games loaded', len(gamelist.yaml_data['games'])) gtk.main()