Initial Commit. Port from other project

This commit is contained in:
luxick
2017-04-12 14:47:17 +02:00
commit 66c57b5452
88 changed files with 1985 additions and 0 deletions

189
cardvault/cardlist.py Normal file
View File

@@ -0,0 +1,189 @@
import gi
import util
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf, GObject
class CardList(Gtk.ScrolledWindow):
def __init__(self, tree, with_filter):
Gtk.ScrolledWindow.__init__(self)
self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
self.set_hexpand(True)
self.set_vexpand(True)
self.filtered = with_filter
self.list = tree
self.lib = {}
# Columns are these:
# 0 Multiverse ID
# 1 Card Name
# 2 Card Supertypes (Legendary,..)
# 3 Card types (Creature, etc)
# 4 Rarity
# 5 Power
# 6 Toughness
# 7 Printings (Sets with this card in it)
# 8 Mana Cost(Form: {G}{2})
# 9 CMC
# 10 Edition
self.store = Gtk.ListStore(int, str, str, str, str, str, str, str, GdkPixbuf.Pixbuf, int, str)
if self.filtered:
self.filter = self.store.filter_new()
self.filter_and_sort = Gtk.TreeModelSort(self.filter)
self.filter_and_sort.set_sort_func(4, self.compare_rarity, None)
self.list = Gtk.TreeView(self.filter_and_sort)
else:
self.store.set_sort_func(4, self.compare_rarity, None)
self.list = Gtk.TreeView(self.store)
self.add(self.list)
self.list.set_rules_hint(True)
self.selection = self.list.get_selection()
bold_renderer = Gtk.CellRendererText(xalign=0.5, yalign=0.5)
bold_renderer.set_property("weight", 800)
text_renderer = Gtk.CellRendererText(xalign=0.5, yalign=0.5)
text_renderer.set_property("weight", 500)
image_renderer = Gtk.CellRendererPixbuf()
col_id = Gtk.TreeViewColumn(title="Multiverse ID", cell_renderer=text_renderer, text=0)
col_id.set_visible(False)
col_title = Gtk.TreeViewColumn(title="Name", cell_renderer=bold_renderer, text=1)
col_title.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
col_title.set_expand(True)
col_title.set_sort_column_id(1)
col_supertypes = Gtk.TreeViewColumn(title="Supertypes", cell_renderer=text_renderer, text=2)
col_supertypes.set_sort_column_id(2)
col_supertypes.set_visible(False)
col_types = Gtk.TreeViewColumn(title="Types", cell_renderer=text_renderer, text=3)
col_types.set_sort_column_id(3)
col_rarity = Gtk.TreeViewColumn(title="Rarity", cell_renderer=text_renderer, text=4)
col_rarity.set_sort_column_id(4)
col_power = Gtk.TreeViewColumn(title="Power", cell_renderer=text_renderer, text=5)
col_power.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
col_power.set_fixed_width(50)
col_power.set_sort_column_id(5)
col_power.set_visible(False)
col_thoughness = Gtk.TreeViewColumn(title="Toughness", cell_renderer=text_renderer, text=6)
col_thoughness.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
col_thoughness.set_fixed_width(50)
col_thoughness.set_sort_column_id(6)
col_thoughness.set_visible(False)
col_printings = Gtk.TreeViewColumn(title="Printings", cell_renderer=text_renderer, text=7)
col_printings.set_sort_column_id(7)
col_printings.set_visible(False)
col_mana = Gtk.TreeViewColumn(title="Mana Cost", cell_renderer=image_renderer, pixbuf=8)
col_mana.set_expand(False)
col_mana.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
col_mana.set_sort_column_id(9)
col_cmc = Gtk.TreeViewColumn(title="CMC", cell_renderer=text_renderer, text=9)
col_cmc.set_visible(False)
col_set_name = Gtk.TreeViewColumn(title="Edition", cell_renderer=text_renderer, text=10)
col_set_name.set_expand(False)
col_set_name.set_sort_column_id(10)
self.list.append_column(col_id)
self.list.append_column(col_title)
self.list.append_column(col_supertypes)
self.list.append_column(col_types)
self.list.append_column(col_rarity)
self.list.append_column(col_set_name)
self.list.append_column(col_power)
self.list.append_column(col_thoughness)
self.list.append_column(col_printings)
self.list.append_column(col_mana)
self.list.append_column(col_cmc)
def update(self, library):
self.store.clear()
if library is None:
return
self.lib = library
if self.filtered:
self.list.freeze_child_notify()
self.list.set_model(None)
for multiverse_id, card in library.items():
if card.multiverse_id is not None:
if card.supertypes is None:
card.supertypes = ""
item =[
card.multiverse_id,
card.name,
" ".join(card.supertypes),
" ".join(card.types),
card.rarity,
card.power,
card.toughness,
", ".join(card.printings),
util.create_mana_icons(card.mana_cost),
card.cmc,
card.set_name]
self.store.append(item)
if self.filtered:
self.list.set_model(self.filter_and_sort)
self.list.thaw_child_notify()
def update_generate(self, library, step=128):
n = 0
self.store.clear()
self.list.freeze_child_notify()
for multiverse_id, card in library.items():
if card.multiverse_id is not None:
if card.supertypes is None:
card.supertypes = ""
item =[
card.multiverse_id,
card.name,
" ".join(card.supertypes),
" ".join(card.types),
card.rarity,
card.power,
card.toughness,
", ".join(card.printings),
util.create_mana_icons(card.mana_cost),
card.cmc,
card.set_name]
self.store.append(item)
n += 1
if (n % step) == 0:
self.list.thaw_child_notify()
yield True
self.list.freeze_child_notify()
self.list.thaw_child_notify()
# stop idle_add()
yield False
def compare_rarity(self, model, row1, row2, user_data):
# Column for rarity
sort_column = 4
value1 = model.get_value(row1, sort_column)
value2 = model.get_value(row2, sort_column)
if util.rarity_dict[value1.lower()] < util.rarity_dict[value2.lower()]:
return -1
elif value1 == value2:
return 0
else:
return 1

