From b4d1c47eb343302fd945b6c7f8d607bdfe47d57c Mon Sep 17 00:00:00 2001 From: luxick Date: Wed, 8 Mar 2017 14:08:53 +0100 Subject: [PATCH] Feature: Add cards to library via search view --- mtg-collector/config.py | 7 ++++- mtg-collector/details.py | 4 +-- mtg-collector/gui.py | 41 +++++++++++++++++++++++++----- mtg-collector/search.py | 34 +++++++++++++++++++++++++ mtg-collector/util.py | 55 ++++++++++++++++++++++++++++++++++++++-- 5 files changed, 128 insertions(+), 13 deletions(-) diff --git a/mtg-collector/config.py b/mtg-collector/config.py index e8e5772..9eec337 100644 --- a/mtg-collector/config.py +++ b/mtg-collector/config.py @@ -1,11 +1,16 @@ -# Title of the Program Window import os +from gi.repository import Gdk +# Title of the Program Window application_title= "MTG Collector (working title) v0.1" # Path of image cache cache_path= os.path.dirname(__file__) + "/.cache/" image_cache_path=os.path.dirname(__file__) + "/.cache/images/" +# Colors to use in the Application +green_color = Gdk.color_parse('#87ff89') +red_color = Gdk.color_parse('#ff6d6d') + # When True Search view will list a card multiple times for each set they appear in show_from_all_sets=False \ No newline at end of file diff --git a/mtg-collector/details.py b/mtg-collector/details.py index 3dec5e5..cbc0099 100644 --- a/mtg-collector/details.py +++ b/mtg-collector/details.py @@ -12,7 +12,7 @@ class DetailBar(Gtk.ScrolledWindow): self.add(self.grid) self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) - # Create area for big card an fill it with a dummy image + # Create area for big card self.image_area = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) self.bigcard = Gtk.Image() pixbuf = util.load_dummy_image(63 * 5, 88 * 5) @@ -67,8 +67,6 @@ class DetailBar(Gtk.ScrolledWindow): self.rulesstore.clear() def set_card_detail(self, card): - print("Loading infos for \"" + card.name + "\"") - self.update_big_card(card) self.rulesstore.clear() self.rulingslabel.set_visible(False) diff --git a/mtg-collector/gui.py b/mtg-collector/gui.py index 6cdb6fb..25d7b63 100644 --- a/mtg-collector/gui.py +++ b/mtg-collector/gui.py @@ -13,6 +13,13 @@ class MainWindow(Gtk.Window): self.set_border_width(2) self.set_size_request(1000, 700) + self.status_bar = Gtk.Statusbar() + self.status_bar.set_no_show_all(True) + + # Set reference to status bar in util + util.status_bar = self.status_bar + util.push_status("Application started") + # Load local image Data util.reload_image_cache() util.load_mana_icons() @@ -20,31 +27,53 @@ class MainWindow(Gtk.Window): util.window = self util.load_sets() - - self.status_bar = Gtk.Statusbar() - self.status_bar.set_no_show_all(True) + util.load_library() self.notebook = Gtk.Notebook() # region Menu Bar mb_main = Gtk.Menu() + mb_lib = Gtk.Menu() self.menu_import = Gtk.MenuItem("Import Library") self.menu_export = Gtk.MenuItem("Export Library") self.menu_quit = Gtk.ImageMenuItem('Quit', Gtk.Image.new_from_icon_name(Gtk.STOCK_QUIT, 0)) self.menu_quit.connect("activate", Gtk.main_quit) + self.lib_save = Gtk.ImageMenuItem("Save", Gtk.Image.new_from_icon_name(Gtk.STOCK_SAVE, 0)) + self.lib_save.connect("activate", self.mb_save_lib) + self.lib_debug_print = Gtk.MenuItem("DEBUG: Print Library") + self.lib_debug_print.connect("activate", util.print_lib) + mb_main.append(self.menu_import) mb_main.append(self.menu_export) mb_main.append(Gtk.SeparatorMenuItem()) mb_main.append(self.menu_quit) + mb_lib.append(self.lib_save) + mb_lib.append(self.lib_debug_print) + root_menu_main = Gtk.MenuItem("Main") root_menu_main.set_submenu(mb_main) + root_menu_lib = Gtk.MenuItem("Library") + root_menu_lib.set_submenu(mb_lib) + mb = Gtk.MenuBar() mb.append(root_menu_main) + mb.append(root_menu_lib) + + # endregion + + # region Accelerators + + accelgrp = Gtk.AccelGroup() + + key, mod = Gtk.accelerator_parse("Q") + self.menu_quit.add_accelerator("activate", accelgrp, key, mod, Gtk.AccelFlags.VISIBLE) + + self.add_accel_group(accelgrp) # endregion @@ -53,10 +82,6 @@ class MainWindow(Gtk.Window): vbox.pack_start(self.notebook, True, True, 0) vbox.pack_start(self.status_bar, False, False, 0) - # Set reference to status bar in util - util.status_bar = self.status_bar - util.push_status("Application started") - self.collectionView = Gtk.Box() self.collectionView.add(collection.CollectionView()) @@ -72,6 +97,8 @@ class MainWindow(Gtk.Window): self.add(vbox) + def mb_save_lib(self, menu_item): + util.save_library() win = MainWindow() win.connect('delete-event', Gtk.main_quit) diff --git a/mtg-collector/search.py b/mtg-collector/search.py index e7b9175..262c18a 100644 --- a/mtg-collector/search.py +++ b/mtg-collector/search.py @@ -16,6 +16,7 @@ class SearchView(Gtk.Grid): def __init__(self): Gtk.Grid.__init__(self) self.set_column_spacing(5) + self.current_card = None # region Search Box self.searchbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, @@ -178,6 +179,12 @@ class SearchView(Gtk.Grid): # Detail View for selected Card self.details = details.DetailBar() + + # Button to add to library + self.add_delete_button = Gtk.Button() + self.add_delete_button.set_no_show_all(True) + self.add_delete_button.connect("clicked", self.on_add_delete) + # Bring it all together left_pane = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) left_pane.pack_start(self.searchbox, False, False, 0) @@ -193,6 +200,8 @@ class SearchView(Gtk.Grid): self.attach(Gtk.VSeparator(), 3, 0, 1, 1) # Details self.attach(self.details, 4, 0, 1, 1) + # Add/delete Button + self.attach(self.add_delete_button, 4, 1, 1, 1) self.selection = self.list.get_selection() self.selection.connect("changed", self.on_card_selected) @@ -201,11 +210,24 @@ class SearchView(Gtk.Grid): # region UI Events + def on_add_delete(self, button): + if util.library.__contains__(self.current_card.multiverse_id): + util.remove_card_from_lib(self.current_card) + print(self.current_card.name + " removed to library") + else: + util.add_card_to_lib(self.current_card) + print(self.current_card.name + " added to library") + self._do_update_add_button() + def online_search_clicked(self, button): # Clear old data from liststore self.store.clear() # Reset details pane self.details.reset() + # Reset selected card + self.current_card = None + # Hide Add delete button + self.add_delete_button.set_visible(False) # Define the function to load cards in a seperate thread, so the UI is not blocked self.loadthread = threading.Thread(target=self.load_cards) # Deamonize Thread so it tops if the main thread exits @@ -235,6 +257,10 @@ class SearchView(Gtk.Grid): selected_card = card if selected_card is not None: self.details.set_card_detail(selected_card) + self.current_card = selected_card + + self.add_delete_button.set_visible(True) + self._do_update_add_button() # endregion @@ -332,6 +358,14 @@ class SearchView(Gtk.Grid): # region Private Functions + def _do_update_add_button(self): + if not util.library.__contains__(self.current_card.multiverse_id): + self.add_delete_button.set_label("Add to Library") + self.add_delete_button.modify_bg(Gtk.StateType.NORMAL, config.green_color) + else: + self.add_delete_button.set_label("Remove from Library") + self.add_delete_button.modify_bg(Gtk.StateType.NORMAL, config.red_color) + def _match_selected(self, completion, model, iter): self.set_combo.set_active_iter(iter) diff --git a/mtg-collector/util.py b/mtg-collector/util.py index 721a4ef..f698604 100644 --- a/mtg-collector/util.py +++ b/mtg-collector/util.py @@ -8,18 +8,69 @@ import network from gi.repository import GdkPixbuf, Gtk from PIL import Image as PImage from urllib import request +from mtgsdk import Card gi.require_version('Gtk', '3.0') # Locally stored images for faster loading times imagecache = [] manaicons = {} +#Card library object +library = {} + set_list = [] window = None status_bar = None +def add_card_to_lib(card): + library[card.multiverse_id] = card + + +def remove_card_from_lib(card): + del library[card.multiverse_id] + + +def print_lib(menuItem): + print("Printing library:\n") + counter = 1 + for card_id, card in library.items(): + print(str(counter) + ": " + card.name + " (" + str(card_id) + ")") + counter += 1 + print("\nDone.") + + +def save_library(): + if not os.path.exists(config.cache_path): + os.makedirs(config.cache_path) + path = config.cache_path + "library" + # Serialize library object using pickle + try: + pickle.dump(library, open(path, 'wb')) + push_status("Library saved.") + print("Library saved") + except: + show_message("Error", "Error while saving library to disk") + + +def load_library(): + path = config.cache_path + "library" + library.clear() + if os.path.isfile(path): + # Deserialize using pickle + try: + library_loaded = pickle.load(open(path, 'rb')) + for id, card in library_loaded.items(): + library[id] = card + push_status("Library loaded.") + except : + show_message("Error", "Error while loading library from disk") + else: + save_library() + print("No library file found on disk, created new one") + + def load_sets(): path = config.cache_path + "sets" if not os.path.isfile(path): @@ -29,9 +80,9 @@ def load_sets(): show_message("API Error", "Could not retrieve Set infos") return # Serialize the loaded data to a file - pickle.dump(new_sets, open(config.cache_path + "sets", 'wb')) + pickle.dump(new_sets, open(path, 'wb')) # Deserialize set data from local file - sets = pickle.load(open(config.cache_path + "sets", 'rb')) + sets = pickle.load(open(path, 'rb')) # Sort the loaded sets based on the sets name for set in sorted(sets, key=lambda x: x.name): set_list.append(set)