Restructure project
19
README.rst
Normal file
@@ -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
|
||||||
2
bin/cardvault
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from cardvault import application
|
||||||
|
application.main()
|
||||||
0
cardvault/__init__.py
Normal file
263
cardvault/application.py
Normal file
@@ -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("<span fgcolor=\""+color+"\">" + legality["format"] + ":" + "</span>")
|
||||||
|
text_label.set_markup("<span fgcolor=\""+color+"\">" + legality["legality"] + "</span>")
|
||||||
|
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()
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import gi
|
import gi
|
||||||
import util
|
from cardvault import util
|
||||||
import logger
|
|
||||||
from gi.repository import Gtk, GdkPixbuf, Gdk
|
from gi.repository import Gtk, GdkPixbuf, Gdk
|
||||||
import time
|
import time
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
@@ -8,7 +7,7 @@ gi.require_version('Gdk', '3.0')
|
|||||||
|
|
||||||
|
|
||||||
class CardList(Gtk.ScrolledWindow):
|
class CardList(Gtk.ScrolledWindow):
|
||||||
def __init__(self, with_filter):
|
def __init__(self, with_filter, app):
|
||||||
Gtk.ScrolledWindow.__init__(self)
|
Gtk.ScrolledWindow.__init__(self)
|
||||||
self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
||||||
self.set_hexpand(True)
|
self.set_hexpand(True)
|
||||||
@@ -16,6 +15,7 @@ class CardList(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
self.filtered = with_filter
|
self.filtered = with_filter
|
||||||
self.lib = {}
|
self.lib = {}
|
||||||
|
self.app = app
|
||||||
|
|
||||||
# Columns are these:
|
# Columns are these:
|
||||||
# 0 Multiverse ID
|
# 0 Multiverse ID
|
||||||
@@ -136,11 +136,16 @@ class CardList(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
if card.multiverse_id is not None:
|
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"]
|
color = util.card_view_colors["owned"]
|
||||||
else:
|
else:
|
||||||
color = util.card_view_colors["unowned"]
|
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 =[
|
item =[
|
||||||
card.multiverse_id,
|
card.multiverse_id,
|
||||||
card.name,
|
card.name,
|
||||||
@@ -150,13 +155,13 @@ class CardList(Gtk.ScrolledWindow):
|
|||||||
card.power,
|
card.power,
|
||||||
card.toughness,
|
card.toughness,
|
||||||
", ".join(card.printings),
|
", ".join(card.printings),
|
||||||
util.get_mana_icons(card.mana_cost),
|
mana_cost,
|
||||||
card.cmc,
|
card.cmc,
|
||||||
card.set_name,
|
card.set_name,
|
||||||
color]
|
color]
|
||||||
self.store.append(item)
|
self.store.append(item)
|
||||||
end = time.time()
|
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:
|
if self.filtered:
|
||||||
self.list.set_model(self.filter_and_sort)
|
self.list.set_model(self.filter_and_sort)
|
||||||
self.list.thaw_child_notify()
|
self.list.thaw_child_notify()
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
import gi
|
import gi
|
||||||
import config
|
import datetime
|
||||||
import lib_funct
|
import os
|
||||||
import search_funct
|
|
||||||
import util
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
|
from cardvault import lib_funct
|
||||||
|
from cardvault import search_funct
|
||||||
|
from cardvault import util
|
||||||
|
|
||||||
|
|
||||||
class Handlers:
|
class Handlers:
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
@@ -14,14 +17,44 @@ class Handlers:
|
|||||||
# ----------------Main Window-----------------
|
# ----------------Main Window-----------------
|
||||||
|
|
||||||
def do_save_library(self, item):
|
def do_save_library(self, item):
|
||||||
util.save_library()
|
self.app.save_library()
|
||||||
|
|
||||||
def do_export_library(self, item):
|
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):
|
def do_import_library(self, item):
|
||||||
util.import_library()
|
# Show file picker dialog for import
|
||||||
self.app.current_page.emit('show')
|
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):
|
def on_view_changed(self, item):
|
||||||
if item.get_active():
|
if item.get_active():
|
||||||
@@ -34,22 +67,24 @@ class Handlers:
|
|||||||
container.show_all()
|
container.show_all()
|
||||||
self.app.current_page.emit('show')
|
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)
|
self.app.ui.get_object("mainWindow").set_title(app_title)
|
||||||
|
|
||||||
def do_delete_event(self, arg1, arg2):
|
def do_delete_event(self, arg1, arg2):
|
||||||
if util.unsaved_changes:
|
if self.app.unsaved_changes:
|
||||||
response = util.show_question_dialog("Unsaved Changes", "You have unsaved changes in your library. "
|
response = self.app.show_question_dialog("Unsaved Changes", "You have unsaved changes in your library. "
|
||||||
"Save before exiting?")
|
"Save before exiting?")
|
||||||
if response == Gtk.ResponseType.YES:
|
if response == Gtk.ResponseType.YES:
|
||||||
util.save_library()
|
self.app.save_library()
|
||||||
|
|
||||||
# ----------------Search-----------------
|
# ----------------Search-----------------
|
||||||
|
|
||||||
def do_search_cards(self, sender):
|
def do_search_cards(self, sender):
|
||||||
search_term = self.app.ui.get_object("searchEntry").get_text()
|
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 = self.app.ui.get_object("searchResults").get_child()
|
||||||
card_list.update(results, colorize=True)
|
card_list.update(results, colorize=True)
|
||||||
@@ -72,10 +107,10 @@ class Handlers:
|
|||||||
tree_iter = model.get_iter(path)
|
tree_iter = model.get_iter(path)
|
||||||
card_id = model.get_value(tree_iter, 0)
|
card_id = model.get_value(tree_iter, 0)
|
||||||
card = card_view.lib[card_id]
|
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)
|
search_funct.reload_serach_view(self.app)
|
||||||
|
|
||||||
#----------------Library-----------------
|
# ----------------Library-----------------
|
||||||
|
|
||||||
def do_reload_library(self, view):
|
def do_reload_library(self, view):
|
||||||
lib_funct.reload_library(self.app)
|
lib_funct.reload_library(self.app)
|
||||||
@@ -103,11 +138,11 @@ class Handlers:
|
|||||||
selected_cards = card_view.get_selected_cards()
|
selected_cards = card_view.get_selected_cards()
|
||||||
tag = entry.get_text()
|
tag = entry.get_text()
|
||||||
if tag != "":
|
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)
|
lib_funct.reload_library(self.app, tag)
|
||||||
entry.set_text("")
|
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")
|
print("drag received")
|
||||||
|
|
||||||
def on_tag_selected(self, selection, path, column):
|
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
|
# Handlers for TreeViews etc. wich have been not added by Glade
|
||||||
|
|
||||||
#----------------Search-----------------
|
# ----------------Search-----------------
|
||||||
|
|
||||||
def on_search_card_selected(self, tree, row_no, column):
|
def on_search_card_selected(self, tree, row_no, column):
|
||||||
(model, path_list) = tree.get_selection().get_selected_rows()
|
(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_list = self.app.ui.get_object("libraryContainer").get_child()
|
||||||
card = card_list.lib[card_id]
|
card = card_list.lib[card_id]
|
||||||
self.app.show_card_details(card)
|
self.app.show_card_details(card)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import cardlist
|
from cardvault import cardlist
|
||||||
import util
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
@@ -7,7 +6,7 @@ gi.require_version('Gtk', '3.0')
|
|||||||
def init_library_view(app):
|
def init_library_view(app):
|
||||||
# Create Tree View for library
|
# Create Tree View for library
|
||||||
container = app.ui.get_object("libraryContainer")
|
container = app.ui.get_object("libraryContainer")
|
||||||
card_list = cardlist.CardList(True)
|
card_list = cardlist.CardList(True, app)
|
||||||
card_list.set_name("libScroller")
|
card_list.set_name("libScroller")
|
||||||
card_list.list.connect("row-activated", app.handlers.on_library_card_selected)
|
card_list.list.connect("row-activated", app.handlers.on_library_card_selected)
|
||||||
container.add(card_list)
|
container.add(card_list)
|
||||||
@@ -20,10 +19,10 @@ def init_library_view(app):
|
|||||||
|
|
||||||
def reload_library(app, tag=None):
|
def reload_library(app, tag=None):
|
||||||
if tag == "untagged":
|
if tag == "untagged":
|
||||||
lib = util.get_untagged_cards()
|
lib = app.get_untagged_cards()
|
||||||
tag = None
|
tag = None
|
||||||
else:
|
else:
|
||||||
lib = util.get_library(tag)
|
lib = app.get_tagged_cards(tag)
|
||||||
reload_tag_list(app, tag)
|
reload_tag_list(app, tag)
|
||||||
card_tree = app.ui.get_object("libraryContainer").get_child()
|
card_tree = app.ui.get_object("libraryContainer").get_child()
|
||||||
if lib:
|
if lib:
|
||||||
@@ -35,9 +34,8 @@ def reload_library(app, tag=None):
|
|||||||
app.ui.get_object("noResults").set_visible(True)
|
app.ui.get_object("noResults").set_visible(True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_new_tag(name, app):
|
def add_new_tag(name, app):
|
||||||
util.add_tag(name)
|
app.add_tag(name)
|
||||||
reload_tag_list(app, True)
|
reload_tag_list(app, True)
|
||||||
|
|
||||||
|
|
||||||
@@ -46,17 +44,17 @@ def reload_tag_list(app, preserve=False):
|
|||||||
(path, column) = tree.get_cursor()
|
(path, column) = tree.get_cursor()
|
||||||
store = tree.get_model()
|
store = tree.get_model()
|
||||||
store.clear()
|
store.clear()
|
||||||
for tag, ids in util.tags.items():
|
for tag, ids in app.tags.items():
|
||||||
store.append([tag, tag + " (" + str(len(ids)) + ")"])
|
store.append([tag, tag + " (" + str(len(ids)) + ")"])
|
||||||
if preserve:
|
if preserve:
|
||||||
tree.set_cursor(path if path else 0)
|
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
|
# Check if tag exist and create if necessary
|
||||||
if not util.tags.__contains__(tag):
|
if not app.tags.__contains__(tag):
|
||||||
util.add_tag(tag)
|
app.add_tag(tag)
|
||||||
|
|
||||||
for card in card_list.values():
|
for card in card_list.values():
|
||||||
if not util.tags[tag].__contains__(card.multiverse_id):
|
if not app.tags[tag].__contains__(card.multiverse_id):
|
||||||
util.tag_card(card, tag)
|
app.tag_card(card, tag)
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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
|
|
||||||
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
@@ -1,8 +1,6 @@
|
|||||||
import gi
|
import gi
|
||||||
import util
|
from cardvault import util
|
||||||
import config
|
from cardvault import cardlist
|
||||||
import cardlist
|
|
||||||
import logger
|
|
||||||
from gi.repository import Gtk, Gdk
|
from gi.repository import Gtk, Gdk
|
||||||
from mtgsdk import Card
|
from mtgsdk import Card
|
||||||
from urllib.error import URLError, HTTPError
|
from urllib.error import URLError, HTTPError
|
||||||
@@ -13,9 +11,9 @@ def init_search_view(app):
|
|||||||
# set mana icons on filter buttons
|
# set mana icons on filter buttons
|
||||||
buttons = [x for x in app.ui.get_object("manaFilterGrid").get_children()
|
buttons = [x for x in app.ui.get_object("manaFilterGrid").get_children()
|
||||||
if isinstance(x, Gtk.ToggleButton)]
|
if isinstance(x, Gtk.ToggleButton)]
|
||||||
_init_mana_buttons(buttons)
|
_init_mana_buttons(app, buttons)
|
||||||
# set auto completion for filter entry
|
# 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
|
# Fill rarity box
|
||||||
_init_combo_box(app.ui.get_object("rarityCombo"), util.rarity_dict.keys())
|
_init_combo_box(app.ui.get_object("rarityCombo"), util.rarity_dict.keys())
|
||||||
# Fill type box
|
# Fill type box
|
||||||
@@ -30,15 +28,34 @@ def reload_serach_view(app):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def add_to_library(card):
|
def get_filters(app):
|
||||||
util.add_card_to_lib(card)
|
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):
|
def search_cards(term, filters):
|
||||||
logger.log("Starting online search for '" + term + "'", logger.LogLevel.Info)
|
util.log("Starting online search for '" + term + "'", util.LogLevel.Info)
|
||||||
# Load filters from UI
|
util.log("Used Filters: " + str(filters), util.LogLevel.Info)
|
||||||
filters = _get_filters(util.app)
|
|
||||||
logger.log("Used Filters: " + str(filters), logger.LogLevel.Info)
|
|
||||||
|
|
||||||
# Load card info from internet
|
# Load card info from internet
|
||||||
try:
|
try:
|
||||||
@@ -56,9 +73,9 @@ def search_cards(term):
|
|||||||
if len(cards) == 0:
|
if len(cards) == 0:
|
||||||
# TODO UI show no cards found
|
# TODO UI show no cards found
|
||||||
return
|
return
|
||||||
logger.log("Found " + str(len(cards)) + " cards", logger.LogLevel.Info)
|
util.log("Found " + str(len(cards)) + " cards", util.LogLevel.Info)
|
||||||
# Remove duplicate entries
|
# Remove duplicate entries
|
||||||
if config.show_from_all_sets is False:
|
if util.SHOW_FROM_ALL_SETS is False:
|
||||||
cards = _remove_duplicates(cards)
|
cards = _remove_duplicates(cards)
|
||||||
|
|
||||||
# Pack results in a dictionary
|
# Pack results in a dictionary
|
||||||
@@ -70,7 +87,7 @@ def search_cards(term):
|
|||||||
|
|
||||||
def _init_results_tree(app):
|
def _init_results_tree(app):
|
||||||
overlay = app.ui.get_object("searchResults")
|
overlay = app.ui.get_object("searchResults")
|
||||||
card_list = cardlist.CardList(False)
|
card_list = cardlist.CardList(False, app)
|
||||||
card_list.set_name("resultsScroller")
|
card_list.set_name("resultsScroller")
|
||||||
card_list.list.connect("row-activated", app.handlers.on_search_card_selected)
|
card_list.list.connect("row-activated", app.handlers.on_search_card_selected)
|
||||||
card_list.selection.connect("changed", app.handlers.on_search_selection_changed)
|
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)
|
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):
|
def _remove_duplicates(cards):
|
||||||
unique_cards = []
|
unique_cards = []
|
||||||
unique_names = []
|
unique_names = []
|
||||||
@@ -133,15 +125,15 @@ def _get_combo_value(combo):
|
|||||||
return value.replace("All", "")
|
return value.replace("All", "")
|
||||||
|
|
||||||
|
|
||||||
def _init_mana_buttons(button_list):
|
def _init_mana_buttons(app, button_list):
|
||||||
for button in 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)
|
button.set_image(image)
|
||||||
|
|
||||||
|
|
||||||
def _init_set_entry(entry):
|
def _init_set_entry(app, entry):
|
||||||
set_store = Gtk.ListStore(str, str)
|
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])
|
set_store.append([set.name, set.code])
|
||||||
completer = Gtk.EntryCompletion()
|
completer = Gtk.EntryCompletion()
|
||||||
completer.set_model(set_store)
|
completer.set_model(set_store)
|
||||||
|
|||||||
@@ -1,34 +1,46 @@
|
|||||||
import os
|
import os
|
||||||
import datetime
|
|
||||||
import gi
|
import gi
|
||||||
import re
|
import re
|
||||||
import config
|
import enum
|
||||||
import logger
|
|
||||||
import network
|
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
from gi.repository import GdkPixbuf, Gtk
|
from gi.repository import GdkPixbuf, Gtk
|
||||||
from PIL import Image as PImage
|
from PIL import Image as PImage
|
||||||
from urllib import request
|
from urllib import request
|
||||||
import six.moves.cPickle as pickle
|
import six.moves.cPickle as pickle
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
|
from mtgsdk import Set
|
||||||
|
from mtgsdk import MtgException
|
||||||
|
|
||||||
# Locally stored images for faster loading times
|
# Title of the Program Window
|
||||||
imagecache = {}
|
APPLICATION_TITLE = "Card Vault"
|
||||||
manaicons = {}
|
|
||||||
mana_icons_preconstructed = {}
|
|
||||||
|
|
||||||
set_list = []
|
# Program version
|
||||||
set_dict = {}
|
VERSION = "0.5.0"
|
||||||
|
|
||||||
# Card library object
|
# Path of image cache
|
||||||
library = {}
|
CACHE_PATH = os.path.expanduser('~') + "/.cardvault/"
|
||||||
# Dictionary for tagged cards
|
IMAGE_CACHE_PATH = os.path.expanduser('~') + "/.cardvault/images/"
|
||||||
tags = {}
|
ICON_CACHE_PATH = os.path.expanduser('~') + "/.cardvault/icons/"
|
||||||
|
|
||||||
status_bar = None
|
# When True Search view will list a card multiple times for each set they appear in
|
||||||
app = None
|
SHOW_FROM_ALL_SETS = True
|
||||||
unsaved_changes = False
|
|
||||||
|
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 ={
|
legality_colors ={
|
||||||
"Banned": "#C65642",
|
"Banned": "#C65642",
|
||||||
@@ -52,264 +64,176 @@ rarity_dict = {
|
|||||||
card_types = ["Creature", "Artifact", "Instant", "Enchantment", "Sorcery", "Land", "Planeswalker"]
|
card_types = ["Creature", "Artifact", "Instant", "Enchantment", "Sorcery", "Land", "Planeswalker"]
|
||||||
|
|
||||||
|
|
||||||
def export_library():
|
class LogLevel(enum.Enum):
|
||||||
dialog = Gtk.FileChooserDialog("Export Library", app.ui.get_object("mainWindow"),
|
Error = 1
|
||||||
Gtk.FileChooserAction.SAVE,
|
Warning = 2
|
||||||
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
Info = 3
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
def import_library():
|
def log(message, log_level):
|
||||||
dialog = Gtk.FileChooserDialog("Import Library", app.ui.get_object("mainWindow"),
|
if log_level.value <= LOG_LEVEL:
|
||||||
Gtk.FileChooserAction.OPEN,
|
level_string = "[" + log_level.name + "] "
|
||||||
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
print(level_string + message)
|
||||||
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 save_library():
|
def parse_config(filename, default):
|
||||||
if not os.path.exists(config.cache_path):
|
config = copy.copy(default)
|
||||||
os.makedirs(config.cache_path)
|
|
||||||
lib_path = config.cache_path + "library"
|
|
||||||
tag_path = config.cache_path + "tags"
|
|
||||||
|
|
||||||
# Serialize library object using pickle
|
|
||||||
try:
|
try:
|
||||||
pickle.dump(library, open(lib_path, 'wb'))
|
with open(filename) as configfile:
|
||||||
pickle.dump(tags, open(tag_path, 'wb'))
|
loaded_config = json.load(configfile)
|
||||||
except OSError as err:
|
if 'legality_colors' in config and 'legality_colors' in loaded_config:
|
||||||
show_message("Error", err.strerror)
|
# Need to prevent nested dict from being overwritten with an incomplete dict
|
||||||
logger.log(str(err), logger.LogLevel.Error)
|
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
|
return
|
||||||
|
return config
|
||||||
global unsaved_changes
|
|
||||||
unsaved_changes = False
|
|
||||||
app.push_status("Library saved.")
|
|
||||||
logger.log("library saved", logger.LogLevel.Info)
|
|
||||||
|
|
||||||
|
|
||||||
def load_library():
|
def save_config(config_dict, filename):
|
||||||
lib_path = config.cache_path + "library"
|
path = os.path.dirname(filename)
|
||||||
library.clear()
|
if not os.path.isdir(path):
|
||||||
|
os.mkdir(path)
|
||||||
|
|
||||||
if os.path.isfile(lib_path):
|
with open(filename, 'wb') as configfile:
|
||||||
# Deserialize using pickle
|
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:
|
try:
|
||||||
library_loaded = pickle.load(open(lib_path, 'rb'))
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path + imagefile)
|
||||||
for id, card in library_loaded.items():
|
# Strip filename extension
|
||||||
library[id] = card
|
imagename = os.path.splitext(imagefile)[0]
|
||||||
|
cache[imagename] = pixbuf
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
show_message("Error", err.strerror)
|
log("Error loading image: " + str(err), LogLevel.Error)
|
||||||
logger.log(str(err), logger.LogLevel.Error)
|
return cache
|
||||||
else:
|
|
||||||
save_library()
|
|
||||||
logger.log("No Library file found, creating new one", logger.LogLevel.Warning)
|
|
||||||
|
|
||||||
|
|
||||||
def load_tags():
|
def reload_preconstructed_icons(path):
|
||||||
tag_path = config.cache_path + "tags"
|
cache = {}
|
||||||
tags.clear()
|
if not os.path.exists(path):
|
||||||
if not os.path.isfile(tag_path):
|
os.makedirs(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)
|
|
||||||
|
|
||||||
|
iconfiles = os.listdir(path)
|
||||||
def load_sets():
|
for file in iconfiles:
|
||||||
path = config.cache_path + "sets"
|
# Split filename into single icon names and remove extension
|
||||||
if not os.path.isfile(path):
|
without_ext = file.split(".")[0]
|
||||||
# use mtgsdk api to retrieve al list of all sets
|
list = without_ext.split("_")
|
||||||
new_sets = network.net_load_sets()
|
# Compute size of the finished icon
|
||||||
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))
|
|
||||||
pic_width = len(list) * 105
|
pic_width = len(list) * 105
|
||||||
pic_height = 105
|
pic_height = 105
|
||||||
try:
|
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)
|
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:
|
except OSError as err:
|
||||||
print("Error loading icon: " + str(err))
|
log("Error loading image: " + str(err), LogLevel.Error)
|
||||||
|
return cache
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
def load_mana_icons(path):
|
||||||
|
|
||||||
|
|
||||||
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/"
|
|
||||||
if not os.path.exists(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
|
||||||
# return array of icons
|
icons = {}
|
||||||
imagelist = os.listdir(path)
|
filenames = os.listdir(path)
|
||||||
manaicons.clear()
|
for file in filenames:
|
||||||
for image in imagelist:
|
img = PImage.open(path + file)
|
||||||
img = PImage.open(path + image)
|
# Strip file extension
|
||||||
manaicons[os.path.splitext(image)[0]] = img
|
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):
|
def load_dummy_image(sizex, sizey):
|
||||||
@@ -320,38 +244,17 @@ def load_dummy_image(sizex, sizey):
|
|||||||
def load_card_image_online(card, sizex, sizey):
|
def load_card_image_online(card, sizex, sizey):
|
||||||
url = card.image_url
|
url = card.image_url
|
||||||
if url is None:
|
if url is None:
|
||||||
print("No Image URL provided")
|
log("No Image URL for " + card.name, LogLevel.Warning)
|
||||||
return load_dummy_image(sizex, sizey)
|
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)
|
request.urlretrieve(url, filename)
|
||||||
reload_image_cache()
|
|
||||||
return GdkPixbuf.Pixbuf.new_from_file_at_size(filename, sizex, sizey)
|
return GdkPixbuf.Pixbuf.new_from_file_at_size(filename, sizex, sizey)
|
||||||
|
|
||||||
|
|
||||||
def load_card_image(card, sizex, sizey):
|
def create_mana_icons(icon_dict, mana_string):
|
||||||
# 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):
|
|
||||||
# Convert the string to a List
|
# 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:
|
if len(list) == 0:
|
||||||
return
|
return
|
||||||
# Compute horizontal size for the final image
|
# 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
|
# Go through all entries an add the correspondent icon to the final image
|
||||||
for icon in list:
|
for icon in list:
|
||||||
xpos = poscounter * 105
|
xpos = poscounter * 105
|
||||||
loaded = manaicons.get(icon.replace("/", ""))
|
try:
|
||||||
if loaded is None:
|
loaded = icon_dict[icon]
|
||||||
print("ERROR: No icon file named \"" + icon + "\" found.")
|
except KeyError as err:
|
||||||
else:
|
log("No icon file named '" + icon + "' found.", LogLevel.Warning)
|
||||||
image.paste(loaded, (xpos, 0))
|
return
|
||||||
|
image.paste(loaded, (xpos, 0))
|
||||||
poscounter += 1
|
poscounter += 1
|
||||||
path = config.icon_cache_path + mana_string.replace("/", "") + ".png"
|
# Save Icon file
|
||||||
|
path = ICON_CACHE_PATH + "_".join(list) + ".png"
|
||||||
image.save(path)
|
image.save(path)
|
||||||
try:
|
try:
|
||||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
|
||||||
pixbuf = pixbuf.scale_simple(image.width / 5, image.height / 5, GdkPixbuf.InterpType.HYPER)
|
pixbuf = pixbuf.scale_simple(image.width / 5, image.height / 5, GdkPixbuf.InterpType.HYPER)
|
||||||
except:
|
except:
|
||||||
return
|
return
|
||||||
mana_icons_preconstructed[mana_string.replace("/", "") + ".png"] = pixbuf
|
|
||||||
return pixbuf
|
return pixbuf
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
|||||||
@@ -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("<span fgcolor=\""+color+"\">" + legality["format"] + ":" + "</span>")
|
|
||||||
text_label.set_markup("<span fgcolor=\""+color+"\">" + legality["legality"] + "</span>")
|
|
||||||
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()
|
|
||||||
38
setup.py
Executable file
@@ -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',
|
||||||
|
]
|
||||||
|
)
|
||||||