22
cardvault/config.py Normal file
View File

@@ -0,0 +1,22 @@
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/"
# 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"

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkScrolledWindow" id="list_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<placeholder/>
</child>
</object>
</interface>

View File

@@ -0,0 +1,249 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="cardDetails">
<property name="can_focus">False</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="bigCard">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixbuf">../resources/images/dummy_315x450.png</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="margin_right">2</property>
<property name="label" translatable="yes">Card Name:</property>
<property name="justify">right</property>
<property name="xalign">0.89999997615814209</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cardName">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loading...</property>
<property name="xalign">0.10000000149011612</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.3"/>
</attributes>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="margin_right">2</property>
<property name="label" translatable="yes">Type:</property>
<property name="justify">right</property>
<property name="xalign">0.89999997615814209</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cardTypes">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loading...</property>
<property name="xalign">0.10000000149011612</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="margin_right">2</property>
<property name="label" translatable="yes">Rarity:</property>
<property name="justify">right</property>
<property name="xalign">0.89999997615814209</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cardRarity">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loading...</property>
<property name="xalign">0.10000000149011612</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="margin_right">2</property>
<property name="label" translatable="yes">Release:</property>
<property name="justify">right</property>
<property name="xalign">0.89999997615814209</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cardReleaseDate">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loading...</property>
<property name="xalign">0.10000000149011612</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="margin_right">2</property>
<property name="label" translatable="yes">Edition:</property>
<property name="justify">right</property>
<property name="xalign">0.89999997615814209</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cardSet">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loading...</property>
<property name="xalign">0.10000000149011612</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="margin_right">2</property>
<property name="label" translatable="yes">Other Printings:</property>
<property name="justify">right</property>
<property name="xalign">0.89999997615814209</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cardPrintings">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loading...</property>
<property name="xalign">0.10000000149011612</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Legalities:</property>
<property name="justify">right</property>
<property name="xalign">0.89999997615814209</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cardLegalities">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loading...</property>
<property name="xalign">0.10000000149011612</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<child>
<placeholder/>
</child>
</object>
</interface>

