From b7ee25d224db4963a4e4f5e5f00d8d2204a9976f Mon Sep 17 00:00:00 2001 From: luxick Date: Mon, 17 Apr 2017 16:55:33 +0200 Subject: [PATCH] Restructure project --- README.rst | 19 + bin/cardvault | 2 + cardvault/__init__.py | 0 cardvault/application.py | 263 ++++++++++ cardvault/cardlist.py | 17 +- cardvault/config.py | 25 - cardvault/handlers.py | 73 ++- cardvault/lib_funct.py | 24 +- cardvault/logger.py | 14 - cardvault/network.py | 11 - cardvault/resources/mana/{BP.png => B-P.png} | Bin cardvault/resources/mana/{BR.png => B-R.png} | Bin cardvault/resources/mana/{GP.png => G-P.png} | Bin cardvault/resources/mana/{GU.png => G-U.png} | Bin cardvault/resources/mana/{GW.png => G-W.png} | Bin cardvault/resources/mana/{RG.png => R-G.png} | Bin cardvault/resources/mana/{RP.png => R-P.png} | Bin cardvault/resources/mana/{RW.png => R-W.png} | Bin cardvault/resources/mana/{UB.png => U-B.png} | Bin cardvault/resources/mana/{UP.png => U-P.png} | Bin cardvault/resources/mana/{UR.png => U-R.png} | Bin cardvault/resources/mana/{WB.png => W-B.png} | Bin cardvault/resources/mana/{WP.png => W-P.png} | Bin cardvault/resources/mana/{WU.png => W-U.png} | Bin cardvault/search_funct.py | 82 ++-- cardvault/util.py | 477 ++++++++----------- cardvault/window.py | 140 ------ setup.py | 38 ++ 28 files changed, 626 insertions(+), 559 deletions(-) create mode 100644 README.rst create mode 100644 bin/cardvault create mode 100644 cardvault/__init__.py create mode 100644 cardvault/application.py delete mode 100644 cardvault/config.py delete mode 100644 cardvault/logger.py delete mode 100644 cardvault/network.py rename cardvault/resources/mana/{BP.png => B-P.png} (100%) rename cardvault/resources/mana/{BR.png => B-R.png} (100%) rename cardvault/resources/mana/{GP.png => G-P.png} (100%) rename cardvault/resources/mana/{GU.png => G-U.png} (100%) rename cardvault/resources/mana/{GW.png => G-W.png} (100%) rename cardvault/resources/mana/{RG.png => R-G.png} (100%) rename cardvault/resources/mana/{RP.png => R-P.png} (100%) rename cardvault/resources/mana/{RW.png => R-W.png} (100%) rename cardvault/resources/mana/{UB.png => U-B.png} (100%) rename cardvault/resources/mana/{UP.png => U-P.png} (100%) rename cardvault/resources/mana/{UR.png => U-R.png} (100%) rename cardvault/resources/mana/{WB.png => W-B.png} (100%) rename cardvault/resources/mana/{WP.png => W-P.png} (100%) rename cardvault/resources/mana/{WU.png => W-U.png} (100%) delete mode 100644 cardvault/window.py create mode 100755 setup.py diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..6725d42 --- /dev/null +++ b/README.rst @@ -0,0 +1,19 @@ +# Card Vault +A desktop application for building and organizing MTG card libraries and decks. + +## Features + +* Online card search +* Create a library of owned cards +* Import and Export Libraries + +## TODO + +* Organize cards in library +* Build decklists from cards in collection +* Want lists +* Full offline functionality + +### Maybe +* Create fancy exports of decks and wants +* Display prices for cards diff --git a/bin/cardvault b/bin/cardvault new file mode 100644 index 0000000..0e47180 --- /dev/null +++ b/bin/cardvault @@ -0,0 +1,2 @@ +from cardvault import application +application.main() \ No newline at end of file diff --git a/cardvault/__init__.py b/cardvault/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cardvault/application.py b/cardvault/application.py new file mode 100644 index 0000000..3ee1e5b --- /dev/null +++ b/cardvault/application.py @@ -0,0 +1,263 @@ +import sys +try: + import gi + gi.require_version('Gtk', '3.0') + from gi.repository import Gtk + from gi.repository import Pango + from gi.repository import GdkPixbuf +except ImportError as ex: + print("Couldn't import GTK dependencies. Make sure you " + "installed the PyGTK package and %s module." % ex.name) + sys.exit(-1) + +import os +import copy +import re + +from cardvault import handlers +from cardvault import util +from cardvault import search_funct +from cardvault import lib_funct + + +class Application: + + # ---------------------------------Initialize the Application---------------------------------------------- + def __init__(self): + + # Load ui files + self.ui = Gtk.Builder() + self.ui.add_from_file(util.get_ui_filename("mainwindow.glade")) + self.ui.add_from_file(util.get_ui_filename("overlays.glade")) + self.ui.add_from_file(util.get_ui_filename("search.glade")) + self.ui.add_from_file(util.get_ui_filename("library.glade")) + + self.current_page = None + self.unsaved_changes = False + + not_found = self.ui.get_object("pageNotFound") + self.pages = { + "search": self.ui.get_object("searchView"), + "library": self.ui.get_object("libraryView"), + "decks": not_found + } + + # Load configuration file + self.configfile = util.get_root_filename("config.json") + self.config = util.parse_config(self.configfile, util.default_config) + + util.LOG_LEVEL = self.config["log_level"] + + # Load data from cache path + self.image_cache = util.reload_image_cache(util.CACHE_PATH + "images/") + self.precon_icons = util.reload_preconstructed_icons(util.CACHE_PATH + "icons/") + self.mana_icons = util.load_mana_icons(os.path.dirname(__file__) + "/resources/mana/") + + self.sets = util.load_sets(util.get_root_filename("sets")) + + self.library = None + self.tags = None + self.load_library() + + self.handlers = handlers.Handlers(self) + self.ui.connect_signals(self.handlers) + + search_funct.init_search_view(self) + + lib_funct.init_library_view(self) + + self.ui.get_object("mainWindow").connect('delete-event', Gtk.main_quit) + self.ui.get_object("mainWindow").show_all() + self.push_status("Card Vault ready.") + + view_menu = self.ui.get_object("viewMenu") + start_page = [page for page in view_menu.get_children() if page.get_name() == util.START_PAGE] + start_page[0].activate() + + def push_status(self, msg): + status_bar = self.ui.get_object("statusBar") + status_bar.pop(0) + status_bar.push(0, msg) + + def show_card_details(self, card): + builder = Gtk.Builder() + builder.add_from_file(util.get_ui_filename("detailswindow.glade")) + builder.add_from_file(util.get_ui_filename("overlays.glade")) + window = builder.get_object("cardDetails") + window.set_title(card.name) + # Card Image + container = builder.get_object("imageContainer") + pixbuf = self.get_card_image(card, 63 * 5, 88 * 5) + image = Gtk.Image().new_from_pixbuf(pixbuf) + container.add(image) + # Name + builder.get_object("cardName").set_text(card.name) + # Types + supertypes = "" + if card.subtypes is not None: + supertypes = " - " + " ".join(card.subtypes) + types = " ".join(card.types) + supertypes + builder.get_object("cardTypes").set_text(types) + # Rarity + builder.get_object("cardRarity").set_text(card.rarity if card.rarity else "") + # Release + builder.get_object("cardReleaseDate").set_text(card.release_date if card.release_date else "") + # Set + builder.get_object("cardSet").set_text(card.set_name) + # Printings + prints = [] + for set in card.printings: + prints.append(self.sets[set].name) + builder.get_object("cardPrintings").set_text(", ".join(prints)) + # Legalities + grid = builder.get_object("legalitiesGrid") + rows = 1 + for legality in card.legalities if card.legalities else {}: + date_label = Gtk.Label() + date_label.set_halign(Gtk.Align.END) + text_label = Gtk.Label() + text_label.set_line_wrap_mode(Pango.WrapMode.WORD) + text_label.set_line_wrap(True) + text_label.set_halign(Gtk.Align.END) + color = self.config['legality_colors'][legality["legality"]] + date_label.set_markup("" + legality["format"] + ":" + "") + text_label.set_markup("" + legality["legality"] + "") + grid.attach(date_label, 0, rows + 2, 1, 1) + grid.attach(text_label, 1, rows + 2, 1, 1) + + rows += 1 + grid.show_all() + + # Rulings + if card.rulings: + grid = builder.get_object("rulesGrid") + rows = 1 + for rule in card.rulings: + date_label = Gtk.Label(rule["date"]) + text_label = Gtk.Label(rule["text"]) + text_label.set_line_wrap_mode(Pango.WrapMode.WORD) + text_label.set_line_wrap(True) + text_label.set_justify(Gtk.Justification.LEFT) + text_label.set_halign(Gtk.Align.START) + + grid.attach(date_label, 0, rows+2, 1, 1) + grid.attach(text_label, 1, rows+2, 1, 1) + + rows += 1 + grid.show_all() + else: + builder.get_object("ruleBox").set_visible(False) + + window.show_all() + + def eval_key_pressed(widget,event): + key, modifier = Gtk.accelerator_parse('Escape') + keyval = event.keyval + if keyval == key: + window.destroy() + + window.connect("key-press-event", eval_key_pressed) + + def show_question_dialog(self, title, message): + dialog = Gtk.MessageDialog(self.ui.get_object("mainWindow"), 0, Gtk.MessageType.WARNING, + Gtk.ButtonsType.YES_NO, title) + dialog.format_secondary_text(message) + response = dialog.run() + dialog.destroy() + return response + + def show_message(self, title, message): + dialog = Gtk.MessageDialog(self.ui.get_object("mainWindow"), 0, Gtk.MessageType.INFO, + Gtk.ButtonsType.OK, title) + dialog.format_secondary_text(message) + dialog.run() + dialog.destroy() + + def save_library(self): + # Save library file + util.save_file(util.get_root_filename("library"), self.library) + # Save tags file + util.save_file(util.get_root_filename("tags"), self.tags) + self.unsaved_changes = False + self.push_status("Library saved") + + def load_library(self): + # Load library file + self.library = util.load_file(util.get_root_filename("library")) + # Load tags file + self.tags = util.load_file(util.get_root_filename("tags")) + self.push_status("Library loaded") + + def get_untagged_cards(self): + lib = copy.copy(self.library) + for ids in self.tags.values(): + for card_id in ids: + try: + del lib[card_id] + except KeyError: + pass + return lib + + def get_tagged_cards(self, tag): + if not tag: + return self.library + else: + lib = {} + for card_id in self.tags[tag]: + lib[card_id] = self.library[card_id] + return lib + + def tag_card(self, card, tag): + list = self.tags[tag] + list.append(card.multiverse_id) + self.unsaved_changes = True + + def add_tag(self, tag): + self.tags[tag] = [] + self.push_status("Added Tag \"" + tag + "\"") + self.unsaved_changes = True + + def remove_tag(self, tag): + del self.tags[tag] + self.push_status("Removed Tag \"" + tag + "\"") + self.unsaved_changes = True + + def add_card_to_lib(self, card, tag=None): + if tag is not None: + self.tag_card(card, tag) + self.library[card.multiverse_id] = card + self.push_status(card.name + " added to library") + self.unsaved_changes = True + + def remove_card_from_lib(self, card): + del self.library[card.multiverse_id] + self.push_status(card.name + " removed from library") + self.unsaved_changes = True + + def get_card_image(self, card, sizex, sizey): + # Try using file from local cache, or load online + try: + pixbuf = self.image_cache[card.multiverse_id] + except KeyError as err: + util.log("No local image for " + card.name + ". Loading from " + card.image_url, util.LogLevel.Info) + pixbuf = util.load_card_image_online(card, sizex, sizey) + self.image_cache[card.multiverse_id] = pixbuf + return pixbuf + + def get_mana_icons(self, mana_string): + if not mana_string: + util.log("No mana string provided", util.LogLevel.Warning) + return + icon_list = re.findall("{(.*?)}", mana_string) + icon_name = "_".join(icon_list) + try: + icon = self.precon_icons[icon_name] + except KeyError: + icon = util.create_mana_icons(self.mana_icons, mana_string) + self.precon_icons[icon_name] = icon + return icon + + +def main(): + win = Application() + Gtk.main() diff --git a/cardvault/cardlist.py b/cardvault/cardlist.py index cac04f7..1dea2d7 100644 --- a/cardvault/cardlist.py +++ b/cardvault/cardlist.py @@ -1,6 +1,5 @@ import gi -import util -import logger +from cardvault import util from gi.repository import Gtk, GdkPixbuf, Gdk import time gi.require_version('Gtk', '3.0') @@ -8,7 +7,7 @@ gi.require_version('Gdk', '3.0') class CardList(Gtk.ScrolledWindow): - def __init__(self, with_filter): + def __init__(self, with_filter, app): Gtk.ScrolledWindow.__init__(self) self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.set_hexpand(True) @@ -16,6 +15,7 @@ class CardList(Gtk.ScrolledWindow): self.filtered = with_filter self.lib = {} + self.app = app # Columns are these: # 0 Multiverse ID @@ -136,11 +136,16 @@ class CardList(Gtk.ScrolledWindow): if card.multiverse_id is not None: - if util.library.__contains__(card_id) and colorize: + if self.app.library.__contains__(card_id) and colorize: color = util.card_view_colors["owned"] else: color = util.card_view_colors["unowned"] + if card.type == "Land": + mana_cost = None + else: + mana_cost = self.app.get_mana_icons(card.mana_cost) + item =[ card.multiverse_id, card.name, @@ -150,13 +155,13 @@ class CardList(Gtk.ScrolledWindow): card.power, card.toughness, ", ".join(card.printings), - util.get_mana_icons(card.mana_cost), + mana_cost, card.cmc, card.set_name, color] self.store.append(item) end = time.time() - logger.log("Time to build Table: " + str(round(end - start, 3)), logger.LogLevel.Info) + util.log("Time to build Table: " + str(round(end - start, 3)), util.LogLevel.Info) if self.filtered: self.list.set_model(self.filter_and_sort) self.list.thaw_child_notify() diff --git a/cardvault/config.py b/cardvault/config.py deleted file mode 100644 index 4168eab..0000000 --- a/cardvault/config.py +++ /dev/null @@ -1,25 +0,0 @@ -import gi -import os -gi.require_version('Gtk', '3.0') -gi.require_version('Gdk', '3.0') -from gi.repository import Gdk - - -# Title of the Program Window -application_title = "Card Vault v0.5" - -# Path of image cache -cache_path = os.path.dirname(__file__) + "/.cache/" -image_cache_path = os.path.dirname(__file__) + "/.cache/images/" -icon_cache_path = os.path.dirname(__file__) + "/.cache/icons/" - -# 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 = True - -start_page = "search" - -log_level = 3 diff --git a/cardvault/handlers.py b/cardvault/handlers.py index e4650be..d1f7943 100644 --- a/cardvault/handlers.py +++ b/cardvault/handlers.py @@ -1,11 +1,14 @@ import gi -import config -import lib_funct -import search_funct -import util +import datetime +import os from gi.repository import Gtk + gi.require_version('Gtk', '3.0') +from cardvault import lib_funct +from cardvault import search_funct +from cardvault import util + class Handlers: def __init__(self, app): @@ -14,14 +17,44 @@ class Handlers: # ----------------Main Window----------------- def do_save_library(self, item): - util.save_library() + self.app.save_library() def do_export_library(self, item): - util.export_library() + dialog = Gtk.FileChooserDialog("Export Library", self.app.ui.get_object("mainWindow"), + Gtk.FileChooserAction.SAVE, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) + dialog.set_current_name("mtg_export-" + datetime.datetime.now().strftime("%Y-%m-%d")) + dialog.set_current_folder(os.path.expanduser("~")) + response = dialog.run() + + if response == Gtk.ResponseType.OK: + # prepare export file + file = {"library": self.app.library, "tags": self.app.tags} + util.export_library(dialog.get_filename, file) + + dialog.destroy() def do_import_library(self, item): - util.import_library() - self.app.current_page.emit('show') + # Show file picker dialog for import + dialog = Gtk.FileChooserDialog("Import Library", self.app.ui.get_object("mainWindow"), + Gtk.FileChooserAction.OPEN, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) + dialog.set_current_folder(os.path.expanduser("~")) + response = dialog.run() + if response == Gtk.ResponseType.OK: + # Show confirmation message + override_question = self.app.show_question_dialog("Import Library", + "Importing a library will override your current library. " + "Proceed?") + if override_question == Gtk.ResponseType.YES: + (library, tags) = util.import_library(dialog.get_filename()) + self.app.library = library + self.app.tags = tags + # Cause current page to reload with imported data + self.app.current_page.emit('show') + dialog.destroy() def on_view_changed(self, item): if item.get_active(): @@ -34,22 +67,24 @@ class Handlers: container.show_all() self.app.current_page.emit('show') - app_title = new_page.get_name() + " - " + config.application_title + app_title = new_page.get_name() + " - " + util.APPLICATION_TITLE self.app.ui.get_object("mainWindow").set_title(app_title) def do_delete_event(self, arg1, arg2): - if util.unsaved_changes: - response = util.show_question_dialog("Unsaved Changes", "You have unsaved changes in your library. " + if self.app.unsaved_changes: + response = self.app.show_question_dialog("Unsaved Changes", "You have unsaved changes in your library. " "Save before exiting?") if response == Gtk.ResponseType.YES: - util.save_library() + self.app.save_library() # ----------------Search----------------- def do_search_cards(self, sender): search_term = self.app.ui.get_object("searchEntry").get_text() - results = search_funct.search_cards(search_term) + filters = search_funct.get_filters(self.app) + + results = search_funct.search_cards(search_term, filters) card_list = self.app.ui.get_object("searchResults").get_child() card_list.update(results, colorize=True) @@ -72,10 +107,10 @@ class Handlers: tree_iter = model.get_iter(path) card_id = model.get_value(tree_iter, 0) card = card_view.lib[card_id] - search_funct.add_to_library(card) + self.app.add_card_to_lib(card) search_funct.reload_serach_view(self.app) - #----------------Library----------------- + # ----------------Library----------------- def do_reload_library(self, view): lib_funct.reload_library(self.app) @@ -103,11 +138,11 @@ class Handlers: selected_cards = card_view.get_selected_cards() tag = entry.get_text() if tag != "": - lib_funct.tag_cards(selected_cards, tag) + lib_funct.tag_cards(selected_cards, tag, self.app) lib_funct.reload_library(self.app, tag) entry.set_text("") - def on_drag_data_received(self, widget, drag_context, x,y, data,info, time): + def on_drag_data_received(self, widget, drag_context, x, y, data, info, time): print("drag received") def on_tag_selected(self, selection, path, column): @@ -119,7 +154,7 @@ class Handlers: # Handlers for TreeViews etc. wich have been not added by Glade - #----------------Search----------------- + # ----------------Search----------------- def on_search_card_selected(self, tree, row_no, column): (model, path_list) = tree.get_selection().get_selected_rows() @@ -150,5 +185,3 @@ class Handlers: card_list = self.app.ui.get_object("libraryContainer").get_child() card = card_list.lib[card_id] self.app.show_card_details(card) - - diff --git a/cardvault/lib_funct.py b/cardvault/lib_funct.py index 77f0047..4958aa5 100644 --- a/cardvault/lib_funct.py +++ b/cardvault/lib_funct.py @@ -1,5 +1,4 @@ -import cardlist -import util +from cardvault import cardlist import gi gi.require_version('Gtk', '3.0') @@ -7,7 +6,7 @@ gi.require_version('Gtk', '3.0') def init_library_view(app): # Create Tree View for library container = app.ui.get_object("libraryContainer") - card_list = cardlist.CardList(True) + card_list = cardlist.CardList(True, app) card_list.set_name("libScroller") card_list.list.connect("row-activated", app.handlers.on_library_card_selected) container.add(card_list) @@ -20,10 +19,10 @@ def init_library_view(app): def reload_library(app, tag=None): if tag == "untagged": - lib = util.get_untagged_cards() + lib = app.get_untagged_cards() tag = None else: - lib = util.get_library(tag) + lib = app.get_tagged_cards(tag) reload_tag_list(app, tag) card_tree = app.ui.get_object("libraryContainer").get_child() if lib: @@ -35,9 +34,8 @@ def reload_library(app, tag=None): app.ui.get_object("noResults").set_visible(True) - def add_new_tag(name, app): - util.add_tag(name) + app.add_tag(name) reload_tag_list(app, True) @@ -46,17 +44,17 @@ def reload_tag_list(app, preserve=False): (path, column) = tree.get_cursor() store = tree.get_model() store.clear() - for tag, ids in util.tags.items(): + for tag, ids in app.tags.items(): store.append([tag, tag + " (" + str(len(ids)) + ")"]) if preserve: tree.set_cursor(path if path else 0) -def tag_cards(card_list, tag): +def tag_cards(card_list, tag, app): # Check if tag exist and create if necessary - if not util.tags.__contains__(tag): - util.add_tag(tag) + if not app.tags.__contains__(tag): + app.add_tag(tag) for card in card_list.values(): - if not util.tags[tag].__contains__(card.multiverse_id): - util.tag_card(card, tag) + if not app.tags[tag].__contains__(card.multiverse_id): + app.tag_card(card, tag) diff --git a/cardvault/logger.py b/cardvault/logger.py deleted file mode 100644 index aaf2675..0000000 --- a/cardvault/logger.py +++ /dev/null @@ -1,14 +0,0 @@ -import config -import enum - - -class LogLevel(enum.Enum): - Error = 1 - Warning = 2 - Info = 3 - - -def log(message, log_level): - if log_level.value <= config.log_level: - level_string = "[" + log_level.name + "] " - print(level_string + message) diff --git a/cardvault/network.py b/cardvault/network.py deleted file mode 100644 index ffd3cf7..0000000 --- a/cardvault/network.py +++ /dev/null @@ -1,11 +0,0 @@ -from urllib import request -from urllib.error import URLError, HTTPError -from mtgsdk import Set - - -def net_load_sets(): - try: - sets = Set.all() - except: - return "" - return sets diff --git a/cardvault/resources/mana/BP.png b/cardvault/resources/mana/B-P.png similarity index 100% rename from cardvault/resources/mana/BP.png rename to cardvault/resources/mana/B-P.png diff --git a/cardvault/resources/mana/BR.png b/cardvault/resources/mana/B-R.png similarity index 100% rename from cardvault/resources/mana/BR.png rename to cardvault/resources/mana/B-R.png diff --git a/cardvault/resources/mana/GP.png b/cardvault/resources/mana/G-P.png similarity index 100% rename from cardvault/resources/mana/GP.png rename to cardvault/resources/mana/G-P.png diff --git a/cardvault/resources/mana/GU.png b/cardvault/resources/mana/G-U.png similarity index 100% rename from cardvault/resources/mana/GU.png rename to cardvault/resources/mana/G-U.png diff --git a/cardvault/resources/mana/GW.png b/cardvault/resources/mana/G-W.png similarity index 100% rename from cardvault/resources/mana/GW.png rename to cardvault/resources/mana/G-W.png diff --git a/cardvault/resources/mana/RG.png b/cardvault/resources/mana/R-G.png similarity index 100% rename from cardvault/resources/mana/RG.png rename to cardvault/resources/mana/R-G.png diff --git a/cardvault/resources/mana/RP.png b/cardvault/resources/mana/R-P.png similarity index 100% rename from cardvault/resources/mana/RP.png rename to cardvault/resources/mana/R-P.png diff --git a/cardvault/resources/mana/RW.png b/cardvault/resources/mana/R-W.png similarity index 100% rename from cardvault/resources/mana/RW.png rename to cardvault/resources/mana/R-W.png diff --git a/cardvault/resources/mana/UB.png b/cardvault/resources/mana/U-B.png similarity index 100% rename from cardvault/resources/mana/UB.png rename to cardvault/resources/mana/U-B.png diff --git a/cardvault/resources/mana/UP.png b/cardvault/resources/mana/U-P.png similarity index 100% rename from cardvault/resources/mana/UP.png rename to cardvault/resources/mana/U-P.png diff --git a/cardvault/resources/mana/UR.png b/cardvault/resources/mana/U-R.png similarity index 100% rename from cardvault/resources/mana/UR.png rename to cardvault/resources/mana/U-R.png diff --git a/cardvault/resources/mana/WB.png b/cardvault/resources/mana/W-B.png similarity index 100% rename from cardvault/resources/mana/WB.png rename to cardvault/resources/mana/W-B.png diff --git a/cardvault/resources/mana/WP.png b/cardvault/resources/mana/W-P.png similarity index 100% rename from cardvault/resources/mana/WP.png rename to cardvault/resources/mana/W-P.png diff --git a/cardvault/resources/mana/WU.png b/cardvault/resources/mana/W-U.png similarity index 100% rename from cardvault/resources/mana/WU.png rename to cardvault/resources/mana/W-U.png diff --git a/cardvault/search_funct.py b/cardvault/search_funct.py index 529ed00..5605f8f 100644 --- a/cardvault/search_funct.py +++ b/cardvault/search_funct.py @@ -1,8 +1,6 @@ import gi -import util -import config -import cardlist -import logger +from cardvault import util +from cardvault import cardlist from gi.repository import Gtk, Gdk from mtgsdk import Card from urllib.error import URLError, HTTPError @@ -13,9 +11,9 @@ def init_search_view(app): # set mana icons on filter buttons buttons = [x for x in app.ui.get_object("manaFilterGrid").get_children() if isinstance(x, Gtk.ToggleButton)] - _init_mana_buttons(buttons) + _init_mana_buttons(app, buttons) # set auto completion for filter entry - _init_set_entry(app.ui.get_object("setEntry")) + _init_set_entry(app, app.ui.get_object("setEntry")) # Fill rarity box _init_combo_box(app.ui.get_object("rarityCombo"), util.rarity_dict.keys()) # Fill type box @@ -30,15 +28,34 @@ def reload_serach_view(app): pass -def add_to_library(card): - util.add_card_to_lib(card) +def get_filters(app): + output = {} + # Mana colors + color_list = [] + # Go through mana color buttons an get the active filters + for button in app.ui.get_object("manaFilterGrid").get_children(): + if isinstance(button, Gtk.ToggleButton): + if button.get_active(): + color_list.append(button.get_name()) + output["mana"] = ",".join(color_list) + # Rarity + combo = app.ui.get_object("rarityCombo") + output["rarity"] = _get_combo_value(combo) + # Type + combo = app.ui.get_object("typeCombo") + output["type"] = _get_combo_value(combo) + # Set + name = app.ui.get_object("setEntry").get_text() + output["set"] = "" + for set in app.sets.values(): + if set.name == name: + output["set"] = set.code + return output -def search_cards(term): - logger.log("Starting online search for '" + term + "'", logger.LogLevel.Info) - # Load filters from UI - filters = _get_filters(util.app) - logger.log("Used Filters: " + str(filters), logger.LogLevel.Info) +def search_cards(term, filters): + util.log("Starting online search for '" + term + "'", util.LogLevel.Info) + util.log("Used Filters: " + str(filters), util.LogLevel.Info) # Load card info from internet try: @@ -56,9 +73,9 @@ def search_cards(term): if len(cards) == 0: # TODO UI show no cards found return - logger.log("Found " + str(len(cards)) + " cards", logger.LogLevel.Info) + util.log("Found " + str(len(cards)) + " cards", util.LogLevel.Info) # Remove duplicate entries - if config.show_from_all_sets is False: + if util.SHOW_FROM_ALL_SETS is False: cards = _remove_duplicates(cards) # Pack results in a dictionary @@ -70,7 +87,7 @@ def search_cards(term): def _init_results_tree(app): overlay = app.ui.get_object("searchResults") - card_list = cardlist.CardList(False) + card_list = cardlist.CardList(False, app) card_list.set_name("resultsScroller") card_list.list.connect("row-activated", app.handlers.on_search_card_selected) card_list.selection.connect("changed", app.handlers.on_search_selection_changed) @@ -91,31 +108,6 @@ def _init_combo_box(combo, list): combo.set_active(0) -def _get_filters(app): - output = {} - # Mana colors - color_list = [] - # Go through mana color buttons an get the active filters - for button in app.ui.get_object("manaFilterGrid").get_children(): - if isinstance(button, Gtk.ToggleButton): - if button.get_active(): - color_list.append(button.get_name()) - output["mana"] = ",".join(color_list) - # Rarity - combo = app.ui.get_object("rarityCombo") - output["rarity"] = _get_combo_value(combo) - # Type - combo = app.ui.get_object("typeCombo") - output["type"] = _get_combo_value(combo) - # Set - name = app.ui.get_object("setEntry").get_text() - output["set"] = "" - for set in util.set_list: - if set.name == name: - output["set"] = set.code - return output - - def _remove_duplicates(cards): unique_cards = [] unique_names = [] @@ -133,15 +125,15 @@ def _get_combo_value(combo): return value.replace("All", "") -def _init_mana_buttons(button_list): +def _init_mana_buttons(app, button_list): for button in button_list: - image = Gtk.Image.new_from_pixbuf(util.create_mana_icons("{" + button.get_name() + "}")) + image = Gtk.Image.new_from_pixbuf(app.get_mana_icons("{" + button.get_name() + "}")) button.set_image(image) -def _init_set_entry(entry): +def _init_set_entry(app, entry): set_store = Gtk.ListStore(str, str) - for set in util.set_list: + for set in app.sets.values(): set_store.append([set.name, set.code]) completer = Gtk.EntryCompletion() completer.set_model(set_store) diff --git a/cardvault/util.py b/cardvault/util.py index 2fd2a39..5dae635 100644 --- a/cardvault/util.py +++ b/cardvault/util.py @@ -1,34 +1,46 @@ import os -import datetime import gi import re -import config -import logger -import network +import enum import copy +import json from gi.repository import GdkPixbuf, Gtk from PIL import Image as PImage from urllib import request import six.moves.cPickle as pickle gi.require_version('Gtk', '3.0') +from mtgsdk import Set +from mtgsdk import MtgException -# Locally stored images for faster loading times -imagecache = {} -manaicons = {} -mana_icons_preconstructed = {} +# Title of the Program Window +APPLICATION_TITLE = "Card Vault" -set_list = [] -set_dict = {} +# Program version +VERSION = "0.5.0" -# Card library object -library = {} -# Dictionary for tagged cards -tags = {} +# Path of image cache +CACHE_PATH = os.path.expanduser('~') + "/.cardvault/" +IMAGE_CACHE_PATH = os.path.expanduser('~') + "/.cardvault/images/" +ICON_CACHE_PATH = os.path.expanduser('~') + "/.cardvault/icons/" -status_bar = None -app = None -unsaved_changes = False +# When True Search view will list a card multiple times for each set they appear in +SHOW_FROM_ALL_SETS = True + +START_PAGE = "search" + +LOG_LEVEL = 1 + +default_config = { + "hide_duplicates_in_search": False, + "start_page": "search", + "log_level": 3, + "legality_colors": { + "Banned": "#C65642", + "Restricted": "#D39F30", + "Legal": "#62B62F" + } +} legality_colors ={ "Banned": "#C65642", @@ -52,264 +64,176 @@ rarity_dict = { card_types = ["Creature", "Artifact", "Instant", "Enchantment", "Sorcery", "Land", "Planeswalker"] -def export_library(): - dialog = Gtk.FileChooserDialog("Export Library", app.ui.get_object("mainWindow"), - Gtk.FileChooserAction.SAVE, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, - Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) - dialog.set_current_name("mtg_export-" + datetime.datetime.now().strftime("%Y-%m-%d")) - dialog.set_current_folder(os.path.expanduser("~")) - response = dialog.run() - if response == Gtk.ResponseType.OK: - # prepare export file - export = {"library": library, "tags": tags} - try: - pickle.dump(export, open(dialog.get_filename(), 'wb')) - - app.push_status("Library exported to \"" + dialog.get_filename() + "\"") - logger.log("Library exported to \"" + dialog.get_filename() + "\"", logger.LogLevel.Info) - except OSError as err: - show_message("Error", err.strerror) - logger.log(str(err), logger.LogLevel.Error) - - dialog.destroy() +class LogLevel(enum.Enum): + Error = 1 + Warning = 2 + Info = 3 -def import_library(): - dialog = Gtk.FileChooserDialog("Import Library", app.ui.get_object("mainWindow"), - Gtk.FileChooserAction.OPEN, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, - Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) - dialog.set_current_folder(os.path.expanduser("~")) - response = dialog.run() - if response == Gtk.ResponseType.OK: - override_question = show_question_dialog("Import Library", - "Importing a library will override your current library. " - "Proceed?") - if override_question == Gtk.ResponseType.YES: - - try: - imported = pickle.load(open(dialog.get_filename(), 'rb')) - except pickle.UnpicklingError as err: - show_message("Error", "Imported file is invalid") - logger.log(str(err) + " while importing", logger.LogLevel.Error) - dialog.destroy() - return - - # Check imported file - try: - global library - library = imported["library"] - global tags - tags = imported["tags"] - except KeyError as err: - logger.log("Invalid library format " + str(err), logger.LogLevel.Warning) - - # Try fallback method - library.clear() - for id, card in imported.items(): - library[id] = card - - save_library() - app.push_status("Library imported") - logger.log("Library imported", logger.LogLevel.Info) - dialog.destroy() +def log(message, log_level): + if log_level.value <= LOG_LEVEL: + level_string = "[" + log_level.name + "] " + print(level_string + message) -def save_library(): - if not os.path.exists(config.cache_path): - os.makedirs(config.cache_path) - lib_path = config.cache_path + "library" - tag_path = config.cache_path + "tags" - - # Serialize library object using pickle +def parse_config(filename, default): + config = copy.copy(default) try: - pickle.dump(library, open(lib_path, 'wb')) - pickle.dump(tags, open(tag_path, 'wb')) - except OSError as err: - show_message("Error", err.strerror) - logger.log(str(err), logger.LogLevel.Error) + with open(filename) as configfile: + loaded_config = json.load(configfile) + if 'legality_colors' in config and 'legality_colors' in loaded_config: + # Need to prevent nested dict from being overwritten with an incomplete dict + config['legality_colors'].update(loaded_config['legality_colors']) + loaded_config['legality_colors'] = config['legality_colors'] + config.update(loaded_config) + except IOError: + # Will just use the default config + # and create the file for manual editing + save_config(config, filename) + except ValueError: + # There's a syntax error in the config file + log("Syntax error wihle parsing config file", LogLevel.Error) return - - global unsaved_changes - unsaved_changes = False - app.push_status("Library saved.") - logger.log("library saved", logger.LogLevel.Info) + return config -def load_library(): - lib_path = config.cache_path + "library" - library.clear() +def save_config(config_dict, filename): + path = os.path.dirname(filename) + if not os.path.isdir(path): + os.mkdir(path) - if os.path.isfile(lib_path): - # Deserialize using pickle + with open(filename, 'wb') as configfile: + configfile.write(json.dumps(config_dict, sort_keys=True, + indent=4, separators=(',', ': ')).encode('utf-8')) + + +def get_root_filename(filename): + return os.path.expanduser(os.path.join('~', '.cardvault', filename)) + +def get_ui_filename(filename): + return os.path.expanduser(os.path.join(os.path.dirname(__file__), 'gui', filename)) + + +def reload_image_cache(path): + cache = {} + if not os.path.isdir(path): + os.mkdir(path) + imagefiles = os.listdir(path) + for imagefile in imagefiles: try: - library_loaded = pickle.load(open(lib_path, 'rb')) - for id, card in library_loaded.items(): - library[id] = card + pixbuf = GdkPixbuf.Pixbuf.new_from_file(path + imagefile) + # Strip filename extension + imagename = os.path.splitext(imagefile)[0] + cache[imagename] = pixbuf except OSError as err: - show_message("Error", err.strerror) - logger.log(str(err), logger.LogLevel.Error) - else: - save_library() - logger.log("No Library file found, creating new one", logger.LogLevel.Warning) + log("Error loading image: " + str(err), LogLevel.Error) + return cache -def load_tags(): - tag_path = config.cache_path + "tags" - tags.clear() - if not os.path.isfile(tag_path): - save_library() - logger.log("No tags file found, creating new one", logger.LogLevel.Warning) - try: - tags_loaded = pickle.load(open(tag_path, 'rb')) - for tag, ids in tags_loaded.items(): - tags[tag] = ids - except OSError as err: - show_message("Error", err.strerror) - logger.log(str(err), logger.LogLevel.Error) +def reload_preconstructed_icons(path): + cache = {} + if not os.path.exists(path): + os.makedirs(path) - -def load_sets(): - path = config.cache_path + "sets" - if not os.path.isfile(path): - # use mtgsdk api to retrieve al list of all sets - new_sets = network.net_load_sets() - if new_sets == "": - show_message("API Error", "Could not retrieve Set infos") - return - # Serialize the loaded data to a file - pickle.dump(new_sets, open(path, 'wb')) - # Deserialize set data from local file - 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) - set_dict[set.code] = set - - -def reload_image_cache(): - if not os.path.exists(config.image_cache_path): - os.makedirs(config.image_cache_path) - - # return array of images - imageslist = os.listdir(config.image_cache_path) - imagecache.clear() - for image in imageslist: - try: - pixbuf = GdkPixbuf.Pixbuf.new_from_file(config.image_cache_path + image) - imagecache[image] = pixbuf - except OSError as err: - print("Error loading image: " + str(err)) - - -def reload_preconstructed_icons(): - if not os.path.exists(config.icon_cache_path): - os.makedirs(config.icon_cache_path) - - icon_list = os.listdir(config.icon_cache_path) - mana_icons_preconstructed.clear() - for icon in icon_list: - list = re.findall("{(.*?)}", str(icon)) + iconfiles = os.listdir(path) + for file in iconfiles: + # Split filename into single icon names and remove extension + without_ext = file.split(".")[0] + list = without_ext.split("_") + # Compute size of the finished icon pic_width = len(list) * 105 pic_height = 105 try: - pixbuf = GdkPixbuf.Pixbuf.new_from_file(config.icon_cache_path + icon) + pixbuf = GdkPixbuf.Pixbuf.new_from_file(ICON_CACHE_PATH + file) pixbuf = pixbuf.scale_simple(pic_width / 5, pic_height / 5, GdkPixbuf.InterpType.HYPER) - mana_icons_preconstructed[icon] = pixbuf + # Set name for icon + iconname = "_".join(list) + cache[iconname] = pixbuf except OSError as err: - print("Error loading icon: " + str(err)) + log("Error loading image: " + str(err), LogLevel.Error) + return cache -# endregion - - -def get_library(tag=None): - if tag is None or tag == "All": - return library - else: - lib = {} - for card_id in tags[tag]: - lib[card_id] = library[card_id] - return lib - - -def get_untagged_cards(): - lib = copy.copy(library) - for ids in tags.values(): - for card_id in ids: - try: - del lib[card_id] - except KeyError: - pass - return lib - - -def tag_card(card, tag): - list = tags[tag] - list.append(card.multiverse_id) - global unsaved_changes - unsaved_changes = True - - -def add_tag(tag): - tags[tag] = [] - app.push_status("Added Tag \"" + tag + "\"") - global unsaved_changes - unsaved_changes = True - - -def remove_tag(tag): - del tags[tag] - app.push_status("Removed Tag \"" + tag + "\"") - global unsaved_changes - unsaved_changes = True - - -def add_card_to_lib(card, tag=None): - if tag is not None: - tag_card(card, tag) - library[card.multiverse_id] = card - app.push_status(card.name + " added to library") - global unsaved_changes - unsaved_changes = True - - -def remove_card_from_lib(card): - del library[card.multiverse_id] - app.push_status(card.name + " removed from library") - global unsaved_changes - unsaved_changes = True - - -def show_question_dialog(title, message): - dialog = Gtk.MessageDialog(app.ui.get_object("mainWindow"), 0, Gtk.MessageType.WARNING, - Gtk.ButtonsType.YES_NO, title) - dialog.format_secondary_text(message) - response = dialog.run() - dialog.destroy() - return response - - -def show_message(title, message): - dialog = Gtk.MessageDialog(app.ui.get_object("mainWindow"), 0, Gtk.MessageType.INFO, - Gtk.ButtonsType.OK, title) - dialog.format_secondary_text(message) - dialog.run() - dialog.destroy() - - -def load_mana_icons(): - path = os.path.dirname(__file__) + "/resources/mana/" +def load_mana_icons(path): if not os.path.exists(path): - print("ERROR: Directory for mana icons not found") + log("Directory for mana icons not found " + path, LogLevel.Error) return - # return array of icons - imagelist = os.listdir(path) - manaicons.clear() - for image in imagelist: - img = PImage.open(path + image) - manaicons[os.path.splitext(image)[0]] = img + icons = {} + filenames = os.listdir(path) + for file in filenames: + img = PImage.open(path + file) + # Strip file extension + name = os.path.splitext(file)[0] + icons[name] = img + return icons + + +def load_sets(filename): + if not os.path.isfile(filename): + # use mtgsdk api to retrieve al list of all sets + try: + sets = Set.all() + except MtgException as err: + log(str(err), LogLevel.Error) + return + # Serialize the loaded data to a file + pickle.dump(sets, open(filename, 'wb')) + # Deserialize set data from local file + sets = pickle.load(open(filename, 'rb')) + # Sort the loaded sets based on the sets name + output = {} + for set in sorted(sets, key=lambda x: x.name): + output[set.code] = set + return output + + +def export_library(path, file): + try: + pickle.dump(file, open(path, 'wb')) + log("Library exported to \"" + path + "\"", LogLevel.Info) + except OSError as err: + log(str(err), LogLevel.Error) + + +def import_library(path): + try: + imported = pickle.load(open(path, 'rb')) + except pickle.UnpicklingError as err: + log(str(err) + " while importing", LogLevel.Error) + return + # Parse imported file + try: + library = imported["library"] + tags = imported["tags"] + except KeyError as err: + log("Invalid library format " + str(err), LogLevel.Error) + return + + log("Library imported", LogLevel.Info) + return (library, tags) + + +def save_file(path, file): + if not os.path.exists(path): + os.makedirs(path) + # Serialize using cPickle + try: + pickle.dump(file, open(path, 'wb')) + except OSError as err: + log(str(err), LogLevel.Error) + return + log("Saved file " + path, LogLevel.Info) + + +def load_file(path): + if not os.path.isfile(path): + log(path + " does not exist", LogLevel.Error) + try: + loaded = pickle.load(open(path, 'rb')) + except OSError as err: + log(str(err), LogLevel.Error) + return + return loaded def load_dummy_image(sizex, sizey): @@ -320,38 +244,17 @@ def load_dummy_image(sizex, sizey): def load_card_image_online(card, sizex, sizey): url = card.image_url if url is None: - print("No Image URL provided") + log("No Image URL for " + card.name, LogLevel.Warning) return load_dummy_image(sizex, sizey) - filename = config.image_cache_path + card.multiverse_id.__str__() + ".PNG" + filename = IMAGE_CACHE_PATH + str(card.multiverse_id) + ".png" request.urlretrieve(url, filename) - reload_image_cache() return GdkPixbuf.Pixbuf.new_from_file_at_size(filename, sizex, sizey) -def load_card_image(card, sizex, sizey): - # Try loading from disk, if file exists - filename = str(card.multiverse_id) + ".PNG" - if imagecache.__contains__(filename): - pixbuf = imagecache[filename] - return pixbuf.scale_simple(sizex, sizey, GdkPixbuf.InterpType.BILINEAR) - else: - return load_card_image_online(card, sizex, sizey) - - -def get_mana_icons(mana_string): - if not mana_string: - return - try: - icon = mana_icons_preconstructed[mana_string.replace("/", "") + ".png"] - except KeyError: - icon = create_mana_icons(mana_string) - mana_icons_preconstructed[mana_string] = icon - return icon - - -def create_mana_icons(mana_string): +def create_mana_icons(icon_dict, mana_string): # Convert the string to a List - list = re.findall("{(.*?)}", str(mana_string)) + safe_string = mana_string.replace("/", "-") + list = re.findall("{(.*?)}", safe_string) if len(list) == 0: return # Compute horizontal size for the final image @@ -362,18 +265,22 @@ def create_mana_icons(mana_string): # Go through all entries an add the correspondent icon to the final image for icon in list: xpos = poscounter * 105 - loaded = manaicons.get(icon.replace("/", "")) - if loaded is None: - print("ERROR: No icon file named \"" + icon + "\" found.") - else: - image.paste(loaded, (xpos, 0)) + try: + loaded = icon_dict[icon] + except KeyError as err: + log("No icon file named '" + icon + "' found.", LogLevel.Warning) + return + image.paste(loaded, (xpos, 0)) poscounter += 1 - path = config.icon_cache_path + mana_string.replace("/", "") + ".png" + # Save Icon file + path = ICON_CACHE_PATH + "_".join(list) + ".png" image.save(path) try: pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) pixbuf = pixbuf.scale_simple(image.width / 5, image.height / 5, GdkPixbuf.InterpType.HYPER) except: return - mana_icons_preconstructed[mana_string.replace("/", "") + ".png"] = pixbuf return pixbuf + +# endregion + diff --git a/cardvault/window.py b/cardvault/window.py deleted file mode 100644 index 74f1df2..0000000 --- a/cardvault/window.py +++ /dev/null @@ -1,140 +0,0 @@ -import config -import handlers -import util -import search_funct -import lib_funct -import gi -from gi.repository import Gtk, Pango -gi.require_version('Gtk', '3.0') - - -class MainWindow: - def __init__(self): - self.ui = Gtk.Builder() - self.ui.add_from_file("gui/mainwindow.glade") - self.ui.add_from_file("gui/overlays.glade") - self.ui.add_from_file("gui/search.glade") - self.ui.add_from_file("gui/library.glade") - window = self.ui.get_object("mainWindow") - self.current_page = None - util.app = self - not_found = self.ui.get_object("pageNotFound") - - self.pages = { - "search": self.ui.get_object("searchView"), - "library": self.ui.get_object("libraryView"), - "decks": not_found - } - - # Load local image Data - util.reload_image_cache() - util.reload_preconstructed_icons() - util.load_mana_icons() - - util.load_sets() - util.load_library() - util.load_tags() - - self.handlers = handlers.Handlers(self) - self.ui.connect_signals(self.handlers) - - search_funct.init_search_view(self) - - lib_funct.init_library_view(self) - - window.connect('delete-event', Gtk.main_quit) - window.show_all() - self.push_status("Card Vault ready.") - - view_menu = self.ui.get_object("viewMenu") - start_page = [page for page in view_menu.get_children() if page.get_name() == config.start_page] - start_page[0].activate() - - def push_status(self, msg): - status_bar = self.ui.get_object("statusBar") - status_bar.pop(0) - status_bar.push(0, msg) - - def show_card_details(self, card): - builder = Gtk.Builder() - builder.add_from_file("gui/detailswindow.glade") - builder.add_from_file("gui/overlays.glade") - window = builder.get_object("cardDetails") - window.set_title(card.name) - # Card Image - container = builder.get_object("imageContainer") - pixbuf = util.load_card_image(card, 63 * 5, 88 * 5) - image = Gtk.Image().new_from_pixbuf(pixbuf) - container.add(image) - # Name - builder.get_object("cardName").set_text(card.name) - # Types - supertypes = "" - if card.subtypes is not None: - supertypes = " - " + " ".join(card.subtypes) - types = " ".join(card.types) + supertypes - builder.get_object("cardTypes").set_text(types) - # Rarity - builder.get_object("cardRarity").set_text(card.rarity if card.rarity else "") - # Release - builder.get_object("cardReleaseDate").set_text(card.release_date if card.release_date else "") - # Set - builder.get_object("cardSet").set_text(card.set_name) - # Printings - prints = [] - for set in card.printings: - prints.append(util.set_dict[set].name) - builder.get_object("cardPrintings").set_text(", ".join(prints)) - # Legalities - grid = builder.get_object("legalitiesGrid") - rows = 1 - for legality in card.legalities if card.legalities else {}: - date_label = Gtk.Label() - date_label.set_halign(Gtk.Align.END) - text_label = Gtk.Label() - text_label.set_line_wrap_mode(Pango.WrapMode.WORD) - text_label.set_line_wrap(True) - text_label.set_halign(Gtk.Align.END) - color = util.legality_colors[legality["legality"]] - date_label.set_markup("" + legality["format"] + ":" + "") - text_label.set_markup("" + legality["legality"] + "") - grid.attach(date_label, 0, rows + 2, 1, 1) - grid.attach(text_label, 1, rows + 2, 1, 1) - - rows += 1 - grid.show_all() - - # Rulings - if card.rulings: - grid = builder.get_object("rulesGrid") - rows = 1 - for rule in card.rulings: - date_label = Gtk.Label(rule["date"]) - text_label = Gtk.Label(rule["text"]) - text_label.set_line_wrap_mode(Pango.WrapMode.WORD) - text_label.set_line_wrap(True) - text_label.set_justify(Gtk.Justification.LEFT) - text_label.set_halign(Gtk.Align.START) - - grid.attach(date_label, 0, rows+2, 1, 1) - grid.attach(text_label, 1, rows+2, 1, 1) - - rows += 1 - grid.show_all() - else: - builder.get_object("ruleBox").set_visible(False) - - window.show_all() - - def eval_key_pressed(widget,event): - key, modifier = Gtk.accelerator_parse('Escape') - keyval = event.keyval - if keyval == key: - window.destroy() - - window.connect("key-press-event", eval_key_pressed) - - - -win = MainWindow() -Gtk.main() diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..0cd4231 --- /dev/null +++ b/setup.py @@ -0,0 +1,38 @@ +from setuptools import setup, find_packages +from cardvault import util + +try: + LONG_DESCRIPTION = open("README.rst").read() +except IOError: + LONG_DESCRIPTION = __doc__ + + +setup( + name=util.APPLICATION_TITLE, + version=util.VERSION, + packages=find_packages(), + + # install_requires=['pygobject'], + package_data={'cardvault': ['resources/images/*', 'resources/mana/*', 'gui/*']}, + + author='luxick', + author_email='cardvoult@luxick.de', + description='Managing MTG card libraries and decks', + long_description=LONG_DESCRIPTION, + url='https://github.com/luxick/cardvault', + keywords='card manager, gtk, MTG, Magic the Gathering', + license="MIT", + entry_points={ + 'gui_scripts': [ + 'cardvault = cardvault.application:main', + ] + }, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: End Users/Desktop', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'License :: OSI Approved :: MIT License', + ] + )