View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="mainWindow">
<property name="name">Card Vault</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Card Vault</property>
<property name="default_width">800</property>
<property name="default_height">600</property>
<property name="icon_name">application-x-executable</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkMenuBar" id="menuBar">
<property name="name">menuBar</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkMenuItem" id="Main">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Main</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu" id="mainMenu">
<property name="name">mainMenu</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkSeparatorMenuItem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem">
<property name="label">gtk-quit</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem" id="View">
<property name="name">View</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_View</property>
<property name="use_underline">True</property>
<child type="submenu">
<object class="GtkMenu" id="viewMenu">
<property name="name">viewMenu</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkRadioMenuItem" id="searchViewItem">
<property name="name">search</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Search</property>
<property name="use_underline">True</property>
<property name="draw_as_radio">True</property>
<signal name="activate" handler="on_view_changed" swapped="no"/>
<accelerator key="1" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
<object class="GtkRadioMenuItem" id="libraryViewItem">
<property name="name">library</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Library</property>
<property name="use_underline">True</property>
<property name="draw_as_radio">True</property>
<property name="group">searchViewItem</property>
<signal name="activate" handler="on_view_changed" swapped="no"/>
<accelerator key="2" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
<child>
<object class="GtkRadioMenuItem" id="decksViewItem">
<property name="name">decks</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Decks</property>
<property name="use_underline">True</property>
<property name="draw_as_radio">True</property>
<property name="group">searchViewItem</property>
<signal name="activate" handler="on_view_changed" swapped="no"/>
<accelerator key="3" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="contentPage">
<property name="name">contentPage</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStatusbar" id="statusBar">
<property name="name">statusBar</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_start">10</property>
<property name="margin_end">10</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
</interface>

View File

@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkGrid" id="imageLoding">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">10</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Loading Image</property>
<property name="wrap">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">end</property>
<property name="active">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
<object class="GtkGrid" id="pageNotFound">
<property name="name">Not Found</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="row_spacing">10</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">end</property>
<property name="pixel_size">100</property>
<property name="icon_name">edit-find-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Page not found</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<object class="GtkGrid" id="searchOverlay">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="row_spacing">10</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">end</property>
<property name="pixel_size">100</property>
<property name="icon_name">edit-find-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="label" translatable="yes">Search</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="2"/>
</attributes>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Use the entry on the left to search for cards</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
</object>
</interface>

313
cardvault/gui/search.glade Normal file
View File

@@ -0,0 +1,313 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkGrid" id="searchView">
<property name="name">Search</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkOverlay" id="searchResults">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="leftPane">
<property name="name">leftPane</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkBox" id="searchBox">
<property name="name">searchBox</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkEntry" id="searchEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="activate" handler="do_search_cards" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="searchButton">
<property name="label" translatable="yes">Search</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="do_search_cards" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="filterGrid">
<property name="name">filterGrid</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">2</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Filters</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Mana Color</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="manaFilterGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToggleButton" id="whiteManaButton">
<property name="name">W</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="blueManaButton">
<property name="name">U</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="redManaButton">
<property name="name">R</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="greenManaButton">
<property name="name">G</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="blackManaButton">
<property name="name">B</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="clearManaFilterButton">
<property name="label">gtk-clear</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="do_clear_mana_filter" object="manaFilterGrid" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Rarity</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="rarityCombo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="active_id">0</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Type</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="typeCombo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="active_id">0</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Edition</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="setEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="secondary_icon_stock">gtk-clear</property>
<signal name="icon-press" handler="do_clear_set_filter" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="height">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="selectionToolsBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="addRemoveButton">
<property name="label" translatable="yes">Add Card to Library</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="no_show_all">True</property>
<signal name="clicked" handler="do_add_remove_clicked" object="searchResults" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
</interface>

60
cardvault/handlers.py Normal file
View File

@@ -0,0 +1,60 @@
import gi
import config
import util
import search_funct
from mtgsdk import Card
from gi.repository import Gtk
gi.require_version('Gtk', '3.0')
class Handlers:
def __init__(self, app):
self.app = app
def do_search_cards(self, sender):
search_term = self.app.ui.get_object("searchEntry").get_text()
results = search_funct.search_cards(search_term)
card_list = self.app.ui.get_object("searchResults").get_child()
card_list.update(results)
self.app.ui.get_object("searchOverlay").set_visible(False)
def on_view_changed(self, item):
if item.get_active():
container = self.app.ui.get_object("contentPage")
new_page = self.app.pages[item.get_name()]
if self.app.current_page:
container.remove(self.app.current_page)
self.app.current_page = new_page
container.pack_start(self.app.current_page, True, True, 0)
container.show_all()
app_title = new_page.get_name() + " - " + config.application_title
self.app.ui.get_object("mainWindow").set_title(app_title)
def do_clear_mana_filter(self, mana_filter_grid):
for toggle_button in mana_filter_grid.get_children():
if isinstance(toggle_button, Gtk.ToggleButton):
toggle_button.set_active(False)
def do_clear_set_filter(self, entry, icon_pos, button):
entry.set_text("")
def do_add_remove_clicked(self, button):
pass
# Handlers for TreeViews etc. wich have been not added by Glade
def on_search_card_selected(self, tree, row_no, column):
(model, path_list) = tree.get_selection().get_selected_rows()
for path in path_list:
tree_iter = model.get_iter(path)
card_id = model.get_value(tree_iter, 0)
card_list = self.app.ui.get_object("searchResults").get_child()
card = card_list.lib[card_id]
self.app.show_card_details(card)

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
from mtgsdk.config import __version__, __pypi_packagename__, __github_username__, __github_reponame__, __endpoint__
from mtgsdk.card import Card
from mtgsdk.set import Set
from mtgsdk.supertype import Supertype
from mtgsdk.subtype import Subtype
from mtgsdk.type import Type
from mtgsdk.changelog import Changelog
from mtgsdk.restclient import RestClient
from mtgsdk.restclient import MtgException
from mtgsdk.querybuilder import QueryBuilder

67
cardvault/mtgsdk/card.py Normal file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
from mtgsdk.querybuilder import QueryBuilder
class Card(object):
RESOURCE = 'cards'
def __init__(self, response_dict={}):
self.name = response_dict.get('name')
self.layout = response_dict.get('layout')
self.mana_cost = response_dict.get('manaCost')
self.cmc = response_dict.get('cmc')
self.colors = response_dict.get('colors')
self.names = response_dict.get('names')
self.type = response_dict.get('type')
self.supertypes = response_dict.get('supertypes')
self.subtypes = response_dict.get('subtypes')
self.types = response_dict.get('types')
self.rarity = response_dict.get('rarity')
self.text = response_dict.get('text')
self.flavor = response_dict.get('flavor')
self.artist = response_dict.get('artist')
self.number = response_dict.get('number')
self.power = response_dict.get('power')
self.toughness = response_dict.get('toughness')
self.loyalty = response_dict.get('loyalty')
self.multiverse_id = response_dict.get('multiverseid')
self.variations = response_dict.get('variations')
self.watermark = response_dict.get('watermark')
self.border = response_dict.get('border')
self.timeshifted = response_dict.get('timeshifted')
self.hand = response_dict.get('hand')
self.life = response_dict.get('life')
self.release_date = response_dict.get('releaseDate')
self.starter = response_dict.get('starter')
self.printings = response_dict.get('printings')
self.original_text = response_dict.get('originalText')
self.original_type = response_dict.get('originalType')
self.source = response_dict.get('source')
self.image_url = response_dict.get('imageUrl')
self.set = response_dict.get('set')
self.set_name = response_dict.get('setName')
self.id = response_dict.get('id')
self.legalities = response_dict.get('legalities')
self.rulings = response_dict.get('rulings')
self.foreign_names = response_dict.get('foreignNames')
@staticmethod
def find(id):
return QueryBuilder(Card).find(id)
@staticmethod
def where(**kwargs):
return QueryBuilder(Card).where(**kwargs)
@staticmethod
def all():
return QueryBuilder(Card).all()

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
from mtgsdk.querybuilder import QueryBuilder
class Changelog(object):
RESOURCE = 'changelogs'
def __init__(self, response_dict={}):
self.id = response_dict.get('id')
self.version = response_dict.get('version')
self.details = response_dict.get('details')
self.release_date = response_dict.get('releaseDate')
@staticmethod
def all():
return QueryBuilder(Changelog).all()

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
__version__ = "1.2.0"
__pypi_packagename__ = "mtgsdk"
__github_username__ = "MagicTheGathering"
__github_reponame__ = "mtg-sdk-python"
__endpoint__ = "https://api.magicthegathering.io/v1"

View File

@@ -0,0 +1,100 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
from mtgsdk.restclient import RestClient
from mtgsdk.config import __endpoint__
class QueryBuilder(object):
def __init__(self, type):
self.params = {}
self.type = type
def find(self, id):
"""Get a resource by its id
Args:
id (string): Resource id
Returns:
object: Instance of the resource type
"""
url = "{}/{}/{}".format(__endpoint__, self.type.RESOURCE, id)
response = RestClient.get(url)[self.type.RESOURCE[:-1]]
return self.type(response)
def find_many(self, url, type, resource):
"""Get a list of resources
Args:
url (string): URL to invoke
type (class): Class type
resource (string): The REST Resource
Returns:
list of object: List of resource instances
"""
list = []
response = RestClient.get(url)[resource]
if len(response) > 0:
for item in response:
list.append(type(item))
return list
def where(self, **kwargs):
"""Adds a parameter to the dictionary of query parameters
Args:
**kwargs: Arbitrary keyword arguments.
Returns:
QueryBuilder: Instance of the QueryBuilder
"""
for key, value in kwargs.items():
self.params[key] = value
return self
def all(self):
"""Get all resources, automatically paging through data
Returns:
list of object: List of resource objects
"""
list = []
page = 1
fetch_all = True
url = "{}/{}".format(__endpoint__, self.type.RESOURCE)
if 'page' in self.params:
page = self.params['page']
fetch_all = False
while True:
response = RestClient.get(url, self.params)[self.type.RESOURCE]
if len(response) > 0:
for item in response:
list.append(self.type(item))
if not fetch_all:
break
else:
page += 1
self.where(page=page)
else:
break
return list
def array(self):
"""Get all resources and return the result as an array
Returns:
array of str: Array of resources
"""
url = "{}/{}".format(__endpoint__, self.type.RESOURCE)
return RestClient.get(url, self.params)[self.type.RESOURCE]

View File

@@ -0,0 +1,47 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
import json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
from urllib.parse import urlencode
class RestClient(object):
@staticmethod
def get(url, params={}):
"""Invoke an HTTP GET request on a url
Args:
url (string): URL endpoint to request
params (dict): Dictionary of url parameters
Returns:
dict: JSON response as a dictionary
"""
request_url = url
if len(params) > 0:
request_url = "{}?{}".format(url, urlencode(params))
try:
req = Request(request_url, headers={'User-Agent': 'Mozilla/5.0'})
response = json.loads(urlopen(req).read().decode("utf-8"))
return response
except HTTPError as err:
raise MtgException(err.read())
class MtgException(Exception):
def __init__(self, description):
self.description = description
def __str__(self):
return self.description

49
cardvault/mtgsdk/set.py Normal file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
from mtgsdk.querybuilder import QueryBuilder
from mtgsdk.config import __endpoint__
from mtgsdk.card import Card
class Set(object):
RESOURCE = 'sets'
def __init__(self, response_dict={}):
self.code = response_dict.get('code')
self.name = response_dict.get('name')
self.type = response_dict.get('type')
self.border = response_dict.get('border')
self.mkm_id = response_dict.get('mkm_id')
self.mkm_name = response_dict.get('mkm_name')
self.release_date = response_dict.get('releaseDate')
self.gatherer_code = response_dict.get('gathererCode')
self.magic_cards_info_code = response_dict.get('magicCardsInfoCode')
self.booster = response_dict.get('booster')
self.old_code = response_dict.get('oldCode')
self.block = response_dict.get('block')
self.online_only = response_dict.get('onlineOnly')
@staticmethod
def find(id):
return QueryBuilder(Set).find(id)
@staticmethod
def where(**kwargs):
return QueryBuilder(Set).where(**kwargs)
@staticmethod
def all():
return QueryBuilder(Set).all()
@staticmethod
def generate_booster(code):
url = "{}/{}/{}/booster".format(__endpoint__, Set.RESOURCE, code)
return QueryBuilder(Set).find_many(url, Card, Card.RESOURCE)

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
from mtgsdk.querybuilder import QueryBuilder
class Subtype(object):
RESOURCE = 'subtypes'
@staticmethod
def all():
return QueryBuilder(Subtype).array()

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
from mtgsdk.querybuilder import QueryBuilder
class Supertype(object):
RESOURCE = 'supertypes'
@staticmethod
def all():
return QueryBuilder(Supertype).array()

19
cardvault/mtgsdk/type.py Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of mtgsdk.
# https://github.com/MagicTheGathering/mtg-sdk-python
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2016, Andrew Backes <backes.andrew@gmail.com>
from mtgsdk.querybuilder import QueryBuilder
class Type(object):
RESOURCE = 'types'
@staticmethod
def all():
return QueryBuilder(Type).array()

11
cardvault/network.py Normal file
View File

@@ -0,0 +1,11 @@
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

135
cardvault/search_funct.py Normal file
View File

@@ -0,0 +1,135 @@
import gi
import util
import config
import cardlist
import handlers
from gi.repository import Gtk
from mtgsdk import Card
from urllib.error import URLError, HTTPError
gi.require_version('Gtk', '3.0')
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)
# set auto completion for filter entry
_init_set_entry(app.ui.get_object("setEntry"))
# Fill rarity box
_init_combo_box(app.ui.get_object("rarityCombo"), util.rarity_dict.keys())
# Fill type box
_init_combo_box(app.ui.get_object("typeCombo"), util.card_types)
# Create Model for search results
_init_results_tree(app.ui.get_object("cardTree"), app)
def search_cards(term):
# Load filters from UI
filters = _get_filters(util.app)
# Load card info from internet
try:
cards = Card.where(name=term) \
.where(colorIdentity=filters["mana"]) \
.where(types=filters["type"]) \
.where(set=filters["set"]) \
.where(rarity=filters["rarity"]) \
.where(pageSize=50) \
.where(page=1).all()
except (URLError, HTTPError) as err:
print("Error connecting to the internet")
return
if len(cards) == 0:
# TODO UI show no cards found
return
# Remove duplicate entries
if config.show_from_all_sets is False:
cards = _remove_duplicates(cards)
# Pack results in a dictionary
lib = {}
for card in cards:
lib[card.multiverse_id] = card
return lib
def _init_results_tree(tree_view, app):
overlay = app.ui.get_object("searchResults")
card_list = cardlist.CardList(tree_view, False)
card_list.set_name("resultsScroller")
card_list.list.connect("row-activated", app.handlers.on_search_card_selected)
overlay.add(card_list)
overlay.add_overlay(app.ui.get_object("searchOverlay"))
overlay.show_all()
def _init_combo_box(combo, list):
model = Gtk.ListStore(str)
model.append(["All"])
for entry in list:
model.append([entry.title()])
combo.set_model(model)
cell = Gtk.CellRendererText()
combo.pack_start(cell, True)
combo.add_attribute(cell, "text", 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()
for set in util.set_list:
if set.name == name:
output["set"] = set.code
return output
def _remove_duplicates(cards):
unique_cards = []
unique_names = []
# Reverse cardlist so we get the version with the most modern art
for card in reversed(cards):
if card.name not in unique_names:
unique_names.append(card.name)
unique_cards.append(card)
return unique_cards
def _get_combo_value(combo):
tree_iter = combo.get_active_iter()
value = combo.get_model().get_value(tree_iter, 0)
return value.replace("All", "")
def _init_mana_buttons(button_list):
for button in button_list:
image = Gtk.Image.new_from_pixbuf(util.create_mana_icons("{" + button.get_name() + "}"))
button.set_image(image)
def _init_set_entry(entry):
set_store = Gtk.ListStore(str, str)
for set in util.set_list:
set_store.append([set.name, set.code])
completer = Gtk.EntryCompletion()
completer.set_model(set_store)
completer.set_text_column(0)
entry.set_completion(completer)

273
cardvault/util.py Normal file
View File

@@ -0,0 +1,273 @@
import os
import datetime
import gi
import re
import config
import network
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')
# Locally stored images for faster loading times
imagecache = {}
manaicons = {}
set_list = []
# Card library object
library = {}
# Dictionary for tagged cards
tags = {}
status_bar = None
app = None
unsaved_changes = False
rarity_dict = {
"special": 0,
"common": 1,
"uncommon": 2,
"rare": 3,
"mythic rare": 4
}
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:
try:
pickle.dump(library, open(dialog.get_filename(), 'wb'))
except:
show_message("Error", "Error while saving library to disk")
app.push_status("Library exported to \"" + dialog.get_filename() + "\"")
print("Library exported to \"", dialog.get_filename() + "\"")
dialog.destroy()
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:
imported = pickle.load(open(dialog.get_filename(), 'rb'))
library.clear()
for id, card in imported.items():
library[id] = card
save_library()
app.push_status("Library imported")
print("Library imported")
dialog.destroy()
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
try:
pickle.dump(library, open(lib_path, 'wb'))
pickle.dump(tags, open(tag_path, 'wb'))
except:
show_message("Error", "Error while saving library to disk")
return
global unsaved_changes
unsaved_changes = False
app.push_status("Library saved.")
def load_library():
lib_path = config.cache_path + "library"
library.clear()
if os.path.isfile(lib_path):
# Deserialize using pickle
try:
library_loaded = pickle.load(open(lib_path, 'rb'))
for id, card in library_loaded.items():
library[id] = card
except :
show_message("Error", "Error while loading library from disk")
else:
save_library()
print("No library file found, created new one")
def load_tags():
tag_path = config.cache_path + "tags"
tags.clear()
if not os.path.isfile(tag_path):
save_library()
print("No tags file found, created new one")
try:
tags_loaded = pickle.load(open(tag_path, 'rb'))
for tag, ids in tags_loaded.items():
tags[tag] = ids
except:
show_message("Error", "Error while loading library from disk")
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)
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))
# endregion
def add_tag(tag):
tags[tag] = {}
app.push_status("Added Tag \"" + tag + "\"")
global unsaved_changes
unsaved_changes = True
def remove_tag(tag):
tags[tag] = None
app.push_status("Removed Tag \"" + tag + "\"")
global unsaved_changes
unsaved_changes = True
def add_card_to_lib(card):
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.QUESTION,
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):
print("ERROR: Directory for mana icons not found")
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
def load_dummy_image(sizex, sizey):
return GdkPixbuf.Pixbuf.new_from_file_at_size(os.path.dirname(__file__)
+ '/resources/images/dummy.jpg', sizex, sizey)
def load_card_image_online(card, sizex, sizey):
url = card.image_url
if url is None:
print("No Image URL provided")
return load_dummy_image(sizex, sizey)
filename = config.image_cache_path + card.multiverse_id.__str__() + ".PNG"
print("Loading image for " + card.name + "from: " + url)
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 create_mana_icons(mana_string):
# Convert the string to a List
list = re.findall("{(.*?)}", str(mana_string))
if len(list) == 0:
return
# Compute horizontal size for the final image
imagesize = len(list) * 105
image = PImage.new("RGBA", (imagesize, 105))
# incerment for each position of an icon (Workaround: 2 or more of the same icon will be rendered in the same poisition)
poscounter = 0
# 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))
poscounter += 1
filename = "icon.png"
path = config.cache_path + filename
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
# os.remove(path)
return pixbuf

61
cardvault/window.py Normal file
View File

@@ -0,0 +1,61 @@
import config
import handlers
import util
import search_funct
import gi
from gi.repository import Gtk
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/detailswindow.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": not_found,
"decks": not_found
}
# Load local image Data
util.reload_image_cache()
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)
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):
print("Show", card.name)
pass
win = MainWindow()
Gtk.main()